Merge "AudioService: add missing audio becoming noisy intent" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index 3b57f18..a400fa6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20,8 +20,8 @@
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
- field public static final java.lang.String BIND_CARRIER_CONFIG_SERVICE = "android.permission.BIND_CARRIER_CONFIG_SERVICE";
- field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+ field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+ field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
@@ -15730,7 +15730,7 @@
method public void restoreKeys(byte[], byte[]);
method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler);
- method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler);
+ method public void setOnKeyStatusChangeListener(android.media.MediaDrm.OnKeyStatusChangeListener, android.os.Handler);
method public void setPropertyByteArray(java.lang.String, byte[]);
method public void setPropertyString(java.lang.String, java.lang.String);
field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
@@ -15738,11 +15738,6 @@
field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
- field public static final int KEY_STATUS_EXPIRED = 1; // 0x1
- field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4
- field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2
- field public static final int KEY_STATUS_PENDING = 3; // 0x3
- field public static final int KEY_STATUS_USABLE = 0; // 0x0
field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
field public static final int KEY_TYPE_RELEASE = 3; // 0x3
field public static final int KEY_TYPE_STREAMING = 1; // 0x1
@@ -15751,9 +15746,6 @@
field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
field public static final java.lang.String PROPERTY_VENDOR = "vendor";
field public static final java.lang.String PROPERTY_VERSION = "version";
- field public static final int REQUEST_TYPE_INITIAL = 0; // 0x0
- field public static final int REQUEST_TYPE_RELEASE = 2; // 0x2
- field public static final int REQUEST_TYPE_RENEWAL = 1; // 0x1
}
public final class MediaDrm.CryptoSession {
@@ -15767,11 +15759,19 @@
method public byte[] getData();
method public java.lang.String getDefaultUrl();
method public int getRequestType();
+ field public static final int REQUEST_TYPE_INITIAL = 0; // 0x0
+ field public static final int REQUEST_TYPE_RELEASE = 2; // 0x2
+ field public static final int REQUEST_TYPE_RENEWAL = 1; // 0x1
}
public static final class MediaDrm.KeyStatus {
method public byte[] getKeyId();
method public int getStatusCode();
+ field public static final int STATUS_EXPIRED = 1; // 0x1
+ field public static final int STATUS_INTERNAL_ERROR = 4; // 0x4
+ field public static final int STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2
+ field public static final int STATUS_PENDING = 3; // 0x3
+ field public static final int STATUS_USABLE = 0; // 0x0
}
public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
@@ -15786,8 +15786,8 @@
method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long);
}
- public static abstract interface MediaDrm.OnKeysChangeListener {
- method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
+ public static abstract interface MediaDrm.OnKeyStatusChangeListener {
+ method public abstract void onKeyStatusChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
}
public static final class MediaDrm.ProvisionRequest {
diff --git a/api/system-current.txt b/api/system-current.txt
index dbe0d4f..351ec8e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -28,8 +28,8 @@
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
- field public static final java.lang.String BIND_CARRIER_CONFIG_SERVICE = "android.permission.BIND_CARRIER_CONFIG_SERVICE";
- field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+ field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+ field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
field public static final java.lang.String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
field public static final deprecated java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
@@ -8367,6 +8367,7 @@
field public static final java.lang.String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
+ field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
@@ -16967,7 +16968,7 @@
method public void restoreKeys(byte[], byte[]);
method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler);
- method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler);
+ method public void setOnKeyStatusChangeListener(android.media.MediaDrm.OnKeyStatusChangeListener, android.os.Handler);
method public void setPropertyByteArray(java.lang.String, byte[]);
method public void setPropertyString(java.lang.String, java.lang.String);
method public void unprovisionDevice();
@@ -16976,11 +16977,6 @@
field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
- field public static final int KEY_STATUS_EXPIRED = 1; // 0x1
- field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4
- field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2
- field public static final int KEY_STATUS_PENDING = 3; // 0x3
- field public static final int KEY_STATUS_USABLE = 0; // 0x0
field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
field public static final int KEY_TYPE_RELEASE = 3; // 0x3
field public static final int KEY_TYPE_STREAMING = 1; // 0x1
@@ -16989,9 +16985,6 @@
field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
field public static final java.lang.String PROPERTY_VENDOR = "vendor";
field public static final java.lang.String PROPERTY_VERSION = "version";
- field public static final int REQUEST_TYPE_INITIAL = 0; // 0x0
- field public static final int REQUEST_TYPE_RELEASE = 2; // 0x2
- field public static final int REQUEST_TYPE_RENEWAL = 1; // 0x1
}
public final class MediaDrm.CryptoSession {
@@ -17005,11 +16998,19 @@
method public byte[] getData();
method public java.lang.String getDefaultUrl();
method public int getRequestType();
+ field public static final int REQUEST_TYPE_INITIAL = 0; // 0x0
+ field public static final int REQUEST_TYPE_RELEASE = 2; // 0x2
+ field public static final int REQUEST_TYPE_RENEWAL = 1; // 0x1
}
public static final class MediaDrm.KeyStatus {
method public byte[] getKeyId();
method public int getStatusCode();
+ field public static final int STATUS_EXPIRED = 1; // 0x1
+ field public static final int STATUS_INTERNAL_ERROR = 4; // 0x4
+ field public static final int STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2
+ field public static final int STATUS_PENDING = 3; // 0x3
+ field public static final int STATUS_USABLE = 0; // 0x0
}
public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
@@ -17024,8 +17025,8 @@
method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long);
}
- public static abstract interface MediaDrm.OnKeysChangeListener {
- method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
+ public static abstract interface MediaDrm.OnKeyStatusChangeListener {
+ method public abstract void onKeyStatusChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
}
public static final class MediaDrm.ProvisionRequest {
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 4a8cf08..0dad4dc 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -71,6 +71,8 @@
runHasAdoptable();
} else if ("get-primary-storage-uuid".equals(op)) {
runGetPrimaryStorageUuid();
+ } else if ("set-force-adoptable".equals(op)) {
+ runSetForceAdoptable();
} else if ("partition".equals(op)) {
runPartition();
} else if ("mount".equals(op)) {
@@ -116,14 +118,19 @@
}
public void runHasAdoptable() {
- System.out.println(SystemProperties.getBoolean(StorageManager.PROP_HAS_ADOPTABLE, false)
- || SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false));
+ System.out.println(SystemProperties.getBoolean(StorageManager.PROP_HAS_ADOPTABLE, false));
}
public void runGetPrimaryStorageUuid() throws RemoteException {
System.out.println(mSm.getPrimaryStorageUuid());
}
+ public void runSetForceAdoptable() throws RemoteException {
+ final boolean forceAdoptable = Boolean.parseBoolean(nextArg());
+ mSm.setDebugFlags(forceAdoptable ? StorageManager.DEBUG_FORCE_ADOPTABLE : 0,
+ StorageManager.DEBUG_FORCE_ADOPTABLE);
+ }
+
public void runPartition() throws RemoteException {
final String diskId = nextArg();
final String type = nextArg();
@@ -177,6 +184,7 @@
System.err.println(" sm list-volumes [public|private|emulated|all]");
System.err.println(" sm has-adoptable");
System.err.println(" sm get-primary-storage-uuid");
+ System.err.println(" sm set-force-adoptable [true|false]");
System.err.println("");
System.err.println(" sm partition DISK [public|private|mixed] [ratio]");
System.err.println(" sm mount VOLUME");
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7d76760..2db623b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1535,6 +1535,22 @@
"android.intent.action.MANAGE_APP_PERMISSIONS";
/**
+ * Activity action: Launch UI to manage permissions.
+ * <p>
+ * Input: Nothing.
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_PERMISSIONS =
+ "android.intent.action.MANAGE_PERMISSIONS";
+
+ /**
* Intent extra: An app package name.
* <p>
* Type: String
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4dfe0de..5f515eb 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -425,6 +425,24 @@
public abstract long getMobileRadioActiveTime(int which);
public abstract int getMobileRadioActiveCount(int which);
+ /**
+ * Get the total cpu time (in microseconds) this UID had processes executing in userspace.
+ */
+ public abstract long getUserCpuTimeUs(int which);
+
+ /**
+ * Get the total cpu time (in microseconds) this UID had processes executing kernel syscalls.
+ */
+ public abstract long getSystemCpuTimeUs(int which);
+
+ /**
+ * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed.
+ * @param speedStep the index of the CPU speed. This is not the actual speed of the CPU.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
+ * @see BatteryStats#getCpuSpeedSteps()
+ */
+ public abstract long getTimeAtCpuSpeed(int step, int which);
+
public static abstract class Sensor {
/*
* FIXME: it's not correct to use this magic value because it
@@ -506,15 +524,6 @@
*/
public abstract long getForegroundTime(int which);
- /**
- * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed.
- * @param speedStep the index of the CPU speed. This is not the actual speed of the
- * CPU.
- * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
- * @see BatteryStats#getCpuSpeedSteps()
- */
- public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
-
public abstract int countExcessivePowers();
public abstract ExcessivePower getExcessivePower(int i);
@@ -3873,6 +3882,16 @@
}
}
+ final long userCpuTimeUs = u.getUserCpuTimeUs(which);
+ final long systemCpuTimeUs = u.getSystemCpuTimeUs(which);
+ if (userCpuTimeUs > 0 || systemCpuTimeUs > 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Total cpu time: ");
+ formatTimeMs(sb, (userCpuTimeUs + systemCpuTimeUs) / 1000);
+ pw.println(sb.toString());
+ }
+
final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
= u.getProcessStats();
for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 2b058a8..e55ae99 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1005,6 +1005,22 @@
}
@Override
+ public long benchmark(String volId) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(volId);
+ mRemote.transact(Stub.TRANSACTION_benchmark, _data, _reply, 0);
+ _reply.readException();
+ return _reply.readLong();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
public void partitionPublic(String diskId) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -1113,6 +1129,22 @@
}
@Override
+ public void setDebugFlags(int _flags, int _mask) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(_flags);
+ _data.writeInt(_mask);
+ mRemote.transact(Stub.TRANSACTION_setDebugFlags, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
+
+ @Override
public String getPrimaryStorageUuid() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -1257,6 +1289,9 @@
static final int TRANSACTION_getPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 57;
static final int TRANSACTION_setPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 58;
+ static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59;
+ static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -1726,6 +1761,14 @@
reply.writeNoException();
return true;
}
+ case TRANSACTION_benchmark: {
+ data.enforceInterface(DESCRIPTOR);
+ String volId = data.readString();
+ long res = benchmark(volId);
+ reply.writeNoException();
+ reply.writeLong(res);
+ return true;
+ }
case TRANSACTION_partitionPublic: {
data.enforceInterface(DESCRIPTOR);
String diskId = data.readString();
@@ -1778,6 +1821,14 @@
reply.writeNoException();
return true;
}
+ case TRANSACTION_setDebugFlags: {
+ data.enforceInterface(DESCRIPTOR);
+ int _flags = data.readInt();
+ int _mask = data.readInt();
+ setDebugFlags(_flags, _mask);
+ reply.writeNoException();
+ return true;
+ }
case TRANSACTION_getPrimaryStorageUuid: {
data.enforceInterface(DESCRIPTOR);
String volumeUuid = getPrimaryStorageUuid();
@@ -2088,6 +2139,7 @@
public void mount(String volId) throws RemoteException;
public void unmount(String volId) throws RemoteException;
public void format(String volId) throws RemoteException;
+ public long benchmark(String volId) throws RemoteException;
public void partitionPublic(String diskId) throws RemoteException;
public void partitionPrivate(String diskId) throws RemoteException;
@@ -2097,6 +2149,7 @@
public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException;
public void forgetVolume(String fsUuid) throws RemoteException;
public void forgetAllVolumes() throws RemoteException;
+ public void setDebugFlags(int flags, int mask) throws RemoteException;
public String getPrimaryStorageUuid() throws RemoteException;
public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8c0bbbf..8ff56f8 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -82,6 +82,9 @@
/** {@hide} */
public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
+ /** {@hide} */
+ public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0;
+
private final Context mContext;
private final ContentResolver mResolver;
@@ -641,6 +644,15 @@
}
/** {@hide} */
+ public long benchmark(String volId) {
+ try {
+ return mMountService.benchmark(volId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
public void partitionPublic(String diskId) {
try {
mMountService.partitionPublic(diskId);
diff --git a/core/java/android/service/carrier/CarrierConfigService.java b/core/java/android/service/carrier/CarrierConfigService.java
index bc42b6b..bf33ad5 100644
--- a/core/java/android/service/carrier/CarrierConfigService.java
+++ b/core/java/android/service/carrier/CarrierConfigService.java
@@ -23,14 +23,14 @@
* A service that sets carrier configuration for telephony services.
* <p>
* To extend this class, you must declare the service in your manifest file to require the
- * {@link android.Manifest.permission#BIND_CARRIER_CONFIG_SERVICE} permission and include an intent
+ * {@link android.Manifest.permission#BIND_CARRIER_SERVICES} permission and include an intent
* filter with the {@link #SERVICE_INTERFACE} action. For example:
* </p>
*
* <pre>{@code
* <service android:name=".MyCarrierConfigService"
* android:label="@string/service_name"
- * android:permission="android.permission.BIND_CARRIER_CONFIG_SERVICE">
+ * android:permission="android.permission.BIND_CARRIER_SERVICES">
* <intent-filter>
* <action android:name="android.service.carrier.CarrierConfigService" />
* </intent-filter>
diff --git a/core/java/android/service/carrier/CarrierMessagingService.java b/core/java/android/service/carrier/CarrierMessagingService.java
index d7bf10c..f5396a3 100644
--- a/core/java/android/service/carrier/CarrierMessagingService.java
+++ b/core/java/android/service/carrier/CarrierMessagingService.java
@@ -31,12 +31,12 @@
* A service that receives calls from the system when new SMS and MMS are
* sent or received.
* <p>To extend this class, you must declare the service in your manifest file with
- * the {@link android.Manifest.permission#BIND_CARRIER_MESSAGING_SERVICE} permission
+ * the {@link android.Manifest.permission#BIND_CARRIER_SERVICES} permission
* and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
* <pre>
* <service android:name=".MyMessagingService"
* android:label="@string/service_name"
- * android:permission="android.permission.BIND_CARRIER_MESSAGING_SERVICE">
+ * android:permission="android.permission.BIND_CARRIER_SERVICES">
* <intent-filter>
* <action android:name="android.service.carrier.CarrierMessagingService" />
* </intent-filter>
diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java
index 2a2589a..7ea9da1 100644
--- a/core/java/android/text/BidiFormatter.java
+++ b/core/java/android/text/BidiFormatter.java
@@ -25,7 +25,7 @@
/**
* Utility class for formatting text for display in a potentially opposite-directionality context
* without garbling. The directionality of the context is set at formatter creation and the
- * directionality of the text can be either estimated or passed in when known.
+ * directionality of the text can be either estimated or passed in when known.
*
* <p>To support versions lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
* you can use the support library's {@link android.support.v4.text.BidiFormatter} class.
@@ -377,9 +377,11 @@
* See {@link TextDirectionHeuristics} for pre-defined heuristics.
* @param isolate Whether to directionally isolate the string to prevent it from garbling the
* content around it
- * @return Input string after applying the above processing.
+ * @return Input string after applying the above processing. {@code null} if {@code str} is
+ * {@code null}.
*/
public String unicodeWrap(String str, TextDirectionHeuristic heuristic, boolean isolate) {
+ if (str == null) return null;
final boolean isRtl = heuristic.isRtl(str, 0, str.length());
StringBuilder result = new StringBuilder();
if (getStereoReset() && isolate) {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 9782d72..b7d529e 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -40,7 +40,10 @@
import dalvik.system.VMRuntime;
import java.io.File;
+import java.io.IOException;
import java.util.Arrays;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
/**
* Top level factory, used creating all the main WebView implementation classes.
@@ -323,15 +326,30 @@
long newVmSize = 0L;
for (String path : nativeLibs) {
+ if (path == null || TextUtils.isEmpty(path)) continue;
if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
- if (path == null) continue;
File f = new File(path);
if (f.exists()) {
- long length = f.length();
- if (length > newVmSize) {
- newVmSize = length;
+ newVmSize = Math.max(newVmSize, f.length());
+ continue;
+ }
+ if (path.contains("!")) {
+ String[] split = TextUtils.split(path, "!");
+ if (split.length == 2) {
+ try {
+ ZipFile z = new ZipFile(split[0]);
+ ZipEntry e = z.getEntry(split[1]);
+ if (e != null && e.getMethod() == ZipEntry.STORED) {
+ newVmSize = Math.max(newVmSize, e.getSize());
+ continue;
+ }
+ }
+ catch (IOException e) {
+ Log.e(LOGTAG, "error reading APK file " + split[0] + ", ", e);
+ }
}
}
+ Log.e(LOGTAG, "error sizing load for " + path);
}
if (DEBUG) {
@@ -355,6 +373,27 @@
}
// throws MissingWebViewPackageException
+ private static String getLoadFromApkPath(String apkPath,
+ String[] abiList,
+ String nativeLibFileName) {
+ // Search the APK for a native library conforming to a listed ABI.
+ try {
+ ZipFile z = new ZipFile(apkPath);
+ for (String abi : abiList) {
+ final String entry = "lib/" + abi + "/" + nativeLibFileName;
+ ZipEntry e = z.getEntry(entry);
+ if (e != null && e.getMethod() == ZipEntry.STORED) {
+ // Return a path formatted for dlopen() load from APK.
+ return apkPath + "!" + entry;
+ }
+ }
+ } catch (IOException e) {
+ throw new MissingWebViewPackageException(e);
+ }
+ return "";
+ }
+
+ // throws MissingWebViewPackageException
private static String[] getWebViewNativeLibraryPaths() {
ApplicationInfo ai = getWebViewApplicationInfo();
final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
@@ -382,8 +421,29 @@
path32 = ai.nativeLibraryDir;
path64 = "";
}
- if (!TextUtils.isEmpty(path32)) path32 += "/" + NATIVE_LIB_FILE_NAME;
- if (!TextUtils.isEmpty(path64)) path64 += "/" + NATIVE_LIB_FILE_NAME;
+
+ // Form the full paths to the extracted native libraries.
+ // If libraries were not extracted, try load from APK paths instead.
+ if (!TextUtils.isEmpty(path32)) {
+ path32 += "/" + NATIVE_LIB_FILE_NAME;
+ File f = new File(path32);
+ if (!f.exists()) {
+ path32 = getLoadFromApkPath(ai.sourceDir,
+ Build.SUPPORTED_32_BIT_ABIS,
+ NATIVE_LIB_FILE_NAME);
+ }
+ }
+ if (!TextUtils.isEmpty(path64)) {
+ path64 += "/" + NATIVE_LIB_FILE_NAME;
+ File f = new File(path64);
+ if (!f.exists()) {
+ path64 = getLoadFromApkPath(ai.sourceDir,
+ Build.SUPPORTED_64_BIT_ABIS,
+ NATIVE_LIB_FILE_NAME);
+ }
+ }
+
+ if (DEBUG) Log.v(LOGTAG, "Native 32-bit lib: " + path32 + ", 64-bit lib: " + path64);
return new String[] { path32, path64 };
}
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index d271af2..8fe8252 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -186,11 +186,12 @@
}
private int getMonthForPosition(int position) {
- return position % MONTHS_IN_YEAR + mMinDate.get(Calendar.MONTH);
+ return (position + mMinDate.get(Calendar.MONTH)) % MONTHS_IN_YEAR;
}
private int getYearForPosition(int position) {
- return position / MONTHS_IN_YEAR + mMinDate.get(Calendar.YEAR);
+ final int yearOffset = (position + mMinDate.get(Calendar.MONTH)) / MONTHS_IN_YEAR;
+ return yearOffset + mMinDate.get(Calendar.YEAR);
}
private int getPositionForDay(@Nullable Calendar day) {
@@ -198,8 +199,8 @@
return -1;
}
- final int yearOffset = (day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR));
- final int monthOffset = (day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH));
+ final int yearOffset = day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
+ final int monthOffset = day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
final int position = yearOffset * MONTHS_IN_YEAR + monthOffset;
return position;
}
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index a434317..dc772fb 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -176,8 +176,6 @@
}
}
});
-
- updateButtonVisibility(mViewPager.getCurrentItem());
}
private void updateButtonVisibility(int position) {
@@ -346,6 +344,8 @@
// Changing the min/max date changes the selection position since we
// don't really have stable IDs. Jumps immediately to the new position.
setDate(mSelectedDay.getTimeInMillis(), false, false);
+
+ updateButtonVisibility(mViewPager.getCurrentItem());
}
/**
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 1d6f6dc..c829783 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3426,9 +3426,13 @@
protected void updateDrawable() {
final int offset = getCurrentCursorOffset();
final boolean isRtlCharAtOffset = mTextView.getLayout().isRtlCharAt(offset);
+ final Drawable oldDrawable = mDrawable;
mDrawable = isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr;
mHotspotX = getHotspotX(mDrawable, isRtlCharAtOffset);
mHorizontalGravity = getHorizontalGravity(isRtlCharAtOffset);
+ if (oldDrawable != mDrawable) {
+ postInvalidate();
+ }
}
protected abstract int getHotspotX(Drawable drawable, boolean isRtlRun);
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 80bc5fe..49230c1 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -45,33 +45,11 @@
import android.widget.ImageView;
public class PlatLogoActivity extends Activity {
- final static int[] FLAVORS = {
- 0xFF9C27B0, 0xFFBA68C8, // grape
- 0xFFFF9800, 0xFFFFB74D, // orange
- 0xFFF06292, 0xFFF8BBD0, // bubblegum
- 0xFFAFB42B, 0xFFCDDC39, // lime
- 0xFFFFEB3B, 0xFFFFF176, // lemon
- 0xFF795548, 0xFFA1887F, // mystery flavor
- };
FrameLayout mLayout;
int mTapCount;
int mKeyCount;
PathInterpolator mInterpolator = new PathInterpolator(0f, 0f, 0.5f, 1f);
- static int newColorIndex() {
- return 2*((int) (Math.random()*FLAVORS.length/2));
- }
-
- Drawable makeRipple() {
- final int idx = newColorIndex();
- final ShapeDrawable popbg = new ShapeDrawable(new OvalShape());
- popbg.getPaint().setColor(FLAVORS[idx]);
- final RippleDrawable ripple = new RippleDrawable(
- ColorStateList.valueOf(FLAVORS[idx+1]),
- popbg, null);
- return ripple;
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -87,120 +65,62 @@
final int size = (int)
(Math.min(Math.min(dm.widthPixels, dm.heightPixels), 600*dp) - 100*dp);
- final View stick = new View(this) {
- Paint mPaint = new Paint();
- Path mShadow = new Path();
-
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- setWillNotDraw(false);
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRect(0, getHeight() / 2, getWidth(), getHeight());
- }
- });
- }
- @Override
- public void onDraw(Canvas c) {
- final int w = c.getWidth();
- final int h = c.getHeight() / 2;
- c.translate(0, h);
- final GradientDrawable g = new GradientDrawable();
- g.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);
- g.setGradientCenter(w * 0.75f, 0);
- g.setColors(new int[] { 0xFFFFFFFF, 0xFFAAAAAA });
- g.setBounds(0, 0, w, h);
- g.draw(c);
- mPaint.setColor(0xFFAAAAAA);
- mShadow.reset();
- mShadow.moveTo(0,0);
- mShadow.lineTo(w, 0);
- mShadow.lineTo(w, size/2 + 1.5f*w);
- mShadow.lineTo(0, size/2);
- mShadow.close();
- c.drawPath(mShadow, mPaint);
- }
- };
- mLayout.addView(stick, new FrameLayout.LayoutParams((int) (32 * dp),
- ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER_HORIZONTAL));
- stick.setAlpha(0f);
-
- final ImageView im = new ImageView(this);
+ final View im = new View(this);
im.setTranslationZ(20);
- im.setScaleX(0);
- im.setScaleY(0);
+ im.setScaleX(0.5f);
+ im.setScaleY(0.5f);
+ im.setAlpha(0f);
+ im.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ final int pad = (int) (8*dp);
+ outline.setOval(pad, pad, view.getWidth()-pad, view.getHeight()-pad);
+ }
+ });
final Drawable platlogo = getDrawable(com.android.internal.R.drawable.platlogo);
- platlogo.setAlpha(0);
- im.setImageDrawable(platlogo);
- im.setBackground(makeRipple());
+ im.setBackground(new RippleDrawable(
+ ColorStateList.valueOf(0xFFFFFFFF),
+ platlogo,
+ null));
im.setClickable(true);
- final ShapeDrawable highlight = new ShapeDrawable(new OvalShape());
- highlight.getPaint().setColor(0x10FFFFFF);
- highlight.setBounds((int)(size*.15f), (int)(size*.15f),
- (int)(size*.6f), (int)(size*.6f));
- im.getOverlay().add(highlight);
im.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- if (mTapCount == 0) {
- im.animate()
- .translationZ(40)
- .scaleX(1)
- .scaleY(1)
- .setInterpolator(mInterpolator)
- .setDuration(700)
- .setStartDelay(500)
- .start();
+ im.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mTapCount < 5) return false;
- final ObjectAnimator a = ObjectAnimator.ofInt(platlogo, "alpha", 0, 255);
- a.setInterpolator(mInterpolator);
- a.setStartDelay(1000);
- a.start();
-
- stick.animate()
- .translationZ(20)
- .alpha(1)
- .setInterpolator(mInterpolator)
- .setDuration(700)
- .setStartDelay(750)
- .start();
-
- im.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (mTapCount < 5) return false;
-
- final ContentResolver cr = getContentResolver();
- if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0)
- == 0) {
- // For posterity: the moment this user unlocked the easter egg
+ final ContentResolver cr = getContentResolver();
+ if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0)
+ == 0) {
+ // For posterity: the moment this user unlocked the easter egg
+ try {
Settings.System.putLong(cr,
Settings.System.EGG_MODE,
System.currentTimeMillis());
+ } catch (RuntimeException e) {
+ Log.e("PlatLogoActivity", "Can't write settings", e);
}
- im.post(new Runnable() {
- @Override
- public void run() {
- try {
- startActivity(new Intent(Intent.ACTION_MAIN)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
- .addCategory("com.android.internal.category.PLATLOGO"));
- } catch (ActivityNotFoundException ex) {
- Log.e("PlatLogoActivity", "No more eggs.");
- }
- finish();
- }
- });
- return true;
}
- });
- } else {
- im.setBackground(makeRipple());
- }
+ im.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ startActivity(new Intent(Intent.ACTION_MAIN)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .addCategory("com.android.internal.category.PLATLOGO"));
+ } catch (ActivityNotFoundException ex) {
+ Log.e("PlatLogoActivity", "No more eggs.");
+ }
+ finish();
+ }
+ });
+ return true;
+ }
+ });
mTapCount++;
}
});
@@ -229,7 +149,7 @@
mLayout.addView(im, new FrameLayout.LayoutParams(size, size, Gravity.CENTER));
- im.animate().scaleX(0.3f).scaleY(0.3f)
+ im.animate().scaleX(1f).scaleY(1f).alpha(1f)
.setInterpolator(mInterpolator)
.setDuration(500)
.setStartDelay(800)
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index a53d46c..fbe87c5 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -615,6 +615,7 @@
mStatsType);
if (bs.sumPower() > 0) {
aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
+ mUsageList.add(bs);
}
}
@@ -742,7 +743,6 @@
parcel.setDataPosition(0);
BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
.createFromParcel(parcel);
- stats.distributeWorkLocked(BatteryStats.STATS_SINCE_CHARGED);
return stats;
} catch (IOException e) {
Log.w(TAG, "Unable to read statistics stream", e);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index c2212f7..eaca43b 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -105,7 +105,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 125 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 126 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -132,6 +132,9 @@
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
+ private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
+ private final KernelCpuSpeedReader mKernelCpuSpeedReader = new KernelCpuSpeedReader();
+
public interface BatteryCallback {
public void batteryNeedsCpuUpdate();
public void batteryPowerChanged(boolean onBattery);
@@ -794,20 +797,6 @@
}
}
- public static class SamplingCounter extends Counter {
- SamplingCounter(TimeBase timeBase, Parcel in) {
- super(timeBase, in);
- }
-
- SamplingCounter(TimeBase timeBase) {
- super(timeBase);
- }
-
- public void addCountAtomic(long count) {
- mCount.addAndGet((int)count);
- }
- }
-
public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
final TimeBase mTimeBase;
long mCount;
@@ -2918,8 +2907,7 @@
public void finishAddingCpuLocked(int perc, int remainUTime, int remainSTtime,
int totalUTime, int totalSTime, int statUserTime, int statSystemTime,
- int statIOWaitTime, int statIrqTime, int statSoftIrqTime, int statIdleTime,
- long[] cpuSpeedTimes) {
+ int statIOWaitTime, int statIrqTime, int statSoftIrqTime, int statIdleTime) {
if (DEBUG) Slog.d(TAG, "Adding cpu: tuser=" + totalUTime + " tsys=" + totalSTime
+ " user=" + statUserTime + " sys=" + statSystemTime
+ " io=" + statIOWaitTime + " irq=" + statIrqTime
@@ -2959,7 +2947,7 @@
remainSTtime -= mySTime;
num--;
Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*");
- proc.addCpuTimeLocked(myUTime, mySTime, cpuSpeedTimes);
+ proc.addCpuTimeLocked(myUTime, mySTime);
}
}
}
@@ -2970,7 +2958,7 @@
Uid uid = getUidStatsLocked(Process.SYSTEM_UID);
if (uid != null) {
Uid.Proc proc = uid.getProcessStatsLocked("*lost*");
- proc.addCpuTimeLocked(remainUTime, remainSTtime, cpuSpeedTimes);
+ proc.addCpuTimeLocked(remainUTime, remainSTtime);
}
}
}
@@ -4398,6 +4386,10 @@
long mCurStepUserTime;
long mCurStepSystemTime;
+ LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
+ LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
+ LongSamplingCounter[] mSpeedBins;
+
/**
* The statistics we have collected for this uid's wake locks.
*/
@@ -4455,6 +4447,7 @@
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mOnBatteryTimeBase);
mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE];
+ mSpeedBins = new LongSamplingCounter[getCpuSpeedSteps()];
}
@Override
@@ -4925,6 +4918,26 @@
}
@Override
+ public long getUserCpuTimeUs(int which) {
+ return mUserCpuTime.getCountLocked(which);
+ }
+
+ @Override
+ public long getSystemCpuTimeUs(int which) {
+ return mSystemCpuTime.getCountLocked(which);
+ }
+
+ @Override
+ public long getTimeAtCpuSpeed(int step, int which) {
+ if (step >= 0 && step < mSpeedBins.length) {
+ if (mSpeedBins[step] != null) {
+ return mSpeedBins[step].getCountLocked(which);
+ }
+ }
+ return 0;
+ }
+
+ @Override
public long getWifiControllerActivity(int type, int which) {
if (type >= 0 && type < NUM_CONTROLLER_ACTIVITY_TYPES &&
mWifiControllerTime[type] != null) {
@@ -5026,6 +5039,15 @@
}
}
+ mUserCpuTime.reset(false);
+ mSystemCpuTime.reset(false);
+ for (int i = 0; i < mSpeedBins.length; i++) {
+ LongSamplingCounter c = mSpeedBins[i];
+ if (c != null) {
+ c.reset(false);
+ }
+ }
+
final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap();
for (int iw=wakeStats.size()-1; iw>=0; iw--) {
Wakelock wl = wakeStats.valueAt(iw);
@@ -5159,6 +5181,15 @@
}
}
mPids.clear();
+
+ mUserCpuTime.detach();
+ mSystemCpuTime.detach();
+ for (int i = 0; i < mSpeedBins.length; i++) {
+ LongSamplingCounter c = mSpeedBins[i];
+ if (c != null) {
+ c.detach();
+ }
+ }
}
return !active;
@@ -5317,6 +5348,20 @@
out.writeInt(0);
}
}
+
+ mUserCpuTime.writeToParcel(out);
+ mSystemCpuTime.writeToParcel(out);
+
+ out.writeInt(mSpeedBins.length);
+ for (int i = 0; i < mSpeedBins.length; i++) {
+ LongSamplingCounter c = mSpeedBins[i];
+ if (c != null) {
+ out.writeInt(1);
+ c.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
}
void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
@@ -5482,6 +5527,18 @@
mBluetoothControllerTime[i] = null;
}
}
+
+ mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
+
+ int bins = in.readInt();
+ int steps = getCpuSpeedSteps();
+ mSpeedBins = new LongSamplingCounter[bins >= steps ? bins : steps];
+ for (int i = 0; i < bins; i++) {
+ if (in.readInt() != 0) {
+ mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ }
+ }
}
/**
@@ -5762,14 +5819,11 @@
*/
int mProcessState = PROCESS_STATE_NONE;
- SamplingCounter[] mSpeedBins;
-
ArrayList<ExcessivePower> mExcessivePower;
Proc(String name) {
mName = name;
mOnBatteryTimeBase.add(this);
- mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -5791,25 +5845,12 @@
mLoadedStarts = mLoadedNumCrashes = mLoadedNumAnrs = 0;
mUnpluggedUserTime = mUnpluggedSystemTime = mUnpluggedForegroundTime = 0;
mUnpluggedStarts = mUnpluggedNumCrashes = mUnpluggedNumAnrs = 0;
- for (int i = 0; i < mSpeedBins.length; i++) {
- SamplingCounter c = mSpeedBins[i];
- if (c != null) {
- c.reset(false);
- }
- }
mExcessivePower = null;
}
void detach() {
mActive = false;
mOnBatteryTimeBase.remove(this);
- for (int i = 0; i < mSpeedBins.length; i++) {
- SamplingCounter c = mSpeedBins[i];
- if (c != null) {
- mOnBatteryTimeBase.remove(c);
- mSpeedBins[i] = null;
- }
- }
}
public int countExcessivePowers() {
@@ -5903,18 +5944,6 @@
out.writeInt(mUnpluggedStarts);
out.writeInt(mUnpluggedNumCrashes);
out.writeInt(mUnpluggedNumAnrs);
-
- out.writeInt(mSpeedBins.length);
- for (int i = 0; i < mSpeedBins.length; i++) {
- SamplingCounter c = mSpeedBins[i];
- if (c != null) {
- out.writeInt(1);
- c.writeToParcel(out);
- } else {
- out.writeInt(0);
- }
- }
-
writeExcessivePowerToParcelLocked(out);
}
@@ -5937,39 +5966,12 @@
mUnpluggedStarts = in.readInt();
mUnpluggedNumCrashes = in.readInt();
mUnpluggedNumAnrs = in.readInt();
-
- int bins = in.readInt();
- int steps = getCpuSpeedSteps();
- mSpeedBins = new SamplingCounter[bins >= steps ? bins : steps];
- for (int i = 0; i < bins; i++) {
- if (in.readInt() != 0) {
- mSpeedBins[i] = new SamplingCounter(mOnBatteryTimeBase, in);
- }
- }
-
readExcessivePowerFromParcelLocked(in);
}
- public BatteryStatsImpl getBatteryStats() {
- return BatteryStatsImpl.this;
- }
-
- public void addCpuTimeLocked(int utime, int stime, long[] speedStepBins) {
+ public void addCpuTimeLocked(int utime, int stime) {
mUserTime += utime;
- mCurStepUserTime += utime;
mSystemTime += stime;
- mCurStepSystemTime += stime;
-
- for (int i = 0; i < mSpeedBins.length && i < speedStepBins.length; i++) {
- long amt = speedStepBins[i];
- if (amt != 0) {
- SamplingCounter c = mSpeedBins[i];
- if (c == null) {
- mSpeedBins[i] = c = new SamplingCounter(mOnBatteryTimeBase);
- }
- c.addCountAtomic(speedStepBins[i]);
- }
- }
}
public void addForegroundTimeLocked(long ttime) {
@@ -6058,16 +6060,6 @@
}
return val;
}
-
- @Override
- public long getTimeAtCpuSpeedStep(int speedStep, int which) {
- if (speedStep < mSpeedBins.length) {
- SamplingCounter c = mSpeedBins[speedStep];
- return c != null ? c.getCountLocked(which) : 0;
- } else {
- return 0;
- }
- }
}
/**
@@ -7729,7 +7721,7 @@
* @param info The energy information from the bluetooth controller.
*/
public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
- if (info != null && mOnBatteryInternal && false) {
+ if (info != null && mOnBatteryInternal) {
mHasBluetoothEnergyReporting = true;
mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
info.getControllerRxTimeMillis());
@@ -7785,6 +7777,32 @@
}
}
+ /**
+ * Read and distribute CPU usage across apps.
+ */
+ public void updateCpuTimeLocked(boolean firstTime) {
+ final int cpuSpeedSteps = getCpuSpeedSteps();
+ final long[] cpuSpeeds = mKernelCpuSpeedReader.readDelta();
+ KernelUidCpuTimeReader.Callback callback = null;
+ if (mOnBatteryInternal && !firstTime) {
+ callback = new KernelUidCpuTimeReader.Callback() {
+ @Override
+ public void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs) {
+ final Uid u = getUidStatsLocked(mapUid(uid));
+ u.mUserCpuTime.addCountLocked(userTimeUs);
+ u.mSystemCpuTime.addCountLocked(systemTimeUs);
+ for (int i = 0; i < cpuSpeedSteps; i++) {
+ if (u.mSpeedBins[i] == null) {
+ u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+ }
+ u.mSpeedBins[i].addCountLocked(cpuSpeeds[i]);
+ }
+ }
+ };
+ }
+ mKernelUidCpuTimeReader.readDelta(callback);
+ }
+
boolean setChargingLocked(boolean charging) {
if (mCharging != charging) {
mCharging = charging;
@@ -8407,6 +8425,7 @@
* Remove the statistics object for a particular uid.
*/
public void removeUidStatsLocked(int uid) {
+ mKernelUidCpuTimeReader.removeUid(uid);
mUidStats.remove(uid);
}
@@ -8440,58 +8459,6 @@
return u.getServiceStatsLocked(pkg, name);
}
- /**
- * Massage data to distribute any reasonable work down to more specific
- * owners. Must only be called on a dead BatteryStats object!
- */
- public void distributeWorkLocked(int which) {
- // Aggregate all CPU time associated with WIFI.
- Uid wifiUid = mUidStats.get(Process.WIFI_UID);
- if (wifiUid != null) {
- long uSecTime = computeBatteryRealtime(SystemClock.elapsedRealtime() * 1000, which);
- for (int ip=wifiUid.mProcessStats.size()-1; ip>=0; ip--) {
- Uid.Proc proc = wifiUid.mProcessStats.valueAt(ip);
- long totalRunningTime = getGlobalWifiRunningTime(uSecTime, which);
- for (int i=0; i<mUidStats.size(); i++) {
- Uid uid = mUidStats.valueAt(i);
- if (uid.mUid != Process.WIFI_UID) {
- long uidRunningTime = uid.getWifiRunningTime(uSecTime, which);
- if (uidRunningTime > 0) {
- Uid.Proc uidProc = uid.getProcessStatsLocked("*wifi*");
- long time = proc.getUserTime(which);
- time = (time*uidRunningTime)/totalRunningTime;
- uidProc.mUserTime += time;
- proc.mUserTime -= time;
- time = proc.getSystemTime(which);
- time = (time*uidRunningTime)/totalRunningTime;
- uidProc.mSystemTime += time;
- proc.mSystemTime -= time;
- time = proc.getForegroundTime(which);
- time = (time*uidRunningTime)/totalRunningTime;
- uidProc.mForegroundTime += time;
- proc.mForegroundTime -= time;
- for (int sb=0; sb<proc.mSpeedBins.length; sb++) {
- SamplingCounter sc = proc.mSpeedBins[sb];
- if (sc != null) {
- time = sc.getCountLocked(which);
- time = (time*uidRunningTime)/totalRunningTime;
- SamplingCounter uidSc = uidProc.mSpeedBins[sb];
- if (uidSc == null) {
- uidSc = new SamplingCounter(mOnBatteryTimeBase);
- uidProc.mSpeedBins[sb] = uidSc;
- }
- uidSc.mCount.addAndGet((int)time);
- sc.mCount.addAndGet((int)-time);
- }
- }
- totalRunningTime -= uidRunningTime;
- }
- }
- }
- }
- }
- }
-
public void shutdownLocked() {
recordShutdownLocked(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
writeSyncLocked();
@@ -8950,6 +8917,23 @@
u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in);
}
+ u.mUserCpuTime.readSummaryFromParcelLocked(in);
+ u.mSystemCpuTime.readSummaryFromParcelLocked(in);
+
+ int NSB = in.readInt();
+ if (NSB > 100) {
+ Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
+ return;
+ }
+
+ u.mSpeedBins = new LongSamplingCounter[NSB];
+ for (int i=0; i<NSB; i++) {
+ if (in.readInt() != 0) {
+ u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+ u.mSpeedBins[i].readSummaryFromParcelLocked(in);
+ }
+ }
+
int NW = in.readInt();
if (NW > 100) {
Slog.w(TAG, "File corrupt: too many wake locks " + NW);
@@ -9007,18 +8991,6 @@
p.mStarts = p.mLoadedStarts = in.readInt();
p.mNumCrashes = p.mLoadedNumCrashes = in.readInt();
p.mNumAnrs = p.mLoadedNumAnrs = in.readInt();
- int NSB = in.readInt();
- if (NSB > 100) {
- Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
- return;
- }
- p.mSpeedBins = new SamplingCounter[NSB];
- for (int i=0; i<NSB; i++) {
- if (in.readInt() != 0) {
- p.mSpeedBins[i] = new SamplingCounter(mOnBatteryTimeBase);
- p.mSpeedBins[i].readSummaryFromParcelLocked(in);
- }
- }
if (!p.readExcessivePowerFromParcelLocked(in)) {
return;
}
@@ -9278,6 +9250,20 @@
u.mMobileRadioActiveCount.writeSummaryFromParcelLocked(out);
}
+ u.mUserCpuTime.writeSummaryFromParcelLocked(out);
+ u.mSystemCpuTime.writeSummaryFromParcelLocked(out);
+
+ out.writeInt(u.mSpeedBins.length);
+ for (int i = 0; i < u.mSpeedBins.length; i++) {
+ LongSamplingCounter speedBin = u.mSpeedBins[i];
+ if (speedBin != null) {
+ out.writeInt(1);
+ speedBin.writeSummaryFromParcelLocked(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+
final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap();
int NW = wakeStats.size();
out.writeInt(NW);
@@ -9344,16 +9330,6 @@
out.writeInt(ps.mStarts);
out.writeInt(ps.mNumCrashes);
out.writeInt(ps.mNumAnrs);
- final int N = ps.mSpeedBins.length;
- out.writeInt(N);
- for (int i=0; i<N; i++) {
- if (ps.mSpeedBins[i] != null) {
- out.writeInt(1);
- ps.mSpeedBins[i].writeSummaryFromParcelLocked(out);
- } else {
- out.writeInt(0);
- }
- }
ps.writeExcessivePowerToParcelLocked(out);
}
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 6c3f958..a3ef612 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -44,55 +44,57 @@
long rawUptimeUs, int statsType) {
final int speedSteps = mSpeedStepTimes.length;
+ long totalTimeAtSpeeds = 0;
+ for (int step = 0; step < speedSteps; step++) {
+ mSpeedStepTimes[step] = u.getTimeAtCpuSpeed(step, statsType);
+ totalTimeAtSpeeds += mSpeedStepTimes[step];
+ }
+ totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
+
+ app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
+ if (DEBUG && app.cpuTimeMs != 0) {
+ Log.d(TAG, "UID " + u.getUid() + ": CPU time " + app.cpuTimeMs + " ms");
+ }
+
+ double cpuPowerMaMs = 0;
+ for (int step = 0; step < speedSteps; step++) {
+ final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds;
+ final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mPowerCpuNormal[step];
+ if (DEBUG && ratio != 0) {
+ Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
+ + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
+ + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
+ }
+ cpuPowerMaMs += cpuSpeedStepPower;
+ }
+
+ if (DEBUG && cpuPowerMaMs != 0) {
+ Log.d(TAG, "UID " + u.getUid() + ": cpu total power="
+ + BatteryStatsHelper.makemAh(cpuPowerMaMs / (60 * 60 * 1000)));
+ }
+
// Keep track of the package with highest drain.
double highestDrain = 0;
+ app.cpuFgTimeMs = 0;
final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
final int processStatsCount = processStats.size();
for (int i = 0; i < processStatsCount; i++) {
final BatteryStats.Uid.Proc ps = processStats.valueAt(i);
final String processName = processStats.keyAt(i);
-
app.cpuFgTimeMs += ps.getForegroundTime(statsType);
- final long totalCpuTime = ps.getUserTime(statsType) + ps.getSystemTime(statsType);
- app.cpuTimeMs += totalCpuTime;
- // Calculate the total CPU time spent at the various speed steps.
- long totalTimeAtSpeeds = 0;
- for (int step = 0; step < speedSteps; step++) {
- mSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, statsType);
- totalTimeAtSpeeds += mSpeedStepTimes[step];
- }
- totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
-
- // Then compute the ratio of time spent at each speed and figure out
- // the total power consumption.
- double cpuPower = 0;
- for (int step = 0; step < speedSteps; step++) {
- final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds;
- final double cpuSpeedStepPower = ratio * totalCpuTime * mPowerCpuNormal[step];
- if (DEBUG && ratio != 0) {
- Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
- + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
- + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
- }
- cpuPower += cpuSpeedStepPower;
- }
-
- if (DEBUG && cpuPower != 0) {
- Log.d(TAG, String.format("process %s, cpu power=%s",
- processName, BatteryStatsHelper.makemAh(cpuPower / (60 * 60 * 1000))));
- }
- app.cpuPowerMah += cpuPower;
+ final long costValue = ps.getUserTime(statsType) + ps.getSystemTime(statsType)
+ + ps.getForegroundTime(statsType);
// Each App can have multiple packages and with multiple running processes.
// Keep track of the package who's process has the highest drain.
if (app.packageWithHighestDrain == null ||
app.packageWithHighestDrain.startsWith("*")) {
- highestDrain = cpuPower;
+ highestDrain = costValue;
app.packageWithHighestDrain = processName;
- } else if (highestDrain < cpuPower && !processName.startsWith("*")) {
- highestDrain = cpuPower;
+ } else if (highestDrain < costValue && !processName.startsWith("*")) {
+ highestDrain = costValue;
app.packageWithHighestDrain = processName;
}
}
@@ -108,6 +110,6 @@
}
// Convert the CPU power to mAh
- app.cpuPowerMah /= (60 * 60 * 1000);
+ app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000);
}
}
diff --git a/core/java/com/android/internal/os/KernelCpuSpeedReader.java b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
new file mode 100644
index 0000000..c30df28
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.text.TextUtils;
+import android.util.Slog;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Reads CPU time spent at various frequencies and provides a delta from the last call to
+ * {@link #readDelta}. Each line in the proc file has the format:
+ *
+ * freq time
+ *
+ * where time is measured in 1/100 seconds.
+ */
+public class KernelCpuSpeedReader {
+ private static final String TAG = "KernelCpuSpeedReader";
+ private static final String sProcFile =
+ "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state";
+ private static final int MAX_SPEEDS = 60;
+
+ private long[] mLastSpeedTimes = new long[MAX_SPEEDS];
+ private long[] mDeltaSpeedTimes = new long[MAX_SPEEDS];
+
+ /**
+ * The returned array is modified in subsequent calls to {@link #readDelta}.
+ * @return The time (in milliseconds) spent at different cpu speeds since the last call to
+ * {@link #readDelta}.
+ */
+ public long[] readDelta() {
+ try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
+ TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
+ String line;
+ int speedIndex = 0;
+ while ((line = reader.readLine()) != null) {
+ splitter.setString(line);
+ Long.parseLong(splitter.next());
+
+ // The proc file reports time in 1/100 sec, so convert to milliseconds.
+ long time = Long.parseLong(splitter.next()) * 10;
+ mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex];
+ mLastSpeedTimes[speedIndex] = time;
+ speedIndex++;
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read cpu-freq", e);
+ Arrays.fill(mDeltaSpeedTimes, 0);
+ }
+ return mDeltaSpeedTimes;
+ }
+}
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
new file mode 100644
index 0000000..b236378
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.util.SparseLongArray;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * Reads /proc/uid_cputime/show_uid_stat which has the line format:
+ *
+ * uid: user_time_micro_seconds system_time_micro_seconds
+ *
+ * This provides the time a UID's processes spent executing in user-space and kernel-space.
+ * The file contains a monotonically increasing count of time for a single boot. This class
+ * maintains the previous results of a call to {@link #readDelta} in order to provide a proper
+ * delta.
+ */
+public class KernelUidCpuTimeReader {
+ private static final String TAG = "KernelUidCpuTimeReader";
+ private static final String sProcFile = "/proc/uid_cputime/show_uid_stat";
+ private static final String sRemoveUidProcFile = "/proc/uid_cputime/remove_uid_range";
+
+ /**
+ * Callback interface for processing each line of the proc file.
+ */
+ public interface Callback {
+ void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs);
+ }
+
+ private SparseLongArray mLastUserTimeUs = new SparseLongArray();
+ private SparseLongArray mLastSystemTimeUs = new SparseLongArray();
+
+ /**
+ * Reads the proc file, calling into the callback with a delta of time for each UID.
+ * @param callback The callback to invoke for each line of the proc file. If null,
+ * the data is consumed and subsequent calls to readDelta will provide
+ * a fresh delta.
+ */
+ public void readDelta(@Nullable Callback callback) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
+ TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
+ String line;
+ while ((line = reader.readLine()) != null) {
+ splitter.setString(line);
+ final String uidStr = splitter.next();
+ final int uid = Integer.parseInt(uidStr.substring(0, uidStr.length() - 1), 10);
+ final long userTimeUs = Long.parseLong(splitter.next(), 10);
+ final long systemTimeUs = Long.parseLong(splitter.next(), 10);
+
+ if (callback != null) {
+ long userTimeDeltaUs = userTimeUs;
+ long systemTimeDeltaUs = systemTimeUs;
+ int index = mLastUserTimeUs.indexOfKey(uid);
+ if (index >= 0) {
+ userTimeDeltaUs -= mLastUserTimeUs.valueAt(index);
+ systemTimeDeltaUs -= mLastSystemTimeUs.valueAt(index);
+
+ if (userTimeDeltaUs < 0 || systemTimeDeltaUs < 0) {
+ // The UID must have been removed from accounting, then added back.
+ userTimeDeltaUs = userTimeUs;
+ systemTimeDeltaUs = systemTimeUs;
+ }
+ }
+
+ if (userTimeDeltaUs != 0 || systemTimeDeltaUs != 0) {
+ callback.onUidCpuTime(uid, userTimeDeltaUs, systemTimeDeltaUs);
+ }
+ }
+ mLastUserTimeUs.put(uid, userTimeUs);
+ mLastSystemTimeUs.put(uid, systemTimeUs);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to read uid_cputime", e);
+ }
+ }
+
+ /**
+ * Removes the UID from the kernel module and from internal accounting data.
+ * @param uid The UID to remove.
+ */
+ public void removeUid(int uid) {
+ int index = mLastUserTimeUs.indexOfKey(uid);
+ if (index >= 0) {
+ mLastUserTimeUs.removeAt(index);
+ mLastSystemTimeUs.removeAt(index);
+ }
+
+ try (FileWriter writer = new FileWriter(sRemoveUidProcFile)) {
+ writer.write(Integer.toString(uid) + "-" + Integer.toString(uid));
+ writer.flush();
+ } catch (IOException e) {
+ Slog.e(TAG, "failed to remove uid from uid_cputime module", e);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 2983047..8393e2a 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -170,21 +170,6 @@
private byte[] mBuffer = new byte[4096];
- /**
- * The time in microseconds that the CPU has been running at each speed.
- */
- private long[] mCpuSpeedTimes;
-
- /**
- * The relative time in microseconds that the CPU has been running at each speed.
- */
- private long[] mRelCpuSpeedTimes;
-
- /**
- * The different speeds that the CPU can be running at.
- */
- private long[] mCpuSpeeds;
-
public static class Stats {
public final int pid;
public final int uid;
@@ -590,70 +575,6 @@
}
}
- /**
- * Returns the delta time (in clock ticks, or 1/100 sec) spent at each CPU
- * speed, since the last call to this method. If this is the first call, it
- * will return 1 for each value.
- */
- public long[] getLastCpuSpeedTimes() {
- if (mCpuSpeedTimes == null) {
- mCpuSpeedTimes = getCpuSpeedTimes(null);
- mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
- for (int i = 0; i < mCpuSpeedTimes.length; i++) {
- mRelCpuSpeedTimes[i] = 1; // Initialize
- }
- } else {
- getCpuSpeedTimes(mRelCpuSpeedTimes);
- for (int i = 0; i < mCpuSpeedTimes.length; i++) {
- long temp = mRelCpuSpeedTimes[i];
- mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
- mCpuSpeedTimes[i] = temp;
- }
- }
- return mRelCpuSpeedTimes;
- }
-
- private long[] getCpuSpeedTimes(long[] out) {
- long[] tempTimes = out;
- long[] tempSpeeds = mCpuSpeeds;
- final int MAX_SPEEDS = 60;
- if (out == null) {
- tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
- tempSpeeds = new long[MAX_SPEEDS];
- }
- int speed = 0;
- String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
- // Note: file may be null on kernels without cpufreq (i.e. the emulator's)
- if (file != null) {
- StringTokenizer st = new StringTokenizer(file, "\n ");
- while (st.hasMoreElements()) {
- String token = st.nextToken();
- try {
- long val = Long.parseLong(token);
- tempSpeeds[speed] = val;
- token = st.nextToken();
- val = Long.parseLong(token);
- tempTimes[speed] = val;
- speed++;
- if (speed == MAX_SPEEDS) break; // No more
- if (localLOGV && out == null) {
- Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
- + "\t" + tempTimes[speed - 1]);
- }
- } catch (NumberFormatException nfe) {
- Slog.i(TAG, "Unable to parse time_in_state");
- }
- }
- }
- if (out == null) {
- out = new long[speed];
- mCpuSpeeds = new long[speed];
- System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
- System.arraycopy(tempTimes, 0, out, 0, speed);
- }
- return out;
- }
-
final public int getLastUserTime() {
return mRelUserTime;
}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index f98fbfc..fdc3547 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -79,7 +79,6 @@
private final FloatingToolbarPopup mPopup;
private final Rect mContentRect = new Rect();
- private final Point mCoordinates = new Point();
private Menu mMenu;
private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>();
@@ -87,7 +86,6 @@
private int mSuggestedWidth;
private boolean mWidthChanged = true;
- private int mOverflowDirection;
/**
* Initializes a floating toolbar.
@@ -157,11 +155,9 @@
mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth);
mShowingTitles = getMenuItemTitles(menuItems);
}
- refreshCoordinates();
- mPopup.setOverflowDirection(mOverflowDirection);
- mPopup.updateCoordinates(mCoordinates.x, mCoordinates.y);
+ mPopup.updateCoordinates(mContentRect);
if (!mPopup.isShowing()) {
- mPopup.show(mCoordinates.x, mCoordinates.y);
+ mPopup.show(mContentRect);
}
mWidthChanged = false;
return this;
@@ -209,25 +205,6 @@
}
/**
- * Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}.
- */
- private void refreshCoordinates() {
- int x = mContentRect.centerX() - mPopup.getWidth() / 2;
- int y;
- if (mContentRect.top > mPopup.getHeight()) {
- y = mContentRect.top - mPopup.getHeight();
- mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP;
- } else if (mContentRect.top > mPopup.getToolbarHeightWithVerticalMargin()) {
- y = mContentRect.top - mPopup.getToolbarHeightWithVerticalMargin();
- mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
- } else {
- y = mContentRect.bottom;
- mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
- }
- mCoordinates.set(x, y);
- }
-
- /**
* Returns true if this floating toolbar is currently showing the specified menu items.
*/
private boolean isCurrentlyShowing(List<MenuItem> menuItems) {
@@ -345,6 +322,8 @@
}
};
+ private final Point mCoords = new Point();
+
private final Region mTouchableRegion = new Region();
private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
new ViewTreeObserver.OnComputeInternalInsetsListener() {
@@ -378,6 +357,7 @@
mShowAnimation = createGrowFadeInFromBottom(mContentContainer);
mDismissAnimation = createShrinkFadeOutFromBottomAnimation(
mContentContainer,
+ 0,
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -387,6 +367,7 @@
});
mHideAnimation = createShrinkFadeOutFromBottomAnimation(
mContentContainer,
+ 150,
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -404,6 +385,8 @@
*/
public void layoutMenuItems(List<MenuItem> menuItems,
MenuItem.OnMenuItemClickListener menuItemClickListener, int suggestedWidth) {
+ Preconditions.checkNotNull(menuItems);
+
mContentContainer.removeAllViews();
if (mMainPanel == null) {
mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow);
@@ -426,7 +409,9 @@
* Shows this popup at the specified coordinates.
* The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
*/
- public void show(int x, int y) {
+ public void show(Rect contentRect) {
+ Preconditions.checkNotNull(contentRect);
+
if (isShowing()) {
return;
}
@@ -435,6 +420,7 @@
mDismissed = false;
cancelDismissAndHideAnimations();
cancelOverflowAnimations();
+
// Make sure a panel is set as the content.
if (mContentContainer.getChildCount() == 0) {
setMainPanelAsContent();
@@ -442,8 +428,10 @@
// The "show" animation will make this visible.
mContentContainer.setAlpha(0);
}
+ updateOverflowHeight(contentRect.top - (mMarginVertical * 2));
+ refreshCoordinatesAndOverflowDirection(contentRect);
preparePopupContent();
- mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y);
+ mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoords.x, mCoords.y);
setTouchableSurfaceInsetsComputer();
runShowAnimation();
}
@@ -496,27 +484,17 @@
* The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
* This is a no-op if this popup is not showing.
*/
- public void updateCoordinates(int x, int y) {
+ public void updateCoordinates(Rect contentRect) {
+ Preconditions.checkNotNull(contentRect);
+
if (!isShowing() || !mPopupWindow.isShowing()) {
return;
}
cancelOverflowAnimations();
+ refreshCoordinatesAndOverflowDirection(contentRect);
preparePopupContent();
- mPopupWindow.update(x, y, getWidth(), getHeight());
- }
-
- /**
- * Sets the direction in which the overflow will open. i.e. up or down.
- *
- * @param overflowDirection Either {@link #OVERFLOW_DIRECTION_UP}
- * or {@link #OVERFLOW_DIRECTION_DOWN}.
- */
- public void setOverflowDirection(int overflowDirection) {
- mOverflowDirection = overflowDirection;
- if (mOverflowPanel != null) {
- mOverflowPanel.setOverflowDirection(mOverflowDirection);
- }
+ mPopupWindow.update(mCoords.x, mCoords.y, getWidth(), getHeight());
}
/**
@@ -540,7 +518,26 @@
return mContentContainer.getContext();
}
- int getToolbarHeightWithVerticalMargin() {
+ private void refreshCoordinatesAndOverflowDirection(Rect contentRect) {
+ int x = contentRect.centerX() - getWidth() / 2;
+ int y;
+ if (contentRect.top > getHeight()) {
+ y = contentRect.top - getHeight();
+ mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP;
+ } else if (contentRect.top > getToolbarHeightWithVerticalMargin()) {
+ y = contentRect.top - getToolbarHeightWithVerticalMargin();
+ mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
+ } else {
+ y = contentRect.bottom;
+ mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
+ }
+ mCoords.set(x, y);
+ if (mOverflowPanel != null) {
+ mOverflowPanel.setOverflowDirection(mOverflowDirection);
+ }
+ }
+
+ private int getToolbarHeightWithVerticalMargin() {
return getEstimatedToolbarHeight(mParent.getContext()) + mMarginVertical * 2;
}
@@ -693,16 +690,24 @@
}
// Reset position.
- if (mMainPanel != null
- && mContentContainer.getChildAt(0) == mMainPanel.getView()) {
+ if (isMainPanelContent()) {
positionMainPanel();
}
- if (mOverflowPanel != null
- && mContentContainer.getChildAt(0) == mOverflowPanel.getView()) {
+ if (isOverflowPanelContent()) {
positionOverflowPanel();
}
}
+ private boolean isMainPanelContent() {
+ return mMainPanel != null
+ && mContentContainer.getChildAt(0) == mMainPanel.getView();
+ }
+
+ private boolean isOverflowPanelContent() {
+ return mOverflowPanel != null
+ && mContentContainer.getChildAt(0) == mOverflowPanel.getView();
+ }
+
/**
* Sets the current content to be the main view panel.
*/
@@ -765,6 +770,25 @@
setContentAreaAsTouchableSurface();
}
+ private void updateOverflowHeight(int height) {
+ if (mOverflowPanel != null) {
+ mOverflowPanel.setSuggestedHeight(height);
+
+ // Re-measure the popup and it's contents.
+ boolean mainPanelContent = isMainPanelContent();
+ boolean overflowPanelContent = isOverflowPanelContent();
+ mContentContainer.removeAllViews(); // required to update popup size.
+ updatePopupSize();
+ // Reset the appropriate content.
+ if (mainPanelContent) {
+ setMainPanelAsContent();
+ }
+ if (overflowPanelContent) {
+ setOverflowPanelAsContent();
+ }
+ }
+ }
+
private void updatePopupSize() {
int width = 0;
int height = 0;
@@ -864,6 +888,8 @@
* @return The menu items that are not included in this main panel.
*/
public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int suggestedWidth) {
+ Preconditions.checkNotNull(menuItems);
+
final int toolbarWidth = getAdjustedToolbarWidth(mContext, suggestedWidth)
// Reserve space for the "open overflow" button.
- getEstimatedOpenOverflowButtonWidth(mContext);
@@ -972,6 +998,7 @@
private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
private int mOverflowWidth = 0;
+ private int mSuggestedHeight;
/**
* Initializes a floating toolbar popup overflow view panel.
@@ -981,6 +1008,7 @@
*/
public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) {
mCloseOverflow = Preconditions.checkNotNull(closeOverflow);
+ mSuggestedHeight = getScreenHeight(context);
mContentView = new LinearLayout(context);
mContentView.setOrientation(LinearLayout.VERTICAL);
@@ -1043,6 +1071,11 @@
mContentView.addView(mBackButtonContainer, index);
}
+ public void setSuggestedHeight(int height) {
+ mSuggestedHeight = height;
+ setListViewHeight();
+ }
+
/**
* Returns the content view of the overflow.
*/
@@ -1074,9 +1107,17 @@
int itemHeight = getEstimatedToolbarHeight(mContentView.getContext());
int height = mListView.getAdapter().getCount() * itemHeight;
int maxHeight = mContentView.getContext().getResources().
+ getDimensionPixelSize(R.dimen.floating_toolbar_maximum_overflow_height);
+ int minHeight = mContentView.getContext().getResources().
getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height);
+ int availableHeight = mSuggestedHeight - (mSuggestedHeight % itemHeight)
+ - itemHeight; // reserve space for the back button.
ViewGroup.LayoutParams params = mListView.getLayoutParams();
- params.height = Math.min(height, maxHeight);
+ if (availableHeight >= minHeight) {
+ params.height = Math.min(Math.min(availableHeight, maxHeight), height);
+ } else {
+ params.height = Math.min(maxHeight, height);
+ }
mListView.setLayoutParams(params);
}
@@ -1224,15 +1265,16 @@
* Creates a "shrink and fade out from bottom" animation for the specified view.
*
* @param view The view to animate
+ * @param startDelay The start delay of the animation
* @param listener The animation listener
*/
private static AnimatorSet createShrinkFadeOutFromBottomAnimation(
- View view, Animator.AnimatorListener listener) {
+ View view, int startDelay, Animator.AnimatorListener listener) {
AnimatorSet shrinkFadeOutFromBottomAnimation = new AnimatorSet();
shrinkFadeOutFromBottomAnimation.playTogether(
ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125),
ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75));
- shrinkFadeOutFromBottomAnimation.setStartDelay(150);
+ shrinkFadeOutFromBottomAnimation.setStartDelay(startDelay);
shrinkFadeOutFromBottomAnimation.addListener(listener);
return shrinkFadeOutFromBottomAnimation;
}
@@ -1271,16 +1313,4 @@
private static int getScreenHeight(Context context) {
return context.getResources().getDisplayMetrics().heightPixels;
}
-
- /**
- * Returns value, restricted to the range min->max (inclusive).
- * If maximum is less than minimum, the result is undefined.
- *
- * @param value The value to clamp.
- * @param minimum The minimum value in the range.
- * @param maximum The maximum value in the range. Must not be less than minimum.
- */
- private static int clamp(int value, int minimum, int maximum) {
- return Math.max(minimum, Math.min(value, maximum));
- }
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3d23986..e5ef60c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1097,8 +1097,11 @@
Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
return;
}
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
+
+ if (isDeviceEncryptionEnabled()){
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
+ }
}
private boolean isDoNotAskCredentialsOnBootSet() {
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 01e835b..be727f1 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -661,13 +661,20 @@
}
}
+ final int oldCollapsibleHeight = mCollapsibleHeight;
mCollapsibleHeight = Math.max(0,
heightUsed - alwaysShowHeight - getMaxCollapsedHeight());
mUncollapsibleHeight = heightUsed - mCollapsibleHeight;
if (isLaidOut()) {
final boolean isCollapsedOld = mCollapseOffset != 0;
- mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
+ if (oldCollapsibleHeight < mCollapsibleHeight
+ && mCollapseOffset == oldCollapsibleHeight) {
+ // Stay closed even at the new height.
+ mCollapseOffset = mCollapsibleHeight;
+ } else {
+ mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
+ }
final boolean isCollapsedNew = mCollapseOffset != 0;
if (isCollapsedOld != isCollapsedNew) {
notifyViewAccessibilityStateChangedIfNeeded(
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 348b0ec..e69f64e 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -102,8 +102,8 @@
canvas->translate(bounds.fLeft, bounds.fTop);
canvas->scale(scale, scale);
- bounds.fRight = SkScalarDiv(bounds.fRight-bounds.fLeft, scale);
- bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale);
+ bounds.fRight = (bounds.fRight-bounds.fLeft) / scale;
+ bounds.fBottom = (bounds.fBottom-bounds.fTop) / scale;
bounds.fLeft = bounds.fTop = 0;
ALOGV("Drawing scaled 9-patch: (%g,%g)-(%g,%g) srcDensity=%d destDensity=%d",
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index 26ce967..323f832 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -94,8 +94,7 @@
SkScalar spaceRemaining = boundsLimit - startingPoint;
SkScalar stretchySpaceRemaining =
spaceRemaining - SkIntToScalar(numFixedPixelsRemaining);
- return SkScalarMulDiv(srcSpace, stretchySpaceRemaining,
- numStrechyPixelsRemaining);
+ return srcSpace * stretchySpaceRemaining / numStrechyPixelsRemaining;
}
void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4c034b3..608d718 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -678,6 +678,7 @@
<!-- Allows an app to use fingerprint hardware. -->
<permission android:name="android.permission.USE_FINGERPRINT"
+ android:permissionGroup="android.permission-group.SENSORS"
android:label="@string/permlab_useFingerprint"
android:description="@string/permdesc_useFingerprint"
android:protectionLevel="dangerous" />
@@ -2404,8 +2405,7 @@
<permission android:name="android.permission.REMOVE_DRM_CERTIFICATES"
android:protectionLevel="signature|system" />
- <!-- Must be required by a {@link android.service.carrier.CarrierMessagingService}.
- Any service that filters for this intent must be a carrier privileged app. -->
+ <!-- @deprecated Use {@link android.Manifest.permission#BIND_CARRIER_SERVICES} instead -->
<permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
android:protectionLevel="signature|system" />
@@ -2427,13 +2427,12 @@
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature" />
- <!-- The system process that pulls carrier configuration from carrier apps will
- have this permission. Carrier apps that provide
- {@link android.service.carrier.CarrierConfigService} should require this
- permission for clients binding to their service. -->
- <permission android:name="android.permission.BIND_CARRIER_CONFIG_SERVICE"
- android:label="@string/permlab_bindCarrierConfigService"
- android:description="@string/permdesc_bindCarrierConfigService"
+ <!-- The system process that is allowed to bind to services in carrier apps will
+ have this permission. Carrier apps should use this permission to protect
+ their services that only the system is allowed to bind to. -->
+ <permission android:name="android.permission.BIND_CARRIER_SERVICES"
+ android:label="@string/permlab_bindCarrierServices"
+ android:description="@string/permdesc_bindCarrierServices"
android:protectionLevel="signature|system" />
<!-- Allows an application to query whether DO_NOT_ASK_CREDENTIALS_ON_BOOT
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index 65cb046..f5d945a 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -14,35 +14,30 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="560.0dp"
- android:height="560.0dp"
- android:viewportWidth="560.0"
- android:viewportHeight="560.0">
+ android:width="480dp"
+ android:height="480dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
<path
- android:pathData="M264.079987,240.736l0.0,9.82c7.31,-7.15 17.139999,-11.56 28.07,-11.56c22.639999,0.0 40.799999,18.48 40.799999,41.12c0.0,22.48 -18.16,40.880 -40.799999,40.880c-10.93,0.0 -20.280,-4.09 -27.59,-10.93L264.559998,339.0l-11.32,0.0l0.0,-98.269997L264.079987,240.731zM265.809998,264.869995c-0.47,0.79 -1.26,2.04 -1.26,4.79l0.0,21.07c0.0,1.97 0.47,3.07 1.1,4.17c5.19,8.88 14.78,14.94 25.63,14.94c16.43,0.0 29.950,-13.44 29.950,-29.870c0.0,-16.280 -13.52,-29.799999 -29.950,-29.799999C280.51,250.169998 271.0,256.059998 265.809998,264.869995z"
+ android:pathData="M24.0,2.0C11.8,2.0 2.0,11.8 2.0,24.0c0.0,6.1 2.5,11.6 6.4,15.6L39.6,8.4C35.6,4.5 30.1,2.0 24.0,2.0z"
+ android:fillColor="#F57C00"/>
+ <path
+ android:pathData="M39.6,8.4L8.4,39.6c4.0,4.0 9.5,6.4 15.6,6.4c12.2,0.0 22.0,-9.8 22.0,-22.0C46.0,17.9 43.5,12.4 39.6,8.4z"
+ android:fillColor="#FF9800"/>
+ <path
+ android:pathData="M45.9,25.9L34.0,14.0L14.0,34.0l11.9,11.9C36.5,45.0 45.0,36.5 45.9,25.9z"
+ android:fillAlpha="0.33"
+ android:fillColor="#F57C00"/>
+ <path
+ android:pathData="M24.0,24.0c0.0,0.0 0.0,2.2 0.0,5.0s0.0,5.0 0.0,5.0l10.0,-10.0L34.0,14.0L24.0,24.0z"
android:fillColor="#FFFFFF"/>
<path
- android:pathData="M445.731,240.736l0.0,9.82c7.31,-7.15 17.139999,-11.56 28.07,-11.56c22.639999,0.0 40.799999,18.48 40.799999,41.12c0.0,22.48 -18.16,40.880 -40.799999,40.880c-10.93,0.0 -20.280,-4.09 -27.59,-10.93L446.210052,339.0l-11.32,0.0l0.0,-98.269997L445.731,240.731zM447.459991,264.869995c-0.47,0.79 -1.26,2.04 -1.26,4.79l0.0,21.07c0.0,1.97 0.47,3.07 1.1,4.17c5.19,8.88 14.78,14.94 25.63,14.94c16.43,0.0 29.950,-13.44 29.950,-29.870c0.0,-16.280 -13.52,-29.799999 -29.950,-29.799999C462.160004,250.169998 452.649994,256.059998 447.459991,264.869995z"
- android:fillColor="#FFFFFF"/>
+ android:pathData="M24.0,24.0L14.0,14.0l0.0,10.0l10.0,10.0c0.0,0.0 0.0,-2.2 0.0,-5.0S24.0,24.0 24.0,24.0z"
+ android:fillColor="#EEEEEE"/>
<path
- android:pathData="M169.490005,279.880005c0.0,22.639999 -18.32,41.12 -40.810,41.12c-22.639999,0.0 -41.040,-18.48 -41.040,-41.12c0.0,-22.48 18.389999,-40.880 41.040,-40.880C151.169998,239.0 169.490005,257.399994 169.490005,279.880005zM158.089996,280.040009c0.0,-16.43 -13.13,-29.870 -29.41,-29.870c-16.51,0.0 -29.4,13.44 -29.4,29.870c0.0,16.280 12.89,29.799999 29.4,29.799999C144.960007,309.8387 158.089996,296.309998 158.089996,280.040009z"
- android:fillColor="#FFFFFF"/>
+ android:pathData="M14.0,34.0l10.0,0.0 -10.0,-10.0z"
+ android:fillColor="#DDDDDD"/>
<path
- android:pathData="M423.790009,279.880005c0.0,22.639999 -18.32,41.12 -40.810,41.12c-22.639999,0.0 -41.040,-18.48 -41.040,-41.12c0.0,-22.48 18.389999,-40.880 41.040,-40.880C405.470,239.0 423.790009,257.399994 423.790009,279.880005zM412.395,280.040009c0.0,-16.43 -13.13,-29.870 -29.41,-29.870c-16.51,0.0 -29.4,13.44 -29.4,29.870c0.0,16.280 12.89,29.799999 29.4,29.799999C399.26,309.8387 412.395,296.309998 412.395,280.040009z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M229.02,221.0l11.17,0.0l0.0,11.48l-11.17,0.0z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M229.02,240.65l11.17,0.0l0.0,78.62l-11.17,0.0z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M65.4,221.0l11.17,0.0l0.0,98.27l-11.17,0.0z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M180.58,221.0l11.17,0.0l0.0,98.27l-11.17,0.0z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M204.8,221.0l11.17,0.0l0.0,98.27l-11.17,0.0z"
- android:fillColor="#FFFFFF"/>
+ android:pathData="M34.0,34.0l0.0,-10.0 -10.0,10.0z"
+ android:fillColor="#DDDDDD"/>
</vector>
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index d89d1f9..8f5109df 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -19,9 +19,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:pathData="M19.000000,10.000000c0.000000,3.866000 -3.134000,7.000000 -7.000000,7.000000s-7.000000,-3.134000 -7.000000,-7.000000c0.000000,-2.318000 1.131000,-4.367000 2.867000,-5.641000L5.778000,2.270000l0.824000,-0.825000l2.290000,2.290000C9.830000,3.269000 10.882000,3.000000 12.000000,3.000000c1.118000,0.000000 2.170000,0.269000 3.107000,0.734000l2.290000,-2.290000l0.824000,0.825000l-2.089000,2.090000C17.868000,5.633000 19.000000,7.682000 19.000000,10.000000zM10.000000,8.000000c0.000000,-0.552000 -0.447000,-1.000000 -1.000000,-1.000000S8.000000,7.448000 8.000000,8.000000s0.447000,1.000000 1.000000,1.000000S10.000000,8.552000 10.000000,8.000000zM16.000000,8.000000c0.000000,-0.552000 -0.447000,-1.000000 -1.000000,-1.000000s-1.000000,0.448000 -1.000000,1.000000s0.447000,1.000000 1.000000,1.000000S16.000000,8.552000 16.000000,8.000000z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M11,18l2,0l0,5l-2,0z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#FF000000"
+ android:pathData="M12.0,12.0l-10.0,-10.0 0.0,10.0 0.0,10.0 10.0,0.0 10.0,0.0 0.0,-10.0 0.0,-10.0z"/>
</vector>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 84747f1..813591b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -392,7 +392,8 @@
<dimen name="floating_toolbar_text_size">14sp</dimen>
<dimen name="floating_toolbar_menu_button_minimum_width">48dp</dimen>
<dimen name="floating_toolbar_preferred_width">328dp</dimen>
- <dimen name="floating_toolbar_minimum_overflow_height">144dp</dimen>
+ <dimen name="floating_toolbar_minimum_overflow_height">96dp</dimen>
+ <dimen name="floating_toolbar_maximum_overflow_height">192dp</dimen>
<dimen name="floating_toolbar_horizontal_margin">16dp</dimen>
<dimen name="floating_toolbar_vertical_margin">8dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1c0122d..0e6b2df 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1408,9 +1408,9 @@
<string name="permdesc_bindCarrierMessagingService">Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_bindCarrierConfigService">bind to a carrier config service</string>
+ <string name="permlab_bindCarrierServices">bind to carrier services</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_bindCarrierConfigService">Allows the holder to bind to a carrier config service. Should never be needed for normal apps.</string>
+ <string name="permdesc_bindCarrierServices">Allows the holder to bind to carrier services. Should never be needed for normal apps.</string>
<!-- Policy administration -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0d306c6..64e3964 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2256,6 +2256,7 @@
<java-symbol type="dimen" name="floating_toolbar_menu_button_minimum_width" />
<java-symbol type="dimen" name="floating_toolbar_preferred_width" />
<java-symbol type="dimen" name="floating_toolbar_minimum_overflow_height" />
+ <java-symbol type="dimen" name="floating_toolbar_maximum_overflow_height" />
<java-symbol type="dimen" name="floating_toolbar_horizontal_margin" />
<java-symbol type="dimen" name="floating_toolbar_vertical_margin" />
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 0da4275..bd8eae0 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -432,7 +432,8 @@
@Override
public int getChangingConfigurations() {
- return mChangingConfigurations | mDrawableState.getChangingConfigurations();
+ return mChangingConfigurations
+ | (mDrawableState != null ? mDrawableState.getChangingConfigurations() : 0);
}
public boolean canConstantState() {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index ba7bd74..f893fdd 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -242,7 +242,7 @@
/**
* The audio channel mask used for calling native AudioTrack
*/
- private int mChannels = AudioFormat.CHANNEL_OUT_MONO;
+ private int mChannelMask = AudioFormat.CHANNEL_OUT_MONO;
/**
* The type of the audio stream to play. See
@@ -485,7 +485,7 @@
session[0] = sessionId;
// native initialization
int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
- mSampleRate, mChannels, mChannelIndexMask, mAudioFormat,
+ mSampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode, session);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
@@ -699,7 +699,7 @@
// This is where constructor IllegalArgumentException-s are thrown
// postconditions:
// mChannelCount is valid
- // mChannels is valid
+ // mChannelMask is valid
// mAudioFormat is valid
// mSampleRate is valid
// mDataLoadMode is valid
@@ -722,12 +722,12 @@
case AudioFormat.CHANNEL_OUT_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
mChannelCount = 1;
- mChannels = AudioFormat.CHANNEL_OUT_MONO;
+ mChannelMask = AudioFormat.CHANNEL_OUT_MONO;
break;
case AudioFormat.CHANNEL_OUT_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
mChannelCount = 2;
- mChannels = AudioFormat.CHANNEL_OUT_STEREO;
+ mChannelMask = AudioFormat.CHANNEL_OUT_STEREO;
break;
default:
if (channelConfig == AudioFormat.CHANNEL_INVALID && channelIndexMask != 0) {
@@ -738,7 +738,7 @@
// input channel configuration features unsupported channels
throw new IllegalArgumentException("Unsupported channel configuration.");
}
- mChannels = channelConfig;
+ mChannelMask = channelConfig;
mChannelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
}
// check the channel index configuration (if present)
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index acff301..52ba9ec 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -110,10 +110,10 @@
private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
private EventHandler mEventHandler;
- private EventHandler mOnKeysChangeEventHandler;
+ private EventHandler mOnKeyStatusChangeEventHandler;
private EventHandler mOnExpirationUpdateEventHandler;
private OnEventListener mOnEventListener;
- private OnKeysChangeListener mOnKeysChangeListener;
+ private OnKeyStatusChangeListener mOnKeyStatusChangeListener;
private OnExpirationUpdateListener mOnExpirationUpdateListener;
private long mNativeContext;
@@ -297,8 +297,8 @@
* @param handler the handler on which the listener should be invoked, or
* null if the listener should be invoked on the calling thread's looper.
*/
- public void setOnKeysChangeListener(
- @Nullable OnKeysChangeListener listener, @Nullable Handler handler) {
+ public void setOnKeyStatusChangeListener(
+ @Nullable OnKeyStatusChangeListener listener, @Nullable Handler handler) {
if (listener != null) {
Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
if (looper != null) {
@@ -307,14 +307,14 @@
}
}
}
- mOnKeysChangeListener = listener;
+ mOnKeyStatusChangeListener = listener;
}
/**
* Interface definition for a callback to be invoked when the keys in a drm
* session change states.
*/
- public interface OnKeysChangeListener
+ public interface OnKeyStatusChangeListener
{
/**
* Called when the keys in a session change status, such as when the license
@@ -328,64 +328,64 @@
* which may trigger an attempt to resume playback on the media stream
* if it is currently blocked waiting for a key.
*/
- void onKeysChange(
+ void onKeyStatusChange(
@NonNull MediaDrm md, @NonNull byte[] sessionId,
@NonNull List<KeyStatus> keyInformation,
boolean hasNewUsableKey);
}
/**
- * The key is currently usable to decrypt media data
- */
- public static final int KEY_STATUS_USABLE = 0;
-
- /**
- * The key is no longer usable to decrypt media data because its
- * expiration time has passed.
- */
- public static final int KEY_STATUS_EXPIRED = 1;
-
- /**
- * The key is not currently usable to decrypt media data because its
- * output requirements cannot currently be met.
- */
- public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2;
-
- /**
- * The status of the key is not yet known and is being determined.
- * The status will be updated with the actual status when it has
- * been determined.
- */
- public static final int KEY_STATUS_PENDING = 3;
-
- /**
- * The key is not currently usable to decrypt media data because of an
- * internal error in processing unrelated to input parameters. This error
- * is not actionable by an app.
- */
- public static final int KEY_STATUS_INTERNAL_ERROR = 4;
-
- /** @hide */
- @IntDef({
- KEY_STATUS_USABLE,
- KEY_STATUS_EXPIRED,
- KEY_STATUS_OUTPUT_NOT_ALLOWED,
- KEY_STATUS_PENDING,
- KEY_STATUS_INTERNAL_ERROR,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface KeyStatusCode {}
-
- /**
* Defines the status of a key.
* A KeyStatus for each key in a session is provided to the
- * {@link OnKeysChangeListener#onKeysChange}
+ * {@link OnKeyStatusChangeListener#onKeyStatusChange}
* listener.
*/
public static final class KeyStatus {
private final byte[] mKeyId;
private final int mStatusCode;
+ /**
+ * The key is currently usable to decrypt media data
+ */
+ public static final int STATUS_USABLE = 0;
+
+ /**
+ * The key is no longer usable to decrypt media data because its
+ * expiration time has passed.
+ */
+ public static final int STATUS_EXPIRED = 1;
+
+ /**
+ * The key is not currently usable to decrypt media data because its
+ * output requirements cannot currently be met.
+ */
+ public static final int STATUS_OUTPUT_NOT_ALLOWED = 2;
+
+ /**
+ * The status of the key is not yet known and is being determined.
+ * The status will be updated with the actual status when it has
+ * been determined.
+ */
+ public static final int STATUS_PENDING = 3;
+
+ /**
+ * The key is not currently usable to decrypt media data because of an
+ * internal error in processing unrelated to input parameters. This error
+ * is not actionable by an app.
+ */
+ public static final int STATUS_INTERNAL_ERROR = 4;
+
+ /** @hide */
+ @IntDef({
+ STATUS_USABLE,
+ STATUS_EXPIRED,
+ STATUS_OUTPUT_NOT_ALLOWED,
+ STATUS_PENDING,
+ STATUS_INTERNAL_ERROR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface KeyStatusCode {}
+
KeyStatus(@NonNull byte[] keyId, @KeyStatusCode int statusCode) {
mKeyId = keyId;
mStatusCode = statusCode;
@@ -393,6 +393,9 @@
/**
* Returns the status code for the key
+ * @return one of {@link #STATUS_USABLE}, {@link #STATUS_EXPIRED},
+ * {@link #STATUS_OUTPUT_NOT_ALLOWED}, {@link #STATUS_PENDING}
+ * or {@link #STATUS_INTERNAL_ERROR}.
*/
@KeyStatusCode
public int getStatusCode() { return mStatusCode; }
@@ -484,7 +487,7 @@
private static final int DRM_EVENT = 200;
private static final int EXPIRATION_UPDATE = 201;
- private static final int KEYS_CHANGE = 202;
+ private static final int KEY_STATUS_CHANGE = 202;
private class EventHandler extends Handler
{
@@ -522,8 +525,8 @@
}
return;
- case KEYS_CHANGE:
- if (mOnKeysChangeListener != null) {
+ case KEY_STATUS_CHANGE:
+ if (mOnKeyStatusChangeListener != null) {
if (msg.obj != null && msg.obj instanceof Parcel) {
Parcel parcel = (Parcel)msg.obj;
byte[] sessionId = parcel.createByteArray();
@@ -531,9 +534,9 @@
List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
boolean hasNewUsableKey = (parcel.readInt() != 0);
- Log.i(TAG, "Drm keys change");
- mOnKeysChangeListener.onKeysChange(mMediaDrm, sessionId, keyStatusList,
- hasNewUsableKey);
+ Log.i(TAG, "Drm key status changed");
+ mOnKeyStatusChangeListener.onKeyStatusChange(mMediaDrm, sessionId,
+ keyStatusList, hasNewUsableKey);
}
}
}
@@ -641,30 +644,6 @@
public @interface KeyType {}
/**
- * Key request type is initial license request
- */
- public static final int REQUEST_TYPE_INITIAL = 0;
-
- /**
- * Key request type is license renewal
- */
- public static final int REQUEST_TYPE_RENEWAL = 1;
-
- /**
- * Key request type is license release
- */
- public static final int REQUEST_TYPE_RELEASE = 2;
-
- /** @hide */
- @IntDef({
- REQUEST_TYPE_INITIAL,
- REQUEST_TYPE_RENEWAL,
- REQUEST_TYPE_RELEASE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface RequestType {}
-
- /**
* Contains the opaque data an app uses to request keys from a license server
*/
public static final class KeyRequest {
@@ -672,6 +651,30 @@
private String mDefaultUrl;
private int mRequestType;
+ /**
+ * Key request type is initial license request
+ */
+ public static final int REQUEST_TYPE_INITIAL = 0;
+
+ /**
+ * Key request type is license renewal
+ */
+ public static final int REQUEST_TYPE_RENEWAL = 1;
+
+ /**
+ * Key request type is license release
+ */
+ public static final int REQUEST_TYPE_RELEASE = 2;
+
+ /** @hide */
+ @IntDef({
+ REQUEST_TYPE_INITIAL,
+ REQUEST_TYPE_RENEWAL,
+ REQUEST_TYPE_RELEASE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RequestType {}
+
KeyRequest() {}
/**
@@ -707,6 +710,8 @@
/**
* Get the type of the request
+ * @return one of {@link #REQUEST_TYPE_INITIAL},
+ * {@link #REQUEST_TYPE_RENEWAL} or {@link #REQUEST_TYPE_RELEASE}
*/
@RequestType
public int getRequestType() { return mRequestType; }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index e3a6a83..f148606 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -40,6 +40,7 @@
import android.system.ErrnoException;
import android.system.OsConstants;
import android.util.Log;
+import android.util.Pair;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.widget.VideoView;
@@ -70,6 +71,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetSocketAddress;
+import java.util.BitSet;
+import java.util.HashSet;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
@@ -639,9 +642,7 @@
}
mTimeProvider = new TimeProvider(this);
- mOutOfBandSubtitleTracks = new Vector<SubtitleTrack>();
mOpenSubtitleSources = new Vector<InputStream>();
- mInbandSubtitleTracks = new SubtitleTrack[0];
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
mAppOps = IAppOpsService.Stub.asInterface(b);
@@ -1693,8 +1694,6 @@
}
mOpenSubtitleSources.clear();
}
- mOutOfBandSubtitleTracks.clear();
- mInbandSubtitleTracks = new SubtitleTrack[0];
if (mSubtitleController != null) {
mSubtitleController.reset();
}
@@ -1709,6 +1708,11 @@
if (mEventHandler != null) {
mEventHandler.removeCallbacksAndMessages(null);
}
+
+ synchronized (mIndexTrackPairs) {
+ mIndexTrackPairs.clear();
+ mInbandTrackIndices.clear();
+ };
}
private native void _reset();
@@ -2050,6 +2054,16 @@
};
+ // We would like domain specific classes with more informative names than the `first` and `second`
+ // in generic Pair, but we would also like to avoid creating new/trivial classes. As a compromise
+ // we document the meanings of `first` and `second` here:
+ //
+ // Pair.first - inband track index; non-null iff representing an inband track.
+ // Pair.second - a SubtitleTrack registered with mSubtitleController; non-null iff representing
+ // an inband subtitle track or any out-of-band track (subtitle or timedtext).
+ private Vector<Pair<Integer, SubtitleTrack>> mIndexTrackPairs = new Vector<>();
+ private BitSet mInbandTrackIndices = new BitSet();
+
/**
* Returns an array of track information.
*
@@ -2061,17 +2075,20 @@
public TrackInfo[] getTrackInfo() throws IllegalStateException {
TrackInfo trackInfo[] = getInbandTrackInfo();
// add out-of-band tracks
- TrackInfo allTrackInfo[] = new TrackInfo[trackInfo.length + mOutOfBandSubtitleTracks.size()];
- System.arraycopy(trackInfo, 0, allTrackInfo, 0, trackInfo.length);
- int i = trackInfo.length;
- for (SubtitleTrack track: mOutOfBandSubtitleTracks) {
- int type = track.isTimedText()
- ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT
- : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE;
- allTrackInfo[i] = new TrackInfo(type, track.getFormat());
- ++i;
+ synchronized (mIndexTrackPairs) {
+ TrackInfo allTrackInfo[] = new TrackInfo[mIndexTrackPairs.size()];
+ for (int i = 0; i < allTrackInfo.length; i++) {
+ Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
+ if (p.first != null) {
+ // inband track
+ allTrackInfo[i] = trackInfo[p.first];
+ } else {
+ SubtitleTrack track = p.second;
+ allTrackInfo[i] = new TrackInfo(track.getTrackType(), track.getFormat());
+ }
+ }
+ return allTrackInfo;
}
- return allTrackInfo;
}
private TrackInfo[] getInbandTrackInfo() throws IllegalStateException {
@@ -2167,22 +2184,21 @@
}
}
- private final Object mInbandSubtitleLock = new Object();
- private SubtitleTrack[] mInbandSubtitleTracks;
private int mSelectedSubtitleTrackIndex = -1;
- private Vector<SubtitleTrack> mOutOfBandSubtitleTracks;
private Vector<InputStream> mOpenSubtitleSources;
private OnSubtitleDataListener mSubtitleDataListener = new OnSubtitleDataListener() {
@Override
public void onSubtitleData(MediaPlayer mp, SubtitleData data) {
int index = data.getTrackIndex();
- if (index >= mInbandSubtitleTracks.length) {
- return;
- }
- SubtitleTrack track = mInbandSubtitleTracks[index];
- if (track != null) {
- track.onData(data);
+ synchronized (mIndexTrackPairs) {
+ for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
+ if (p.first != null && p.first == index && p.second != null) {
+ // inband subtitle track that owns data
+ SubtitleTrack track = p.second;
+ track.onData(data);
+ }
+ }
}
}
};
@@ -2201,18 +2217,24 @@
if (track == null) {
return;
}
- for (int i = 0; i < mInbandSubtitleTracks.length; i++) {
- if (mInbandSubtitleTracks[i] == track) {
- Log.v(TAG, "Selecting subtitle track " + i);
- mSelectedSubtitleTrackIndex = i;
- try {
- selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
- } catch (IllegalStateException e) {
+
+ synchronized (mIndexTrackPairs) {
+ for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
+ if (p.first != null && p.second == track) {
+ // inband subtitle track that is selected
+ mSelectedSubtitleTrackIndex = p.first;
+ break;
}
- setOnSubtitleDataListener(mSubtitleDataListener);
- break;
}
}
+
+ if (mSelectedSubtitleTrackIndex >= 0) {
+ try {
+ selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
+ } catch (IllegalStateException e) {
+ }
+ setOnSubtitleDataListener(mSubtitleDataListener);
+ }
// no need to select out-of-band tracks
}
@@ -2252,7 +2274,9 @@
mOpenSubtitleSources.remove(fIs);
}
scanner.close();
- mOutOfBandSubtitleTracks.add(track);
+ synchronized (mIndexTrackPairs) {
+ mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
+ }
track.onData(contents.getBytes(), true /* eos */, ~0 /* runID: keep forever */);
return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
}
@@ -2270,27 +2294,37 @@
private void scanInternalSubtitleTracks() {
if (mSubtitleController == null) {
- Log.e(TAG, "Should have subtitle controller already set");
- return;
+ Log.w(TAG, "setSubtitleAnchor in MediaPlayer");
+ setSubtitleAnchor();
}
+ populateInbandTracks();
+
+ if (mSubtitleController != null) {
+ mSubtitleController.selectDefaultTrack();
+ }
+ }
+
+ private void populateInbandTracks() {
TrackInfo[] tracks = getInbandTrackInfo();
- synchronized (mInbandSubtitleLock) {
- SubtitleTrack[] inbandTracks = new SubtitleTrack[tracks.length];
- for (int i=0; i < tracks.length; i++) {
+ synchronized (mIndexTrackPairs) {
+ for (int i = 0; i < tracks.length; i++) {
+ if (mInbandTrackIndices.get(i)) {
+ continue;
+ } else {
+ mInbandTrackIndices.set(i);
+ }
+
+ // newly appeared inband track
if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
- if (i < mInbandSubtitleTracks.length) {
- inbandTracks[i] = mInbandSubtitleTracks[i];
- } else {
- SubtitleTrack track = mSubtitleController.addTrack(
- tracks[i].getFormat());
- inbandTracks[i] = track;
- }
+ SubtitleTrack track = mSubtitleController.addTrack(
+ tracks[i].getFormat());
+ mIndexTrackPairs.add(Pair.create(i, track));
+ } else {
+ mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(i, null));
}
}
- mInbandSubtitleTracks = inbandTracks;
}
- mSubtitleController.selectDefaultTrack();
}
/* TODO: Limit the total number of external timed text source to a reasonable number.
@@ -2438,7 +2472,9 @@
mSubtitleController.registerRenderer(new SRTRenderer(context, mEventHandler));
}
final SubtitleTrack track = mSubtitleController.addTrack(fFormat);
- mOutOfBandSubtitleTracks.add(track);
+ synchronized (mIndexTrackPairs) {
+ mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
+ }
final FileDescriptor fd3 = fd2;
final long offset2 = offset;
@@ -2510,12 +2546,18 @@
* @see #deselectTrack(int)
*/
public int getSelectedTrack(int trackType) throws IllegalStateException {
- if (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE && mSubtitleController != null) {
+ if (mSubtitleController != null
+ && (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
+ || trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT)) {
SubtitleTrack subtitleTrack = mSubtitleController.getSelectedTrack();
if (subtitleTrack != null) {
- int index = mOutOfBandSubtitleTracks.indexOf(subtitleTrack);
- if (index >= 0) {
- return mInbandSubtitleTracks.length + index;
+ synchronized (mIndexTrackPairs) {
+ for (int i = 0; i < mIndexTrackPairs.size(); i++) {
+ Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
+ if (p.second == subtitleTrack && subtitleTrack.getTrackType() == trackType) {
+ return i;
+ }
+ }
}
}
}
@@ -2527,8 +2569,16 @@
request.writeInt(INVOKE_ID_GET_SELECTED_TRACK);
request.writeInt(trackType);
invoke(request, reply);
- int selectedTrack = reply.readInt();
- return selectedTrack;
+ int inbandTrackIndex = reply.readInt();
+ synchronized (mIndexTrackPairs) {
+ for (int i = 0; i < mIndexTrackPairs.size(); i++) {
+ Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
+ if (p.first != null && p.first == inbandTrackIndex) {
+ return i;
+ }
+ }
+ }
+ return -1;
} finally {
request.recycle();
reply.recycle();
@@ -2588,36 +2638,30 @@
private void selectOrDeselectTrack(int index, boolean select)
throws IllegalStateException {
// handle subtitle track through subtitle controller
- SubtitleTrack track = null;
- synchronized (mInbandSubtitleLock) {
- if (mInbandSubtitleTracks.length == 0) {
- TrackInfo[] tracks = getInbandTrackInfo();
- mInbandSubtitleTracks = new SubtitleTrack[tracks.length];
- for (int i=0; i < tracks.length; i++) {
- if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
- mInbandSubtitleTracks[i] = mSubtitleController.addTrack(tracks[i].getFormat());
- }
- }
- }
+ populateInbandTracks();
+
+ Pair<Integer,SubtitleTrack> p = null;
+ try {
+ p = mIndexTrackPairs.get(index);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // ignore bad index
+ return;
}
- if (index < mInbandSubtitleTracks.length) {
- track = mInbandSubtitleTracks[index];
- } else if (index < mInbandSubtitleTracks.length + mOutOfBandSubtitleTracks.size()) {
- track = mOutOfBandSubtitleTracks.get(index - mInbandSubtitleTracks.length);
+ SubtitleTrack track = p.second;
+ if (track == null) {
+ // inband (de)select
+ selectOrDeselectInbandTrack(p.first, select);
+ return;
}
- if (mSubtitleController != null && track != null) {
- if (select) {
- if (track.isTimedText()) {
- int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
- if (ttIndex >= 0 && ttIndex < mInbandSubtitleTracks.length) {
- // deselect inband counterpart
- selectOrDeselectInbandTrack(ttIndex, false);
- }
- }
- mSubtitleController.selectTrack(track);
- } else if (mSubtitleController.getSelectedTrack() == track) {
+ if (mSubtitleController == null) {
+ return;
+ }
+
+ if (!select) {
+ // out-of-band deselect
+ if (mSubtitleController.getSelectedTrack() == track) {
mSubtitleController.selectTrack(null);
} else {
Log.w(TAG, "trying to deselect track that was not selected");
@@ -2625,7 +2669,20 @@
return;
}
- selectOrDeselectInbandTrack(index, select);
+ // out-of-band select
+ if (track.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
+ int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
+ synchronized (mIndexTrackPairs) {
+ if (ttIndex >= 0 && ttIndex < mIndexTrackPairs.size()) {
+ Pair<Integer,SubtitleTrack> p2 = mIndexTrackPairs.get(ttIndex);
+ if (p2.first != null && p2.second == null) {
+ // deselect inband counterpart
+ selectOrDeselectInbandTrack(p2.first, false);
+ }
+ }
+ }
+ }
+ mSubtitleController.selectTrack(track);
}
private void selectOrDeselectInbandTrack(int index, boolean select)
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
index f82dbe0..fd72b39 100644
--- a/media/java/android/media/SubtitleController.java
+++ b/media/java/android/media/SubtitleController.java
@@ -20,6 +20,7 @@
import java.util.Vector;
import android.content.Context;
+import android.media.MediaPlayer.TrackInfo;
import android.media.SubtitleTrack.RenderingWidget;
import android.os.Handler;
import android.os.Looper;
@@ -275,7 +276,8 @@
mSelectedTrack.getFormat().getInteger(
MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
show();
- } else if (mSelectedTrack != null && !mSelectedTrack.isTimedText()) {
+ } else if (mSelectedTrack != null
+ && mSelectedTrack.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
hide();
}
mVisibilityIsExplicit = false;
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index c760810..6c8e323 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -17,6 +17,7 @@
package android.media;
import android.graphics.Canvas;
+import android.media.MediaPlayer.TrackInfo;
import android.os.Handler;
import android.util.Log;
import android.util.LongSparseArray;
@@ -609,8 +610,10 @@
}
/** @hide whether this is a text track who fires events instead getting rendered */
- public boolean isTimedText() {
- return getRenderingWidget() == null;
+ public int getTrackType() {
+ return getRenderingWidget() == null
+ ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT
+ : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE;
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index f8146a7..d456dc10 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -99,7 +99,7 @@
struct EventWhat {
jint kWhatDrmEvent;
jint kWhatExpirationUpdate;
- jint kWhatKeysChange;
+ jint kWhatKeyStatusChange;
} gEventWhat;
struct KeyTypes {
@@ -221,7 +221,7 @@
jwhat = gEventWhat.kWhatExpirationUpdate;
break;
case DrmPlugin::kDrmPluginEventKeysChange:
- jwhat = gEventWhat.kWhatKeysChange;
+ jwhat = gEventWhat.kWhatKeyStatusChange;
break;
default:
ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
@@ -609,8 +609,8 @@
gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "KEYS_CHANGE", "I");
- gEventWhat.kWhatKeysChange = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
+ gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
@@ -619,13 +619,6 @@
GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
- gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
- gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
- gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
-
GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
@@ -636,6 +629,13 @@
GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
+ GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
+ gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
+ gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
+ gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
+
FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 6c1bd97..8038cdf 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -229,7 +229,7 @@
{
ALOGV("unload: sampleID=%d", sampleID);
Mutex::Autolock lock(&mLock);
- return mSamples.removeItem(sampleID);
+ return mSamples.removeItem(sampleID) >= 0; // removeItem() returns index or BAD_VALUE
}
int SoundPool::play(int sampleID, float leftVolume, float rightVolume,
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index cc20d39..883c8c6 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -784,12 +784,12 @@
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
}
- while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE && !mOperationDone) {
if (!sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL)) {
break;
}
}
- while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
+ while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE && !mOperationDone) {
mParent.sendRequest(ObexHelper.OBEX_OPCODE_GET_FINAL, null,
mReplyHeader, mPrivateInput, false);
// Regardless of the SRM state, wait for the response.
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index dda9358..fd0ba73 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -95,6 +95,8 @@
<uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
<uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
<uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
+ <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
+ <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
<application android:label="@string/app_label">
<provider
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 9d6d937..e47c7a0 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -184,16 +184,17 @@
<activity android:name=".tuner.TunerActivity"
android:enabled="false"
- android:icon="@*android:drawable/stat_sys_adb"
+ android:icon="@drawable/tuner"
android:theme="@android:style/Theme.Material.Settings"
android:label="@string/system_ui_tuner"
+ android:process=":tuner"
android:exported="true">
<intent-filter>
<action android:name="com.android.settings.action.EXTRA_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.category"
- android:value="com.android.settings.category.device" />
+ android:value="com.android.settings.category.system" />
</activity>
<!-- Alternate Recents -->
@@ -319,6 +320,19 @@
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".egg.ShruggyActivity"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:exported="true"
+ android:launchMode="singleInstance"
+ android:screenOrientation="locked"
+ android:process=":sweetsweetdesserts"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT" />
<category android:name="com.android.internal.category.PLATLOGO" />
</intent-filter>
</activity>
diff --git a/packages/SystemUI/docs/demo_mode.md b/packages/SystemUI/docs/demo_mode.md
index 18ae4cb..258c76b 100644
--- a/packages/SystemUI/docs/demo_mode.md
+++ b/packages/SystemUI/docs/demo_mode.md
@@ -38,6 +38,8 @@
| | ```datatype``` | Values: ```1x```, ```3g```, ```4g```, ```e```, ```g```, ```h```, ```lte```, ```roam```, any other value to hide
| | ```level``` | Sets mobile signal strength level (null or 0-4)
| ```carriernetworkchange``` | | Sets mobile signal icon to carrier network change UX when disconnected (```show``` to show icon, any other value to hide)
+ | ```sims``` | | Sets the number of sims (1-8)
+ | ```nosim``` | | ```show``` to show icon, any other value to hide
```bars``` | | | Control the visual style of the bars (opaque, translucent, etc)
| ```mode``` | | Sets the bars visual style (opaque, translucent, semi-transparent)
```status``` | | | Control the system status icons
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index dc1e633..7b8975a 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -14,47 +14,30 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48dp"
- android:height="48dp"
- android:viewportWidth="560.0"
- android:viewportHeight="560.0">
+ android:width="48.0dp"
+ android:height="48.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
<path
- android:pathData="M280.000000,288.000000m-260.000000,0.000000a260.000000,260.000000 0.000000,1.000000 1.000000,520.000000 0.000000a260.000000,260.000000 0.000000,1.000000 1.000000,-520.000000 0.000000"
- android:fillColor="#14000000"/>
+ android:pathData="M24.0,2.0C11.8,2.0 2.0,11.8 2.0,24.0c0.0,6.1 2.5,11.6 6.4,15.6L39.6,8.4C35.6,4.5 30.1,2.0 24.0,2.0z"
+ android:fillColor="#F57C00"/>
<path
- android:pathData="M280.000000,285.000000m-255.000000,0.000000a255.000000,255.000000 0.000000,1.000000 1.000000,510.000000 0.000000a255.000000,255.000000 0.000000,1.000000 1.000000,-510.000000 0.000000"
- android:fillColor="#26000000"/>
+ android:pathData="M39.6,8.4L8.4,39.6c4.0,4.0 9.5,6.4 15.6,6.4c12.2,0.0 22.0,-9.8 22.0,-22.0C46.0,17.9 43.5,12.4 39.6,8.4z"
+ android:fillColor="#FF9800"/>
<path
- android:pathData="M280.000000,282.000000m-252.000000,0.000000a252.000000,252.000000 0.000000,1.000000 1.000000,504.000000 0.000000a252.000000,252.000000 0.000000,1.000000 1.000000,-504.000000 0.000000"
- android:fillColor="#26000000"/>
+ android:pathData="M45.9,25.9L34.0,14.0L14.0,34.0l11.9,11.9C36.5,45.0 45.0,36.5 45.9,25.9z"
+ android:fillAlpha="0.33"
+ android:fillColor="#F57C00"/>
<path
- android:pathData="M280.000000,280.000000m-250.000000,0.000000a250.000000,250.000000 0.000000,1.000000 1.000000,500.000000 0.000000a250.000000,250.000000 0.000000,1.000000 1.000000,-500.000000 0.000000"
- android:fillColor="#9C27B0"/>
- <path
- android:pathData="M265.786011,244.938004l0.000000,8.768000c6.527000,-6.384000 15.303000,-10.321000 25.063000,-10.321000c20.214001,0.000000 36.429001,16.500000 36.429001,36.714001c0.000000,20.072001 -16.215000,36.500000 -36.429001,36.500000c-9.759000,0.000000 -18.107000,-3.651000 -24.634001,-9.759000l0.000000,25.839001l-10.107000,0.000000l0.000000,-87.740997L265.786011,244.937988L265.786011,244.938004zM267.330994,266.490997c-0.420000,0.706000 -1.125000,1.821000 -1.125000,4.277000l0.000000,18.813000c0.000000,1.759000 0.420000,2.740000 0.982000,3.723000c4.634000,7.929000 13.197000,13.339000 22.882999,13.339000c14.671000,0.000000 26.742001,-11.999000 26.742001,-26.669001c0.000000,-14.536000 -12.071000,-26.607000 -26.742001,-26.607000C280.454987,253.365997 271.963989,258.625000 267.330994,266.490997z"
+ android:pathData="M24.0,24.0c0.0,0.0 0.0,2.2 0.0,5.0s0.0,5.0 0.0,5.0l10.0,-10.0L34.0,14.0L24.0,24.0z"
android:fillColor="#FFFFFF"/>
<path
- android:pathData="M427.973999,244.938004l0.000000,8.768000c6.526000,-6.384000 15.304000,-10.321000 25.062000,-10.321000c20.215000,0.000000 36.429001,16.500000 36.429001,36.714001c0.000000,20.072001 -16.214001,36.500000 -36.429001,36.500000c-9.758000,0.000000 -18.106001,-3.651000 -24.634001,-9.759000l0.000000,25.839001l-10.107000,0.000000l0.000000,-87.740997L427.973999,244.937988L427.973999,244.938004zM429.518005,266.490997c-0.419000,0.706000 -1.125000,1.821000 -1.125000,4.277000l0.000000,18.813000c0.000000,1.759000 0.420000,2.740000 0.982000,3.723000c4.634000,7.929000 13.196000,13.339000 22.884001,13.339000c14.670000,0.000000 26.740999,-11.999000 26.740999,-26.669001c0.000000,-14.536000 -12.071000,-26.607000 -26.740999,-26.607000C442.643005,253.365997 434.152008,258.625000 429.518005,266.490997z"
- android:fillColor="#FFFFFF"/>
+ android:pathData="M24.0,24.0L14.0,14.0l0.0,10.0l10.0,10.0c0.0,0.0 0.0,-2.2 0.0,-5.0S24.0,24.0 24.0,24.0z"
+ android:fillColor="#EEEEEE"/>
<path
- android:pathData="M181.330994,279.893005c0.000000,20.214001 -16.357000,36.715000 -36.438000,36.715000c-20.214001,0.000000 -36.643002,-16.500999 -36.643002,-36.715000c0.000000,-20.070999 16.419001,-36.500000 36.643002,-36.500000C164.973007,243.393005 181.330994,259.821014 181.330994,279.893005zM171.151993,280.036011c0.000000,-14.669000 -11.723000,-26.669001 -26.259001,-26.669001c-14.741000,0.000000 -26.250000,12.000000 -26.250000,26.669001c0.000000,14.536000 11.509000,26.607000 26.250000,26.607000C159.429001,306.634003 171.151993,294.562012 171.151993,280.036011z"
- android:fillColor="#FFFFFF"/>
+ android:pathData="M14.0,34.0l10.0,0.0 -10.0,-10.0z"
+ android:fillColor="#DDDDDD"/>
<path
- android:pathData="M408.384003,279.893005c0.000000,20.214001 -16.357000,36.715000 -36.437000,36.715000c-20.215000,0.000000 -36.644001,-16.500999 -36.644001,-36.715000c0.000000,-20.070999 16.420000,-36.500000 36.644001,-36.500000C392.026001,243.393005 408.384003,259.821014 408.384003,279.893005zM398.204987,280.036011c0.000000,-14.669000 -11.723000,-26.669001 -26.257999,-26.669001c-14.742000,0.000000 -26.250999,12.000000 -26.250999,26.669001c0.000000,14.536000 11.509000,26.607000 26.250999,26.607000C386.481995,306.634003 398.204987,294.562012 398.204987,280.036011z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M234.481995,227.320999l9.973000,0.000000l0.000000,10.250000l-9.973000,0.000000z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M234.481995,244.865997l9.973000,0.000000l0.000000,70.195999l-9.973000,0.000000z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M88.392998,227.320999l9.973000,0.000000l0.000000,87.740997l-9.973000,0.000000z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M191.231995,227.320999l9.973000,0.000000l0.000000,87.740997l-9.973000,0.000000z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M212.856995,227.320999l9.974000,0.000000l0.000000,87.740997l-9.974000,0.000000z"
- android:fillColor="#FFFFFF"/>
+ android:pathData="M34.0,34.0l0.0,-10.0 -10.0,10.0z"
+ android:fillColor="#DDDDDD"/>
</vector>
diff --git a/packages/SystemUI/res/drawable-nodpi/tuner.xml b/packages/SystemUI/res/drawable-nodpi/tuner.xml
new file mode 100644
index 0000000..e27423f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/tuner.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48.0dp"
+ android:height="48.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M29.9,24.8c0.0,-0.3 0.1,-0.5 0.1,-0.8s0.0,-0.5 -0.1,-0.8l1.7,-1.3c0.2,-0.1 0.2,-0.3 0.1,-0.5l-1.6,-2.8c-0.1,-0.2 -0.3,-0.2 -0.5,-0.2l-2.0,0.8c-0.4,-0.3 -0.9,-0.6 -1.4,-0.8L26.0,16.3c0.0,-0.2 -0.2,-0.3 -0.4,-0.3l-3.2,0.0c-0.2,0.0 -0.4,0.1 -0.4,0.3l-0.3,2.1c-0.5,0.2 -0.9,0.5 -1.4,0.8l-2.0,-0.8c-0.2,-0.1 -0.4,0.0 -0.5,0.2l-1.6,2.8c-0.1,0.2 -0.1,0.4 0.1,0.5l1.7,1.3c0.0,0.3 -0.1,0.5 -0.1,0.8s0.0,0.5 0.1,0.8l-1.7,1.3c-0.2,0.1 -0.2,0.3 -0.1,0.5l1.6,2.8c0.1,0.2 0.3,0.2 0.5,0.2l2.0,-0.8c0.4,0.3 0.9,0.6 1.4,0.8l0.3,2.1c0.0,0.2 0.2,0.3 0.4,0.3l3.2,0.0c0.2,0.0 0.4,-0.1 0.4,-0.3l0.3,-2.1c0.5,-0.2 0.9,-0.5 1.4,-0.8l2.0,0.8c0.2,0.1 0.4,0.0 0.5,-0.2l1.6,-2.8c0.1,-0.2 0.1,-0.4 -0.1,-0.5L29.9,24.8zM24.0,26.8c-1.5,0.0 -2.8,-1.3 -2.8,-2.8s1.3,-2.8 2.8,-2.8s2.8,1.3 2.8,2.8S25.5,26.8 24.0,26.8z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M18.0,38.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0s0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0S18.6,38.0 18.0,38.0zM24.0,38.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0s0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0S24.6,38.0 24.0,38.0zM30.0,38.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0s0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0S30.6,38.0 30.0,38.0zM42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,28.0c0.0,2.2 1.8,4.0 4.0,4.0l36.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0zM42.0,34.0L6.0,34.0L6.0,14.0l36.0,0.0L42.0,34.0zM9.0,12.0L7.0,12.0l0.0,-2.0l2.0,0.0L9.0,12.0zM13.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0L13.0,12.0zM17.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0L17.0,12.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 2160ca3..731d4c1 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -61,6 +61,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginStart="24dp"
+ android:textDirection="locale"
android:lineSpacingMultiplier="1.20029"
android:layout_toStartOf="@id/zen_introduction_confirm"
android:textAppearance="@style/TextAppearance.QS.Introduction" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index aac0311..f1bbb0d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1023,7 +1023,7 @@
<string name="volume_stream_vibrate_dnd" translatable="false">%s vibrate — Priority only</string>
<!-- Name of special SystemUI debug settings -->
- <string name="system_ui_tuner">SystemUI Tuner</string>
+ <string name="system_ui_tuner">System UI tuner</string>
<!-- Name of quick settings -->
<string name="quick_settings">Quick Settings</string>
@@ -1033,4 +1033,9 @@
<!-- Name of a quick settings tile controlled by broadcast -->
<string name="broadcast_tile">Broadcast Tile</string>
+
+ <!-- For preview release. DO NOT TRANSLATE -->
+ <string name="regrettable_lack_of_easter_egg">
+ ¯\\_(ツ)_/¯
+ </string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/egg/ShruggyActivity.java b/packages/SystemUI/src/com/android/systemui/egg/ShruggyActivity.java
new file mode 100644
index 0000000..7459957
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/egg/ShruggyActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.egg;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+import com.android.systemui.R;
+
+public class ShruggyActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Toast.makeText(this, getString(R.string.regrettable_lack_of_easter_egg),
+ Toast.LENGTH_SHORT).show();
+ Log.v("SystemUI", "Hey, it's just a preview; what did you expect?");
+ finish();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 3b217df..72bb136 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -24,23 +24,21 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
-import com.android.internal.logging.MetricsLogger;
import com.android.systemui.qs.QSTile.State;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.Listenable;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.ZenModeController;
import java.util.Collection;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 1721335..dcf0438 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -30,9 +30,11 @@
import com.android.systemui.qs.QSTileView;
import com.android.systemui.qs.SignalTileView;
import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataController;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
/** Quick settings tile: Cellular **/
public class CellularTile extends QSTile<QSTile.SignalState> {
@@ -63,9 +65,9 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mController.addNetworkSignalChangedCallback(mCallback);
+ mController.addSignalCallback(mSignalCallback);
} else {
- mController.removeNetworkSignalChangedCallback(mCallback);
+ mController.removeSignalCallback(mSignalCallback);
}
}
@@ -138,7 +140,6 @@
private static final class CallbackInfo {
boolean enabled;
boolean wifiEnabled;
- boolean wifiConnected;
boolean airplaneModeEnabled;
int mobileSignalIconId;
String signalContentDescription;
@@ -151,40 +152,39 @@
boolean isDataTypeIconWide;
}
- private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
+ private final SignalCallback mSignalCallback = new SignalCallbackAdapter() {
private final CallbackInfo mInfo = new CallbackInfo();
-
@Override
- public void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId,
- boolean activityIn, boolean activityOut,
- String wifiSignalContentDescriptionId, String description) {
+ public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+ boolean activityIn, boolean activityOut, String description) {
mInfo.wifiEnabled = enabled;
- mInfo.wifiConnected = connected;
refreshState(mInfo);
}
@Override
- public void onMobileDataSignalChanged(boolean enabled,
- int mobileSignalIconId,
- String mobileSignalContentDescriptionId, int dataTypeIconId,
- boolean activityIn, boolean activityOut,
- String dataTypeContentDescriptionId, String description,
- boolean isDataTypeIconWide) {
- mInfo.enabled = enabled;
- mInfo.mobileSignalIconId = mobileSignalIconId;
- mInfo.signalContentDescription = mobileSignalContentDescriptionId;
- mInfo.dataTypeIconId = dataTypeIconId;
- mInfo.dataContentDescription = dataTypeContentDescriptionId;
+ public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon,
+ int darkStatusIcon, int statusType, int qsType, boolean activityIn,
+ boolean activityOut, String typeContentDescription, String description,
+ boolean isWide, int subId) {
+ if (qsIcon == null) {
+ // Not data sim, don't display.
+ return;
+ }
+ mInfo.enabled = qsIcon.visible;
+ mInfo.mobileSignalIconId = qsIcon.icon;
+ mInfo.signalContentDescription = qsIcon.contentDescription;
+ mInfo.dataTypeIconId = qsType;
+ mInfo.dataContentDescription = typeContentDescription;
mInfo.activityIn = activityIn;
mInfo.activityOut = activityOut;
mInfo.enabledDesc = description;
- mInfo.isDataTypeIconWide = isDataTypeIconWide;
+ mInfo.isDataTypeIconWide = qsType != 0 && isWide;
refreshState(mInfo);
}
@Override
- public void onNoSimVisibleChanged(boolean visible) {
- mInfo.noSim = visible;
+ public void setNoSims(boolean show) {
+ mInfo.noSim = show;
if (mInfo.noSim) {
// Make sure signal gets cleared out when no sims.
mInfo.mobileSignalIconId = 0;
@@ -199,12 +199,13 @@
}
@Override
- public void onAirplaneModeChanged(boolean enabled) {
- mInfo.airplaneModeEnabled = enabled;
+ public void setIsAirplaneMode(IconState icon) {
+ mInfo.airplaneModeEnabled = icon.visible;
refreshState(mInfo);
}
- public void onMobileDataEnabled(boolean enabled) {
+ @Override
+ public void setMobileDataEnabled(boolean enabled) {
mDetailAdapter.setMobileDataEnabled(enabled);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index c3f9e33..9504ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -16,8 +16,6 @@
package com.android.systemui.qs.tiles;
-import java.util.List;
-
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -36,7 +34,11 @@
import com.android.systemui.qs.SignalTileView;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
+
+import java.util.List;
/** Quick settings tile: Wifi **/
public class WifiTile extends QSTile<QSTile.SignalState> {
@@ -67,9 +69,9 @@
@Override
public void setListening(boolean listening) {
if (listening) {
- mController.addNetworkSignalChangedCallback(mCallback);
+ mController.addSignalCallback(mSignalCallback);
} else {
- mController.removeNetworkSignalChangedCallback(mCallback);
+ mController.removeSignalCallback(mSignalCallback);
}
}
@@ -211,46 +213,21 @@
}
}
- private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
+ private final SignalCallback mSignalCallback = new SignalCallbackAdapter() {
@Override
- public void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId,
- boolean activityIn, boolean activityOut,
- String wifiSignalContentDescriptionId, String description) {
+ public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+ boolean activityIn, boolean activityOut, String description) {
if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
final CallbackInfo info = new CallbackInfo();
info.enabled = enabled;
- info.connected = connected;
- info.wifiSignalIconId = wifiSignalIconId;
+ info.connected = qsIcon.visible;
+ info.wifiSignalIconId = qsIcon.icon;
info.enabledDesc = description;
info.activityIn = activityIn;
info.activityOut = activityOut;
- info.wifiSignalContentDescription = wifiSignalContentDescriptionId;
+ info.wifiSignalContentDescription = qsIcon.contentDescription;
refreshState(info);
}
-
- @Override
- public void onMobileDataSignalChanged(boolean enabled,
- int mobileSignalIconId,
- String mobileSignalContentDescriptionId, int dataTypeIconId,
- boolean activityIn, boolean activityOut,
- String dataTypeContentDescriptionId, String description,
- boolean isDataTypeIconWide) {
- // noop
- }
-
- public void onNoSimVisibleChanged(boolean noSims) {
- // noop
- }
-
- @Override
- public void onAirplaneModeChanged(boolean enabled) {
- // noop
- }
-
- @Override
- public void onMobileDataEnabled(boolean enabled) {
- // noop
- }
};
private final class WifiDetailAdapter implements DetailAdapter,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index f6629dd..14e491b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -33,6 +33,7 @@
import android.widget.LinearLayout;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
import com.android.systemui.statusbar.policy.SecurityController;
@@ -42,7 +43,7 @@
// Intimately tied to the design of res/layout/signal_cluster_view.xml
public class SignalClusterView
extends LinearLayout
- implements NetworkControllerImpl.SignalCluster,
+ implements NetworkControllerImpl.SignalCallback,
SecurityController.SecurityControllerCallback {
static final String TAG = "SignalClusterView";
@@ -59,7 +60,7 @@
private int mWifiStrengthId = 0;
private boolean mIsAirplaneMode = false;
private int mAirplaneIconId = 0;
- private int mAirplaneContentDescription;
+ private String mAirplaneContentDescription;
private String mWifiDescription;
private String mEthernetDescription;
private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
@@ -166,35 +167,36 @@
}
@Override
- public void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription) {
- mWifiVisible = visible;
- mWifiStrengthId = strengthIcon;
- mWifiDescription = contentDescription;
+ public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+ boolean activityIn, boolean activityOut, String description) {
+ mWifiVisible = statusIcon.visible;
+ mWifiStrengthId = statusIcon.icon;
+ mWifiDescription = statusIcon.contentDescription;
apply();
}
@Override
- public void setMobileDataIndicators(boolean visible, int strengthIcon, int darkStrengthIcon,
- int typeIcon, String contentDescription, String typeContentDescription,
- boolean isTypeIconWide, int subId) {
+ public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int darkStatusIcon,
+ int statusType, int qsType, boolean activityIn, boolean activityOut,
+ String typeContentDescription, String description, boolean isWide, int subId) {
PhoneState state = getOrInflateState(subId);
- state.mMobileVisible = visible;
- state.mMobileStrengthId = strengthIcon;
- state.mMobileDarkStrengthId = darkStrengthIcon;
- state.mMobileTypeId = typeIcon;
- state.mMobileDescription = contentDescription;
+ state.mMobileVisible = statusIcon.visible;
+ state.mMobileStrengthId = statusIcon.icon;
+ state.mMobileDarkStrengthId = darkStatusIcon;
+ state.mMobileTypeId = statusType;
+ state.mMobileDescription = statusIcon.contentDescription;
state.mMobileTypeDescription = typeContentDescription;
- state.mIsMobileTypeIconWide = isTypeIconWide;
+ state.mIsMobileTypeIconWide = statusType != 0 && isWide;
apply();
}
@Override
- public void setEthernetIndicators(boolean visible, int icon, String contentDescription) {
- mEthernetVisible = visible;
- mEthernetIconId = icon;
- mEthernetDescription = contentDescription;
+ public void setEthernetIndicators(IconState state) {
+ mEthernetVisible = state.visible;
+ mEthernetIconId = state.icon;
+ mEthernetDescription = state.contentDescription;
apply();
}
@@ -239,15 +241,20 @@
}
@Override
- public void setIsAirplaneMode(boolean is, int airplaneIconId, int contentDescription) {
- mIsAirplaneMode = is;
- mAirplaneIconId = airplaneIconId;
- mAirplaneContentDescription = contentDescription;
+ public void setIsAirplaneMode(IconState icon) {
+ mIsAirplaneMode = icon.visible;
+ mAirplaneIconId = icon.icon;
+ mAirplaneContentDescription = icon.contentDescription;
apply();
}
@Override
+ public void setMobileDataEnabled(boolean enabled) {
+ // Don't care.
+ }
+
+ @Override
public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
// Standard group layout onPopulateAccessibilityEvent() implementations
// ignore content description, so populate manually
@@ -343,8 +350,7 @@
if (mIsAirplaneMode) {
mAirplane.setImageResource(mAirplaneIconId);
- mAirplane.setContentDescription(mAirplaneContentDescription != 0 ?
- mContext.getString(mAirplaneContentDescription) : null);
+ mAirplane.setContentDescription(mAirplaneContentDescription);
mAirplane.setVisibility(View.VISIBLE);
} else {
mAirplane.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 887b8f4..2a9df19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -779,9 +779,9 @@
(SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
final SignalClusterView signalClusterQs =
(SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
- mNetworkController.addSignalCluster(signalCluster);
- mNetworkController.addSignalCluster(signalClusterKeyguard);
- mNetworkController.addSignalCluster(signalClusterQs);
+ mNetworkController.addSignalCallback(signalCluster);
+ mNetworkController.addSignalCallback(signalClusterKeyguard);
+ mNetworkController.addSignalCallback(signalClusterQs);
signalCluster.setSecurityController(mSecurityController);
signalCluster.setNetworkController(mNetworkController);
signalClusterKeyguard.setSecurityController(mSecurityController);
@@ -3087,6 +3087,16 @@
}
mContext.unregisterReceiver(mBroadcastReceiver);
mAssistManager.destroy();
+
+ final SignalClusterView signalCluster =
+ (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
+ final SignalClusterView signalClusterKeyguard =
+ (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
+ final SignalClusterView signalClusterQs =
+ (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
+ mNetworkController.addSignalCallback(signalCluster);
+ mNetworkController.addSignalCallback(signalClusterKeyguard);
+ mNetworkController.addSignalCallback(signalClusterQs);
}
private boolean mDemoModeAllowed;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
new file mode 100644
index 0000000..7f52191
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.telephony.SubscriptionInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Implements network listeners and forwards the calls along onto other listeners but on
+ * the current or specified Looper.
+ */
+public class CallbackHandler extends Handler implements EmergencyListener, SignalCallback {
+ private static final int MSG_EMERGENCE_CHANGED = 0;
+ private static final int MSG_SUBS_CHANGED = 1;
+ private static final int MSG_NO_SIM_VISIBLE_CHANGED = 2;
+ private static final int MSG_ETHERNET_CHANGED = 3;
+ private static final int MSG_AIRPLANE_MODE_CHANGED = 4;
+ private static final int MSG_MOBILE_DATA_ENABLED_CHANGED = 5;
+ private static final int MSG_ADD_REMOVE_EMERGENCY = 6;
+ private static final int MSG_ADD_REMOVE_SIGNAL = 7;
+
+ // All the callbacks.
+ private final ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<>();
+ private final ArrayList<SignalCallback> mSignalCallbacks = new ArrayList<>();
+
+ public CallbackHandler() {
+ super();
+ }
+
+ @VisibleForTesting
+ CallbackHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_EMERGENCE_CHANGED:
+ for (EmergencyListener listener : mEmergencyListeners) {
+ listener.setEmergencyCallsOnly(msg.arg1 != 0);
+ }
+ break;
+ case MSG_SUBS_CHANGED:
+ for (SignalCallback signalCluster : mSignalCallbacks) {
+ signalCluster.setSubs((List<SubscriptionInfo>) msg.obj);
+ }
+ break;
+ case MSG_NO_SIM_VISIBLE_CHANGED:
+ for (SignalCallback signalCluster : mSignalCallbacks) {
+ signalCluster.setNoSims(msg.arg1 != 0);
+ }
+ break;
+ case MSG_ETHERNET_CHANGED:
+ for (SignalCallback signalCluster : mSignalCallbacks) {
+ signalCluster.setEthernetIndicators((IconState) msg.obj);
+ }
+ break;
+ case MSG_AIRPLANE_MODE_CHANGED:
+ for (SignalCallback signalCluster : mSignalCallbacks) {
+ signalCluster.setIsAirplaneMode((IconState) msg.obj);
+ }
+ break;
+ case MSG_MOBILE_DATA_ENABLED_CHANGED:
+ for (SignalCallback signalCluster : mSignalCallbacks) {
+ signalCluster.setMobileDataEnabled(msg.arg1 != 0);
+ }
+ break;
+ case MSG_ADD_REMOVE_EMERGENCY:
+ if (msg.arg1 != 0) {
+ mEmergencyListeners.add((EmergencyListener) msg.obj);
+ } else {
+ mEmergencyListeners.remove((EmergencyListener) msg.obj);
+ }
+ break;
+ case MSG_ADD_REMOVE_SIGNAL:
+ if (msg.arg1 != 0) {
+ mSignalCallbacks.add((SignalCallback) msg.obj);
+ } else {
+ mSignalCallbacks.remove((SignalCallback) msg.obj);
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void setWifiIndicators(final boolean enabled, final IconState statusIcon,
+ final IconState qsIcon, final boolean activityIn, final boolean activityOut,
+ final String description) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ for (SignalCallback callback : mSignalCallbacks) {
+ callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut,
+ description);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon,
+ final int darkStatusIcon, final int statusType, final int qsType,
+ final boolean activityIn, final boolean activityOut,
+ final String typeContentDescription, final String description, final boolean isWide,
+ final int subId) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ for (SignalCallback signalCluster : mSignalCallbacks) {
+ signalCluster.setMobileDataIndicators(statusIcon, qsIcon, darkStatusIcon,
+ statusType, qsType, activityIn, activityOut, typeContentDescription,
+ description, isWide, subId);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void setSubs(List<SubscriptionInfo> subs) {
+ obtainMessage(MSG_SUBS_CHANGED, subs).sendToTarget();
+ }
+
+ @Override
+ public void setNoSims(boolean show) {
+ obtainMessage(MSG_NO_SIM_VISIBLE_CHANGED, show ? 1 : 0, 0).sendToTarget();
+ }
+
+ @Override
+ public void setMobileDataEnabled(boolean enabled) {
+ obtainMessage(MSG_MOBILE_DATA_ENABLED_CHANGED, enabled ? 1 : 0, 0).sendToTarget();
+ }
+
+ @Override
+ public void setEmergencyCallsOnly(boolean emergencyOnly) {
+ obtainMessage(MSG_EMERGENCE_CHANGED, emergencyOnly ? 1 : 0, 0).sendToTarget();
+ }
+
+ @Override
+ public void setEthernetIndicators(IconState icon) {
+ obtainMessage(MSG_ETHERNET_CHANGED, icon).sendToTarget();;
+ }
+
+ @Override
+ public void setIsAirplaneMode(IconState icon) {
+ obtainMessage(MSG_AIRPLANE_MODE_CHANGED, icon).sendToTarget();;
+ }
+
+ public void setListening(EmergencyListener listener, boolean listening) {
+ obtainMessage(MSG_ADD_REMOVE_EMERGENCY, listening ? 1 : 0, 0, listener).sendToTarget();
+ }
+
+ public void setListening(SignalCallback listener, boolean listening) {
+ obtainMessage(MSG_ADD_REMOVE_SIGNAL, listening ? 1 : 0, 0, listener).sendToTarget();
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
index 9c044c4..bd36462 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
@@ -18,22 +18,18 @@
import android.content.Context;
import android.net.NetworkCapabilities;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import java.util.List;
-import java.util.Objects;
+import java.util.BitSet;
public class EthernetSignalController extends
SignalController<SignalController.State, SignalController.IconGroup> {
public EthernetSignalController(Context context,
- List<NetworkSignalChangedCallback> signalCallbacks,
- List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+ CallbackHandler callbackHandler, NetworkControllerImpl networkController) {
super("EthernetSignalController", context, NetworkCapabilities.TRANSPORT_ETHERNET,
- signalCallbacks, signalClusters, networkController);
+ callbackHandler, networkController);
mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
"Ethernet Icons",
EthernetIcons.ETHERNET_ICONS,
@@ -44,25 +40,23 @@
}
@Override
+ public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
+ mCurrentState.connected = connectedTransports.get(mTransportType);
+ super.updateConnectivity(connectedTransports, validatedTransports);
+ }
+
+ @Override
public void notifyListeners() {
boolean ethernetVisible = mCurrentState.connected;
String contentDescription = getStringIfExists(getContentDescription());
// TODO: wire up data transfer using WifiSignalPoller.
- int signalClustersLength = mSignalClusters.size();
- for (int i = 0; i < signalClustersLength; i++) {
- mSignalClusters.get(i).setEthernetIndicators(ethernetVisible, getCurrentIconId(),
- contentDescription);
- }
+ mCallbackHandler.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(),
+ contentDescription));
}
@Override
public SignalController.State cleanState() {
return new SignalController.State();
}
-
- public void setConnected(boolean connected) {
- mCurrentState.connected = connected;
- notifyListenersIfNecessary();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 22bf47c..0d59953 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.Intent;
import android.net.NetworkCapabilities;
+import android.os.Looper;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -31,12 +32,11 @@
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.cdma.EriInfo;
import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
import java.io.PrintWriter;
-import java.util.List;
+import java.util.BitSet;
import java.util.Objects;
@@ -66,17 +66,17 @@
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
public MobileSignalController(Context context, Config config, boolean hasMobileData,
- TelephonyManager phone, List<NetworkSignalChangedCallback> signalCallbacks,
- List<SignalCluster> signalClusters, NetworkControllerImpl networkController,
- SubscriptionInfo info) {
+ TelephonyManager phone, CallbackHandler callbackHandler,
+ NetworkControllerImpl networkController, SubscriptionInfo info, Looper receiverLooper) {
super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
- NetworkCapabilities.TRANSPORT_CELLULAR, signalCallbacks, signalClusters,
+ NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
networkController);
mNetworkToIconLookup = new SparseArray<>();
mConfig = config;
mPhone = phone;
mSubscriptionInfo = info;
- mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId());
+ mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(),
+ receiverLooper);
mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
mNetworkNameDefault = getStringIfExists(
com.android.internal.R.string.lockscreen_carrier_default);
@@ -106,13 +106,13 @@
notifyListenersIfNecessary();
}
- public void setInetCondition(int inetCondition, int inetConditionForNetwork) {
- // For mobile data, use general inet condition for phone signal indexing,
- // and network specific for data indexing (I think this might be a bug, but
- // keeping for now).
- // TODO: Update with explanation of why.
- mCurrentState.inetForNetwork = inetConditionForNetwork;
- setInetCondition(inetCondition);
+ @Override
+ public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
+ boolean isValidated = validatedTransports.get(mTransportType);
+ mCurrentState.isDefault = connectedTransports.get(mTransportType);
+ // Only show this as not having connectivity if we are default.
+ mCurrentState.inetCondition = (isValidated || !mCurrentState.isDefault) ? 1 : 0;
+ notifyListenersIfNecessary();
}
public void setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode) {
@@ -196,44 +196,33 @@
String contentDescription = getStringIfExists(getContentDescription());
String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
- boolean showDataIcon = mCurrentState.dataConnected && mCurrentState.inetForNetwork != 0
+ // Show icon in QS when we are connected or need to show roaming.
+ boolean showDataIcon = mCurrentState.dataConnected
|| mCurrentState.iconGroup == TelephonyIcons.ROAMING;
+ IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
+ getCurrentIconId(), contentDescription);
+ int qsTypeIcon = 0;
+ IconState qsIcon = null;
+ String description = null;
// Only send data sim callbacks to QS.
if (mCurrentState.dataSim) {
- int qsTypeIcon = showDataIcon ? icons.mQsDataType[mCurrentState.inetForNetwork] : 0;
- int length = mSignalsChangedCallbacks.size();
- for (int i = 0; i < length; i++) {
- mSignalsChangedCallbacks.get(i).onMobileDataSignalChanged(mCurrentState.enabled
- && !mCurrentState.isEmergency,
- getQsCurrentIconId(), contentDescription,
- qsTypeIcon,
- mCurrentState.dataConnected
- && !mCurrentState.carrierNetworkChangeMode
- && mCurrentState.activityIn,
- mCurrentState.dataConnected
- && !mCurrentState.carrierNetworkChangeMode
- && mCurrentState.activityOut,
- dataContentDescription,
- mCurrentState.isEmergency ? null : mCurrentState.networkName,
- // Only wide if actually showing something.
- icons.mIsWide && qsTypeIcon != 0);
- }
+ qsTypeIcon = showDataIcon ? icons.mQsDataType : 0;
+ qsIcon = new IconState(mCurrentState.enabled
+ && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
+ description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
}
+ boolean activityIn = mCurrentState.dataConnected
+ && !mCurrentState.carrierNetworkChangeMode
+ && mCurrentState.activityIn;
+ boolean activityOut = mCurrentState.dataConnected
+ && !mCurrentState.carrierNetworkChangeMode
+ && mCurrentState.activityOut;
+ showDataIcon &= mCurrentState.isDefault;
int typeIcon = showDataIcon ? icons.mDataType : 0;
- int signalClustersLength = mSignalClusters.size();
- for (int i = 0; i < signalClustersLength; i++) {
- mSignalClusters.get(i).setMobileDataIndicators(
- mCurrentState.enabled && !mCurrentState.airplaneMode,
- getCurrentIconId(),
- getCurrentDarkIconId(),
- typeIcon,
- contentDescription,
- dataContentDescription,
- // Only wide if actually showing something.
- icons.mIsWide && typeIcon != 0,
- mSubscriptionInfo.getSubscriptionId());
- }
+ mCallbackHandler.setMobileDataIndicators(statusIcon, qsIcon, getCurrentDarkIconId(),
+ typeIcon, qsTypeIcon, activityIn, activityOut, dataContentDescription, description,
+ icons.mIsWide, mSubscriptionInfo.getSubscriptionId());
}
private int getCurrentDarkIconId() {
@@ -425,8 +414,8 @@
}
class MobilePhoneStateListener extends PhoneStateListener {
- public MobilePhoneStateListener(int subId) {
- super(subId);
+ public MobilePhoneStateListener(int subId, Looper looper) {
+ super(subId, looper);
}
@Override
@@ -483,12 +472,12 @@
final int mDataContentDescription; // mContentDescriptionDataType
final int mDataType;
final boolean mIsWide;
- final int[] mQsDataType;
+ final int mQsDataType;
public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc,
int sbNullState, int qsNullState, int sbDiscState, int qsDiscState,
int discContentDesc, int dataContentDesc, int dataType, boolean isWide,
- int[] qsDataType) {
+ int qsDataType) {
this(name, sbIcons, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState,
sbDiscState, sbDiscState, qsDiscState, discContentDesc, dataContentDesc,
dataType, isWide, qsDataType);
@@ -497,7 +486,7 @@
public MobileIconGroup(String name, int[][] sbIcons, int[][] sbDarkIcons, int[][] qsIcons,
int[] contentDesc, int sbNullState, int qsNullState, int sbDiscState,
int sbDarkDiscState, int qsDiscState, int discContentDesc, int dataContentDesc,
- int dataType, boolean isWide, int[] qsDataType) {
+ int dataType, boolean isWide, int qsDataType) {
super(name, sbIcons, sbDarkIcons, qsIcons, contentDesc, sbNullState, qsNullState,
sbDiscState, sbDarkDiscState, qsDiscState, discContentDesc);
mDataContentDescription = dataContentDesc;
@@ -515,7 +504,7 @@
boolean isEmergency;
boolean airplaneMode;
boolean carrierNetworkChangeMode;
- int inetForNetwork;
+ boolean isDefault;
@Override
public void copyFrom(State s) {
@@ -525,7 +514,7 @@
networkName = state.networkName;
networkNameData = state.networkNameData;
dataConnected = state.dataConnected;
- inetForNetwork = state.inetForNetwork;
+ isDefault = state.isDefault;
isEmergency = state.isEmergency;
airplaneMode = state.airplaneMode;
carrierNetworkChangeMode = state.carrierNetworkChangeMode;
@@ -539,7 +528,7 @@
builder.append("networkName=").append(networkName).append(',');
builder.append("networkNameData=").append(networkNameData).append(',');
builder.append("dataConnected=").append(dataConnected).append(',');
- builder.append("inetForNetwork=").append(inetForNetwork).append(',');
+ builder.append("isDefault=").append(isDefault).append(',');
builder.append("isEmergency=").append(isEmergency).append(',');
builder.append("airplaneMode=").append(airplaneMode).append(',');
builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode);
@@ -555,7 +544,7 @@
&& ((MobileState) o).isEmergency == isEmergency
&& ((MobileState) o).airplaneMode == airplaneMode
&& ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
- && ((MobileState) o).inetForNetwork == inetForNetwork;
+ && ((MobileState) o).isDefault == isDefault;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 9212837..070ca63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -16,7 +16,9 @@
package com.android.systemui.statusbar.policy;
+import android.content.Context;
import android.content.Intent;
+import android.telephony.SubscriptionInfo;
import com.android.settingslib.wifi.AccessPoint;
@@ -25,25 +27,45 @@
public interface NetworkController {
boolean hasMobileDataFeature();
- void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
- void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
+ void addSignalCallback(SignalCallback cb);
+ void removeSignalCallback(SignalCallback cb);
void setWifiEnabled(boolean enabled);
void onUserSwitched(int newUserId);
AccessPointController getAccessPointController();
MobileDataController getMobileDataController();
- public interface NetworkSignalChangedCallback {
- void onWifiSignalChanged(boolean enabled, boolean connected, int wifiSignalIconId,
- boolean activityIn, boolean activityOut,
- String wifiSignalContentDescriptionId, String description);
- void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
- String mobileSignalContentDescriptionId, int dataTypeIconId,
- boolean activityIn, boolean activityOut,
- String dataTypeContentDescriptionId, String description,
- boolean isDataTypeIconWide);
- void onNoSimVisibleChanged(boolean visible);
- void onAirplaneModeChanged(boolean enabled);
- void onMobileDataEnabled(boolean enabled);
+ public interface SignalCallback {
+ void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+ boolean activityIn, boolean activityOut, String description);
+
+ void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int darkStatusIcon,
+ int statusType, int qsType, boolean activityIn, boolean activityOut,
+ String typeContentDescription, String description, boolean isWide, int subId);
+ void setSubs(List<SubscriptionInfo> subs);
+ void setNoSims(boolean show);
+
+ void setEthernetIndicators(IconState icon);
+
+ void setIsAirplaneMode(IconState icon);
+
+ void setMobileDataEnabled(boolean enabled);
+ }
+
+ public static class IconState {
+ public final boolean visible;
+ public final int icon;
+ public final String contentDescription;
+
+ public IconState(boolean visible, int icon, String contentDescription) {
+ this.visible = visible;
+ this.icon = icon;
+ this.contentDescription = contentDescription;
+ }
+
+ public IconState(boolean visible, int icon, int contentDescription,
+ Context context) {
+ this(visible, icon, context.getString(contentDescription));
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 92e0365..e8957f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -28,6 +28,7 @@
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
@@ -36,6 +37,7 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
+import android.util.MathUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.PhoneConstants;
@@ -61,7 +63,7 @@
static final String TAG = "NetworkController";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
// additional diagnostics, but not logspew
- static final boolean CHATTY = Log.isLoggable(TAG + ".Chat", Log.DEBUG);
+ static final boolean CHATTY = Log.isLoggable(TAG + "Chat", Log.DEBUG);
private final Context mContext;
private final TelephonyManager mPhone;
@@ -99,20 +101,19 @@
private boolean mHasNoSims;
private Locale mLocale = null;
// This list holds our ordering.
- private List<SubscriptionInfo> mCurrentSubscriptions
- = new ArrayList<SubscriptionInfo>();
+ private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>();
- // All the callbacks.
- private ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<EmergencyListener>();
- private ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
- private ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
- new ArrayList<NetworkSignalChangedCallback>();
@VisibleForTesting
boolean mListening;
// The current user ID.
private int mCurrentUserId;
+ // Handler that all broadcasts are received on.
+ private final Handler mReceiverHandler;
+ // Handler that all callbacks are made on.
+ private final CallbackHandler mCallbackHandler;
+
/**
* Construct this controller object and register for updates.
*/
@@ -120,20 +121,24 @@
this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
(WifiManager) context.getSystemService(Context.WIFI_SERVICE),
- SubscriptionManager.from(context), Config.readConfig(context),
+ SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
+ new CallbackHandler(),
new AccessPointControllerImpl(context, bgLooper),
new MobileDataControllerImpl(context));
- registerListeners();
+ mReceiverHandler.post(mRegisterListeners);
}
@VisibleForTesting
NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
TelephonyManager telephonyManager, WifiManager wifiManager,
- SubscriptionManager subManager, Config config,
+ SubscriptionManager subManager, Config config, Looper bgLooper,
+ CallbackHandler callbackHandler,
AccessPointControllerImpl accessPointController,
MobileDataControllerImpl mobileDataController) {
mContext = context;
mConfig = config;
+ mReceiverHandler = new Handler(bgLooper);
+ mCallbackHandler = callbackHandler;
mSubscriptionManager = subManager;
mConnectivityManager = connectivityManager;
@@ -141,7 +146,7 @@
mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
// telephony
- mPhone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ mPhone = telephonyManager;
// wifi
mWifiManager = wifiManager;
@@ -154,14 +159,13 @@
mMobileDataController.setCallback(new MobileDataControllerImpl.Callback() {
@Override
public void onMobileDataEnabled(boolean enabled) {
- notifyMobileDataEnabled(enabled);
+ mCallbackHandler.setMobileDataEnabled(enabled);
}
});
mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
- mSignalsChangedCallbacks, mSignalClusters, this);
+ mCallbackHandler, this);
- mEthernetSignalController = new EthernetSignalController(mContext, mSignalsChangedCallbacks,
- mSignalClusters, this);
+ mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this);
// AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
updateAirplaneMode(true /* force callback */);
@@ -186,7 +190,7 @@
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- mContext.registerReceiver(this, filter);
+ mContext.registerReceiver(this, filter, null, mReceiverHandler);
mListening = true;
updateMobileControllers();
@@ -216,15 +220,8 @@
}
public void addEmergencyListener(EmergencyListener listener) {
- mEmergencyListeners.add(listener);
- listener.setEmergencyCallsOnly(isEmergencyOnly());
- }
-
- private void notifyMobileDataEnabled(boolean enabled) {
- final int length = mSignalsChangedCallbacks.size();
- for (int i = 0; i < length; i++) {
- mSignalsChangedCallbacks.get(i).onMobileDataEnabled(enabled);
- }
+ mCallbackHandler.setListening(listener, true);
+ mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
}
public boolean hasMobileDataFeature() {
@@ -276,19 +273,15 @@
* so we should recheck and send out the state to listeners.
*/
void recalculateEmergency() {
- final boolean emergencyOnly = isEmergencyOnly();
- final int length = mEmergencyListeners.size();
- for (int i = 0; i < length; i++) {
- mEmergencyListeners.get(i).setEmergencyCallsOnly(emergencyOnly);
- }
+ mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
}
- public void addSignalCluster(SignalCluster cluster) {
- mSignalClusters.add(cluster);
- cluster.setSubs(mCurrentSubscriptions);
- cluster.setIsAirplaneMode(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON,
- R.string.accessibility_airplane_mode);
- cluster.setNoSims(mHasNoSims);
+ public void addSignalCallback(SignalCallback cb) {
+ mCallbackHandler.setListening(cb, true);
+ mCallbackHandler.setSubs(mCurrentSubscriptions);
+ mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
+ TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
+ mCallbackHandler.setNoSims(mHasNoSims);
mWifiSignalController.notifyListeners();
mEthernetSignalController.notifyListeners();
for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
@@ -296,19 +289,9 @@
}
}
- public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
- mSignalsChangedCallbacks.add(cb);
- cb.onAirplaneModeChanged(mAirplaneMode);
- cb.onNoSimVisibleChanged(mHasNoSims);
- mWifiSignalController.notifyListeners();
- mEthernetSignalController.notifyListeners();
- for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
- mobileSignalController.notifyListeners();
- }
- }
-
- public void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
- mSignalsChangedCallbacks.remove(cb);
+ @Override
+ public void removeSignalCallback(SignalCallback cb) {
+ mCallbackHandler.setListening(cb, false);
}
@Override
@@ -427,10 +410,7 @@
: lhs.getSimSlotIndex() - rhs.getSimSlotIndex();
}
});
- final int length = mSignalClusters.size();
- for (int i = 0; i < length; i++) {
- mSignalClusters.get(i).setSubs(subscriptions);
- }
+ mCallbackHandler.setSubs(subscriptions);
mCurrentSubscriptions = subscriptions;
HashMap<Integer, MobileSignalController> cachedControllers =
@@ -444,8 +424,8 @@
mMobileSignalControllers.put(subId, cachedControllers.remove(subId));
} else {
MobileSignalController controller = new MobileSignalController(mContext, mConfig,
- mHasMobileDataFeature, mPhone, mSignalsChangedCallbacks, mSignalClusters,
- this, subscriptions.get(i));
+ mHasMobileDataFeature, mPhone, mCallbackHandler,
+ this, subscriptions.get(i), mReceiverHandler.getLooper());
mMobileSignalControllers.put(subId, controller);
if (subscriptions.get(i).getSimSlotIndex() == 0) {
mDefaultSignalController = controller;
@@ -521,17 +501,9 @@
* notifyAllListeners.
*/
private void notifyListeners() {
- int length = mSignalClusters.size();
- for (int i = 0; i < length; i++) {
- mSignalClusters.get(i).setIsAirplaneMode(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON,
- R.string.accessibility_airplane_mode);
- mSignalClusters.get(i).setNoSims(mHasNoSims);
- }
- int signalsChangedLength = mSignalsChangedCallbacks.size();
- for (int i = 0; i < signalsChangedLength; i++) {
- mSignalsChangedCallbacks.get(i).onAirplaneModeChanged(mAirplaneMode);
- mSignalsChangedCallbacks.get(i).onNoSimVisibleChanged(mHasNoSims);
- }
+ mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
+ TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
+ mCallbackHandler.setNoSims(mHasNoSims);
}
/**
@@ -566,17 +538,10 @@
private void pushConnectivityToSignals() {
// We want to update all the icons, all at once, for any condition change
for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
- mobileSignalController.setInetCondition(
- mInetCondition ? 1 : 0,
- mValidatedTransports.get(mobileSignalController.getTransportType()) ? 1 : 0);
+ mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
}
- mWifiSignalController.setInetCondition(
- mValidatedTransports.get(mWifiSignalController.getTransportType()) ? 1 : 0);
-
- mEthernetSignalController.setConnected(
- mConnectedTransports.get(mEthernetSignalController.getTransportType()));
- mEthernetSignalController.setInetCondition(
- mValidatedTransports.get(mEthernetSignalController.getTransportType()) ? 1 : 0);
+ mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
+ mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -609,7 +574,7 @@
}
private boolean mDemoMode;
- private int mDemoInetCondition;
+ private boolean mDemoInetCondition;
private WifiSignalController.WifiState mDemoWifiState;
@Override
@@ -618,7 +583,7 @@
if (DEBUG) Log.d(TAG, "Entering demo mode");
unregisterListeners();
mDemoMode = true;
- mDemoInetCondition = mInetCondition ? 1 : 0;
+ mDemoInetCondition = mInetCondition;
mDemoWifiState = mWifiSignalController.getState();
} else if (mDemoMode && command.equals(COMMAND_EXIT)) {
if (DEBUG) Log.d(TAG, "Exiting demo mode");
@@ -630,24 +595,30 @@
controller.resetLastState();
}
mWifiSignalController.resetLastState();
- registerListeners();
+ mReceiverHandler.post(mRegisterListeners);
notifyAllListeners();
} else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
String airplane = args.getString("airplane");
if (airplane != null) {
boolean show = airplane.equals("show");
- int length = mSignalClusters.size();
- for (int i = 0; i < length; i++) {
- mSignalClusters.get(i).setIsAirplaneMode(show, TelephonyIcons.FLIGHT_MODE_ICON,
- R.string.accessibility_airplane_mode);
- }
+ mCallbackHandler.setIsAirplaneMode(new IconState(show,
+ TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode,
+ mContext));
}
String fully = args.getString("fully");
if (fully != null) {
- mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
- mWifiSignalController.setInetCondition(mDemoInetCondition);
+ mDemoInetCondition = Boolean.parseBoolean(fully);
+ BitSet connected = new BitSet();
+
+ if (mDemoInetCondition) {
+ connected.set(mWifiSignalController.mTransportType);
+ }
+ mWifiSignalController.updateConnectivity(connected, connected);
for (MobileSignalController controller : mMobileSignalControllers.values()) {
- controller.setInetCondition(mDemoInetCondition, mDemoInetCondition);
+ if (mDemoInetCondition) {
+ connected.set(controller.mTransportType);
+ }
+ controller.updateConnectivity(connected, connected);
}
}
String wifi = args.getString("wifi");
@@ -664,32 +635,21 @@
}
String sims = args.getString("sims");
if (sims != null) {
- int num = Integer.parseInt(sims);
- List<SubscriptionInfo> subs = new ArrayList<SubscriptionInfo>();
+ int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8);
+ List<SubscriptionInfo> subs = new ArrayList<>();
if (num != mMobileSignalControllers.size()) {
mMobileSignalControllers.clear();
int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
for (int i = start /* get out of normal index range */; i < start + num; i++) {
- SubscriptionInfo info = new SubscriptionInfo(i, "", i, "", "", 0, 0, "", 0,
- null, 0, 0, "");
- subs.add(info);
- mMobileSignalControllers.put(i, new MobileSignalController(mContext,
- mConfig, mHasMobileDataFeature, mPhone, mSignalsChangedCallbacks,
- mSignalClusters, this, info));
+ subs.add(addSignalController(i, i));
}
}
- final int n = mSignalClusters.size();
- for (int i = 0; i < n; i++) {
- mSignalClusters.get(i).setSubs(subs);
- }
+ mCallbackHandler.setSubs(subs);
}
String nosim = args.getString("nosim");
if (nosim != null) {
boolean show = nosim.equals("show");
- final int n = mSignalClusters.size();
- for (int i = 0; i < n; i++) {
- mSignalClusters.get(i).setNoSims(show);
- }
+ mCallbackHandler.setNoSims(show);
}
String mobile = args.getString("mobile");
if (mobile != null) {
@@ -697,6 +657,16 @@
String datatype = args.getString("datatype");
String slotString = args.getString("slot");
int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString);
+ slot = MathUtils.constrain(slot, 0, 8);
+ // Ensure we have enough sim slots
+ List<SubscriptionInfo> subs = new ArrayList<>();
+ while (mMobileSignalControllers.size() <= slot) {
+ int nextSlot = mMobileSignalControllers.size();
+ subs.add(addSignalController(nextSlot, nextSlot));
+ }
+ if (!subs.isEmpty()) {
+ mCallbackHandler.setSubs(subs);
+ }
// Hack to index linearly for easy use.
MobileSignalController controller = mMobileSignalControllers
.values().toArray(new MobileSignalController[0])[slot];
@@ -733,6 +703,15 @@
}
}
+ private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
+ SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
+ null, 0, 0, "");
+ mMobileSignalControllers.put(id, new MobileSignalController(mContext,
+ mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
+ mReceiverHandler.getLooper()));
+ return info;
+ }
+
private final OnSubscriptionsChangedListener mSubscriptionListener =
new OnSubscriptionsChangedListener() {
@Override
@@ -741,28 +720,21 @@
};
};
- public interface SignalCluster {
- void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription);
-
- void setMobileDataIndicators(boolean visible, int strengthIcon, int darkStrengthIcon,
- int typeIcon, String contentDescription, String typeContentDescription,
- boolean isTypeIconWide, int subId);
- void setSubs(List<SubscriptionInfo> subs);
- void setNoSims(boolean show);
-
- void setEthernetIndicators(boolean visible, int icon, String contentDescription);
-
- void setIsAirplaneMode(boolean is, int airplaneIcon, int contentDescription);
- }
+ /**
+ * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
+ * get created will also run on the BG Looper.
+ */
+ private final Runnable mRegisterListeners = new Runnable() {
+ @Override
+ public void run() {
+ registerListeners();
+ }
+ };
public interface EmergencyListener {
void setEmergencyCallsOnly(boolean emergencyOnly);
}
- public interface CarrierLabelListener {
- void setCarrierLabel(String label);
- }
-
@VisibleForTesting
static class Config {
boolean showAtLeast3G = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java
new file mode 100644
index 0000000..83a7d3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalCallbackAdapter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy;
+
+import android.telephony.SubscriptionInfo;
+
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+
+import java.util.List;
+
+
+/**
+ * Provides empty implementations of SignalCallback for those that only want some of
+ * the callbacks.
+ */
+public class SignalCallbackAdapter implements SignalCallback {
+
+ @Override
+ public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+ boolean activityIn, boolean activityOut, String description) {
+ }
+
+ @Override
+ public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon,
+ int darkStatusIcon, int statusType, int qsType, boolean activityIn,
+ boolean activityOut, String typeContentDescription, String description,
+ boolean isWide, int subId) {
+ }
+
+ @Override
+ public void setSubs(List<SubscriptionInfo> subs) {
+ }
+
+ @Override
+ public void setNoSims(boolean show) {
+ }
+
+ @Override
+ public void setEthernetIndicators(IconState icon) {
+ }
+
+ @Override
+ public void setIsAirplaneMode(IconState icon) {
+ }
+
+ @Override
+ public void setMobileDataEnabled(boolean enabled) {
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index f3322a1..e6ca646 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -21,11 +21,8 @@
import android.text.format.DateFormat;
import android.util.Log;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
-
import java.io.PrintWriter;
-import java.util.List;
+import java.util.BitSet;
/**
@@ -49,24 +46,22 @@
// The owner of the SignalController (i.e. NetworkController will maintain the following
// lists and call notifyListeners whenever the list has changed to ensure everyone
// is aware of current state.
- protected final List<NetworkSignalChangedCallback> mSignalsChangedCallbacks;
- protected final List<SignalCluster> mSignalClusters;
protected final NetworkControllerImpl mNetworkController;
+ protected final CallbackHandler mCallbackHandler;
+
// Save the previous HISTORY_SIZE states for logging.
private final State[] mHistory;
// Where to copy the next state into.
private int mHistoryIndex;
- public SignalController(String tag, Context context, int type,
- List<NetworkSignalChangedCallback> signalCallbacks,
- List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+ public SignalController(String tag, Context context, int type, CallbackHandler callbackHandler,
+ NetworkControllerImpl networkController) {
mTag = TAG + "." + tag;
mNetworkController = networkController;
mTransportType = type;
mContext = context;
- mSignalsChangedCallbacks = signalCallbacks;
- mSignalClusters = signalClusters;
+ mCallbackHandler = callbackHandler;
mCurrentState = cleanState();
mLastState = cleanState();
if (RECORD_HISTORY) {
@@ -81,12 +76,8 @@
return mCurrentState;
}
- public int getTransportType() {
- return mTransportType;
- }
-
- public void setInetCondition(int inetCondition) {
- mCurrentState.inetCondition = inetCondition;
+ public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
+ mCurrentState.inetCondition = validatedTransports.get(mTransportType) ? 1 : 0;
notifyListenersIfNecessary();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 053feb12..fa4d464 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -104,10 +104,7 @@
R.drawable.ic_qs_signal_carrier_network_change_animation }
};
- static final int[] QS_DATA_R = {
- R.drawable.ic_qs_signal_r,
- R.drawable.ic_qs_signal_r
- };
+ static final int QS_DATA_R = R.drawable.ic_qs_signal_r;
//***** Data connection icons
@@ -123,10 +120,7 @@
R.drawable.stat_sys_data_fully_connected_g }
};
- static final int[] QS_DATA_G = {
- R.drawable.ic_qs_signal_g,
- R.drawable.ic_qs_signal_g
- };
+ static final int QS_DATA_G = R.drawable.ic_qs_signal_g;
static final int[][] DATA_3G = {
{ R.drawable.stat_sys_data_fully_connected_3g,
@@ -139,10 +133,7 @@
R.drawable.stat_sys_data_fully_connected_3g }
};
- static final int[] QS_DATA_3G = {
- R.drawable.ic_qs_signal_3g,
- R.drawable.ic_qs_signal_3g
- };
+ static final int QS_DATA_3G = R.drawable.ic_qs_signal_3g;
static final int[][] DATA_E = {
{ R.drawable.stat_sys_data_fully_connected_e,
@@ -155,10 +146,7 @@
R.drawable.stat_sys_data_fully_connected_e }
};
- static final int[] QS_DATA_E = {
- R.drawable.ic_qs_signal_e,
- R.drawable.ic_qs_signal_e
- };
+ static final int QS_DATA_E = R.drawable.ic_qs_signal_e;
//3.5G
static final int[][] DATA_H = {
@@ -172,10 +160,7 @@
R.drawable.stat_sys_data_fully_connected_h }
};
- static final int[] QS_DATA_H = {
- R.drawable.ic_qs_signal_h,
- R.drawable.ic_qs_signal_h
- };
+ static final int QS_DATA_H = R.drawable.ic_qs_signal_h;
//CDMA
// Use 3G icons for EVDO data and 1x icons for 1XRTT data
@@ -190,10 +175,7 @@
R.drawable.stat_sys_data_fully_connected_1x }
};
- static final int[] QS_DATA_1X = {
- R.drawable.ic_qs_signal_1x,
- R.drawable.ic_qs_signal_1x
- };
+ static final int QS_DATA_1X = R.drawable.ic_qs_signal_1x;
// LTE and eHRPD
static final int[][] DATA_4G = {
@@ -207,10 +189,7 @@
R.drawable.stat_sys_data_fully_connected_4g }
};
- static final int[] QS_DATA_4G = {
- R.drawable.ic_qs_signal_4g,
- R.drawable.ic_qs_signal_4g
- };
+ static final int QS_DATA_4G = R.drawable.ic_qs_signal_4g;
// LTE branded "LTE"
static final int[][] DATA_LTE = {
@@ -224,10 +203,7 @@
R.drawable.stat_sys_data_fully_connected_lte }
};
- static final int[] QS_DATA_LTE = {
- R.drawable.ic_qs_signal_lte,
- R.drawable.ic_qs_signal_lte
- };
+ static final int QS_DATA_LTE = R.drawable.ic_qs_signal_lte;
static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
static final int ROAMING_ICON = R.drawable.stat_sys_data_fully_connected_roam;
@@ -264,7 +240,7 @@
R.string.accessibility_carrier_network_change_mode,
0,
false,
- null
+ 0
);
static final MobileIconGroup THREE_G = new MobileIconGroup(
@@ -291,7 +267,7 @@
TelephonyIcons.TELEPHONY_NO_NETWORK,
TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
- 0, 0, false, new int[2]
+ 0, 0, false, 0
);
static final MobileIconGroup E = new MobileIconGroup(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index a97ca50..9b1e72a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -29,8 +29,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
import java.util.List;
import java.util.Objects;
@@ -43,10 +42,9 @@
private final boolean mHasMobileData;
public WifiSignalController(Context context, boolean hasMobileData,
- List<NetworkSignalChangedCallback> signalCallbacks,
- List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+ CallbackHandler callbackHandler, NetworkControllerImpl networkController) {
super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
- signalCallbacks, signalClusters, networkController);
+ callbackHandler, networkController);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mHasMobileData = hasMobileData;
Handler handler = new WifiHandler();
@@ -82,19 +80,13 @@
String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
String contentDescription = getStringIfExists(getContentDescription());
- int length = mSignalsChangedCallbacks.size();
- for (int i = 0; i < length; i++) {
- mSignalsChangedCallbacks.get(i).onWifiSignalChanged(mCurrentState.enabled,
- mCurrentState.connected, getQsCurrentIconId(),
- ssidPresent && mCurrentState.activityIn,
- ssidPresent && mCurrentState.activityOut, contentDescription, wifiDesc);
- }
- int signalClustersLength = mSignalClusters.size();
- for (int i = 0; i < signalClustersLength; i++) {
- mSignalClusters.get(i).setWifiIndicators(wifiVisible, getCurrentIconId(),
- contentDescription);
- }
+ IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
+ IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
+ contentDescription);
+ mCallbackHandler.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
+ ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
+ wifiDesc);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 8dfa9b0..ec24d75 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Configuration;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
@@ -175,7 +176,14 @@
});
mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
+ }
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mZenButtons != null) {
+ mZenButtons.updateLocale();
+ }
}
private void confirmZenIntroduction() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
new file mode 100644
index 0000000..c14d06f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy;
+
+import android.os.HandlerThread;
+import android.telephony.SubscriptionInfo;
+import android.test.AndroidTestCase;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CallbackHandlerTest extends AndroidTestCase {
+
+ private CallbackHandler mHandler;
+ private HandlerThread mHandlerThread;
+
+ @Mock
+ private EmergencyListener mEmengencyListener;
+ @Mock
+ private SignalCallback mSignalCallback;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mHandlerThread = new HandlerThread("TestThread");
+ mHandlerThread.start();
+ mHandler = new CallbackHandler(mHandlerThread.getLooper());
+
+ MockitoAnnotations.initMocks(this);
+ mHandler.setListening(mEmengencyListener, true);
+ mHandler.setListening(mSignalCallback, true);
+ }
+
+ public void testEmergencyListener() {
+ mHandler.setEmergencyCallsOnly(true);
+ waitForCallbacks();
+
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mEmengencyListener).setEmergencyCallsOnly(captor.capture());
+ assertTrue(captor.getValue());
+ }
+
+ public void testSignalCallback_setWifiIndicators() {
+ boolean enabled = true;
+ IconState status = new IconState(true, 0, "");
+ IconState qs = new IconState(true, 1, "");
+ boolean in = true;
+ boolean out = true;
+ String description = "Test";
+ mHandler.setWifiIndicators(enabled, status, qs, in, out, description);
+ waitForCallbacks();
+
+ ArgumentCaptor<Boolean> enableArg = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class);
+ ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class);
+ ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
+ Mockito.verify(mSignalCallback).setWifiIndicators(enableArg.capture(),
+ statusArg.capture(), qsArg.capture(), inArg.capture(), outArg.capture(),
+ descArg.capture());
+ assertEquals(enabled, (boolean) enableArg.getValue());
+ assertEquals(status, statusArg.getValue());
+ assertEquals(qs, qsArg.getValue());
+ assertEquals(in, (boolean) inArg.getValue());
+ assertEquals(out, (boolean) outArg.getValue());
+ assertEquals(description, descArg.getValue());
+ }
+
+ public void testSignalCallback_setMobileDataIndicators() {
+ IconState status = new IconState(true, 0, "");
+ IconState qs = new IconState(true, 1, "");
+ int dark = 2;
+ boolean in = true;
+ boolean out = true;
+ String typeDescription = "Test 1";
+ String description = "Test 2";
+ int type = R.drawable.stat_sys_data_fully_connected_1x;
+ int qsType = R.drawable.ic_qs_signal_1x;
+ boolean wide = true;
+ int subId = 5;
+ mHandler.setMobileDataIndicators(status, qs, dark, type, qsType, in, out, typeDescription,
+ description, wide, subId);
+ waitForCallbacks();
+
+ ArgumentCaptor<IconState> statusArg = ArgumentCaptor.forClass(IconState.class);
+ ArgumentCaptor<IconState> qsArg = ArgumentCaptor.forClass(IconState.class);
+ ArgumentCaptor<Integer> darkStrengthArg = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<String> typeContentArg = ArgumentCaptor.forClass(String.class);
+ ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
+ ArgumentCaptor<Boolean> wideArg = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> subIdArg = ArgumentCaptor.forClass(Integer.class);
+ Mockito.verify(mSignalCallback).setMobileDataIndicators(statusArg.capture(), qsArg.capture(),
+ darkStrengthArg.capture(), typeIconArg.capture(), qsTypeIconArg.capture(),
+ inArg.capture(), outArg.capture(), typeContentArg.capture(), descArg.capture(),
+ wideArg.capture(), subIdArg.capture());
+ assertEquals(status, statusArg.getValue());
+ assertEquals(qs, qsArg.getValue());
+ assertEquals(dark, (int) darkStrengthArg.getValue());
+ assertEquals(type, (int) typeIconArg.getValue());
+ assertEquals(qsType, (int) qsTypeIconArg.getValue());
+ assertEquals(in, (boolean) inArg.getValue());
+ assertEquals(out, (boolean) outArg.getValue());
+ assertEquals(typeDescription, typeContentArg.getValue());
+ assertEquals(description, descArg.getValue());
+ assertEquals(wide, (boolean) wideArg.getValue());
+ assertEquals(subId, (int) subIdArg.getValue());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testSignalCallback_setSubs() {
+ List<SubscriptionInfo> subs = new ArrayList<>();
+ mHandler.setSubs(subs);
+ waitForCallbacks();
+
+ ArgumentCaptor<ArrayList> subsArg = ArgumentCaptor.forClass(ArrayList.class);
+ Mockito.verify(mSignalCallback).setSubs(subsArg.capture());
+ assertTrue(subs == subsArg.getValue());
+ }
+
+ public void testSignalCallback_setNoSims() {
+ boolean noSims = true;
+ mHandler.setNoSims(noSims);
+ waitForCallbacks();
+
+ ArgumentCaptor<Boolean> noSimsArg = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mSignalCallback).setNoSims(noSimsArg.capture());
+ assertEquals(noSims, (boolean) noSimsArg.getValue());
+ }
+
+ public void testSignalCallback_setEthernetIndicators() {
+ IconState state = new IconState(true, R.drawable.stat_sys_ethernet, "Test Description");
+ mHandler.setEthernetIndicators(state);
+ waitForCallbacks();
+
+ ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
+ Mockito.verify(mSignalCallback).setEthernetIndicators(iconArg.capture());
+ assertEquals(state, iconArg.getValue());
+ }
+
+ public void testSignalCallback_setIsAirplaneMode() {
+ IconState state = new IconState(true, R.drawable.stat_sys_airplane_mode, "Test Description");
+ mHandler.setIsAirplaneMode(state);
+ waitForCallbacks();
+
+ ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
+ Mockito.verify(mSignalCallback).setIsAirplaneMode(iconArg.capture());
+ assertEquals(state, iconArg.getValue());
+ }
+
+ private void waitForCallbacks() {
+ mHandlerThread.quitSafely();
+ try {
+ mHandlerThread.join();
+ } catch (InterruptedException e) {
+ }
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 29f461e..2d6bb68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -23,6 +23,7 @@
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.wifi.WifiManager;
+import android.os.Looper;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -31,12 +32,10 @@
import android.telephony.TelephonyManager;
import android.util.Log;
-import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.cdma.EriInfo;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -59,8 +58,6 @@
protected NetworkControllerImpl mNetworkController;
protected MobileSignalController mMobileSignalController;
protected PhoneStateListener mPhoneStateListener;
- protected SignalCluster mSignalCluster;
- protected NetworkSignalChangedCallback mNetworkSignalChangedCallback;
private SignalStrength mSignalStrength;
private ServiceState mServiceState;
protected ConnectivityManager mMockCm;
@@ -68,6 +65,7 @@
protected SubscriptionManager mMockSm;
protected TelephonyManager mMockTm;
protected Config mConfig;
+ protected CallbackHandler mCallbackHandler;
protected int mSubId;
@@ -91,33 +89,36 @@
mConfig = new Config();
mConfig.hspaDataDistinguishable = true;
+ mCallbackHandler = mock(CallbackHandler.class);
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
- mConfig, mock(AccessPointControllerImpl.class),
- mock(MobileDataControllerImpl.class));
+ mConfig, Looper.getMainLooper(), mCallbackHandler,
+ mock(AccessPointControllerImpl.class), mock(MobileDataControllerImpl.class));
setupNetworkController();
}
protected void setupNetworkController() {
// For now just pretend to be the data sim, so we can test that too.
- mSubId = SubscriptionManager.getDefaultDataSubId();
+ mSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
SubscriptionInfo subscription = mock(SubscriptionInfo.class);
List<SubscriptionInfo> subs = new ArrayList<SubscriptionInfo>();
when(subscription.getSubscriptionId()).thenReturn(mSubId);
subs.add(subscription);
mNetworkController.setCurrentSubscriptions(subs);
mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
+ mMobileSignalController.getState().dataSim = true;
mPhoneStateListener = mMobileSignalController.mPhoneStateListener;
- mSignalCluster = mock(SignalCluster.class);
- mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class);
- mNetworkController.addSignalCluster(mSignalCluster);
- mNetworkController.addNetworkSignalChangedCallback(mNetworkSignalChangedCallback);
+
+ // Trigger blank callbacks to always get the current state (some tests don't trigger
+ // changes from default state).
+ mNetworkController.addSignalCallback(null);
}
protected NetworkControllerImpl setUpNoMobileData() {
when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
NetworkControllerImpl networkControllerNoMobile
= new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
- mConfig, mock(AccessPointControllerImpl.class),
+ mConfig, Looper.getMainLooper(), mCallbackHandler,
+ mock(AccessPointControllerImpl.class),
mock(MobileDataControllerImpl.class));
setupNetworkController();
@@ -144,10 +145,10 @@
setLevel(DEFAULT_LEVEL);
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_UMTS);
- setConnectivity(100, ConnectivityManager.TYPE_MOBILE, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, true, true);
}
- public void setConnectivity(int inetCondition, int networkType, boolean isConnected) {
+ public void setConnectivity(int networkType, boolean inetCondition, boolean isConnected) {
Intent i = new Intent(ConnectivityManager.INET_CONDITION_ACTION);
// TODO: Separate out into several NetworkCapabilities.
if (isConnected) {
@@ -155,7 +156,7 @@
} else {
mNetCapabilities.removeTransportType(networkType);
}
- if (inetCondition != 0) {
+ if (inetCondition) {
mNetCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
} else {
mNetCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
@@ -242,34 +243,30 @@
protected void verifyHasNoSims(boolean hasNoSimsVisible) {
ArgumentCaptor<Boolean> hasNoSimsArg = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setNoSims(hasNoSimsArg.capture());
- assertEquals("No sims in status bar", hasNoSimsVisible, (boolean) hasNoSimsArg.getValue());
-
- Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce())
- .onNoSimVisibleChanged(hasNoSimsArg.capture());
- assertEquals("No sims in quick settings", hasNoSimsVisible,
- (boolean) hasNoSimsArg.getValue());
+ Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setNoSims(hasNoSimsArg.capture());
+ assertEquals("No sims", hasNoSimsVisible, (boolean) hasNoSimsArg.getValue());
}
protected void verifyLastQsMobileDataIndicators(boolean visible, int icon, int typeIcon,
boolean dataIn, boolean dataOut) {
- ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Boolean> dataInArg = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce())
- .onMobileDataSignalChanged(visibleArg.capture(), iconArg.capture(),
- ArgumentCaptor.forClass(String.class).capture(),
- typeIconArg.capture(),
- dataInArg.capture(),
- dataOutArg.capture(),
- ArgumentCaptor.forClass(String.class).capture(),
- ArgumentCaptor.forClass(String.class).capture(),
- ArgumentCaptor.forClass(Boolean.class).capture());
- assertEquals("Visibility in, quick settings", visible, (boolean) visibleArg.getValue());
- assertEquals("Signal icon in, quick settings", icon, (int) iconArg.getValue());
+ Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
+ ArgumentCaptor.forClass(IconState.class).capture(),
+ iconArg.capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(),
+ ArgumentCaptor.forClass(String.class).capture(),
+ ArgumentCaptor.forClass(String.class).capture(),
+ ArgumentCaptor.forClass(Boolean.class).capture(),
+ ArgumentCaptor.forClass(Integer.class).capture());
+ IconState iconState = iconArg.getValue();
+ assertEquals("Visibility in, quick settings", visible, iconState.visible);
+ assertEquals("Signal icon in, quick settings", icon, iconState.icon);
assertEquals("Data icon in, quick settings", typeIcon, (int) typeIconArg.getValue());
assertEquals("Data direction in, in quick settings", dataIn,
(boolean) dataInArg.getValue());
@@ -283,29 +280,32 @@
protected void verifyLastMobileDataIndicators(boolean visible, int strengthIcon,
int darkStrengthIcon, int typeIcon) {
- ArgumentCaptor<Integer> strengthIconArg = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
ArgumentCaptor<Integer> darkStrengthIconArg = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class);
// TODO: Verify all fields.
- Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setMobileDataIndicators(
- visibleArg.capture(), strengthIconArg.capture(), darkStrengthIconArg.capture(),
- typeIconArg.capture(),
+ Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
+ iconArg.capture(),
+ ArgumentCaptor.forClass(IconState.class).capture(),
+ darkStrengthIconArg.capture(), typeIconArg.capture(),
+ ArgumentCaptor.forClass(Integer.class).capture(),
+ ArgumentCaptor.forClass(Boolean.class).capture(),
+ ArgumentCaptor.forClass(Boolean.class).capture(),
ArgumentCaptor.forClass(String.class).capture(),
ArgumentCaptor.forClass(String.class).capture(),
ArgumentCaptor.forClass(Boolean.class).capture(),
ArgumentCaptor.forClass(Integer.class).capture());
+ IconState iconState = iconArg.getValue();
- assertEquals("Signal strength icon in status bar", strengthIcon,
- (int) strengthIconArg.getValue());
+ assertEquals("Signal strength icon in status bar", strengthIcon, iconState.icon);
assertEquals("Signal strength icon (dark mode) in status bar", darkStrengthIcon,
(int) darkStrengthIconArg.getValue());
assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
- assertEquals("Visibility in status bar", visible, (boolean) visibleArg.getValue());
+ assertEquals("Visibility in status bar", visible, iconState.visible);
}
protected void assertNetworkNameEquals(String expected) {
- assertEquals("Network name", expected, mNetworkController.getMobileDataNetworkName());
+ assertEquals("Network name", expected, mMobileSignalController.getState().networkName);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 3f9312d..15752e1de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -1,16 +1,17 @@
package com.android.systemui.statusbar.policy;
-import org.mockito.Mockito;
-
+import android.os.Looper;
import android.telephony.TelephonyManager;
+import org.mockito.Mockito;
+
public class NetworkControllerDataTest extends NetworkControllerBaseTest {
public void test3gDataIcon() {
setupDefaultSignal();
verifyDataIndicators(TelephonyIcons.DATA_3G[1][0 /* No direction */],
- TelephonyIcons.QS_DATA_3G[1]);
+ TelephonyIcons.QS_DATA_3G);
}
public void testRoamingDataIcon() {
@@ -22,7 +23,7 @@
TelephonyIcons.ROAMING_ICON);
verifyLastQsMobileDataIndicators(true,
TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL],
- TelephonyIcons.QS_DATA_R[1], false, false);
+ TelephonyIcons.QS_DATA_R, false, false);
}
public void test2gDataIcon() {
@@ -31,7 +32,7 @@
TelephonyManager.NETWORK_TYPE_GSM);
verifyDataIndicators(TelephonyIcons.DATA_G[1][0 /* No direction */],
- TelephonyIcons.QS_DATA_G[1]);
+ TelephonyIcons.QS_DATA_G);
}
public void testCdmaDataIcon() {
@@ -40,7 +41,7 @@
TelephonyManager.NETWORK_TYPE_CDMA);
verifyDataIndicators(TelephonyIcons.DATA_1X[1][0 /* No direction */],
- TelephonyIcons.QS_DATA_1X[1]);
+ TelephonyIcons.QS_DATA_1X);
}
public void testEdgeDataIcon() {
@@ -49,7 +50,7 @@
TelephonyManager.NETWORK_TYPE_EDGE);
verifyDataIndicators(TelephonyIcons.DATA_E[1][0 /* No direction */],
- TelephonyIcons.QS_DATA_E[1]);
+ TelephonyIcons.QS_DATA_E);
}
public void testLteDataIcon() {
@@ -58,7 +59,7 @@
TelephonyManager.NETWORK_TYPE_LTE);
verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */],
- TelephonyIcons.QS_DATA_LTE[1]);
+ TelephonyIcons.QS_DATA_LTE);
}
public void testHspaDataIcon() {
@@ -67,14 +68,15 @@
TelephonyManager.NETWORK_TYPE_HSPA);
verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */],
- TelephonyIcons.QS_DATA_H[1]);
+ TelephonyIcons.QS_DATA_H);
}
public void test4gDataIcon() {
// Switch to showing 4g icon and re-initialize the NetworkController.
mConfig.show4gForLte = true;
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
- mConfig, Mockito.mock(AccessPointControllerImpl.class),
+ mConfig, Looper.getMainLooper(), mCallbackHandler,
+ Mockito.mock(AccessPointControllerImpl.class),
Mockito.mock(MobileDataControllerImpl.class));
setupNetworkController();
@@ -83,7 +85,7 @@
TelephonyManager.NETWORK_TYPE_LTE);
verifyDataIndicators(TelephonyIcons.DATA_4G[1][0 /* No direction */],
- TelephonyIcons.QS_DATA_4G[1]);
+ TelephonyIcons.QS_DATA_4G);
}
public void test4gDataIconConfigChange() {
@@ -99,7 +101,7 @@
mNetworkController.handleConfigurationChanged();
verifyDataIndicators(TelephonyIcons.DATA_4G[1][0 /* No direction */],
- TelephonyIcons.QS_DATA_4G[1]);
+ TelephonyIcons.QS_DATA_4G);
}
public void testDataActivity() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
index 82ced9f..5d63d8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java
@@ -2,6 +2,8 @@
import android.net.NetworkCapabilities;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -24,17 +26,16 @@
}
protected void setEthernetState(boolean connected, boolean validated) {
- setConnectivity(validated ? 100 : 0, NetworkCapabilities.TRANSPORT_ETHERNET, connected);
+ setConnectivity(NetworkCapabilities.TRANSPORT_ETHERNET, validated, connected);
}
protected void verifyLastEthernetIcon(boolean visible, int icon) {
- ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
- Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setEthernetIndicators(
- visibleArg.capture(), iconArg.capture(),
- ArgumentCaptor.forClass(String.class).capture());
- assertEquals("Ethernet visible, in status bar", visible, (boolean) visibleArg.getValue());
- assertEquals("Ethernet icon, in status bar", icon, (int) iconArg.getValue());
+ Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setEthernetIndicators(
+ iconArg.capture());
+ IconState iconState = iconArg.getValue();
+ assertEquals("Ethernet visible, in status bar", visible, iconState.visible);
+ assertEquals("Ethernet icon, in status bar", icon, iconState.icon);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 389ad6f..874fdf9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -19,12 +19,13 @@
import android.content.Intent;
import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+import android.os.Looper;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
-import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.R;
@@ -41,8 +42,8 @@
Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
// Create a new NetworkController as this is currently handled in constructor.
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
- mConfig, mock(AccessPointControllerImpl.class),
- mock(MobileDataControllerImpl.class));
+ mConfig, Looper.getMainLooper(), mCallbackHandler,
+ mock(AccessPointControllerImpl.class), mock(MobileDataControllerImpl.class));
setupNetworkController();
verifyLastMobileDataIndicators(false, 0, 0);
@@ -61,8 +62,8 @@
Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
// Create a new NetworkController as this is currently handled in constructor.
mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
- mConfig, mock(AccessPointControllerImpl.class),
- mock(MobileDataControllerImpl.class));
+ mConfig, Looper.getMainLooper(), mCallbackHandler,
+ mock(AccessPointControllerImpl.class), mock(MobileDataControllerImpl.class));
setupNetworkController();
// No Subscriptions.
@@ -79,13 +80,12 @@
setLevel(testStrength);
verifyLastMobileDataIndicators(true,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength],
- DEFAULT_ICON);
+ TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength], DEFAULT_ICON);
// Verify low inet number indexing.
- setConnectivity(0, ConnectivityManager.TYPE_MOBILE, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, true);
verifyLastMobileDataIndicators(true,
- TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[0][testStrength], 0);
+ TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[0][testStrength], DEFAULT_ICON);
}
}
@@ -154,18 +154,12 @@
}
}
- public void testNoRoamingWithoutSignal() {
+ public void testNoBangWithWifi() {
setupDefaultSignal();
- setCdma();
- setCdmaRoaming(true);
- setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
- setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
+ setConnectivity(mMobileSignalController.mTransportType, false, false);
+ setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
- // This exposes the bug in b/18034542, and should be switched to the commented out
- // verification below (and pass), once the bug is fixed.
- verifyLastMobileDataIndicators(true, R.drawable.stat_sys_signal_null,
- TelephonyIcons.ROAMING_ICON);
- //verifyLastMobileDataIndicators(true, R.drawable.stat_sys_signal_null, 0 /* No Icon */);
+ verifyLastMobileDataIndicators(true, TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][2], 0);
}
// Some tests of actual NetworkController code, just internals not display stuff
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 2e0e9a3..cecf2fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -1,11 +1,13 @@
package com.android.systemui.statusbar.policy;
import android.content.Intent;
-import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@@ -25,9 +27,9 @@
for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
setWifiLevel(testLevel);
- setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
- setConnectivity(0, ConnectivityManager.TYPE_WIFI, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, false, true);
verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]);
}
}
@@ -45,10 +47,10 @@
for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
setWifiLevel(testLevel);
- setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel],
testSsid);
- setConnectivity(0, ConnectivityManager.TYPE_WIFI, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, false, true);
verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[0][testLevel],
testSsid);
}
@@ -61,7 +63,7 @@
setWifiEnabled(true);
setWifiState(true, testSsid);
setWifiLevel(testLevel);
- setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
verifyLastQsWifiIcon(true, true,
WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], testSsid);
@@ -82,13 +84,13 @@
setWifiEnabled(true);
setWifiState(true, testSsid);
setWifiLevel(testLevel);
- setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
setupDefaultSignal();
setGsmRoaming(true);
// Still be on wifi though.
- setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+ setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
verifyLastMobileDataIndicators(true,
TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][DEFAULT_LEVEL],
TelephonyIcons.ROAMING_ICON);
@@ -133,46 +135,39 @@
ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce()).onWifiSignalChanged(
- ArgumentCaptor.forClass(Boolean.class).capture(),
- ArgumentCaptor.forClass(Boolean.class).capture(),
- ArgumentCaptor.forClass(Integer.class).capture(),
- inArg.capture(), outArg.capture(),
- ArgumentCaptor.forClass(String.class).capture(),
- ArgumentCaptor.forClass(String.class).capture());
+ Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
+ Mockito.anyBoolean(), Mockito.any(IconState.class), Mockito.any(IconState.class),
+ inArg.capture(), outArg.capture(), Mockito.anyString());
assertEquals("WiFi data in, in quick settings", in, (boolean) inArg.getValue());
assertEquals("WiFi data out, in quick settings", out, (boolean) outArg.getValue());
}
protected void verifyLastQsWifiIcon(boolean enabled, boolean connected, int icon,
String description) {
+ ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
ArgumentCaptor<Boolean> enabledArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Boolean> connectedArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
- Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce()).onWifiSignalChanged(
- enabledArg.capture(), connectedArg.capture(), iconArg.capture(),
- ArgumentCaptor.forClass(Boolean.class).capture(),
- ArgumentCaptor.forClass(Boolean.class).capture(),
- ArgumentCaptor.forClass(String.class).capture(),
+ Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
+ enabledArg.capture(), Mockito.any(IconState.class),
+ iconArg.capture(), Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
descArg.capture());
+ IconState iconState = iconArg.getValue();
assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue());
- assertEquals("WiFi connected, in quick settings", connected,
- (boolean) connectedArg.getValue());
- assertEquals("WiFi signal, in quick settings", icon, (int) iconArg.getValue());
- assertEquals("WiFI desc (ssid), in quick settings", description,
- (String) descArg.getValue());
+ assertEquals("WiFi connected, in quick settings", connected, iconState.visible);
+ assertEquals("WiFi signal, in quick settings", icon, iconState.icon);
+ assertEquals("WiFI desc (ssid), in quick settings", description, descArg.getValue());
}
protected void verifyLastWifiIcon(boolean visible, int icon) {
- ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class);
- ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
- Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setWifiIndicators(
- visibleArg.capture(), iconArg.capture(),
- ArgumentCaptor.forClass(String.class).capture());
- assertEquals("WiFi visible, in status bar", visible, (boolean) visibleArg.getValue());
- assertEquals("WiFi signal, in status bar", icon, (int) iconArg.getValue());
+ Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
+ Mockito.anyBoolean(), iconArg.capture(), Mockito.any(IconState.class),
+ Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.anyString());
+ IconState iconState = iconArg.getValue();
+ assertEquals("WiFi visible, in status bar", visible, iconState.visible);
+ assertEquals("WiFi signal, in status bar", icon, iconState.icon);
}
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index c32de41..e00cf5b 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -16,8 +16,10 @@
package com.android.server;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readStringAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -37,6 +39,7 @@
import android.mtp.MtpStorage;
import android.net.Uri;
import android.os.Binder;
+import android.os.DropBoxManager;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
import android.os.FileUtils;
@@ -174,6 +177,7 @@
private static final boolean WATCHDOG_ENABLE = false;
private static final String TAG = "MountService";
+ private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
private static final String VOLD_TAG = "VoldConnector";
@@ -233,6 +237,7 @@
public static final int VOLUME_DESTROYED = 659;
public static final int MOVE_STATUS = 660;
+ public static final int BENCHMARK_RESULT = 661;
/*
* 700 series - fstrim
@@ -247,6 +252,7 @@
private static final String TAG_VOLUMES = "volumes";
private static final String ATTR_VERSION = "version";
private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
+ private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
private static final String TAG_VOLUME = "volume";
private static final String ATTR_TYPE = "type";
private static final String ATTR_FS_UUID = "fsUuid";
@@ -276,6 +282,8 @@
private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
@GuardedBy("mLock")
private String mPrimaryStorageUuid;
+ @GuardedBy("mLock")
+ private boolean mForceAdoptable;
/** Map from disk ID to latches */
@GuardedBy("mLock")
@@ -810,7 +818,8 @@
if (cooked.length != 3) break;
final String id = cooked[1];
int flags = Integer.parseInt(cooked[2]);
- if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)) {
+ if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
+ || mForceAdoptable) {
flags |= DiskInfo.FLAG_ADOPTABLE;
}
mDisks.put(id, new DiskInfo(id, flags));
@@ -927,6 +936,12 @@
break;
}
+ case VoldResponseCode.BENCHMARK_RESULT: {
+ final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
+ dropBox.addText(TAG_STORAGE_BENCHMARK, raw);
+ break;
+ }
+
case VoldResponseCode.FstrimCompleted: {
EventLogTags.writeFstrimFinish(SystemClock.elapsedRealtime());
break;
@@ -1199,6 +1214,7 @@
private void readSettingsLocked() {
mRecords.clear();
mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
+ mForceAdoptable = false;
FileInputStream fis = null;
try {
@@ -1220,6 +1236,7 @@
mPrimaryStorageUuid = readStringAttribute(in,
ATTR_PRIMARY_STORAGE_UUID);
}
+ mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
} else if (TAG_VOLUME.equals(tag)) {
final VolumeRecord rec = readVolumeRecord(in);
@@ -1249,6 +1266,7 @@
out.startTag(null, TAG_VOLUMES);
writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
+ writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
final int size = mRecords.size();
for (int i = 0; i < size; i++) {
final VolumeRecord rec = mRecords.valueAt(i);
@@ -1406,6 +1424,19 @@
}
@Override
+ public long benchmark(String volId) {
+ enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+ waitForReady();
+
+ try {
+ final NativeDaemonEvent res = mConnector.execute("volume", "benchmark", volId);
+ return Long.parseLong(res.getMessage());
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
public void partitionPublic(String diskId) {
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
waitForReady();
@@ -1520,6 +1551,21 @@
}
@Override
+ public void setDebugFlags(int flags, int mask) {
+ enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ waitForReady();
+
+ synchronized (mLock) {
+ if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
+ mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
+ }
+
+ writeSettingsLocked();
+ resetIfReadyAndConnected();
+ }
+ }
+
+ @Override
public String getPrimaryStorageUuid() {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
@@ -3014,6 +3060,7 @@
pw.println();
pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
+ pw.println("Force adoptable: " + mForceAdoptable);
}
synchronized (mObbMounts) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2158395..a8ab667 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2441,7 +2441,6 @@
}
}
- long[] cpuSpeedTimes = mProcessCpuTracker.getLastCpuSpeedTimes();
final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
synchronized(bstats) {
synchronized(mPidsSelfLocked) {
@@ -2472,7 +2471,7 @@
pr.info.uid, pr.processName);
}
ps.addCpuTimeLocked(st.rel_utime - otherUTime,
- st.rel_stime - otherSTime, cpuSpeedTimes);
+ st.rel_stime - otherSTime);
pr.curCpuTime += st.rel_utime + st.rel_stime;
} else {
BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
@@ -2481,7 +2480,7 @@
bstats.mapUid(st.uid), st.name);
}
ps.addCpuTimeLocked(st.rel_utime - otherUTime,
- st.rel_stime - otherSTime, cpuSpeedTimes);
+ st.rel_stime - otherSTime);
}
}
final int userTime = mProcessCpuTracker.getLastUserTime();
@@ -2492,7 +2491,7 @@
final int idleTime = mProcessCpuTracker.getLastIdleTime();
bstats.finishAddingCpuLocked(perc, remainUTime,
remainSTime, totalUTime, totalSTime, userTime, systemTime,
- iowaitTime, irqTime, softIrqTime, idleTime, cpuSpeedTimes);
+ iowaitTime, irqTime, softIrqTime, idleTime);
}
}
}
@@ -5299,7 +5298,7 @@
private final boolean killPackageProcessesLocked(String packageName, int appId,
int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
boolean doit, boolean evenPersistent, String reason) {
- ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
+ ArrayList<ProcessRecord> procs = new ArrayList<>();
// Remove all processes this package may have touched: all with the
// same UID (except for the system or root user), and all whose name
@@ -5446,6 +5445,13 @@
for (int i = providers.size() - 1; i >= 0; i--) {
removeDyingProviderLocked(null, providers.get(i), true);
}
+
+ // Clean-up disabled broadcast receivers.
+ for (int i = mBroadcastQueues.length - 1; i >= 0; i--) {
+ mBroadcastQueues[i].cleanupDisabledPackageReceiversLocked(
+ packageName, disabledClasses, userId, true);
+ }
+
}
private final boolean forceStopPackageLocked(String packageName, int appId,
@@ -5542,6 +5548,13 @@
// Remove transient permissions granted from/to this package/user
removeUriPermissionsForPackageLocked(packageName, userId, false);
+ if (doit) {
+ for (i = mBroadcastQueues.length - 1; i >= 0; i--) {
+ didSomething |= mBroadcastQueues[i].cleanupDisabledPackageReceiversLocked(
+ packageName, null, userId, doit);
+ }
+ }
+
if (packageName == null || uninstalling) {
// Remove pending intents. For now we only do this when force
// stopping users, because we have some problems when doing this
@@ -15089,7 +15102,7 @@
ContentProviderRecord cpr = app.pubProviders.valueAt(i);
final boolean always = app.bad || !allowRestart;
boolean inLaunching = removeDyingProviderLocked(app, cpr, always);
- if ((inLaunching || always) && !cpr.connections.isEmpty()) {
+ if ((inLaunching || always) && cpr.hasConnectionOrHandle()) {
// We left the provider in the launching list, need to
// restart it.
restart = true;
@@ -15233,7 +15246,7 @@
for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
ContentProviderRecord cpr = mLaunchingProviders.get(i);
if (cpr.launchingApp == app) {
- if (!alwaysBad && !app.bad && !cpr.connections.isEmpty()) {
+ if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
restart = true;
} else {
removeDyingProviderLocked(app, cpr, true);
@@ -16130,10 +16143,7 @@
final int uid = intentExtras != null
? intentExtras.getInt(Intent.EXTRA_UID) : -1;
if (uid >= 0) {
- BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
- synchronized (bs) {
- bs.removeUidStatsLocked(uid);
- }
+ mBatteryStatsService.removeUid(uid);
mAppOpsService.uidRemoved(uid);
}
break;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 58665d7..a61223a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -64,6 +64,7 @@
implements PowerManagerInternal.LowPowerModeListener {
static final String TAG = "BatteryStatsService";
+ private boolean mFirstExternalStatsUpdate = true;
static IBatteryStats sService;
final BatteryStatsImpl mStats;
final BatteryStatsHandler mHandler;
@@ -177,6 +178,15 @@
// These are for direct use by the activity manager...
+ /**
+ * Remove a UID from the BatteryStats and BatteryStats' external dependencies.
+ */
+ void removeUid(int uid) {
+ synchronized (mStats) {
+ mStats.removeUidStatsLocked(uid);
+ }
+ }
+
void addIsolatedUid(int isolatedUid, int appUid) {
synchronized (mStats) {
mStats.addIsolatedUidLocked(isolatedUid, appUid);
@@ -1150,11 +1160,18 @@
mStats.addHistoryEventLocked(elapsedRealtime, uptime,
BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, reason, 0);
}
+ mStats.updateCpuTimeLocked(mFirstExternalStatsUpdate);
mStats.updateKernelWakelocksLocked();
mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime());
mStats.updateWifiStateLocked(wifiEnergyInfo);
mStats.updateBluetoothStateLocked(bluetoothEnergyInfo);
}
+
+ if (mFirstExternalStatsUpdate) {
+ // We have read the stats for the first time, which means we have a baseline
+ // from which to calculate delta.
+ mFirstExternalStatsUpdate = false;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index e89ef57..745cb7e 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -21,6 +21,7 @@
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
+import java.util.Set;
import android.app.ActivityManager;
import android.app.AppGlobals;
@@ -209,7 +210,7 @@
}
public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
- for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+ for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) {
if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"***** DROPPING PARALLEL ["
@@ -222,7 +223,7 @@
}
public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
- for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
+ for (int i = mOrderedBroadcasts.size() - 1; i > 0; i--) {
if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"***** DROPPING ORDERED ["
@@ -1097,6 +1098,28 @@
mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY);
}
+ boolean cleanupDisabledPackageReceiversLocked(
+ String packageName, Set<String> filterByClasses, int userId, boolean doit) {
+ boolean didSomething = false;
+ for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) {
+ didSomething |= mParallelBroadcasts.get(i).cleanupDisabledPackageReceiversLocked(
+ packageName, filterByClasses, userId, doit);
+ if (!doit && didSomething) {
+ return true;
+ }
+ }
+
+ for (int i = mOrderedBroadcasts.size() - 1; i >= 0; i--) {
+ didSomething |= mOrderedBroadcasts.get(i).cleanupDisabledPackageReceiversLocked(
+ packageName, filterByClasses, userId, doit);
+ if (!doit && didSomething) {
+ return true;
+ }
+ }
+
+ return didSomething;
+ }
+
final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
if (r.nextReceiver > 0) {
Object curReceiver = r.receivers.get(r.nextReceiver-1);
@@ -1130,7 +1153,7 @@
if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
|| mPendingBroadcast != null) {
boolean printed = false;
- for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+ for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) {
BroadcastRecord br = mParallelBroadcasts.get(i);
if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
continue;
@@ -1148,7 +1171,7 @@
}
printed = false;
needSep = true;
- for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+ for (int i = mOrderedBroadcasts.size() - 1; i >= 0; i--) {
BroadcastRecord br = mOrderedBroadcasts.get(i);
if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
continue;
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 9a4d7a0..c050d03f 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -26,12 +26,14 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.PrintWriterPrinter;
import android.util.TimeUtils;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
+import java.util.Set;
/**
* An active intent broadcast.
@@ -164,7 +166,7 @@
final int N = receivers != null ? receivers.size() : 0;
String p2 = prefix + " ";
PrintWriterPrinter printer = new PrintWriterPrinter(pw);
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
Object o = receivers.get(i);
pw.print(prefix); pw.print("Receiver #"); pw.print(i);
pw.print(": "); pw.println(o);
@@ -205,6 +207,36 @@
state = IDLE;
}
+ boolean cleanupDisabledPackageReceiversLocked(
+ String packageName, Set<String> filterByClasses, int userId, boolean doit) {
+ if ((userId != UserHandle.USER_ALL && this.userId != userId) || receivers == null) {
+ return false;
+ }
+
+ boolean didSomething = false;
+ Object o;
+ for (int i = receivers.size() - 1; i >= 0; i--) {
+ o = receivers.get(i);
+ if (!(o instanceof ResolveInfo)) {
+ continue;
+ }
+ ActivityInfo info = ((ResolveInfo)o).activityInfo;
+
+ final boolean sameComponent = packageName == null
+ || (info.applicationInfo.packageName.equals(packageName)
+ && (filterByClasses == null || filterByClasses.contains(info.name)));
+ if (sameComponent) {
+ if (!doit) {
+ return true;
+ }
+ didSomething = true;
+ receivers.remove(i);
+ }
+ }
+
+ return didSomething;
+ }
+
public String toString() {
return "BroadcastRecord{"
+ Integer.toHexString(System.identityHashCode(this))
diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
index a37249d..dceadf4 100644
--- a/services/core/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/core/java/com/android/server/am/ContentProviderRecord.java
@@ -139,6 +139,10 @@
return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0);
}
+ public boolean hasConnectionOrHandle() {
+ return !connections.isEmpty() || hasExternalProcessHandles();
+ }
+
void dump(PrintWriter pw, String prefix, boolean full) {
if (full) {
pw.print(prefix); pw.print("package=");
diff --git a/services/core/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java
index a1dc3e3..ed8b1dd 100644
--- a/services/core/java/com/android/server/am/ProviderMap.java
+++ b/services/core/java/com/android/server/am/ProviderMap.java
@@ -210,8 +210,11 @@
boolean collectPackageProvidersLocked(String packageName, Set<String> filterByClasses,
boolean doit, boolean evenPersistent, int userId,
ArrayList<ContentProviderRecord> result) {
- boolean didSomething = collectPackageProvidersLocked(packageName, filterByClasses,
- doit, evenPersistent, mSingletonByClass, result);
+ boolean didSomething = false;
+ if (userId == UserHandle.USER_ALL || userId == UserHandle.USER_OWNER) {
+ didSomething = collectPackageProvidersLocked(packageName, filterByClasses,
+ doit, evenPersistent, mSingletonByClass, result);
+ }
if (!doit && didSomething) {
return true;
}
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
index 1fb22be..259ff1d 100644
--- a/services/core/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java
@@ -48,7 +48,7 @@
// Capabilities provided by FlpCallbacks
private boolean mHaveBatchingCapabilities;
private int mBatchingCapabilities;
- private int mVersion;
+ private int mVersion = 1;
private static FlpHardwareProvider sSingletonInstance = null;
@@ -154,7 +154,9 @@
private void setVersion(int version) {
mVersion = version;
- getGeofenceHardwareSink().setVersion(version);
+ if (mGeofenceHardwareSink != null) {
+ mGeofenceHardwareSink.setVersion(version);
+ }
}
private void maybeSendCapabilities() {
@@ -480,6 +482,7 @@
private GeofenceHardwareImpl getGeofenceHardwareSink() {
if (mGeofenceHardwareSink == null) {
mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext);
+ mGeofenceHardwareSink.setVersion(mVersion);
}
return mGeofenceHardwareSink;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index b505f7e..7024ec8 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -17,9 +17,12 @@
package com.android.server.pm;
import android.annotation.Nullable;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
+import android.os.PowerManager;
import android.os.UserHandle;
+import android.os.WorkSource;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -50,8 +53,14 @@
private final PackageManagerService mPackageManagerService;
private ArraySet<PackageParser.Package> mDeferredDexOpt;
+ private final PowerManager.WakeLock mDexoptWakeLock;
+ private volatile boolean mSystemReady;
+
PackageDexOptimizer(PackageManagerService packageManagerService) {
this.mPackageManagerService = packageManagerService;
+ PowerManager powerManager = (PowerManager)packageManagerService.mContext.getSystemService(
+ Context.POWER_SERVICE);
+ mDexoptWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*dexopt*");
}
/**
@@ -71,7 +80,18 @@
done = null;
}
synchronized (mPackageManagerService.mInstallLock) {
- return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
+ final boolean useLock = mSystemReady;
+ if (useLock) {
+ mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
+ mDexoptWakeLock.acquire();
+ }
+ try {
+ return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
+ } finally {
+ if (useLock) {
+ mDexoptWakeLock.release();
+ }
+ }
}
}
@@ -242,4 +262,8 @@
}
mDeferredDexOpt.add(pkg);
}
+
+ void systemReady() {
+ mSystemReady = true;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8e0cdf1..509289b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13486,6 +13486,7 @@
storage.registerListener(mStorageListener);
mInstallerService.systemReady();
+ mPackageDexOptimizer.systemReady();
}
@Override
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 025ede5..91639c5 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -189,16 +189,16 @@
}
struct CompileItem {
- Source source;
ResourceName name;
ConfigDescription config;
+ Source source;
std::string extension;
};
struct LinkItem {
- Source source;
ResourceName name;
ConfigDescription config;
+ Source source;
std::string originalPath;
ZipFile* apk;
std::u16string originalPackage;
@@ -236,7 +236,8 @@
return buildFileReference(item.name, item.config, getExtension<char>(item.originalPath));
}
-bool addFileReference(const std::shared_ptr<ResourceTable>& table, const CompileItem& item) {
+template <typename T>
+bool addFileReference(const std::shared_ptr<ResourceTable>& table, const T& item) {
StringPool& pool = table->getValueStringPool();
StringPool::Ref ref = pool.makeRef(util::utf8ToUtf16(buildFileReference(item)),
StringPool::Context{ 0, item.config });
@@ -334,9 +335,40 @@
return true;
}
-bool linkXml(const AaptOptions& options, const std::shared_ptr<IResolver>& resolver,
- const LinkItem& item, const void* data, size_t dataLen, ZipFile* outApk,
- std::queue<LinkItem>* outQueue) {
+/**
+ * Determines if a layout should be auto generated based on SDK level. We do not
+ * generate a layout if there is already a layout defined whose SDK version is greater than
+ * the one we want to generate.
+ */
+bool shouldGenerateVersionedResource(const std::shared_ptr<const ResourceTable>& table,
+ const ResourceName& name, const ConfigDescription& config,
+ int sdkVersionToGenerate) {
+ assert(sdkVersionToGenerate > config.sdkVersion);
+ const ResourceTableType* type;
+ const ResourceEntry* entry;
+ std::tie(type, entry) = table->findResource(name);
+ assert(type && entry);
+
+ auto iter = std::lower_bound(entry->values.begin(), entry->values.end(), config,
+ [](const ResourceConfigValue& lhs, const ConfigDescription& config) -> bool {
+ return lhs.config < config;
+ });
+
+ assert(iter != entry->values.end());
+ ++iter;
+
+ if (iter == entry->values.end()) {
+ return true;
+ }
+
+ ConfigDescription newConfig = config;
+ newConfig.sdkVersion = sdkVersionToGenerate;
+ return newConfig < iter->config;
+}
+
+bool linkXml(const AaptOptions& options, const std::shared_ptr<ResourceTable>& table,
+ const std::shared_ptr<IResolver>& resolver, const LinkItem& item,
+ const void* data, size_t dataLen, ZipFile* outApk, std::queue<LinkItem>* outQueue) {
std::shared_ptr<android::ResXMLTree> tree = std::make_shared<android::ResXMLTree>();
if (tree->setTo(data, dataLen, false) != android::NO_ERROR) {
return false;
@@ -376,9 +408,21 @@
if (minStrippedSdk.value() > 0) {
// Something was stripped, so let's generate a new file
// with the version of the smallest SDK version stripped.
- LinkItem newWork = item;
- newWork.config.sdkVersion = minStrippedSdk.value();
- outQueue->push(newWork);
+ // We can only generate a versioned layout if there doesn't exist a layout
+ // with sdk version greater than the current one but less than the one we
+ // want to generate.
+ if (shouldGenerateVersionedResource(table, item.name, item.config,
+ minStrippedSdk.value())) {
+ LinkItem newWork = item;
+ newWork.config.sdkVersion = minStrippedSdk.value();
+ outQueue->push(newWork);
+
+ if (!addFileReference(table, newWork)) {
+ Logger::error(options.output) << "failed to add auto-versioned resource '"
+ << newWork.name << "'." << std::endl;
+ return false;
+ }
+ }
}
if (outApk->add(outBuffer, buildFileReference(item).data(), ZipEntry::kCompressDeflated,
@@ -604,7 +648,7 @@
newSource.path += "/";
newSource.path += pathUtf8;
outLinkQueue->push(LinkItem{
- newSource, name, value.config, pathUtf8, apk.get(),
+ name, value.config, newSource, pathUtf8, apk.get(),
table->getPackage() });
// Now rewrite the file path.
if (mangle) {
@@ -743,8 +787,8 @@
void* uncompressedData = item.apk->uncompress(entry);
assert(uncompressedData);
- if (!linkXml(options, resolver, item, uncompressedData, entry->getUncompressedLen(),
- &outApk, &linkQueue)) {
+ if (!linkXml(options, outTable, resolver, item, uncompressedData,
+ entry->getUncompressedLen(), &outApk, &linkQueue)) {
Logger::error(options.output) << "failed to link '" << item.originalPath << "'."
<< std::endl;
return false;
@@ -862,9 +906,9 @@
}
compileQueue.push(CompileItem{
- source,
ResourceName{ table->getPackage(), *type, pathData.name },
pathData.config,
+ source,
pathData.extension
});
}
diff --git a/tools/aapt2/data/Makefile b/tools/aapt2/data/Makefile
index 6b5fafa..ce5201b 100644
--- a/tools/aapt2/data/Makefile
+++ b/tools/aapt2/data/Makefile
@@ -49,7 +49,7 @@
# returns: out/values-v4.apk: res/values-v4/styles.xml res/values-v4/colors.xml
define make-collect-rule
$(LOCAL_OUT)/$1.apk: $(filter $(LOCAL_RESOURCE_DIR)/$1/%,$(PRIVATE_RESOURCES))
- $(AAPT) compile --package $(LOCAL_PACKAGE) --binding $(LOCAL_GEN) -o $$@ $$^
+ $(AAPT) compile --package $(LOCAL_PACKAGE) -o $$@ $$^
endef
# Collect: out/values-v4.apk <- res/values-v4/styles.xml res/values-v4/colors.xml