Merge "Add PrepareUpdateService."
This commit is contained in:
commit
2e33cbeb20
7 changed files with 110 additions and 113 deletions
|
@ -33,7 +33,7 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<service android:name=".services.PrepareStreamingService"/>
|
<service android:name=".services.PrepareUpdateService"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -220,7 +220,7 @@ privileged system app, so it's granted the required permissions to access
|
||||||
- [x] Add Sample app update state (separate from update_engine status)
|
- [x] Add Sample app update state (separate from update_engine status)
|
||||||
- [x] Add smart update completion detection using onStatusUpdate
|
- [x] Add smart update completion detection using onStatusUpdate
|
||||||
- [x] Add pause/resume demo
|
- [x] Add pause/resume demo
|
||||||
- [x] Verify system partition checksum for package
|
- [-] Verify system partition checksum for package
|
||||||
|
|
||||||
|
|
||||||
## Running tests
|
## Running tests
|
||||||
|
@ -235,8 +235,8 @@ privileged system app, so it's granted the required permissions to access
|
||||||
5. Run a test file
|
5. Run a test file
|
||||||
```
|
```
|
||||||
adb shell am instrument \
|
adb shell am instrument \
|
||||||
-w com.example.android.systemupdatersample.tests/android.support.test.runner.AndroidJUnitRunner \
|
-w -e class com.example.android.systemupdatersample.UpdateManagerTest#applyUpdate_appliesPayloadToUpdateEngine \
|
||||||
-c com.example.android.systemupdatersample.util.PayloadSpecsTest
|
com.example.android.systemupdatersample.tests/android.support.test.runner.AndroidJUnitRunner
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,19 +17,18 @@
|
||||||
package com.example.android.systemupdatersample;
|
package com.example.android.systemupdatersample;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.UpdateEngine;
|
import android.os.UpdateEngine;
|
||||||
import android.os.UpdateEngineCallback;
|
import android.os.UpdateEngineCallback;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.example.android.systemupdatersample.services.PrepareStreamingService;
|
import com.example.android.systemupdatersample.services.PrepareUpdateService;
|
||||||
import com.example.android.systemupdatersample.util.PayloadSpecs;
|
|
||||||
import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes;
|
import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes;
|
||||||
import com.example.android.systemupdatersample.util.UpdateEngineProperties;
|
import com.example.android.systemupdatersample.util.UpdateEngineProperties;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.util.concurrent.AtomicDouble;
|
import com.google.common.util.concurrent.AtomicDouble;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -50,11 +49,10 @@ public class UpdateManager {
|
||||||
private static final String TAG = "UpdateManager";
|
private static final String TAG = "UpdateManager";
|
||||||
|
|
||||||
/** HTTP Header: User-Agent; it will be sent to the server when streaming the payload. */
|
/** HTTP Header: User-Agent; it will be sent to the server when streaming the payload. */
|
||||||
private static final String HTTP_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
static final String HTTP_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
||||||
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";
|
+ "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";
|
||||||
|
|
||||||
private final UpdateEngine mUpdateEngine;
|
private final UpdateEngine mUpdateEngine;
|
||||||
private final PayloadSpecs mPayloadSpecs;
|
|
||||||
|
|
||||||
private AtomicInteger mUpdateEngineStatus =
|
private AtomicInteger mUpdateEngineStatus =
|
||||||
new AtomicInteger(UpdateEngine.UpdateStatusConstants.IDLE);
|
new AtomicInteger(UpdateEngine.UpdateStatusConstants.IDLE);
|
||||||
|
@ -84,9 +82,15 @@ public class UpdateManager {
|
||||||
private final UpdateManager.UpdateEngineCallbackImpl
|
private final UpdateManager.UpdateEngineCallbackImpl
|
||||||
mUpdateEngineCallback = new UpdateManager.UpdateEngineCallbackImpl();
|
mUpdateEngineCallback = new UpdateManager.UpdateEngineCallbackImpl();
|
||||||
|
|
||||||
public UpdateManager(UpdateEngine updateEngine, PayloadSpecs payloadSpecs) {
|
private final Handler mHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param updateEngine UpdateEngine instance.
|
||||||
|
* @param handler Handler for {@link PrepareUpdateService} intent service.
|
||||||
|
*/
|
||||||
|
public UpdateManager(UpdateEngine updateEngine, Handler handler) {
|
||||||
this.mUpdateEngine = updateEngine;
|
this.mUpdateEngine = updateEngine;
|
||||||
this.mPayloadSpecs = payloadSpecs;
|
this.mHandler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -293,45 +297,17 @@ public class UpdateManager {
|
||||||
mManualSwitchSlotRequired.set(false);
|
mManualSwitchSlotRequired.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.getInstallType() == UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING) {
|
Log.d(TAG, "Starting PrepareUpdateService");
|
||||||
applyAbNonStreamingUpdate(config);
|
PrepareUpdateService.startService(context, config, mHandler, (code, payloadSpec) -> {
|
||||||
} else {
|
if (code != PrepareUpdateService.RESULT_CODE_SUCCESS) {
|
||||||
applyAbStreamingUpdate(context, config);
|
Log.e(TAG, "PrepareUpdateService failed, result code is " + code);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyAbNonStreamingUpdate(UpdateConfig config)
|
|
||||||
throws UpdaterState.InvalidTransitionException {
|
|
||||||
UpdateData.Builder builder = UpdateData.builder()
|
|
||||||
.setExtraProperties(prepareExtraProperties(config));
|
|
||||||
|
|
||||||
try {
|
|
||||||
builder.setPayload(mPayloadSpecs.forNonStreaming(config.getUpdatePackageFile()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Error creating payload spec", e);
|
|
||||||
setUpdaterState(UpdaterState.ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
updateEngineApplyPayload(builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyAbStreamingUpdate(Context context, UpdateConfig config) {
|
|
||||||
UpdateData.Builder builder = UpdateData.builder()
|
|
||||||
.setExtraProperties(prepareExtraProperties(config));
|
|
||||||
|
|
||||||
Log.d(TAG, "Starting PrepareStreamingService");
|
|
||||||
PrepareStreamingService.startService(context, config, (code, payloadSpec) -> {
|
|
||||||
if (code == PrepareStreamingService.RESULT_CODE_SUCCESS) {
|
|
||||||
builder.setPayload(payloadSpec);
|
|
||||||
builder.addExtraProperty("USER_AGENT=" + HTTP_USER_AGENT);
|
|
||||||
config.getAbConfig()
|
|
||||||
.getAuthorization()
|
|
||||||
.ifPresent(s -> builder.addExtraProperty("AUTHORIZATION=" + s));
|
|
||||||
updateEngineApplyPayload(builder.build());
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "PrepareStreamingService failed, result code is " + code);
|
|
||||||
setUpdaterStateSilent(UpdaterState.ERROR);
|
setUpdaterStateSilent(UpdaterState.ERROR);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
updateEngineApplyPayload(UpdateData.builder()
|
||||||
|
.setExtraProperties(prepareExtraProperties(config))
|
||||||
|
.setPayload(payloadSpec)
|
||||||
|
.build());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,6 +319,12 @@ public class UpdateManager {
|
||||||
// User will enable it manually by clicking "Switch Slot" button on the screen.
|
// User will enable it manually by clicking "Switch Slot" button on the screen.
|
||||||
extraProperties.add(UpdateEngineProperties.PROPERTY_DISABLE_SWITCH_SLOT_ON_REBOOT);
|
extraProperties.add(UpdateEngineProperties.PROPERTY_DISABLE_SWITCH_SLOT_ON_REBOOT);
|
||||||
}
|
}
|
||||||
|
if (config.getInstallType() == UpdateConfig.AB_INSTALL_TYPE_STREAMING) {
|
||||||
|
extraProperties.add("USER_AGENT=" + HTTP_USER_AGENT);
|
||||||
|
config.getAbConfig()
|
||||||
|
.getAuthorization()
|
||||||
|
.ifPresent(s -> extraProperties.add("AUTHORIZATION=" + s));
|
||||||
|
}
|
||||||
return extraProperties;
|
return extraProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,14 +479,14 @@ public class UpdateManager {
|
||||||
* system/update_engine/binder_service_android.cc in
|
* system/update_engine/binder_service_android.cc in
|
||||||
* function BinderUpdateEngineAndroidService::bind).
|
* function BinderUpdateEngineAndroidService::bind).
|
||||||
*
|
*
|
||||||
* @param status one of {@link UpdateEngine.UpdateStatusConstants}.
|
* @param status one of {@link UpdateEngine.UpdateStatusConstants}.
|
||||||
* @param progress a number from 0.0 to 1.0.
|
* @param progress a number from 0.0 to 1.0.
|
||||||
*/
|
*/
|
||||||
private void onStatusUpdate(int status, float progress) {
|
private void onStatusUpdate(int status, float progress) {
|
||||||
Log.d(TAG, String.format(
|
Log.d(TAG, String.format(
|
||||||
"onStatusUpdate invoked, status=%s, progress=%.2f",
|
"onStatusUpdate invoked, status=%s, progress=%.2f",
|
||||||
status,
|
status,
|
||||||
progress));
|
progress));
|
||||||
|
|
||||||
int previousStatus = mUpdateEngineStatus.get();
|
int previousStatus = mUpdateEngineStatus.get();
|
||||||
mUpdateEngineStatus.set(status);
|
mUpdateEngineStatus.set(status);
|
||||||
|
@ -555,7 +537,6 @@ public class UpdateManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Contains update data - PayloadSpec and extra properties list.
|
* Contains update data - PayloadSpec and extra properties list.
|
||||||
*
|
*
|
||||||
* <p>{@code mPayload} contains url, offset and size to {@code PAYLOAD_BINARY_FILE_NAME}.
|
* <p>{@code mPayload} contains url, offset and size to {@code PAYLOAD_BINARY_FILE_NAME}.
|
||||||
|
|
|
@ -28,6 +28,7 @@ import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.RecoverySystem;
|
import android.os.RecoverySystem;
|
||||||
import android.os.ResultReceiver;
|
import android.os.ResultReceiver;
|
||||||
|
import android.os.UpdateEngine;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.example.android.systemupdatersample.PayloadSpec;
|
import com.example.android.systemupdatersample.PayloadSpec;
|
||||||
|
@ -49,10 +50,10 @@ import java.util.Optional;
|
||||||
* without downloading the whole package. And it constructs {@link PayloadSpec}.
|
* without downloading the whole package. And it constructs {@link PayloadSpec}.
|
||||||
* All this work required to install streaming A/B updates.
|
* All this work required to install streaming A/B updates.
|
||||||
*
|
*
|
||||||
* PrepareStreamingService runs on it's own thread. It will notify activity
|
* PrepareUpdateService runs on it's own thread. It will notify activity
|
||||||
* using interface {@link UpdateResultCallback} when update is ready to install.
|
* using interface {@link UpdateResultCallback} when update is ready to install.
|
||||||
*/
|
*/
|
||||||
public class PrepareStreamingService extends IntentService {
|
public class PrepareUpdateService extends IntentService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UpdateResultCallback result codes.
|
* UpdateResultCallback result codes.
|
||||||
|
@ -61,62 +62,63 @@ public class PrepareStreamingService extends IntentService {
|
||||||
public static final int RESULT_CODE_ERROR = 1;
|
public static final int RESULT_CODE_ERROR = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface is used to send results from {@link PrepareStreamingService} to
|
* Extra params that will be sent to IntentService.
|
||||||
|
*/
|
||||||
|
public static final String EXTRA_PARAM_CONFIG = "config";
|
||||||
|
public static final String EXTRA_PARAM_RESULT_RECEIVER = "result-receiver";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is used to send results from {@link PrepareUpdateService} to
|
||||||
* {@code MainActivity}.
|
* {@code MainActivity}.
|
||||||
*/
|
*/
|
||||||
public interface UpdateResultCallback {
|
public interface UpdateResultCallback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when files are downloaded and payload spec is constructed.
|
* Invoked when files are downloaded and payload spec is constructed.
|
||||||
*
|
*
|
||||||
* @param resultCode result code, values are defined in {@link PrepareStreamingService}
|
* @param resultCode result code, values are defined in {@link PrepareUpdateService}
|
||||||
* @param payloadSpec prepared payload spec for streaming update
|
* @param payloadSpec prepared payload spec for streaming update
|
||||||
*/
|
*/
|
||||||
void onReceiveResult(int resultCode, PayloadSpec payloadSpec);
|
void onReceiveResult(int resultCode, PayloadSpec payloadSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts PrepareStreamingService.
|
* Starts PrepareUpdateService.
|
||||||
*
|
*
|
||||||
* @param context application context
|
* @param context application context
|
||||||
* @param config update config
|
* @param config update config
|
||||||
* @param resultCallback callback that will be called when the update is ready to be installed
|
* @param resultCallback callback that will be called when the update is ready to be installed
|
||||||
*/
|
*/
|
||||||
public static void startService(Context context,
|
public static void startService(Context context,
|
||||||
UpdateConfig config,
|
UpdateConfig config,
|
||||||
|
Handler handler,
|
||||||
UpdateResultCallback resultCallback) {
|
UpdateResultCallback resultCallback) {
|
||||||
Log.d(TAG, "Starting PrepareStreamingService");
|
Log.d(TAG, "Starting PrepareUpdateService");
|
||||||
ResultReceiver receiver = new CallbackResultReceiver(new Handler(), resultCallback);
|
ResultReceiver receiver = new CallbackResultReceiver(handler, resultCallback);
|
||||||
Intent intent = new Intent(context, PrepareStreamingService.class);
|
Intent intent = new Intent(context, PrepareUpdateService.class);
|
||||||
intent.putExtra(EXTRA_PARAM_CONFIG, config);
|
intent.putExtra(EXTRA_PARAM_CONFIG, config);
|
||||||
intent.putExtra(EXTRA_PARAM_RESULT_RECEIVER, receiver);
|
intent.putExtra(EXTRA_PARAM_RESULT_RECEIVER, receiver);
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrepareStreamingService() {
|
public PrepareUpdateService() {
|
||||||
super(TAG);
|
super(TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TAG = "PrepareStreamingService";
|
private static final String TAG = "PrepareUpdateService";
|
||||||
|
|
||||||
/**
|
|
||||||
* Extra params that will be sent from Activity to IntentService.
|
|
||||||
*/
|
|
||||||
private static final String EXTRA_PARAM_CONFIG = "config";
|
|
||||||
private static final String EXTRA_PARAM_RESULT_RECEIVER = "result-receiver";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The files that should be downloaded before streaming.
|
* The files that should be downloaded before streaming.
|
||||||
*/
|
*/
|
||||||
private static final ImmutableSet<String> PRE_STREAMING_FILES_SET =
|
private static final ImmutableSet<String> PRE_STREAMING_FILES_SET =
|
||||||
ImmutableSet.of(
|
ImmutableSet.of(
|
||||||
PackageFiles.CARE_MAP_FILE_NAME,
|
PackageFiles.CARE_MAP_FILE_NAME,
|
||||||
PackageFiles.COMPATIBILITY_ZIP_FILE_NAME,
|
PackageFiles.COMPATIBILITY_ZIP_FILE_NAME,
|
||||||
PackageFiles.METADATA_FILE_NAME,
|
PackageFiles.METADATA_FILE_NAME,
|
||||||
PackageFiles.PAYLOAD_PROPERTIES_FILE_NAME
|
PackageFiles.PAYLOAD_PROPERTIES_FILE_NAME
|
||||||
);
|
);
|
||||||
|
|
||||||
private final PayloadSpecs mPayloadSpecs = new PayloadSpecs();
|
private final PayloadSpecs mPayloadSpecs = new PayloadSpecs();
|
||||||
|
private final UpdateEngine mUpdateEngine = new UpdateEngine();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onHandleIntent(Intent intent) {
|
protected void onHandleIntent(Intent intent) {
|
||||||
|
@ -142,6 +144,10 @@ public class PrepareStreamingService extends IntentService {
|
||||||
private PayloadSpec execute(UpdateConfig config)
|
private PayloadSpec execute(UpdateConfig config)
|
||||||
throws IOException, PreparationFailedException {
|
throws IOException, PreparationFailedException {
|
||||||
|
|
||||||
|
if (config.getInstallType() == UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING) {
|
||||||
|
return mPayloadSpecs.forNonStreaming(config.getUpdatePackageFile());
|
||||||
|
}
|
||||||
|
|
||||||
downloadPreStreamingFiles(config, OTA_PACKAGE_DIR);
|
downloadPreStreamingFiles(config, OTA_PACKAGE_DIR);
|
||||||
|
|
||||||
Optional<UpdateConfig.PackageFile> payloadBinary =
|
Optional<UpdateConfig.PackageFile> payloadBinary =
|
||||||
|
@ -176,6 +182,7 @@ public class PrepareStreamingService extends IntentService {
|
||||||
* Downloads files defined in {@link UpdateConfig#getAbConfig()}
|
* Downloads files defined in {@link UpdateConfig#getAbConfig()}
|
||||||
* and exists in {@code PRE_STREAMING_FILES_SET}, and put them
|
* and exists in {@code PRE_STREAMING_FILES_SET}, and put them
|
||||||
* in directory {@code dir}.
|
* in directory {@code dir}.
|
||||||
|
*
|
||||||
* @throws IOException when can't download a file
|
* @throws IOException when can't download a file
|
||||||
*/
|
*/
|
||||||
private void downloadPreStreamingFiles(UpdateConfig config, String dir)
|
private void downloadPreStreamingFiles(UpdateConfig config, String dir)
|
||||||
|
@ -212,7 +219,7 @@ public class PrepareStreamingService extends IntentService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by {@link PrepareStreamingService} to pass {@link PayloadSpec}
|
* Used by {@link PrepareUpdateService} to pass {@link PayloadSpec}
|
||||||
* to {@link UpdateResultCallback#onReceiveResult}.
|
* to {@link UpdateResultCallback#onReceiveResult}.
|
||||||
*/
|
*/
|
||||||
private static class CallbackResultReceiver extends ResultReceiver {
|
private static class CallbackResultReceiver extends ResultReceiver {
|
|
@ -21,6 +21,7 @@ import android.app.AlertDialog;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.UpdateEngine;
|
import android.os.UpdateEngine;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -34,7 +35,6 @@ import com.example.android.systemupdatersample.R;
|
||||||
import com.example.android.systemupdatersample.UpdateConfig;
|
import com.example.android.systemupdatersample.UpdateConfig;
|
||||||
import com.example.android.systemupdatersample.UpdateManager;
|
import com.example.android.systemupdatersample.UpdateManager;
|
||||||
import com.example.android.systemupdatersample.UpdaterState;
|
import com.example.android.systemupdatersample.UpdaterState;
|
||||||
import com.example.android.systemupdatersample.util.PayloadSpecs;
|
|
||||||
import com.example.android.systemupdatersample.util.UpdateConfigs;
|
import com.example.android.systemupdatersample.util.UpdateConfigs;
|
||||||
import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes;
|
import com.example.android.systemupdatersample.util.UpdateEngineErrorCodes;
|
||||||
import com.example.android.systemupdatersample.util.UpdateEngineStatuses;
|
import com.example.android.systemupdatersample.util.UpdateEngineStatuses;
|
||||||
|
@ -67,7 +67,7 @@ public class MainActivity extends Activity {
|
||||||
private List<UpdateConfig> mConfigs;
|
private List<UpdateConfig> mConfigs;
|
||||||
|
|
||||||
private final UpdateManager mUpdateManager =
|
private final UpdateManager mUpdateManager =
|
||||||
new UpdateManager(new UpdateEngine(), new PayloadSpecs());
|
new UpdateManager(new UpdateEngine(), new Handler());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ import java.net.URLConnection;
|
||||||
* Downloads chunk of a file from given url using {@code offset} and {@code size},
|
* Downloads chunk of a file from given url using {@code offset} and {@code size},
|
||||||
* and saves to a given location.
|
* and saves to a given location.
|
||||||
*
|
*
|
||||||
* In real-life application this helper class should download from HTTP Server,
|
* In a real-life application this helper class should download from HTTP Server,
|
||||||
* but in this sample app it will only download from a local file.
|
* but in this sample app it will only download from a local file.
|
||||||
*/
|
*/
|
||||||
public final class FileDownloader {
|
public final class FileDownloader {
|
||||||
|
|
|
@ -18,20 +18,25 @@ package com.example.android.systemupdatersample;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.ResultReceiver;
|
||||||
import android.os.UpdateEngine;
|
import android.os.UpdateEngine;
|
||||||
import android.os.UpdateEngineCallback;
|
import android.os.UpdateEngineCallback;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
|
import android.support.test.annotation.UiThreadTest;
|
||||||
import android.support.test.filters.SmallTest;
|
import android.support.test.filters.SmallTest;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.example.android.systemupdatersample.services.PrepareUpdateService;
|
||||||
import com.example.android.systemupdatersample.tests.R;
|
import com.example.android.systemupdatersample.tests.R;
|
||||||
import com.example.android.systemupdatersample.util.PayloadSpecs;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.io.CharStreams;
|
import com.google.common.io.CharStreams;
|
||||||
|
|
||||||
|
@ -43,7 +48,6 @@ import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnit;
|
import org.mockito.junit.MockitoJUnit;
|
||||||
import org.mockito.junit.MockitoRule;
|
import org.mockito.junit.MockitoRule;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
@ -60,49 +64,39 @@ public class UpdateManagerTest {
|
||||||
@Mock
|
@Mock
|
||||||
private UpdateEngine mUpdateEngine;
|
private UpdateEngine mUpdateEngine;
|
||||||
@Mock
|
@Mock
|
||||||
private PayloadSpecs mPayloadSpecs;
|
private Context mMockContext;
|
||||||
private UpdateManager mSubject;
|
private UpdateManager mSubject;
|
||||||
private Context mContext;
|
private Context mTestContext;
|
||||||
private UpdateConfig mNonStreamingUpdate003;
|
private UpdateConfig mStreamingUpdate002;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mContext = InstrumentationRegistry.getContext();
|
mTestContext = InstrumentationRegistry.getContext();
|
||||||
mSubject = new UpdateManager(mUpdateEngine, mPayloadSpecs);
|
mSubject = new UpdateManager(mUpdateEngine, null);
|
||||||
mNonStreamingUpdate003 =
|
mStreamingUpdate002 =
|
||||||
UpdateConfig.fromJson(readResource(R.raw.update_config_003_nonstream));
|
UpdateConfig.fromJson(readResource(R.raw.update_config_002_stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void applyUpdate_appliesPayloadToUpdateEngine() throws Exception {
|
public void applyUpdate_appliesPayloadToUpdateEngine() throws Exception {
|
||||||
PayloadSpec payload = buildMockPayloadSpec();
|
mockContextStartServiceAnswer(buildMockPayloadSpec());
|
||||||
when(mPayloadSpecs.forNonStreaming(any(File.class))).thenReturn(payload);
|
mSubject.applyUpdate(mMockContext, mStreamingUpdate002);
|
||||||
when(mUpdateEngine.bind(any(UpdateEngineCallback.class))).thenAnswer(answer -> {
|
|
||||||
// When UpdateManager is bound to update_engine, it passes
|
|
||||||
// UpdateEngineCallback as a callback to update_engine.
|
|
||||||
UpdateEngineCallback callback = answer.getArgument(0);
|
|
||||||
callback.onStatusUpdate(
|
|
||||||
UpdateEngine.UpdateStatusConstants.IDLE,
|
|
||||||
/*engineProgress*/ 0.0f);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
mSubject.bind();
|
|
||||||
mSubject.applyUpdate(null, mNonStreamingUpdate003);
|
|
||||||
|
|
||||||
verify(mUpdateEngine).applyPayload(
|
verify(mUpdateEngine).applyPayload(
|
||||||
"file://blah",
|
"file://blah",
|
||||||
120,
|
120,
|
||||||
340,
|
340,
|
||||||
new String[] {
|
new String[]{
|
||||||
"SWITCH_SLOT_ON_REBOOT=0" // ab_config.force_switch_slot = false
|
"SWITCH_SLOT_ON_REBOOT=0", // ab_config.force_switch_slot = false
|
||||||
|
"USER_AGENT=" + UpdateManager.HTTP_USER_AGENT
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void stateIsRunningAndEngineStatusIsIdle_reApplyLastUpdate() throws Exception {
|
@UiThreadTest
|
||||||
PayloadSpec payload = buildMockPayloadSpec();
|
public void stateIsRunningAndEngineStatusIsIdle_reApplyLastUpdate() throws Throwable {
|
||||||
when(mPayloadSpecs.forNonStreaming(any(File.class))).thenReturn(payload);
|
mockContextStartServiceAnswer(buildMockPayloadSpec());
|
||||||
|
// UpdateEngine always returns IDLE status.
|
||||||
when(mUpdateEngine.bind(any(UpdateEngineCallback.class))).thenAnswer(answer -> {
|
when(mUpdateEngine.bind(any(UpdateEngineCallback.class))).thenAnswer(answer -> {
|
||||||
// When UpdateManager is bound to update_engine, it passes
|
// When UpdateManager is bound to update_engine, it passes
|
||||||
// UpdateEngineCallback as a callback to update_engine.
|
// UpdateEngineCallback as a callback to update_engine.
|
||||||
|
@ -114,21 +108,36 @@ public class UpdateManagerTest {
|
||||||
});
|
});
|
||||||
|
|
||||||
mSubject.bind();
|
mSubject.bind();
|
||||||
mSubject.applyUpdate(null, mNonStreamingUpdate003);
|
mSubject.applyUpdate(mMockContext, mStreamingUpdate002);
|
||||||
mSubject.unbind();
|
mSubject.unbind();
|
||||||
mSubject.bind(); // re-bind - now it should re-apply last update
|
mSubject.bind(); // re-bind - now it should re-apply last update
|
||||||
|
|
||||||
assertEquals(mSubject.getUpdaterState(), UpdaterState.RUNNING);
|
assertEquals(mSubject.getUpdaterState(), UpdaterState.RUNNING);
|
||||||
// it should be called 2 times
|
|
||||||
verify(mUpdateEngine, times(2)).applyPayload(
|
verify(mUpdateEngine, times(2)).applyPayload(
|
||||||
"file://blah",
|
"file://blah",
|
||||||
120,
|
120,
|
||||||
340,
|
340,
|
||||||
new String[] {
|
new String[]{
|
||||||
"SWITCH_SLOT_ON_REBOOT=0" // ab_config.force_switch_slot = false
|
"SWITCH_SLOT_ON_REBOOT=0", // ab_config.force_switch_slot = false
|
||||||
|
"USER_AGENT=" + UpdateManager.HTTP_USER_AGENT
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mockContextStartServiceAnswer(PayloadSpec payloadSpec) {
|
||||||
|
doAnswer(args -> {
|
||||||
|
Intent intent = args.getArgument(0);
|
||||||
|
ResultReceiver resultReceiver = intent.getParcelableExtra(
|
||||||
|
PrepareUpdateService.EXTRA_PARAM_RESULT_RECEIVER);
|
||||||
|
Bundle b = new Bundle();
|
||||||
|
b.putSerializable(
|
||||||
|
/* PrepareUpdateService.CallbackResultReceiver.BUNDLE_PARAM_PAYLOAD_SPEC */
|
||||||
|
"payload-spec",
|
||||||
|
payloadSpec);
|
||||||
|
resultReceiver.send(PrepareUpdateService.RESULT_CODE_SUCCESS, b);
|
||||||
|
return null;
|
||||||
|
}).when(mMockContext).startService(any(Intent.class));
|
||||||
|
}
|
||||||
|
|
||||||
private PayloadSpec buildMockPayloadSpec() {
|
private PayloadSpec buildMockPayloadSpec() {
|
||||||
PayloadSpec payload = mock(PayloadSpec.class);
|
PayloadSpec payload = mock(PayloadSpec.class);
|
||||||
when(payload.getUrl()).thenReturn("file://blah");
|
when(payload.getUrl()).thenReturn("file://blah");
|
||||||
|
@ -140,7 +149,7 @@ public class UpdateManagerTest {
|
||||||
|
|
||||||
private String readResource(int id) throws IOException {
|
private String readResource(int id) throws IOException {
|
||||||
return CharStreams.toString(new InputStreamReader(
|
return CharStreams.toString(new InputStreamReader(
|
||||||
mContext.getResources().openRawResource(id)));
|
mTestContext.getResources().openRawResource(id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue