Merge "updater_sample: Improve UpdateConfig" am: af5958818a
am: 0b54d77832
Change-Id: I056e1f96f6c444dc0ecfd5f3d7a2f34a0f04f50d
diff --git a/updater_sample/Android.mk b/updater_sample/Android.mk
index 2786de4..056ad66 100644
--- a/updater_sample/Android.mk
+++ b/updater_sample/Android.mk
@@ -26,6 +26,10 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES += guava
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
include $(BUILD_PACKAGE)
# Use the following include to make our test apk.
diff --git a/updater_sample/src/com/example/android/systemupdatersample/UpdateConfig.java b/updater_sample/src/com/example/android/systemupdatersample/UpdateConfig.java
index cbee18f..23510e4 100644
--- a/updater_sample/src/com/example/android/systemupdatersample/UpdateConfig.java
+++ b/updater_sample/src/com/example/android/systemupdatersample/UpdateConfig.java
@@ -19,6 +19,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -26,13 +27,13 @@
import java.io.Serializable;
/**
- * UpdateConfig describes an update. It will be parsed from JSON, which is intended to
+ * An update description. It will be parsed from JSON, which is intended to
* be sent from server to the update app, but in this sample app it will be stored on the device.
*/
public class UpdateConfig implements Parcelable {
- public static final int TYPE_NON_STREAMING = 0;
- public static final int TYPE_STREAMING = 1;
+ public static final int AB_INSTALL_TYPE_NON_STREAMING = 0;
+ public static final int AB_INSTALL_TYPE_STREAMING = 1;
public static final Parcelable.Creator<UpdateConfig> CREATOR =
new Parcelable.Creator<UpdateConfig>() {
@@ -54,18 +55,30 @@
JSONObject o = new JSONObject(json);
c.mName = o.getString("name");
c.mUrl = o.getString("url");
- if (TYPE_NON_STREAMING_JSON.equals(o.getString("type"))) {
- c.mInstallType = TYPE_NON_STREAMING;
- } else if (TYPE_STREAMING_JSON.equals(o.getString("type"))) {
- c.mInstallType = TYPE_STREAMING;
- } else {
- throw new JSONException("Invalid type, expected either "
- + "NON_STREAMING or STREAMING, got " + o.getString("type"));
+ switch (o.getString("ab_install_type")) {
+ case AB_INSTALL_TYPE_NON_STREAMING_JSON:
+ c.mAbInstallType = AB_INSTALL_TYPE_NON_STREAMING;
+ break;
+ case AB_INSTALL_TYPE_STREAMING_JSON:
+ c.mAbInstallType = AB_INSTALL_TYPE_STREAMING;
+ break;
+ default:
+ throw new JSONException("Invalid type, expected either "
+ + "NON_STREAMING or STREAMING, got " + o.getString("ab_install_type"));
}
- if (o.has("metadata")) {
- c.mMetadata = new Metadata(
- o.getJSONObject("metadata").getInt("offset"),
- o.getJSONObject("metadata").getInt("size"));
+ if (c.mAbInstallType == AB_INSTALL_TYPE_STREAMING) {
+ JSONObject meta = o.getJSONObject("ab_streaming_metadata");
+ JSONArray propertyFilesJson = meta.getJSONArray("property_files");
+ InnerFile[] propertyFiles =
+ new InnerFile[propertyFilesJson.length()];
+ for (int i = 0; i < propertyFilesJson.length(); i++) {
+ JSONObject p = propertyFilesJson.getJSONObject(i);
+ propertyFiles[i] = new InnerFile(
+ p.getString("filename"),
+ p.getLong("offset"),
+ p.getLong("size"));
+ }
+ c.mAbStreamingMetadata = new StreamingMetadata(propertyFiles);
}
c.mRawJson = json;
return c;
@@ -74,8 +87,8 @@
/**
* these strings are represent types in JSON config files
*/
- private static final String TYPE_NON_STREAMING_JSON = "NON_STREAMING";
- private static final String TYPE_STREAMING_JSON = "STREAMING";
+ private static final String AB_INSTALL_TYPE_NON_STREAMING_JSON = "NON_STREAMING";
+ private static final String AB_INSTALL_TYPE_STREAMING_JSON = "STREAMING";
/** name will be visible on UI */
private String mName;
@@ -84,10 +97,10 @@
private String mUrl;
/** non-streaming (first saves locally) OR streaming (on the fly) */
- private int mInstallType;
+ private int mAbInstallType;
/** metadata is required only for streaming update */
- private Metadata mMetadata;
+ private StreamingMetadata mAbStreamingMetadata;
private String mRawJson;
@@ -97,15 +110,15 @@
protected UpdateConfig(Parcel in) {
this.mName = in.readString();
this.mUrl = in.readString();
- this.mInstallType = in.readInt();
- this.mMetadata = (Metadata) in.readSerializable();
+ this.mAbInstallType = in.readInt();
+ this.mAbStreamingMetadata = (StreamingMetadata) in.readSerializable();
this.mRawJson = in.readString();
}
public UpdateConfig(String name, String url, int installType) {
this.mName = name;
this.mUrl = url;
- this.mInstallType = installType;
+ this.mAbInstallType = installType;
}
public String getName() {
@@ -121,16 +134,18 @@
}
public int getInstallType() {
- return mInstallType;
+ return mAbInstallType;
+ }
+
+ public StreamingMetadata getStreamingMetadata() {
+ return mAbStreamingMetadata;
}
/**
- * "url" must be the file located on the device.
- *
* @return File object for given url
*/
public File getUpdatePackageFile() {
- if (mInstallType != TYPE_NON_STREAMING) {
+ if (mAbInstallType != AB_INSTALL_TYPE_NON_STREAMING) {
throw new RuntimeException("Expected non-streaming install type");
}
if (!mUrl.startsWith("file://")) {
@@ -148,29 +163,60 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName);
dest.writeString(mUrl);
- dest.writeInt(mInstallType);
- dest.writeSerializable(mMetadata);
+ dest.writeInt(mAbInstallType);
+ dest.writeSerializable(mAbStreamingMetadata);
dest.writeString(mRawJson);
}
/**
- * Metadata for STREAMING update
+ * Metadata for streaming A/B update.
*/
- public static class Metadata implements Serializable {
+ public static class StreamingMetadata implements Serializable {
private static final long serialVersionUID = 31042L;
/** defines beginning of update data in archive */
+ private InnerFile[] mPropertyFiles;
+
+ public StreamingMetadata() {
+ mPropertyFiles = new InnerFile[0];
+ }
+
+ public StreamingMetadata(InnerFile[] propertyFiles) {
+ this.mPropertyFiles = propertyFiles;
+ }
+
+ public InnerFile[] getPropertyFiles() {
+ return mPropertyFiles;
+ }
+ }
+
+ /**
+ * Description of a file in an OTA package zip file.
+ */
+ public static class InnerFile implements Serializable {
+
+ private static final long serialVersionUID = 31043L;
+
+ /** filename in an archive */
+ private String mFilename;
+
+ /** defines beginning of update data in archive */
private long mOffset;
/** size of the update data in archive */
private long mSize;
- public Metadata(long offset, long size) {
+ public InnerFile(String filename, long offset, long size) {
+ this.mFilename = filename;
this.mOffset = offset;
this.mSize = size;
}
+ public String getFilename() {
+ return mFilename;
+ }
+
public long getOffset() {
return mOffset;
}
@@ -178,6 +224,7 @@
public long getSize() {
return mSize;
}
+
}
}
diff --git a/updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java b/updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java
index 72e1b24..8507a9e 100644
--- a/updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java
+++ b/updater_sample/src/com/example/android/systemupdatersample/ui/MainActivity.java
@@ -260,7 +260,7 @@
* Applies the given update
*/
private void applyUpdate(UpdateConfig config) {
- if (config.getInstallType() == UpdateConfig.TYPE_NON_STREAMING) {
+ if (config.getInstallType() == UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING) {
AbNonStreamingUpdate update = new AbNonStreamingUpdate(mUpdateEngine, config);
try {
update.execute();
diff --git a/updater_sample/src/com/example/android/systemupdatersample/util/UpdateConfigs.java b/updater_sample/src/com/example/android/systemupdatersample/util/UpdateConfigs.java
index 089f8b2..71d4df8 100644
--- a/updater_sample/src/com/example/android/systemupdatersample/util/UpdateConfigs.java
+++ b/updater_sample/src/com/example/android/systemupdatersample/util/UpdateConfigs.java
@@ -17,6 +17,7 @@
package com.example.android.systemupdatersample.util;
import android.content.Context;
+import android.util.Log;
import com.example.android.systemupdatersample.UpdateConfig;
@@ -70,6 +71,7 @@
StandardCharsets.UTF_8);
configs.add(UpdateConfig.fromJson(json));
} catch (Exception e) {
+ Log.e("UpdateConfigs", "Can't read/parse config file " + f.getName(), e);
throw new RuntimeException(
"Can't read/parse config file " + f.getName(), e);
}
diff --git a/updater_sample/tests/Android.mk b/updater_sample/tests/Android.mk
index 83082cd..a1a4664 100644
--- a/updater_sample/tests/Android.mk
+++ b/updater_sample/tests/Android.mk
@@ -22,11 +22,15 @@
LOCAL_MODULE_TAGS := tests
LOCAL_JAVA_LIBRARIES := \
android.test.base.stubs \
- android.test.runner.stubs
+ android.test.runner.stubs \
+ guava \
+ mockito-target-minus-junit4
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_INSTRUMENTATION_FOR := SystemUpdaterSample
LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
include $(BUILD_PACKAGE)
diff --git a/updater_sample/tests/AndroidManifest.xml b/updater_sample/tests/AndroidManifest.xml
index 2392bb3..76af5f1 100644
--- a/updater_sample/tests/AndroidManifest.xml
+++ b/updater_sample/tests/AndroidManifest.xml
@@ -17,6 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.systemupdatersample.tests">
+ <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="27" />
+
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
which is needed when building test cases. -->
diff --git a/updater_sample/tests/res/raw/update_config_stream_001.json b/updater_sample/tests/res/raw/update_config_stream_001.json
index 965f737..a9afd33 100644
--- a/updater_sample/tests/res/raw/update_config_stream_001.json
+++ b/updater_sample/tests/res/raw/update_config_stream_001.json
@@ -1,8 +1,8 @@
{
"name": "streaming-001",
"url": "http://foo.bar/update.zip",
- "type": "STREAMING",
- "streaming_metadata": {
+ "ab_install_type": "STREAMING",
+ "ab_streaming_metadata": {
"property_files": [
{
"filename": "payload.bin",
diff --git a/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java b/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java
index 8715371..0975e76 100644
--- a/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java
+++ b/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java
@@ -19,14 +19,23 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import com.example.android.systemupdatersample.tests.R;
+import com.google.common.io.CharStreams;
+
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
/**
* Tests for {@link UpdateConfig}
*/
@@ -36,27 +45,48 @@
private static final String JSON_NON_STREAMING =
"{\"name\": \"vip update\", \"url\": \"file:///builds/a.zip\", "
- + " \"type\": \"NON_STREAMING\"}";
-
- private static final String JSON_STREAMING =
- "{\"name\": \"vip update 2\", \"url\": \"http://foo.bar/a.zip\", "
- + "\"type\": \"STREAMING\"}";
+ + " \"ab_install_type\": \"NON_STREAMING\"}";
@Rule
public final ExpectedException thrown = ExpectedException.none();
+ private Context mContext;
+ private Context mTargetContext;
+ private String mJsonStreaming001;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mTargetContext = InstrumentationRegistry.getTargetContext();
+ mJsonStreaming001 = readResource(R.raw.update_config_stream_001);
+ }
+
@Test
- public void fromJson_parsesJsonConfigWithoutMetadata() throws Exception {
+ public void fromJson_parsesNonStreaming() throws Exception {
UpdateConfig config = UpdateConfig.fromJson(JSON_NON_STREAMING);
assertEquals("name is parsed", "vip update", config.getName());
assertEquals("stores raw json", JSON_NON_STREAMING, config.getRawJson());
- assertSame("type is parsed", UpdateConfig.TYPE_NON_STREAMING, config.getInstallType());
+ assertSame("type is parsed",
+ UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING,
+ config.getInstallType());
assertEquals("url is parsed", "file:///builds/a.zip", config.getUrl());
}
@Test
+ public void fromJson_parsesStreaming() throws Exception {
+ UpdateConfig config = UpdateConfig.fromJson(mJsonStreaming001);
+ assertEquals("streaming-001", config.getName());
+ assertEquals("http://foo.bar/update.zip", config.getUrl());
+ assertSame(UpdateConfig.AB_INSTALL_TYPE_STREAMING, config.getInstallType());
+ assertEquals("payload.bin",
+ config.getStreamingMetadata().getPropertyFiles()[0].getFilename());
+ assertEquals(195, config.getStreamingMetadata().getPropertyFiles()[0].getOffset());
+ assertEquals(8, config.getStreamingMetadata().getPropertyFiles()[0].getSize());
+ }
+
+ @Test
public void getUpdatePackageFile_throwsErrorIfStreaming() throws Exception {
- UpdateConfig config = UpdateConfig.fromJson(JSON_STREAMING);
+ UpdateConfig config = UpdateConfig.fromJson(mJsonStreaming001);
thrown.expect(RuntimeException.class);
config.getUpdatePackageFile();
}
@@ -64,7 +94,7 @@
@Test
public void getUpdatePackageFile_throwsErrorIfNotAFile() throws Exception {
String json = "{\"name\": \"upd\", \"url\": \"http://foo.bar\","
- + " \"type\": \"NON_STREAMING\"}";
+ + " \"ab_install_type\": \"NON_STREAMING\"}";
UpdateConfig config = UpdateConfig.fromJson(json);
thrown.expect(RuntimeException.class);
config.getUpdatePackageFile();
@@ -73,7 +103,11 @@
@Test
public void getUpdatePackageFile_works() throws Exception {
UpdateConfig c = UpdateConfig.fromJson(JSON_NON_STREAMING);
- assertEquals("correct path", "/builds/a.zip", c.getUpdatePackageFile().getAbsolutePath());
+ assertEquals("/builds/a.zip", c.getUpdatePackageFile().getAbsolutePath());
}
+ private String readResource(int id) throws IOException {
+ return CharStreams.toString(new InputStreamReader(
+ mContext.getResources().openRawResource(id)));
+ }
}
diff --git a/updater_sample/tests/src/com/example/android/systemupdatersample/util/UpdateConfigsTest.java b/updater_sample/tests/src/com/example/android/systemupdatersample/util/UpdateConfigsTest.java
index 4aa8c64..c85698c 100644
--- a/updater_sample/tests/src/com/example/android/systemupdatersample/util/UpdateConfigsTest.java
+++ b/updater_sample/tests/src/com/example/android/systemupdatersample/util/UpdateConfigsTest.java
@@ -54,8 +54,8 @@
@Test
public void configsToNames_extractsNames() {
List<UpdateConfig> configs = Arrays.asList(
- new UpdateConfig("blah", "http://", UpdateConfig.TYPE_NON_STREAMING),
- new UpdateConfig("blah 2", "http://", UpdateConfig.TYPE_STREAMING)
+ new UpdateConfig("blah", "http://", UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING),
+ new UpdateConfig("blah 2", "http://", UpdateConfig.AB_INSTALL_TYPE_STREAMING)
);
String[] names = UpdateConfigs.configsToNames(configs);
assertArrayEquals(new String[] {"blah", "blah 2"}, names);