Clearing more leftovers from cloud backup.

This commit is contained in:
Rodrigo Damazio
2010-08-24 20:07:12 -03:00
parent 798637d465
commit 68a9f1bc46
3 changed files with 0 additions and 429 deletions
@@ -1,53 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.backup;
import android.app.backup.BackupDataInput;
import java.io.IOException;
import java.io.InputStream;
/**
* Input stream which reads from backup data.
* This is exactly the same as {@link android.app.backup.BackupDataInputStream},
* but for some odd reason Android doesn't want us instantiating that one.
*
* @author Rodrigo Damazio
*/
class BackupDataInputStream extends InputStream {
private final BackupDataInput data;
private final byte[] oneByte = new byte[1];
public BackupDataInputStream(BackupDataInput data) {
this.data = data;
}
@Override
public int read() throws IOException {
data.readEntityData(oneByte, 0, 1);
return oneByte[0];
}
@Override
public int read(byte[] b) throws IOException {
return data.readEntityData(b, 0, b.length);
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
return data.readEntityData(b, offset, length);
}
}
@@ -1,215 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.MyTracksConstants;
import com.google.android.apps.mytracks.content.Track;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* Manager responsible for reading and writing the backup state.
*
* @author Rodrigo Damazio
*/
class BackupStateManager {
private static final byte BACKUP_VERSION = 1;
/**
* The state of a single track.
*/
public static class TrackState {
public final long trackId;
public final String name;
public final String description;
public final String category;
TrackState(long trackId, String name, String description, String category) {
this.trackId = trackId;
this.name = name;
this.description = description;
this.category = category;
}
/**
* Checks and returns whether this state is representative of the given
* track at its current state.
*/
public boolean represents(Track track) {
return trackId == track.getId() &&
name.equals(track.getName()) &&
description.equals(track.getDescription()) &&
category.equals(track.getCategory());
}
}
// File descriptors to read/write state from/to
private final ParcelFileDescriptor oldState;
private final ParcelFileDescriptor newState;
// Actual state data read from/to be written to the descriptors above
private Map<Long, TrackState> oldTracks;
private List<TrackState> newTrackState;
public BackupStateManager(ParcelFileDescriptor oldState, ParcelFileDescriptor newState) {
this.oldState = oldState;
this.newState = newState;
}
/**
* Reads the old track state.
*
* If any errors occur while reading, this will return a partial or empty map.
*
* @return a map of track ID to its state
*/
public Map<Long, TrackState> getOldTrackState() {
if (oldTracks != null) {
return oldTracks;
}
oldTracks = new TreeMap<Long, TrackState>();
if (!hasOldState()) {
return oldTracks;
}
try {
InputStream stateInputStream = openStateInput();
DataInputStream stateInput = new DataInputStream(stateInputStream);
// Read the version from the header
if (stateInput.readByte() != BACKUP_VERSION) {
throw new IllegalStateException("Bad backup version");
}
int previousNumberOfTracks = stateInput.readInt();
for (int i = 0; i < previousNumberOfTracks; i++) {
TrackState oldTrack = readTrackState(stateInput);
oldTracks.put(oldTrack.trackId, oldTrack);
}
} catch (IOException e) {
// If we fail to read, return whatever we got - this only means
// we'll be backing up more than we should.
Log.e(MyTracksConstants.TAG, "Unable to read old state", e);
}
return oldTracks;
}
/**
* Returns whether we have a known old state.
*/
protected boolean hasOldState() {
return oldState != null;
}
/**
* Opens the old state and returns a stream to read it.
*/
protected InputStream openStateInput() {
return new FileInputStream(oldState.getFileDescriptor());
}
/**
* Opens the new state and returns a stream to write to it.
*/
protected OutputStream openStateOutput() {
return new FileOutputStream(newState.getFileDescriptor());
}
/**
* Reads the state of a single track.
*
* @param stateInput the stream to read from
* @return the state read
* @throws IOException if reading fails
*/
private TrackState readTrackState(DataInputStream stateInput) throws IOException {
long trackId = stateInput.readLong();
String name = stateInput.readUTF();
String desc = stateInput.readUTF();
String category = stateInput.readUTF();
return new TrackState(trackId, name, desc, category);
}
/**
* Adds a track to the current/new state.
* Please notice that the state is not actually written until
* {@link #flushNewState} is called.
*/
public void addTrackState(Track track) {
ensureTrackState();
newTrackState.add(new TrackState(track.getId(), track.getName(),
track.getDescription(), track.getCategory()));
}
/**
* Actually writes out the new state to its output.
*
* @throws IOException if there are errors while writing
*/
public void flushNewState() throws IOException {
ensureTrackState();
OutputStream stateOutputStream = openStateOutput();
DataOutputStream stateOutput = new DataOutputStream(stateOutputStream);
stateOutput.writeByte(BACKUP_VERSION);
stateOutput.writeInt(newTrackState.size());
for (TrackState track : newTrackState) {
writeTrackState(stateOutput, track);
}
stateOutput.flush();
}
/**
* Ensures the track state buffer exists.
*/
private void ensureTrackState() {
if (newTrackState == null) {
newTrackState = new ArrayList<TrackState>();
}
}
/**
* Writes the state of a single track.
*
* @param stateOutput the stream to write to
* @param track the track state to write
* @throws IOException if there are errors while writing
*/
private void writeTrackState(DataOutputStream stateOutput, TrackState track) throws IOException {
stateOutput.writeLong(track.trackId);
stateOutput.writeUTF(track.name);
stateOutput.writeUTF(track.description);
stateOutput.writeUTF(track.category);
}
}
@@ -1,161 +0,0 @@
package com.google.android.apps.mytracks.io.backup;
import com.google.android.apps.mytracks.content.Track;
import com.google.android.apps.mytracks.io.backup.BackupStateManager.TrackState;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import junit.framework.TestCase;
/**
* Tests for {@link BackupStateManager}.
*
* @author Rodrigo Damazio
*/
public class BackupStateManagerTest extends TestCase {
/**
* Testable version of the state manager which doesn't use actual files.
*/
private static class TestableBackupStateManager extends BackupStateManager {
private final byte[] oldStateData;
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public TestableBackupStateManager(byte[] oldStateData) {
super(null, null);
this.oldStateData = oldStateData;
}
@Override
protected OutputStream openStateOutput() {
return outputStream;
}
public ByteArrayOutputStream getOutputStream() {
return outputStream;
}
@Override
protected InputStream openStateInput() {
if (!hasOldState()) {
throw new IllegalStateException("Don't have old state");
}
return new ByteArrayInputStream(oldStateData);
}
@Override
protected boolean hasOldState() {
return oldStateData != null;
}
}
public void testTrackStateRepresents() {
TrackState state = new TrackState(123L, "name", "desc", "cat");
Track stateTrack = makeTrack(123L, "name", "desc", "cat");
assertTrue(state.represents(stateTrack));
}
public void testTrackStateRepresents_wrongId() {
TrackState state = new TrackState(123L, "name", "desc", "cat");
Track stateTrack = makeTrack(456L, "name", "desc", "cat");
assertFalse(state.represents(stateTrack));
}
public void testTrackStateRepresents_wrongName() {
TrackState state = new TrackState(123L, "name", "desc", "cat");
Track stateTrack = makeTrack(123L, "name2", "desc", "cat");
assertFalse(state.represents(stateTrack));
}
public void testTrackStateRepresents_wrongDescription() {
TrackState state = new TrackState(123L, "name", "desc", "cat");
Track stateTrack = makeTrack(123L, "name", "desc2", "cat");
assertFalse(state.represents(stateTrack));
}
public void testTrackStateRepresents_wrongCategory() {
TrackState state = new TrackState(123L, "name", "desc", "cat");
Track stateTrack = makeTrack(123L, "name", "desc", "cat2");
assertFalse(state.represents(stateTrack));
}
public void testGetOldTrackState_empty() {
TestableBackupStateManager stateManager = new TestableBackupStateManager(null);
Map<Long, TrackState> oldState = stateManager.getOldTrackState();
assertTrue(oldState.isEmpty());
}
public void testWriteReadState() throws Exception {
// Initially create a state manager which knows no state
TestableBackupStateManager stateManager = new TestableBackupStateManager(null);
// Add some state to it
stateManager.addTrackState(makeTrack(123L, "Name1"));
stateManager.addTrackState(makeTrack(456L, "Name2"));
stateManager.flushNewState();
// Get the result
byte[] stateData = stateManager.getOutputStream().toByteArray();
// Now create a state manager with the previous serialized state
stateManager = new TestableBackupStateManager(stateData);
// Read its old state and verify it
Map<Long, TrackState> oldState = stateManager.getOldTrackState();
assertEquals(oldState.toString(), 2, oldState.size());
assertTrue(oldState.containsKey(123L));
assertTrue(oldState.containsKey(456L));
assertStateEquals(123L, "Name1", oldState.get(123L));
assertStateEquals(456L, "Name2", oldState.get(456L));
// Write a new, different state
stateManager.addTrackState(makeTrack(123L, "Name1"));
stateManager.addTrackState(makeTrack(987L, "Name3"));
stateManager.flushNewState();
// Get the new result
stateData = stateManager.getOutputStream().toByteArray();
// Create another state manager to read this last state
stateManager = new TestableBackupStateManager(stateData);
// Read and verify it
oldState = stateManager.getOldTrackState();
assertEquals(oldState.toString(), 2, oldState.size());
assertTrue(oldState.containsKey(123L));
assertTrue(oldState.containsKey(987L));
assertStateEquals(123L, "Name1", oldState.get(123L));
assertStateEquals(987L, "Name3", oldState.get(987L));
}
private Track makeTrack(long id, String name) {
return makeTrack(id, name, "Description for " + name, "Category for " + name);
}
private Track makeTrack(long id, String name, String description, String category) {
Track track = new Track();
track.setId(id);
track.setName(name);
track.setDescription(description);
track.setCategory(category);
return track;
}
private void assertStateEquals(long id, String name, TrackState state) {
assertEquals(id, state.trackId);
assertEquals(name, state.name);
assertEquals("Description for " + name, state.description);
assertEquals("Category for " + name, state.category);
}
}