| // Copyright 2016 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.offlinepages; |
| |
| import android.annotation.TargetApi; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.net.ConnectivityManager; |
| import android.net.NetworkInfo; |
| import android.os.BatteryManager; |
| import android.os.Build; |
| import android.os.PowerManager; |
| |
| import org.chromium.base.VisibleForTesting; |
| import org.chromium.net.ConnectionType; |
| import org.chromium.net.NetworkChangeNotifier; |
| |
| /** |
| * Device network and power conditions that can be either checked individually with the specific |
| * static methods or gathered all at once using {@link.getCurrent}. |
| */ |
| public class DeviceConditions { |
| // Battery and power related variables. |
| private boolean mPowerConnected; |
| private int mBatteryPercentage; |
| private boolean mPowerSaveOn; |
| |
| // Network related variables. |
| private int mNetConnectionType = ConnectionType.CONNECTION_NONE; |
| private boolean mActiveNetworkMetered; |
| |
| /** |
| * Creates a DeviceConditions instance that stores a snapshot of the current set of device |
| * network and power conditions. Also used when setting up tests simulating specific conditions. |
| */ |
| @VisibleForTesting |
| public DeviceConditions(boolean powerConnected, int batteryPercentage, int netConnectionType, |
| boolean powerSaveOn, boolean activeNetworkMetered) { |
| mPowerConnected = powerConnected; |
| mBatteryPercentage = batteryPercentage; |
| mPowerSaveOn = powerSaveOn; |
| mNetConnectionType = netConnectionType; |
| mActiveNetworkMetered = activeNetworkMetered; |
| } |
| |
| @VisibleForTesting |
| DeviceConditions() { |
| } |
| |
| /** |
| * Returns the current device conditions if the device supports obtaining battery status. |
| * Otherwise it will return null. |
| */ |
| public static DeviceConditions getCurrent(Context context) { |
| Intent batteryStatus = getBatteryStatus(context); |
| if (batteryStatus == null) return null; |
| |
| return new DeviceConditions(isCurrentlyPowerConnected(context, batteryStatus), |
| getCurrentBatteryPercentage(context, batteryStatus), |
| getCurrentNetConnectionType(context), isCurrentlyInPowerSaveMode(context), |
| isCurrentActiveNetworkMetered(context)); |
| } |
| |
| /** @return Whether the device is connected to a power source. */ |
| public static boolean isCurrentlyPowerConnected(Context context) { |
| Intent batteryStatus = getBatteryStatus(context); |
| if (batteryStatus == null) return false; |
| |
| return isCurrentlyPowerConnected(context, batteryStatus); |
| } |
| |
| private static boolean isCurrentlyPowerConnected(Context context, Intent batteryStatus) { |
| int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); |
| boolean isConnected = (status == BatteryManager.BATTERY_STATUS_CHARGING |
| || status == BatteryManager.BATTERY_STATUS_FULL); |
| return isConnected; |
| } |
| |
| /** @return The battery percentage or 0 if the device can't provide that information. */ |
| public static int getCurrentBatteryPercentage(Context context) { |
| Intent batteryStatus = getBatteryStatus(context); |
| if (batteryStatus == null) return 0; |
| |
| return getCurrentBatteryPercentage(context, batteryStatus); |
| } |
| |
| private static int getCurrentBatteryPercentage(Context context, Intent batteryStatus) { |
| int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); |
| if (scale == 0) return 0; |
| |
| int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); |
| int percentage = Math.round(100 * level / (float) scale); |
| return percentage; |
| } |
| |
| /** |
| * @return Whether the device is in power save mode. This feature is only available in Lollipop |
| * and later versions of Android devices so it will return false for earlier versions. |
| */ |
| public static boolean isCurrentlyInPowerSaveMode(Context context) { |
| if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { |
| return false; |
| } |
| return isCurrentlyInPowerSaveModeLollipop(context); |
| } |
| |
| @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
| private static boolean isCurrentlyInPowerSaveModeLollipop(Context context) { |
| PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); |
| return powerManager.isPowerSaveMode(); |
| } |
| |
| /** |
| * @return Network connection type, where possible values are defined by |
| * org.chromium.net.ConnectionType. |
| */ |
| public static int getCurrentNetConnectionType(Context context) { |
| int connectionType = ConnectionType.CONNECTION_NONE; |
| |
| // If we are starting in the background, native portion might not be initialized. |
| if (NetworkChangeNotifier.isInitialized()) { |
| connectionType = NetworkChangeNotifier.getInstance().getCurrentConnectionType(); |
| } |
| |
| // Sometimes the NetworkConnectionNotifier lags the actual connection type, especially when |
| // the GCM NM wakes us from doze state. If we are really connected, report the connection |
| // type from android. |
| if (connectionType == ConnectionType.CONNECTION_NONE) { |
| // Get the connection type from android in case chromium's type is not yet set. |
| ConnectivityManager cm = |
| (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); |
| boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); |
| if (isConnected) { |
| connectionType = convertAndroidNetworkTypeToConnectionType(activeNetwork.getType()); |
| } |
| } |
| return connectionType; |
| } |
| |
| /** |
| * @return true if the active network is a metered network |
| */ |
| public static boolean isCurrentActiveNetworkMetered(Context context) { |
| ConnectivityManager cm = |
| (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| return cm.isActiveNetworkMetered(); |
| } |
| |
| private static Intent getBatteryStatus(Context context) { |
| IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); |
| // Note this is a sticky intent, so we aren't really registering a receiver, just getting |
| // the sticky intent. That means that we don't need to unregister the filter later. |
| return context.registerReceiver(null, filter); |
| } |
| |
| /** Returns the NCN network type corresponding to the connectivity manager network type */ |
| private static int convertAndroidNetworkTypeToConnectionType( |
| int connectivityManagerNetworkType) { |
| if (connectivityManagerNetworkType == ConnectivityManager.TYPE_WIFI) { |
| return ConnectionType.CONNECTION_WIFI; |
| } |
| // for mobile, we don't know if it is 2G, 3G, or 4G, default to worst case of 2G. |
| if (connectivityManagerNetworkType == ConnectivityManager.TYPE_MOBILE) { |
| return ConnectionType.CONNECTION_2G; |
| } |
| if (connectivityManagerNetworkType == ConnectivityManager.TYPE_BLUETOOTH) { |
| return ConnectionType.CONNECTION_BLUETOOTH; |
| } |
| // Since NetworkConnectivityManager doesn't understand the other types, call them UNKNOWN. |
| return ConnectionType.CONNECTION_UNKNOWN; |
| } |
| |
| /** Returns whether power is connected. */ |
| public boolean isPowerConnected() { |
| return mPowerConnected; |
| } |
| |
| /** Returns the remaining battery power percentage (0-100). */ |
| public int getBatteryPercentage() { |
| return mBatteryPercentage; |
| } |
| |
| /** Returns whether the device is in power save mode. */ |
| public boolean isInPowerSaveMode() { |
| return mPowerSaveOn; |
| } |
| |
| /** |
| * Returns the network connection type based on the values defined in |
| * org.chromium.net.ConnectionType. |
| */ |
| public int getNetConnectionType() { |
| return mNetConnectionType; |
| } |
| |
| /** Returns whether network connection is metered. */ |
| public boolean isActiveNetworkMetered() { |
| return mActiveNetworkMetered; |
| } |
| } |