Commit efb5a135 authored by sadrul's avatar sadrul Committed by Commit bot

precache: Move the java files into //components/precache/android

This moves code out of //java/apps/chrome/.../precache into:
  . //components/precache/android/: classes that provide information about
    device-state, network connectivity etc.
  . //chrome/android/.../precache/: precache service and service launchers.

BUG=401552

Review URL: https://codereview.chromium.org/1031003003

Cr-Commit-Position: refs/heads/master@{#322298}
parent 3551a696
......@@ -86,6 +86,7 @@ android_library("chrome_java") {
"//components/gcm_driver/android:gcm_driver_java",
"//components/invalidation:java",
"//components/navigation_interception/android:navigation_interception_java",
"//components/precache/android:precache_java",
"//components/variations/android:variations_java",
"//components/web_contents_delegate_android:web_contents_delegate_android_java",
"//content/public/android:content_java",
......
......@@ -3,6 +3,7 @@ include_rules = [
"+components/web_contents_delegate_android",
"+components/bookmarks/common/android/java/src/org/chromium/components/bookmarks",
"+components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/core",
"+components/precache/android/java",
"+content/public/android/java",
"+sync/android/java/src/org/chromium/sync",
]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.precache;
import android.content.Context;
import org.chromium.base.CalledByNative;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
import java.util.concurrent.Callable;
/** Class that interacts with the PrecacheManager to control precache cycles. */
public abstract class PrecacheLauncher {
/** Pointer to the native PrecacheLauncher object. Set to 0 when uninitialized. */
private long mNativePrecacheLauncher;
/** Destroy the native PrecacheLauncher, releasing the memory that it was using. */
public void destroy() {
if (mNativePrecacheLauncher != 0) {
nativeDestroy(mNativePrecacheLauncher);
mNativePrecacheLauncher = 0;
}
}
/** Starts a precache cycle. */
public void start() {
// Lazily initialize the native PrecacheLauncher.
if (mNativePrecacheLauncher == 0) {
mNativePrecacheLauncher = nativeInit();
}
nativeStart(mNativePrecacheLauncher);
}
/** Cancel the precache cycle if one is ongoing. */
public void cancel() {
// Lazily initialize the native PrecacheLauncher.
if (mNativePrecacheLauncher == 0) {
mNativePrecacheLauncher = nativeInit();
}
nativeCancel(mNativePrecacheLauncher);
}
/** Called when a precache cycle completes. */
protected abstract void onPrecacheCompleted();
/**
* Called by native code when the precache cycle completes. This method exists because an
* abstract method cannot be directly called from native.
*/
@CalledByNative
private void onPrecacheCompletedCallback() {
onPrecacheCompleted();
}
/**
* Returns true if precaching is enabled by either Finch or the command line flag, and also by
* the predictive network actions preference and current network connection type.
*
* @param privacyPreferencesManager Singleton that manages the prefetch bandwidth preference.
*/
public static boolean isPrecachingEnabled(
final PrivacyPreferencesManager privacyPreferencesManager) {
if (!nativeIsPrecachingEnabled()) return false;
// privacyPreferencesManager.shouldPrerender() can only be executed on the UI thread.
return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() {
@Override
public Boolean call() {
return privacyPreferencesManager.shouldPrerender();
}
});
}
/**
* If precaching is enabled, then allow the PrecacheService to be launched and signal Chrome
* when conditions are right to start precaching. If precaching is disabled, prevent the
* PrecacheService from ever starting.
*
* @param privacyPreferencesManager Singleton that manages the prefetch bandwidth preference.
* @param context The context of the PrecacheServiceLauncher.
*/
public static void updatePrecachingEnabled(PrivacyPreferencesManager privacyPreferencesManager,
Context context) {
PrecacheServiceLauncher.setIsPrecachingEnabled(context,
isPrecachingEnabled(privacyPreferencesManager));
}
private native long nativeInit();
private native void nativeDestroy(long nativePrecacheLauncher);
private native void nativeStart(long nativePrecacheLauncher);
private native void nativeCancel(long nativePrecacheLauncher);
private static native boolean nativeIsPrecachingEnabled();
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.precache;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.SuppressFBWarnings;
import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.base.library_loader.ProcessInitException;
import org.chromium.components.precache.DeviceState;
import org.chromium.content.browser.BrowserStartupController;
/**
* Background service that runs while Chrome is precaching resources. Precaching is only done while
* the device is connected to power, Wi-Fi, and the device is not interactive (e.g., the screen is
* off. This is a sticky service that is started when the {@link PrecacheServiceLauncher}
* determines that conditions are right for precaching. Once started, this service runs until
* either precaching finishes successfully, or the conditions are no longer met.
*/
public class PrecacheService extends Service {
private static final String TAG = "PrecacheService";
public static final String ACTION_START_PRECACHE =
"org.chromium.chrome.browser.precache.PrecacheService.START_PRECACHE";
/** Wakelock that is held while precaching is in progress. */
private WakeLock mPrecachingWakeLock;
/** True if there is a precache in progress. */
private boolean mIsPrecaching = false;
@VisibleForTesting
boolean isPrecaching() {
return mIsPrecaching;
}
private DeviceState mDeviceState = DeviceState.getInstance();
@VisibleForTesting
void setDeviceState(DeviceState deviceState) {
mDeviceState = deviceState;
}
/** Receiver that will be notified when conditions become wrong for precaching. */
private final BroadcastReceiver mDeviceStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mIsPrecaching && (mDeviceState.isInteractive(context)
|| !mDeviceState.isPowerConnected(context)
|| !mDeviceState.isWifiAvailable(context))) {
cancelPrecaching();
}
}
};
@VisibleForTesting
BroadcastReceiver getDeviceStateReceiver() {
return mDeviceStateReceiver;
}
@VisibleForTesting
void handlePrecacheCompleted() {
if (mIsPrecaching) finishPrecaching();
}
/** PrecacheLauncher used to run precaching. */
private PrecacheLauncher mPrecacheLauncher = new PrecacheLauncher() {
@Override
protected void onPrecacheCompleted() {
handlePrecacheCompleted();
}
};
@VisibleForTesting
void setPrecacheLauncher(PrecacheLauncher precacheLauncher) {
mPrecacheLauncher = precacheLauncher;
}
@Override
public void onCreate() {
super.onCreate();
registerDeviceStateReceiver();
}
@Override
public void onDestroy() {
if (mIsPrecaching) cancelPrecaching();
unregisterReceiver(mDeviceStateReceiver);
mPrecacheLauncher.destroy();
releasePrecachingWakeLock();
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
if (intent != null && ACTION_START_PRECACHE.equals(intent.getAction())
&& !mIsPrecaching) {
// Only start precaching if precaching is not already in progress.
startPrecaching();
}
} finally {
PrecacheServiceLauncher.releaseWakeLock();
}
// The PrecacheService should only be running while precaching is in progress. Return
// {@link Service.START_STICKY} if precaching is in progress to keep the service running;
// otherwise, return {@link Service.START_NOT_STICKY} to cause the service to stop once it
// is done processing commands sent to it.
return mIsPrecaching ? START_STICKY : START_NOT_STICKY;
}
/** PrecacheService does not support binding. */
@Override
public IBinder onBind(Intent intent) {
return null;
}
/** Attempt to start up the browser processes and load the native libraries. */
@SuppressFBWarnings("DM_EXIT")
@VisibleForTesting
void prepareNativeLibraries() {
try {
BrowserStartupController.get(getApplicationContext(),
LibraryProcessType.PROCESS_BROWSER)
.startBrowserProcessesSync(false);
} catch (ProcessInitException e) {
Log.e(TAG, "ProcessInitException while starting the browser process");
// Since the library failed to initialize nothing in the application
// can work, so kill the whole application not just the activity.
System.exit(-1);
}
}
/** Begin a precache cycle. */
private void startPrecaching() {
Log.v(TAG, "Start precaching");
prepareNativeLibraries();
mIsPrecaching = true;
acquirePrecachingWakeLock();
// In certain cases, the PrecacheLauncher will skip precaching entirely and call
// finishPrecaching() before this call to mPrecacheLauncher.start() returns, so the call to
// mPrecacheLauncher.start() must happen after acquiring the wake lock to ensure that the
// wake lock is released properly.
mPrecacheLauncher.start();
}
/** End a precache cycle. */
private void finishPrecaching() {
Log.v(TAG, "Finish precaching");
shutdownPrecaching();
}
/** Cancel a precache cycle. */
private void cancelPrecaching() {
Log.v(TAG, "Cancel precaching");
prepareNativeLibraries();
mPrecacheLauncher.cancel();
shutdownPrecaching();
}
/**
* Update state to indicate that precaching is no longer in progress, and stop the service.
*/
private void shutdownPrecaching() {
mIsPrecaching = false;
releasePrecachingWakeLock();
stopSelf();
}
/** Register a BroadcastReceiver to detect when conditions become wrong for precaching. */
private void registerDeviceStateReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mDeviceStateReceiver, filter);
}
/** Acquire the precaching WakeLock. */
private void acquirePrecachingWakeLock() {
if (mPrecachingWakeLock == null) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mPrecachingWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
}
mPrecachingWakeLock.acquire();
}
/** Release the precaching WakeLock if it is held. */
private void releasePrecachingWakeLock() {
if (mPrecachingWakeLock != null && mPrecachingWakeLock.isHeld()) {
mPrecachingWakeLock.release();
}
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.precache;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.components.precache.DeviceState;
/**
* BroadcastReceiver that determines when conditions are right for precaching, and starts the
* {@link PrecacheService} if they are. Conditions are right for precaching when the device is
* connected to power, Wi-Fi, interactivity (e.g., the screen) is off, and at least
* |WAIT_UNTIL_NEXT_PRECACHE_MS| have passed since the last time precaching was done.
*/
public class PrecacheServiceLauncher extends BroadcastReceiver {
private static final String TAG = "PrecacheServiceLauncher";
@VisibleForTesting
static final String PREF_IS_PRECACHING_ENABLED = "precache.is_precaching_enabled";
@VisibleForTesting
static final String PREF_PRECACHE_LAST_TIME = "precache.last_time";
@VisibleForTesting
static final String ACTION_ALARM =
"org.chromium.chrome.browser.precache.PrecacheServiceLauncher.ALARM";
private static final int INTERACTIVE_STATE_POLLING_PERIOD_MS = 15 * 60 * 1000; // 15 minutes.
static final int WAIT_UNTIL_NEXT_PRECACHE_MS = 4 * 60 * 60 * 1000; // 4 hours.
private static WakeLock sWakeLock = null;
private DeviceState mDeviceState = DeviceState.getInstance();
@VisibleForTesting
void setDeviceState(DeviceState deviceState) {
mDeviceState = deviceState;
}
/**
* Set whether or not precaching is enabled. If precaching is enabled, this receiver will start
* the PrecacheService when it receives an intent. If precaching is disabled, any running
* PrecacheService will be stopped, and this receiver will do nothing when it receives an
* intent.
*
* @param context The Context to use.
* @param enabled Whether or not precaching is enabled.
*/
public static void setIsPrecachingEnabled(Context context, boolean enabled) {
Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.putBoolean(PREF_IS_PRECACHING_ENABLED, enabled);
editor.apply();
if (!enabled) {
// Stop any running PrecacheService. If PrecacheService is not running, then this does
// nothing.
Intent serviceIntent = new Intent(null, null, context, PrecacheService.class);
context.stopService(serviceIntent);
}
}
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean isPrecachingEnabled = prefs.getBoolean(PREF_IS_PRECACHING_ENABLED, false);
long lastPrecacheTimeMs = prefs.getLong(PREF_PRECACHE_LAST_TIME, 0L);
if (lastPrecacheTimeMs > getElapsedRealtimeOnSystem()) {
// System.elapsedRealtime() counts milliseconds since boot, so if the device has been
// rebooted since the last time precaching was performed, reset lastPrecacheTimeMs to 0.
lastPrecacheTimeMs = 0L;
}
// Do nothing if precaching is disabled.
if (!isPrecachingEnabled) return;
boolean isPowerConnected = mDeviceState.isPowerConnected(context);
boolean isWifiAvailable = mDeviceState.isWifiAvailable(context);
boolean isInteractive = mDeviceState.isInteractive(context);
boolean areConditionsGoodForPrecaching =
isPowerConnected && isWifiAvailable && !isInteractive;
long timeSinceLastPrecacheMs = getElapsedRealtimeOnSystem() - lastPrecacheTimeMs;
boolean hasEnoughTimePassedSinceLastPrecache =
timeSinceLastPrecacheMs >= WAIT_UNTIL_NEXT_PRECACHE_MS;
// Only start precaching when an alarm action is received. This is to prevent situations
// such as power being connected, precaching starting, then precaching being immediately
// canceled because the screen turns on in response to power being connected.
if (ACTION_ALARM.equals(intent.getAction())
&& areConditionsGoodForPrecaching
&& hasEnoughTimePassedSinceLastPrecache) {
// Store a pref indicating that precaching is starting now.
Editor editor = prefs.edit();
editor.putLong(PREF_PRECACHE_LAST_TIME, getElapsedRealtimeOnSystem());
editor.apply();
setAlarm(context, Math.max(
INTERACTIVE_STATE_POLLING_PERIOD_MS, WAIT_UNTIL_NEXT_PRECACHE_MS));
acquireWakeLockAndStartService(context);
} else {
if (isPowerConnected && isWifiAvailable) {
// If we're just waiting for non-interactivity (e.g., the screen to be off), or for
// enough time to pass after Wi-Fi or power has been connected, then set an alarm
// for the next time to check the device state. We can't receive SCREEN_ON/OFF
// intents as is done for detecting changes in power and connectivity, because
// SCREEN_ON/OFF intents are only delivered to BroadcastReceivers that are
// registered dynamically in code, but the PrecacheServiceLauncher is registered in
// the Android manifest.
setAlarm(context, Math.max(INTERACTIVE_STATE_POLLING_PERIOD_MS,
WAIT_UNTIL_NEXT_PRECACHE_MS - timeSinceLastPrecacheMs));
} else {
// If the device doesn't have connected power or doesn't have Wi-Fi, then there's no
// point in setting an alarm.
cancelAlarm(context);
}
}
}
/** Release the wakelock if it is held. */
@VisibleForTesting
protected static void releaseWakeLock() {
ThreadUtils.assertOnUiThread();
if (sWakeLock != null && sWakeLock.isHeld()) sWakeLock.release();
}
/**
* Acquire the wakelock and start the PrecacheService.
*
* @param context The Context to use to start the service.
*/
private void acquireWakeLockAndStartService(Context context) {
acquireWakeLock(context);
startPrecacheService(context);
}
@VisibleForTesting
protected void startPrecacheService(Context context) {
Intent serviceIntent = new Intent(
PrecacheService.ACTION_START_PRECACHE, null, context, PrecacheService.class);
context.startService(serviceIntent);
}
@VisibleForTesting
protected void acquireWakeLock(Context context) {
ThreadUtils.assertOnUiThread();
if (sWakeLock == null) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
}
sWakeLock.acquire();
}
/**
* Get a PendingIntent for setting an alarm to notify the PrecacheServiceLauncher.
*
* @param context The Context to use for the PendingIntent.
* @return The PendingIntent.
*/
private static PendingIntent getPendingAlarmIntent(Context context) {
return PendingIntent.getBroadcast(context, 0,
new Intent(ACTION_ALARM, null, context, PrecacheServiceLauncher.class),
PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* Set an alarm to notify the PrecacheServiceLauncher in the future.
*
* @param context The Context to use.
* @param delayMs Delay in milliseconds before the alarm goes off.
*/
private void setAlarm(Context context, long delayMs) {
setAlarmOnSystem(context, AlarmManager.ELAPSED_REALTIME_WAKEUP,
getElapsedRealtimeOnSystem() + delayMs, getPendingAlarmIntent(context));
}
/**
* Set the alarm on the system using the given parameters. This method can be overridden in
* tests.
*/
@VisibleForTesting
protected void setAlarmOnSystem(Context context, int type, long triggerAtMillis,
PendingIntent operation) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(type, triggerAtMillis, operation);
}
/**
* Cancel a previously set alarm, if there is one. This method can be overridden in tests.
*
* @param context The Context to use.
*/
private void cancelAlarm(Context context) {
cancelAlarmOnSystem(context, getPendingAlarmIntent(context));
}
/** Cancel a previously set alarm on the system. This method can be overridden in tests. */
@VisibleForTesting
protected void cancelAlarmOnSystem(Context context, PendingIntent operation) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(operation);
}
@VisibleForTesting
protected long getElapsedRealtimeOnSystem() {
return SystemClock.elapsedRealtime();
}
}
include_rules = [
"+components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/core",
"+components/bookmarks/common/android/java/src/org/chromium/components/bookmarks",
"+components/precache/android/javatests",
"+content/public/android/java",
"+sync/android/java/src/org/chromium/sync",
# We should only depend on the util package of something that lives in
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.precache;
/**
* PrecacheService class with native initialization mocked out.
*/
public class MockPrecacheService extends PrecacheService {
@Override
void prepareNativeLibraries() {}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.precache;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import org.chromium.base.test.util.AdvancedMockContext;
import org.chromium.base.test.util.Feature;
import org.chromium.components.precache.MockDeviceState;
import java.util.HashMap;
import java.util.Map;
/**
* Tests the |PrecacheServiceLauncher|.
*/
public class PrecacheServiceLauncherTest extends InstrumentationTestCase {
private Context getContext(boolean enabled, long lastTimeMs) {
AdvancedMockContext context = new AdvancedMockContext() {
@Override
public String getPackageName() {
return getInstrumentation().getTargetContext().getPackageName();
}
};
Map<String, Object> map = new HashMap<String, Object>();
map.put(PrecacheServiceLauncher.PREF_IS_PRECACHING_ENABLED, enabled);
map.put(PrecacheServiceLauncher.PREF_PRECACHE_LAST_TIME, lastTimeMs);
context.addSharedPreferences(context.getPackageName() + "_preferences", map);
return context;
}
/**
* Class mocks out the system-related function of |PrecacheServiceLauncher|
* and provides a method to set a mocked elapsed realtime.
*/
static class MockPrecacheServiceLauncher extends PrecacheServiceLauncher {
private long mElapsedRealtime;
private boolean mCancelAlarmCalled;
private boolean mSetAlarmCalled;
private boolean mStartPrecacheCalled;
@Override
protected void setAlarmOnSystem(Context context, int type, long triggerAtMillis,
PendingIntent operation) {
mSetAlarmCalled = true;
}
@Override
protected void cancelAlarmOnSystem(Context context, PendingIntent operation) {
mCancelAlarmCalled = true;
}
@Override
protected long getElapsedRealtimeOnSystem() {
return mElapsedRealtime;
}
@Override
protected void startPrecacheService(Context context) {
mStartPrecacheCalled = true;
}
@Override
protected void acquireWakeLock(Context context) {}
protected void setElapsedRealtime(long elapsedRealtime) {
mElapsedRealtime = elapsedRealtime;
}
protected void checkExpectations(boolean expectedSetAlarm, boolean expectedCancelAlarm,
boolean expectedStartPrecache) {
assertEquals("Set alarm", expectedSetAlarm, mSetAlarmCalled);
assertEquals("Cancel alarm", expectedCancelAlarm, mCancelAlarmCalled);
assertEquals("Start precache", expectedStartPrecache, mStartPrecacheCalled);
}
}
private static void checkPrefsExpectations(Context context, long expectedLastTime) {
SharedPreferences prefs = context.getSharedPreferences(
context.getPackageName() + "_preferences", Context.MODE_PRIVATE);
assertEquals(expectedLastTime,
prefs.getLong(PrecacheServiceLauncher.PREF_PRECACHE_LAST_TIME, -1L));
}
@SmallTest
@Feature({"Precache"})
public void testDoNothingIfNotEnabled() {
MockPrecacheServiceLauncher launcher = new MockPrecacheServiceLauncher();
MockDeviceState deviceState = new MockDeviceState(0, true, false, true);
launcher.setDeviceState(deviceState);
Context context = getContext(false, 0L);
launcher.setElapsedRealtime(PrecacheServiceLauncher.WAIT_UNTIL_NEXT_PRECACHE_MS);
launcher.onReceive(context, new Intent(PrecacheServiceLauncher.ACTION_ALARM));
launcher.checkExpectations(false, false, false);
checkPrefsExpectations(context, 0L);
}
@SmallTest
@Feature({"Precache"})
public void testGoodConditions() {
MockPrecacheServiceLauncher launcher = new MockPrecacheServiceLauncher();
MockDeviceState deviceState = new MockDeviceState(0, true, false, true);
launcher.setDeviceState(deviceState);
Context context = getContext(true, 0L);
launcher.setElapsedRealtime(PrecacheServiceLauncher.WAIT_UNTIL_NEXT_PRECACHE_MS);
launcher.onReceive(context, new Intent(PrecacheServiceLauncher.ACTION_ALARM));
launcher.checkExpectations(true, false, true);
checkPrefsExpectations(context, PrecacheServiceLauncher.WAIT_UNTIL_NEXT_PRECACHE_MS);
}
@SmallTest
@Feature({"Precache"})
public void testNotEnoughTimeButGoodConditionsOtherwise() {
MockPrecacheServiceLauncher launcher = new MockPrecacheServiceLauncher();
MockDeviceState deviceState = new MockDeviceState(0, true, false, true);
launcher.setDeviceState(deviceState);
Context context = getContext(true, 0L);
launcher.setElapsedRealtime(PrecacheServiceLauncher.WAIT_UNTIL_NEXT_PRECACHE_MS - 1);
launcher.onReceive(context, new Intent(PrecacheServiceLauncher.ACTION_ALARM));
launcher.checkExpectations(true, false, false);
checkPrefsExpectations(context, 0L);
}
@SmallTest
@Feature({"Precache"})
public void testEnoughTimeButNoPower() {
MockPrecacheServiceLauncher launcher = new MockPrecacheServiceLauncher();
MockDeviceState deviceState = new MockDeviceState(0, false, false, true);
launcher.setDeviceState(deviceState);
Context context = getContext(true, 0L);
launcher.setElapsedRealtime(PrecacheServiceLauncher.WAIT_UNTIL_NEXT_PRECACHE_MS - 1);
launcher.onReceive(context, new Intent(PrecacheServiceLauncher.ACTION_ALARM));
launcher.checkExpectations(false, true, false);
checkPrefsExpectations(context, 0L);
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.precache;
import android.content.Intent;
import android.test.ServiceTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.AdvancedMockContext;
import org.chromium.base.test.util.Feature;
import org.chromium.components.precache.MockDeviceState;
/**
* Tests of {@link PrecacheService}.
*/
public class PrecacheServiceTest extends ServiceTestCase<MockPrecacheService> {
/**
* Mock of the {@link PrecacheLauncher}.
*/
static class MockPrecacheLauncher extends PrecacheLauncher {
private MockPrecacheService mService;
public void setService(MockPrecacheService service) {
mService = service;
}
@Override
public void destroy() {}
@Override
public void start() {}
@Override
public void cancel() {}
@Override
protected void onPrecacheCompleted() {
mService.handlePrecacheCompleted();
}
}
private final MockPrecacheLauncher mPrecacheLauncher = new MockPrecacheLauncher();
public PrecacheServiceTest() {
super(MockPrecacheService.class);
}
@Override
protected void setupService() {
super.setupService();
mPrecacheLauncher.setService(getService());
getService().setPrecacheLauncher(mPrecacheLauncher);
}
private void startAndChangeDeviceState(MockPrecacheService service, boolean powerIsConnected,
boolean isInteractive, boolean wifiIsAvailable) {
AdvancedMockContext context = new AdvancedMockContext();
getService().setDeviceState(new MockDeviceState(0, true, false, true));
assertFalse("Precaching should not be in progress initially", service.isPrecaching());
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(getService(), MockPrecacheService.class);
intent.setAction(PrecacheService.ACTION_START_PRECACHE);
startService(intent);
}
});
assertTrue("Precaching should be in progress after start", service.isPrecaching());
getService().setDeviceState(
new MockDeviceState(0, powerIsConnected, isInteractive, wifiIsAvailable));
service.getDeviceStateReceiver().onReceive(context, new Intent());
}
/** Tests that disconnecting power stops a precache. */
@SmallTest
@Feature({"Precache"})
public void testPrecacheWhenPowerDisconnects() {
setupService();
startAndChangeDeviceState(getService(), false, false, true);
assertFalse("Precaching should not be in progress when power is disconnected",
getService().isPrecaching());
}
/** Tests that the device becoming interactive stops a precache. */
@SmallTest
@Feature({"Precache"})
public void testPrecacheWhenDeviceBecomesInteractive() {
setupService();
startAndChangeDeviceState(getService(), true, true, true);
assertFalse("Precaching should not be in progress when the device is interactive",
getService().isPrecaching());
}
/** Tests that going off of Wi-Fi stops a precache. */
@SmallTest
@Feature({"Precache"})
public void testPrecacheWhenNoLongerWifi() {
setupService();
startAndChangeDeviceState(getService(), true, true, true);
assertFalse("Precaching should not be in progress when the network is not Wi-Fi",
getService().isPrecaching());
}
/** Tests that precaching continues if prerequisites are still met. */
@SmallTest
@Feature({"Precache"})
public void testPrecacheWhenPrerequisitesStillMet() {
setupService();
startAndChangeDeviceState(getService(), true, false, true);
assertTrue("Precaching should be in progress", getService().isPrecaching());
}
/**
* Tests that precaching continues until completion while the prerequisite device states
* (Wifi is in use, power is connected, and the device is non-interactive) continue to be met.
*/
@SmallTest
@Feature({"Precache"})
public void testPrecacheCompleted() {
setupService();
startAndChangeDeviceState(getService(), true, false, true);
assertTrue("Precaching should be in progress", getService().isPrecaching());
mPrecacheLauncher.onPrecacheCompleted();
assertFalse("Precaching should not be in progress after completion",
getService().isPrecaching());
}
}
......@@ -192,5 +192,15 @@
<meta-data android:name="org.chromium.chrome.browser.SERVICE_TAB_LAUNCHER"
android:value="org.chromium.chrome.shell.ChromeShellServiceTabLauncher" />
<!-- Precache service. -->
<service android:name="org.chromium.chrome.browser.precache.PrecacheService"
android:exported="false" />
<receiver android:name="org.chromium.chrome.browser.precache.PrecacheServiceLauncher">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
</application>
</manifest>
......@@ -44,6 +44,7 @@
#include "chrome/browser/android/omnibox/autocomplete_controller_android.h"
#include "chrome/browser/android/omnibox/omnibox_prerender.h"
#include "chrome/browser/android/password_ui_view_android.h"
#include "chrome/browser/android/precache/precache_launcher.h"
#include "chrome/browser/android/preferences/autofill/autofill_profile_bridge.h"
#include "chrome/browser/android/preferences/pref_service_bridge.h"
#include "chrome/browser/android/preferences/website_preference_bridge.h"
......@@ -223,6 +224,7 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = {
PasswordUIViewAndroid::RegisterPasswordUIViewAndroid},
{"PersonalDataManagerAndroid",
autofill::PersonalDataManagerAndroid::Register},
{"PrecacheLauncher", RegisterPrecacheLauncher},
{"PrefServiceBridge", RegisterPrefServiceBridge},
{"ProfileAndroid", ProfileAndroid::RegisterProfileAndroid},
{"ProfileDownloader", RegisterProfileDownloader},
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/android/precache/precache_launcher.h"
#include <jni.h>
#include "base/android/jni_android.h"
#include "base/android/jni_weak_ref.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/top_sites_factory.h"
#include "chrome/browser/precache/most_visited_urls_provider.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/history/core/browser/top_sites.h"
#include "components/precache/content/precache_manager.h"
#include "components/precache/content/precache_manager_factory.h"
#include "jni/PrecacheLauncher_jni.h"
using base::android::AttachCurrentThread;
using precache::PrecacheManager;
namespace {
// Get the profile that should be used for precaching.
Profile* GetProfile() {
Profile* profile = g_browser_process->profile_manager()->GetLastUsedProfile()
->GetOriginalProfile();
DCHECK(profile);
DCHECK(g_browser_process->profile_manager()->IsValidProfile(profile));
return profile;
}
// Get the PrecacheManager for the given |profile|.
PrecacheManager* GetPrecacheManager(Profile* profile) {
PrecacheManager* precache_manager =
precache::PrecacheManagerFactory::GetForBrowserContext(profile);
DCHECK(precache_manager);
return precache_manager;
}
bool IsDataReductionProxyEnabled(Profile* profile) {
// TODO(bengr): Use DataReductionProxySettings instead once it is safe to
// instantiate from here.
PrefService* prefs = profile->GetPrefs();
return prefs && prefs->GetBoolean(
data_reduction_proxy::prefs::kDataReductionProxyEnabled);
}
} // namespace
PrecacheLauncher::PrecacheLauncher(JNIEnv* env, jobject obj)
: weak_java_precache_launcher_(env, obj), weak_factory_(this) {}
PrecacheLauncher::~PrecacheLauncher() {}
void PrecacheLauncher::Destroy(JNIEnv* env, jobject obj) {
delete this;
}
void PrecacheLauncher::Start(JNIEnv* env, jobject obj) {
// TODO(bengr): Add integration tests for the whole feature.
Profile* profile = GetProfile();
PrecacheManager* precache_manager = GetPrecacheManager(profile);
scoped_refptr<history::TopSites> ts = TopSitesFactory::GetForProfile(profile);
precache::MostVisitedURLsProvider url_list_provider(ts.get());
if (!IsDataReductionProxyEnabled(profile)) {
Java_PrecacheLauncher_onPrecacheCompletedCallback(
env, weak_java_precache_launcher_.get(env).obj());
return;
}
precache_manager->StartPrecaching(
base::Bind(&PrecacheLauncher::OnPrecacheCompleted,
weak_factory_.GetWeakPtr()),
&url_list_provider);
}
void PrecacheLauncher::Cancel(JNIEnv* env, jobject obj) {
Profile* profile = GetProfile();
PrecacheManager* precache_manager = GetPrecacheManager(profile);
precache_manager->CancelPrecaching();
}
void PrecacheLauncher::OnPrecacheCompleted() {
JNIEnv* env = AttachCurrentThread();
Java_PrecacheLauncher_onPrecacheCompletedCallback(
env, weak_java_precache_launcher_.get(env).obj());
}
static jlong Init(JNIEnv* env, jobject obj) {
return reinterpret_cast<intptr_t>(new PrecacheLauncher(env, obj));
}
static jboolean IsPrecachingEnabled(JNIEnv* env, jclass clazz) {
return PrecacheManager::IsPrecachingEnabled();
}
bool RegisterPrecacheLauncher(JNIEnv* env) {
return RegisterNativesImpl(env);
}
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ANDROID_PRECACHE_PRECACHE_LAUNCHER_H_
#define CHROME_BROWSER_ANDROID_PRECACHE_PRECACHE_LAUNCHER_H_
#include <jni.h>
#include "base/android/jni_android.h"
#include "base/android/jni_weak_ref.h"
#include "base/memory/weak_ptr.h"
class PrecacheLauncher {
public:
PrecacheLauncher(JNIEnv* env, jobject obj);
void Destroy(JNIEnv* env, jobject obj);
void Start(JNIEnv* env, jobject obj);
void Cancel(JNIEnv* env, jobject obj);
private:
~PrecacheLauncher();
// Called when precaching completes.
void OnPrecacheCompleted();
JavaObjectWeakGlobalRef weak_java_precache_launcher_;
// This must be the last member field in the class.
base::WeakPtrFactory<PrecacheLauncher> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PrecacheLauncher);
};
// Registers the native methods to be called from Java.
bool RegisterPrecacheLauncher(JNIEnv* env);
#endif // CHROME_BROWSER_ANDROID_PRECACHE_PRECACHE_LAUNCHER_H_
......@@ -619,6 +619,7 @@
'../components/components.gyp:gcm_driver_java',
'../components/components.gyp:invalidation_java',
'../components/components.gyp:navigation_interception_java',
'../components/components.gyp:precache_java',
'../components/components.gyp:variations_java',
'../components/components.gyp:web_contents_delegate_android_java',
'../content/content.gyp:content_java',
......
......@@ -133,6 +133,8 @@
'browser/android/omnibox/omnibox_prerender.h',
'browser/android/password_ui_view_android.cc',
'browser/android/password_ui_view_android.h',
'browser/android/precache/precache_launcher.cc',
'browser/android/precache/precache_launcher.h',
'browser/android/preferences/autofill/autofill_profile_bridge.cc',
'browser/android/preferences/autofill/autofill_profile_bridge.h',
'browser/android/preferences/pref_service_bridge.cc',
......@@ -1656,6 +1658,7 @@
'android/java/src/org/chromium/chrome/browser/password_manager/Credential.java',
'android/java/src/org/chromium/chrome/browser/password_manager/PasswordAuthenticationManager.java',
'android/java/src/org/chromium/chrome/browser/PasswordUIView.java',
'android/java/src/org/chromium/chrome/browser/precache/PrecacheLauncher.java',
'android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java',
'android/java/src/org/chromium/chrome/browser/preferences/LocationSettings.java',
'android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java',
......
......@@ -2913,6 +2913,7 @@
'../base/base.gyp:base',
'../base/base.gyp:base_java_test_support',
'../components/components.gyp:invalidation_javatests',
'../components/components.gyp:precache_javatests',
'../content/content_shell_and_tests.gyp:content_java_test_support',
'../sync/sync.gyp:sync_javatests',
'../ui/android/ui_android.gyp:ui_javatests',
......
......@@ -70,4 +70,31 @@
'includes': [ '../build/protoc.gypi', ],
},
],
'conditions': [
['OS=="android"', {
'targets': [{
'target_name': 'precache_java',
'type': 'none',
'dependencies': [
'../base/base.gyp:base',
'../content/content.gyp:content_java',
],
'variables': {
'java_in_dir': 'precache/android/java',
},
'includes': [ '../build/java.gypi' ],
}, {
'target_name': 'precache_javatests',
'type': 'none',
'dependencies': [
'precache_java',
'../base/base.gyp:base_java_test_support',
],
'variables': {
'java_in_dir': 'precache/android/javatests',
},
'includes': [ '../build/java.gypi' ],
}],
}],
],
}
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/android/rules.gni")
# GYP: //components/precache.gypi:precache_java
android_library("precache_java") {
deps = [
"//base:base_java",
]
DEPRECATED_java_in_dir = "java/src"
}
android_library("precache_javatests") {
deps = [
"//base:base_java_test_support",
":precache_java",
]
DEPRECATED_java_in_dir = "javatests/src"
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.precache;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.VisibleForTesting;
/**
* Utility class that provides information about the current state of the device.
*/
public class DeviceState {
private static DeviceState sDeviceState = null;
/** Disallow Construction of DeviceState objects. Use {@link #getInstance()} instead to create
* a singleton instance.
*/
protected DeviceState() {}
public static DeviceState getInstance() {
if (sDeviceState == null) sDeviceState = new DeviceState();
return sDeviceState;
}
protected NetworkInfoDelegateFactory mNetworkInfoDelegateFactory =
new NetworkInfoDelegateFactory();
@VisibleForTesting
void setNetworkInfoDelegateFactory(NetworkInfoDelegateFactory factory) {
mNetworkInfoDelegateFactory = factory;
}
/** @return integer representing the current status of the battery. */
@VisibleForTesting
int getStickyBatteryStatus(Context context) {
IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
// Call registerReceiver on context.getApplicationContext(), not on context itself, because
// context could be a BroadcastReceiver context, which would throw an
// android.content.ReceiverCallNotAllowedException.
Intent batteryStatus = context.getApplicationContext().registerReceiver(null, iFilter);
if (batteryStatus == null) {
return BatteryManager.BATTERY_STATUS_UNKNOWN;
}
return batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
}
/** @return whether the device is connected to power. */
public boolean isPowerConnected(Context context) {
int status = getStickyBatteryStatus(context);
return status == BatteryManager.BATTERY_STATUS_CHARGING
|| status == BatteryManager.BATTERY_STATUS_FULL;
}
public boolean isInteractive(Context context) {
return ApiCompatibilityUtils.isInteractive(context);
}
/** @return whether the currently active network is Wi-Fi, not roaming, and not metered. */
public boolean isWifiAvailable(Context context) {
NetworkInfoDelegate networkInfo =
mNetworkInfoDelegateFactory.getNetworkInfoDelegate(context);
return (networkInfo.isValid()
&& networkInfo.getType() == ConnectivityManager.TYPE_WIFI
&& networkInfo.isAvailable()
&& networkInfo.isConnected()
&& !networkInfo.isRoaming()
&& !networkInfo.isActiveNetworkMetered());
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.precache;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import org.chromium.base.VisibleForTesting;
/**
* Wrapper class for NetworkInfo and ConnectivityManager.
*/
public class NetworkInfoDelegate {
private NetworkInfo mNetworkInfo;
private ConnectivityManager mConnectivityManager;
@VisibleForTesting
NetworkInfoDelegate() {}
public NetworkInfoDelegate(Context context) {
getNetworkInfo(context);
}
protected void getNetworkInfo(Context context) {
mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
}
protected boolean isValid() {
return mNetworkInfo != null;
}
protected int getType() {
return mNetworkInfo.getType();
}
protected boolean isAvailable() {
return mNetworkInfo.isAvailable();
}
protected boolean isConnected() {
return mNetworkInfo.isConnected();
}
protected boolean isRoaming() {
return mNetworkInfo.isRoaming();
}
protected boolean isActiveNetworkMetered() {
// ConnectivityManager.isActiveNetworkMetered was added in SDK API 16.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
return false;
}
return mConnectivityManager.isActiveNetworkMetered();
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.precache;
import android.content.Context;
/**
* Factory for creating network info delegates.
*/
public class NetworkInfoDelegateFactory {
NetworkInfoDelegate getNetworkInfoDelegate(Context context) {
return new NetworkInfoDelegate(context);
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.precache;
import android.content.Context;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import org.chromium.base.test.util.AdvancedMockContext;
import org.chromium.base.test.util.Feature;
/**
* Tests for {@link DeviceState}.
*/
public class DeviceStateTest extends InstrumentationTestCase {
/**
* Factory to create {@link MockNetworkInfoDelegate} instances.
*/
static class MockNetworkInfoDelegateFactory extends NetworkInfoDelegateFactory {
private final boolean mIsValid;
private final int mType;
private final boolean mIsAvailable;
private final boolean mIsConnected;
private final boolean mIsRoaming;
private final boolean mIsActiveNetworkMetered;
MockNetworkInfoDelegateFactory(boolean valid, int type, boolean available,
boolean connected, boolean roaming, boolean activeNetworkMetered) {
mIsValid = valid;
mType = type;
mIsAvailable = available;
mIsConnected = connected;
mIsRoaming = roaming;
mIsActiveNetworkMetered = activeNetworkMetered;
}
@Override
NetworkInfoDelegate getNetworkInfoDelegate(Context context) {
return new MockNetworkInfoDelegate(mIsValid, mType, mIsAvailable, mIsConnected,
mIsRoaming, mIsActiveNetworkMetered);
}
}
/**
* Mock of {@link NetworkInfoDelegate}.
*/
static class MockNetworkInfoDelegate extends NetworkInfoDelegate {
private final boolean mIsValid;
private final int mType;
private final boolean mIsAvailable;
private final boolean mIsConnected;
private final boolean mIsRoaming;
private final boolean mIsActiveNetworkMetered;
MockNetworkInfoDelegate(boolean valid, int type, boolean available, boolean connected,
boolean roaming, boolean activeNetworkMetered) {
mIsValid = valid;
mType = type;
mIsAvailable = available;
mIsConnected = connected;
mIsRoaming = roaming;
mIsActiveNetworkMetered = activeNetworkMetered;
}
@Override
protected void getNetworkInfo(Context context) {}
@Override
protected boolean isValid() {
return mIsValid;
}
@Override
protected int getType() {
return mType;
}
@Override
protected boolean isAvailable() {
return mIsAvailable;
}
@Override
protected boolean isConnected() {
return mIsConnected;
}
@Override
protected boolean isRoaming() {
return mIsRoaming;
}
@Override
protected boolean isActiveNetworkMetered() {
return mIsActiveNetworkMetered;
}
}
/**
* Mock of {@link DeviceState}.
*/
static class MockDeviceState extends DeviceState {
int mBatteryStatus;
@Override
int getStickyBatteryStatus(Context context) {
return mBatteryStatus;
}
public void setStickyBatteryStatus(int status) {
mBatteryStatus = status;
}
}
@SmallTest
@Feature({"Precache"})
public void testPowerConnected() {
AdvancedMockContext context = new AdvancedMockContext();
MockDeviceState deviceState = new MockDeviceState();
deviceState.setStickyBatteryStatus(BatteryManager.BATTERY_STATUS_NOT_CHARGING);
assertFalse(deviceState.isPowerConnected(context));
deviceState.setStickyBatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING);
assertTrue(deviceState.isPowerConnected(context));
deviceState.setStickyBatteryStatus(BatteryManager.BATTERY_STATUS_FULL);
assertTrue(deviceState.isPowerConnected(context));
}
@SmallTest
@Feature({"Precache"})
public void testWifiAvailable() {
AdvancedMockContext context = new AdvancedMockContext();
DeviceState deviceState = DeviceState.getInstance();
// Expect WiFi to be reported as available because there is valid {@link NetworkInfo},
// the connection is WiFi, it's available and connected, and not roaming or metered.
deviceState.setNetworkInfoDelegateFactory(
new MockNetworkInfoDelegateFactory(
true, ConnectivityManager.TYPE_WIFI, true, true, false, false));
assertTrue(deviceState.isWifiAvailable(context));
// Expect WiFi to be reported as unavailable because one of the aforementioned required
// conditions is not met.
deviceState.setNetworkInfoDelegateFactory(
new MockNetworkInfoDelegateFactory(
false, ConnectivityManager.TYPE_WIFI, true, true, false, false));
assertFalse(deviceState.isWifiAvailable(context));
deviceState.setNetworkInfoDelegateFactory(
new MockNetworkInfoDelegateFactory(true, 0, false, true, false, false));
assertFalse(deviceState.isWifiAvailable(context));
deviceState.setNetworkInfoDelegateFactory(
new MockNetworkInfoDelegateFactory(
true, ConnectivityManager.TYPE_WIFI, false, true, false, false));
assertFalse(deviceState.isWifiAvailable(context));
deviceState.setNetworkInfoDelegateFactory(
new MockNetworkInfoDelegateFactory(
true, ConnectivityManager.TYPE_WIFI, true, false, false, false));
assertFalse(deviceState.isWifiAvailable(context));
deviceState.setNetworkInfoDelegateFactory(
new MockNetworkInfoDelegateFactory(
true, ConnectivityManager.TYPE_WIFI, true, true, true, false));
assertFalse(deviceState.isWifiAvailable(context));
deviceState.setNetworkInfoDelegateFactory(
new MockNetworkInfoDelegateFactory(
true, ConnectivityManager.TYPE_WIFI, true, true, false, true));
assertFalse(deviceState.isWifiAvailable(context));
deviceState.setNetworkInfoDelegateFactory(
new MockNetworkInfoDelegateFactory(true, 0, false, false, true, true));
assertFalse(deviceState.isWifiAvailable(context));
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.precache;
import android.content.Context;
/**
* Mock of the DeviceState class.
*/
public class MockDeviceState extends DeviceState {
private final int mStickyBatteryStatus;
private final boolean mPowerIsConnected;
private final boolean mInteractive;
private final boolean mWifiIsAvailable;
public MockDeviceState(int stickyBatteryStatus, boolean powerIsConnected,
boolean interactive, boolean wifiIsAvailable) {
mStickyBatteryStatus = stickyBatteryStatus;
mPowerIsConnected = powerIsConnected;
mInteractive = interactive;
mWifiIsAvailable = wifiIsAvailable;
}
@Override
int getStickyBatteryStatus(Context context) {
return mStickyBatteryStatus;
}
@Override
public boolean isPowerConnected(Context context) {
return mPowerIsConnected;
}
@Override
public boolean isInteractive(Context context) {
return mInteractive;
}
@Override
public boolean isWifiAvailable(Context context) {
return mWifiIsAvailable;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment