Merge "Add the CEC message handler for the standby mode." into lmp-dev
diff --git a/Android.mk b/Android.mk
index 8309301..273f5f6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -361,6 +361,8 @@
telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl \
telephony/java/com/android/ims/internal/IImsConfig.aidl \
telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl \
+ telephony/java/com/android/ims/internal/IImsEcbm.aidl \
+ telephony/java/com/android/ims/internal/IImsEcbmListener.aidl \
telephony/java/com/android/ims/internal/IImsService.aidl \
telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl \
telephony/java/com/android/ims/internal/IImsUt.aidl \
diff --git a/api/current.txt b/api/current.txt
index 74fdd31..851d20f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -465,6 +465,7 @@
field public static final int contentInsetLeft = 16843863; // 0x1010457
field public static final int contentInsetRight = 16843864; // 0x1010458
field public static final int contentInsetStart = 16843861; // 0x1010455
+ field public static final int contentRatingSystemXml = 16843957; // 0x10104b5
field public static final int controlX1 = 16843798; // 0x1010416
field public static final int controlX2 = 16843800; // 0x1010418
field public static final int controlY1 = 16843799; // 0x1010417
@@ -4696,6 +4697,7 @@
field public android.os.Bundle extras;
field public int flags;
field public android.app.PendingIntent fullScreenIntent;
+ field public android.widget.RemoteViews headsUpContentView;
field public int icon;
field public int iconLevel;
field public android.graphics.Bitmap largeIcon;
@@ -6580,22 +6582,20 @@
method public int describeContents();
method public boolean getIncludeDeviceName();
method public boolean getIncludeTxPowerLevel();
- method public int getManufacturerId();
- method public byte[] getManufacturerSpecificData();
- method public byte[] getServiceData();
- method public android.os.ParcelUuid getServiceDataUuid();
+ method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
+ method public java.util.Map<android.os.ParcelUuid, byte[]> getServiceData();
method public java.util.List<android.os.ParcelUuid> getServiceUuids();
method public void writeToParcel(android.os.Parcel, int);
}
public static final class AdvertiseData.Builder {
ctor public AdvertiseData.Builder();
+ method public android.bluetooth.le.AdvertiseData.Builder addManufacturerData(int, byte[]);
+ method public android.bluetooth.le.AdvertiseData.Builder addServiceData(android.os.ParcelUuid, byte[]);
method public android.bluetooth.le.AdvertiseData.Builder addServiceUuid(android.os.ParcelUuid);
method public android.bluetooth.le.AdvertiseData build();
method public android.bluetooth.le.AdvertiseData.Builder setIncludeDeviceName(boolean);
method public android.bluetooth.le.AdvertiseData.Builder setIncludeTxPowerLevel(boolean);
- method public android.bluetooth.le.AdvertiseData.Builder setManufacturerData(int, byte[]);
- method public android.bluetooth.le.AdvertiseData.Builder setServiceData(android.os.ParcelUuid, byte[]);
}
public final class AdvertiseSettings implements android.os.Parcelable {
@@ -6656,6 +6656,7 @@
method public int getManufacturerId();
method public byte[] getServiceData();
method public byte[] getServiceDataMask();
+ method public android.os.ParcelUuid getServiceDataUuid();
method public android.os.ParcelUuid getServiceUuid();
method public android.os.ParcelUuid getServiceUuidMask();
method public boolean matches(android.bluetooth.le.ScanResult);
@@ -6679,10 +6680,10 @@
method public int getAdvertiseFlags();
method public byte[] getBytes();
method public java.lang.String getDeviceName();
- method public int getManufacturerId();
- method public byte[] getManufacturerSpecificData();
- method public byte[] getServiceData();
- method public android.os.ParcelUuid getServiceDataUuid();
+ method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
+ method public byte[] getManufacturerSpecificData(int);
+ method public java.util.Map<android.os.ParcelUuid, byte[]> getServiceData();
+ method public byte[] getServiceData(android.os.ParcelUuid);
method public java.util.List<android.os.ParcelUuid> getServiceUuids();
method public int getTxPowerLevel();
}
@@ -14106,6 +14107,9 @@
}
public class AudioFormat {
+ method public int getChannelMask();
+ method public int getEncoding();
+ method public int getSampleRate();
field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
@@ -16843,28 +16847,14 @@
package android.media.tv {
public final class TvContentRating {
- ctor public TvContentRating(java.lang.String);
- ctor public TvContentRating(java.lang.String, java.lang.String[]);
+ method public static android.media.tv.TvContentRating createRating(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String...);
method public java.lang.String flattenToString();
+ method public java.lang.String getCountry();
+ method public java.lang.String getDomain();
method public java.lang.String getMainRating();
+ method public java.lang.String getRatingSystem();
method public java.util.List<java.lang.String> getSubRatings();
method public static android.media.tv.TvContentRating unflattenFromString(java.lang.String);
- field public static final java.lang.String RATING_KR_12 = "RATING_KR_12";
- field public static final java.lang.String RATING_KR_15 = "RATING_KR_15";
- field public static final java.lang.String RATING_KR_19 = "RATING_KR_19";
- field public static final java.lang.String RATING_KR_7 = "RATING_KR_7";
- field public static final java.lang.String RATING_KR_ALL = "RATING_KR_ALL";
- field public static final java.lang.String RATING_US_TV_14 = "RATING_US_TV_14";
- field public static final java.lang.String RATING_US_TV_G = "RATING_US_TV_G";
- field public static final java.lang.String RATING_US_TV_MA = "RATING_US_TV_MA";
- field public static final java.lang.String RATING_US_TV_PG = "RATING_US_TV_PG";
- field public static final java.lang.String RATING_US_TV_Y = "RATING_US_TV_Y";
- field public static final java.lang.String RATING_US_TV_Y7 = "RATING_US_TV_Y7";
- field public static final java.lang.String SUBRATING_US_D = "SUBRATING_US_D";
- field public static final java.lang.String SUBRATING_US_FV = "SUBRATING_US_FV";
- field public static final java.lang.String SUBRATING_US_L = "SUBRATING_US_L";
- field public static final java.lang.String SUBRATING_US_S = "SUBRATING_US_S";
- field public static final java.lang.String SUBRATING_US_V = "SUBRATING_US_V";
}
public final class TvContract {
@@ -27503,11 +27493,12 @@
public class AlwaysOnHotwordDetector {
method public android.content.Intent getManageIntent(int);
method public int getSupportedRecognitionModes();
- method public void startRecognition(int);
- method public void stopRecognition();
+ method public boolean startRecognition(int);
+ method public boolean stopRecognition();
field public static final int MANAGE_ACTION_ENROLL = 0; // 0x0
field public static final int MANAGE_ACTION_RE_ENROLL = 1; // 0x1
field public static final int MANAGE_ACTION_UN_ENROLL = 2; // 0x2
+ field public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 2; // 0x2
field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
field public static final int RECOGNITION_FLAG_NONE = 0; // 0x0
field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
@@ -27520,12 +27511,15 @@
public static abstract interface AlwaysOnHotwordDetector.Callback {
method public abstract void onAvailabilityChanged(int);
- method public abstract void onDetected(byte[]);
- method public abstract void onDetectionStarted();
- method public abstract void onDetectionStopped();
+ method public abstract void onDetected(android.service.voice.AlwaysOnHotwordDetector.TriggerAudio);
method public abstract void onError();
}
+ public static class AlwaysOnHotwordDetector.TriggerAudio {
+ field public final android.media.AudioFormat audioFormat;
+ field public final byte[] data;
+ }
+
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.lang.String, android.service.voice.AlwaysOnHotwordDetector.Callback);
@@ -31758,7 +31752,7 @@
field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
}
- public static abstract class TtsSpan.Builder {
+ public static class TtsSpan.Builder {
ctor public TtsSpan.Builder(java.lang.String);
method public android.text.style.TtsSpan build();
method public C setIntArgument(java.lang.String, int);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 5262a5f..2a17fa6 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -25,4 +25,6 @@
// Called by the power manager.
public abstract void goingToSleep();
public abstract void wakingUp();
+ public abstract int startIsolatedProcess(String entryPoint, String[] mainArgs,
+ String processName, String abiOverride, int uid, Runnable crashHandler);
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index b3046b5..75af2df 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -196,7 +196,7 @@
final protected ArrayList<View> mSharedElements = new ArrayList<View>();
final protected ArrayList<String> mSharedElementNames = new ArrayList<String>();
final protected ArrayList<View> mTransitioningViews = new ArrayList<View>();
- final protected SharedElementListener mListener;
+ protected SharedElementListener mListener;
protected ResultReceiver mResultReceiver;
final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
final protected boolean mIsReturning;
@@ -564,6 +564,7 @@
mTransitioningViews.clear();
mResultReceiver = null;
mPendingTransition = null;
+ mListener = null;
}
protected long getFadeDuration() {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5347f03..772e132 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -454,7 +454,7 @@
* Private non-Binder interfaces
*/
/* package */ boolean testIsSystemReady();
-
+
/** Information you can retrieve about a particular application. */
public static class ContentProviderHolder implements Parcelable {
public final ProviderInfo info;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c7fdbed..c501cca 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -32,6 +32,7 @@
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -247,7 +248,6 @@
/**
- * @hide
* A medium-format version of {@link #contentView}, providing the Notification an
* opportunity to add action buttons to contentView. At its discretion, the system UI may
* choose to show this as a heads-up notification, which will pop up so the user can see
@@ -1911,7 +1911,8 @@
mPriority = PRIORITY_DEFAULT;
mPeople = new ArrayList<String>();
- mColorUtil = NotificationColorUtil.getInstance();
+ mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L ?
+ NotificationColorUtil.getInstance() : null;
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8be52a2..e28f00c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -449,9 +449,17 @@
* active (enabled) in the system.
*/
public boolean isAdminActive(ComponentName who) {
+ return isAdminActiveAsUser(who, UserHandle.myUserId());
+ }
+
+ /**
+ * @see #isAdminActive(ComponentName)
+ * @hide
+ */
+ public boolean isAdminActiveAsUser(ComponentName who, int userId) {
if (mService != null) {
try {
- return mService.isAdminActive(who, UserHandle.myUserId());
+ return mService.isAdminActive(who, userId);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -465,9 +473,17 @@
* returned.
*/
public List<ComponentName> getActiveAdmins() {
+ return getActiveAdminsAsUser(UserHandle.myUserId());
+ }
+
+ /**
+ * @see #getActiveAdmins()
+ * @hide
+ */
+ public List<ComponentName> getActiveAdminsAsUser(int userId) {
if (mService != null) {
try {
- return mService.getActiveAdmins(UserHandle.myUserId());
+ return mService.getActiveAdmins(userId);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2314,9 +2330,17 @@
* @throws IllegalArgumentException if the userId is invalid.
*/
public ComponentName getProfileOwner() throws IllegalArgumentException {
+ return getProfileOwnerAsUser(Process.myUserHandle().getIdentifier());
+ }
+
+ /**
+ * @see #getProfileOwner()
+ * @hide
+ */
+ public ComponentName getProfileOwnerAsUser(final int userId) throws IllegalArgumentException {
if (mService != null) {
try {
- return mService.getProfileOwner(Process.myUserHandle().getIdentifier());
+ return mService.getProfileOwner(userId);
} catch (RemoteException re) {
Log.w(TAG, "Failed to get profile owner");
throw new IllegalArgumentException(
@@ -2856,7 +2880,7 @@
* @see #setAccountManagementDisabled
*/
public String[] getAccountTypesWithManagementDisabled() {
- return getAccountTypesWithManagementDisabledAsUser(UserHandle.getCallingUserId());
+ return getAccountTypesWithManagementDisabledAsUser(UserHandle.myUserId());
}
/**
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 1fe43ec..59d7956 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -16,7 +16,6 @@
package android.bluetooth;
-import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.os.ParcelUuid;
import android.os.RemoteException;
@@ -130,10 +129,10 @@
/*package*/ static final int AUTHENTICATION_MITM = 2;
/**
- * Bluetooth GATT interface callbacks
+ * Bluetooth GATT callbacks. Overrides the default BluetoothGattCallback implementation.
*/
private final IBluetoothGattCallback mBluetoothGattCallback =
- new IBluetoothGattCallback.Stub() {
+ new BluetoothGattCallbackWrapper() {
/**
* Application interface registered - app is ready to go
* @hide
@@ -198,14 +197,6 @@
}
/**
- * Callback reporting an LE scan result.
- * @hide
- */
- public void onScanResult(String address, int rssi, byte[] advData) {
- // no op
- }
-
- /**
* A new GATT service has been discovered.
* The service is added to the internal list and the search
* continues.
@@ -600,23 +591,6 @@
}
/**
- * Advertise state change callback
- * @hide
- */
- public void onAdvertiseStateChange(int state, int status) {
- if (DBG) Log.d(TAG, "onAdvertiseStateChange() - state = "
- + state + " status=" + status);
- }
-
- /**
- * @hide
- */
- @Override
- public void onMultiAdvertiseCallback(int status) {
- // no op.
- }
-
- /**
* Callback invoked when the MTU for a given connection changes
* @hide
*/
@@ -647,20 +621,6 @@
Log.w(TAG, "Unhandled exception in callback", ex);
}
}
-
- @Override
- public void onBatchScanResults(List<ScanResult> results) {
- // no op
- }
-
- /**
- * @hide
- */
- @Override
- public void onFoundOrLost(boolean onFound, String address, int rssi,
- byte[] advData) {
- // no op.
- }
};
/*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
diff --git a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
new file mode 100644
index 0000000..0eb9d21
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 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 android.bluetooth;
+
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.ScanResult;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * Wrapper class for default implementation of IBluetoothGattCallback.
+ *
+ * @hide
+ */
+public class BluetoothGattCallbackWrapper extends IBluetoothGattCallback.Stub {
+
+ @Override
+ public void onClientRegistered(int status, int clientIf) throws RemoteException {
+ }
+
+ @Override
+ public void onClientConnectionState(int status, int clientIf, boolean connected, String address)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onScanResult(ScanResult scanResult) throws RemoteException {
+ }
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> batchResults) throws RemoteException {
+ }
+
+ @Override
+ public void onGetService(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onGetIncludedService(String address, int srvcType, int srvcInstId,
+ ParcelUuid srvcUuid, int inclSrvcType, int inclSrvcInstId, ParcelUuid inclSrvcUuid)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onGetCharacteristic(String address, int srvcType, int srvcInstId,
+ ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int charProps)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onGetDescriptor(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid,
+ int charInstId, ParcelUuid charUuid, int descrInstId, ParcelUuid descrUuid)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onSearchComplete(String address, int status) throws RemoteException {
+ }
+
+ @Override
+ public void onCharacteristicRead(String address, int status, int srvcType, int srvcInstId,
+ ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, byte[] value)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onCharacteristicWrite(String address, int status, int srvcType, int srvcInstId,
+ ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid) throws RemoteException {
+ }
+
+ @Override
+ public void onExecuteWrite(String address, int status) throws RemoteException {
+ }
+
+ @Override
+ public void onDescriptorRead(String address, int status, int srvcType, int srvcInstId,
+ ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int descrInstId,
+ ParcelUuid descrUuid, byte[] value) throws RemoteException {
+ }
+
+ @Override
+ public void onDescriptorWrite(String address, int status, int srvcType, int srvcInstId,
+ ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int descrInstId,
+ ParcelUuid descrUuid) throws RemoteException {
+ }
+
+ @Override
+ public void onNotify(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid,
+ int charInstId, ParcelUuid charUuid, byte[] value) throws RemoteException {
+ }
+
+ @Override
+ public void onReadRemoteRssi(String address, int rssi, int status) throws RemoteException {
+ }
+
+ @Override
+ public void onMultiAdvertiseCallback(int status, boolean isStart,
+ AdvertiseSettings advertiseSettings) throws RemoteException {
+ }
+
+ @Override
+ public void onConfigureMTU(String address, int mtu, int status) throws RemoteException {
+ }
+
+ @Override
+ public void onConnectionCongested(String address, boolean congested) throws RemoteException {
+ }
+
+ @Override
+ public void onFoundOrLost(boolean onFound, String address, int rssi, byte[] advData)
+ throws RemoteException {
+ }
+
+}
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index 18e3f54..f14cce0 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -16,6 +16,7 @@
package android.bluetooth;
import android.os.ParcelUuid;
+import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.ScanResult;
/**
@@ -26,7 +27,7 @@
void onClientRegistered(in int status, in int clientIf);
void onClientConnectionState(in int status, in int clientIf,
in boolean connected, in String address);
- void onScanResult(in String address, in int rssi, in byte[] advData);
+ void onScanResult(in ScanResult scanResult);
void onBatchScanResults(in List<ScanResult> batchResults);
void onGetService(in String address, in int srvcType, in int srvcInstId,
in ParcelUuid srvcUuid);
@@ -64,7 +65,8 @@
in int charInstId, in ParcelUuid charUuid,
in byte[] value);
void onReadRemoteRssi(in String address, in int rssi, in int status);
- void onMultiAdvertiseCallback(in int status);
+ void onMultiAdvertiseCallback(in int status, boolean isStart,
+ in AdvertiseSettings advertiseSettings);
void onConfigureMTU(in String address, in int mtu, in int status);
void onConnectionCongested(in String address, in boolean congested);
void onFoundOrLost(in boolean onFound, in String address, in int rssi,
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
index b137eeb..843cd84 100644
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ b/core/java/android/bluetooth/le/AdvertiseData.java
@@ -17,14 +17,15 @@
package android.bluetooth.le;
import android.annotation.Nullable;
-import android.bluetooth.BluetoothUuid;
import android.os.Parcel;
import android.os.ParcelUuid;
import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.SparseArray;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
/**
@@ -42,27 +43,18 @@
@Nullable
private final List<ParcelUuid> mServiceUuids;
- private final int mManufacturerId;
- @Nullable
- private final byte[] mManufacturerSpecificData;
-
- @Nullable
- private final ParcelUuid mServiceDataUuid;
- @Nullable
- private final byte[] mServiceData;
-
+ private final SparseArray<byte[]> mManufacturerSpecificData;
+ private final Map<ParcelUuid, byte[]> mServiceData;
private final boolean mIncludeTxPowerLevel;
private final boolean mIncludeDeviceName;
private AdvertiseData(List<ParcelUuid> serviceUuids,
- ParcelUuid serviceDataUuid, byte[] serviceData,
- int manufacturerId,
- byte[] manufacturerSpecificData, boolean includeTxPowerLevel,
+ SparseArray<byte[]> manufacturerData,
+ Map<ParcelUuid, byte[]> serviceData,
+ boolean includeTxPowerLevel,
boolean includeDeviceName) {
mServiceUuids = serviceUuids;
- mManufacturerId = manufacturerId;
- mManufacturerSpecificData = manufacturerSpecificData;
- mServiceDataUuid = serviceDataUuid;
+ mManufacturerSpecificData = manufacturerData;
mServiceData = serviceData;
mIncludeTxPowerLevel = includeTxPowerLevel;
mIncludeDeviceName = includeDeviceName;
@@ -77,32 +69,17 @@
}
/**
- * Returns the manufacturer identifier, which is a non-negative number assigned by Bluetooth
- * SIG.
+ * Returns an array of manufacturer Id and the corresponding manufacturer specific data. The
+ * manufacturer id is a non-negative number assigned by Bluetooth SIG.
*/
- public int getManufacturerId() {
- return mManufacturerId;
- }
-
- /**
- * Returns the manufacturer specific data which is the content of manufacturer specific data
- * field. The first 2 bytes of the data contain the company id.
- */
- public byte[] getManufacturerSpecificData() {
+ public SparseArray<byte[]> getManufacturerSpecificData() {
return mManufacturerSpecificData;
}
/**
- * Returns a 16-bit UUID of the service that the service data is associated with.
+ * Returns a map of 16-bit UUID and its corresponding service data.
*/
- public ParcelUuid getServiceDataUuid() {
- return mServiceDataUuid;
- }
-
- /**
- * Returns service data.
- */
- public byte[] getServiceData() {
+ public Map<ParcelUuid, byte[]> getServiceData() {
return mServiceData;
}
@@ -125,8 +102,8 @@
*/
@Override
public int hashCode() {
- return Objects.hash(mServiceUuids, mManufacturerId, mManufacturerSpecificData,
- mServiceDataUuid, mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
+ return Objects.hash(mServiceUuids, mManufacturerSpecificData, mServiceData,
+ mIncludeDeviceName, mIncludeTxPowerLevel);
}
/**
@@ -142,20 +119,17 @@
}
AdvertiseData other = (AdvertiseData) obj;
return Objects.equals(mServiceUuids, other.mServiceUuids) &&
- mManufacturerId == other.mManufacturerId &&
- Objects.deepEquals(mManufacturerSpecificData, other.mManufacturerSpecificData) &&
- Objects.equals(mServiceDataUuid, other.mServiceDataUuid) &&
- Objects.deepEquals(mServiceData, other.mServiceData) &&
+ Utils.equals(mManufacturerSpecificData, other.mManufacturerSpecificData) &&
+ Utils.equals(mServiceData, other.mServiceData) &&
mIncludeDeviceName == other.mIncludeDeviceName &&
mIncludeTxPowerLevel == other.mIncludeTxPowerLevel;
}
@Override
public String toString() {
- return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerId="
- + mManufacturerId + ", mManufacturerSpecificData="
- + Arrays.toString(mManufacturerSpecificData) + ", mServiceDataUuid="
- + mServiceDataUuid + ", mServiceData=" + Arrays.toString(mServiceData)
+ return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerSpecificData="
+ + Utils.toString(mManufacturerSpecificData) + ", mServiceData="
+ + Utils.toString(mServiceData)
+ ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName="
+ mIncludeDeviceName + "]";
}
@@ -169,21 +143,30 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeList(mServiceUuids);
- dest.writeInt(mManufacturerId);
- if (mManufacturerSpecificData == null) {
- dest.writeInt(0);
- } else {
- dest.writeInt(1);
- dest.writeInt(mManufacturerSpecificData.length);
- dest.writeByteArray(mManufacturerSpecificData);
+ // mManufacturerSpecificData could not be null.
+ dest.writeInt(mManufacturerSpecificData.size());
+ for (int i = 0; i < mManufacturerSpecificData.size(); ++i) {
+ dest.writeInt(mManufacturerSpecificData.keyAt(i));
+ byte[] data = mManufacturerSpecificData.valueAt(i);
+ if (data == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ dest.writeInt(data.length);
+ dest.writeByteArray(data);
+ }
}
- dest.writeParcelable(mServiceDataUuid, flags);
- if (mServiceData == null) {
- dest.writeInt(0);
- } else {
- dest.writeInt(1);
- dest.writeInt(mServiceData.length);
- dest.writeByteArray(mServiceData);
+ dest.writeInt(mServiceData.size());
+ for (ParcelUuid uuid : mServiceData.keySet()) {
+ dest.writeParcelable(uuid, flags);
+ byte[] data = mServiceData.get(uuid);
+ if (data == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ dest.writeInt(data.length);
+ dest.writeByteArray(data);
+ }
}
dest.writeByte((byte) (getIncludeTxPowerLevel() ? 1 : 0));
dest.writeByte((byte) (getIncludeDeviceName() ? 1 : 0));
@@ -209,20 +192,26 @@
builder.addServiceUuid(uuid);
}
}
- int manufacturerId = in.readInt();
- if (in.readInt() == 1) {
- int manufacturerDataLength = in.readInt();
- byte[] manufacturerData = new byte[manufacturerDataLength];
- in.readByteArray(manufacturerData);
- builder.setManufacturerData(manufacturerId, manufacturerData);
+ int manufacturerSize = in.readInt();
+ for (int i = 0; i < manufacturerSize; ++i) {
+ int manufacturerId = in.readInt();
+ if (in.readInt() == 1) {
+ int manufacturerDataLength = in.readInt();
+ byte[] manufacturerData = new byte[manufacturerDataLength];
+ in.readByteArray(manufacturerData);
+ builder.addManufacturerData(manufacturerId, manufacturerData);
+ }
}
- ParcelUuid serviceDataUuid = in.readParcelable(
- ParcelUuid.class.getClassLoader());
- if (in.readInt() == 1) {
- int serviceDataLength = in.readInt();
- byte[] serviceData = new byte[serviceDataLength];
- in.readByteArray(serviceData);
- builder.setServiceData(serviceDataUuid, serviceData);
+ int serviceDataSize = in.readInt();
+ for (int i = 0; i < serviceDataSize; ++i) {
+ ParcelUuid serviceDataUuid = in.readParcelable(
+ ParcelUuid.class.getClassLoader());
+ if (in.readInt() == 1) {
+ int serviceDataLength = in.readInt();
+ byte[] serviceData = new byte[serviceDataLength];
+ in.readByteArray(serviceData);
+ builder.addServiceData(serviceDataUuid, serviceData);
+ }
}
builder.setIncludeTxPowerLevel(in.readByte() == 1);
builder.setIncludeDeviceName(in.readByte() == 1);
@@ -236,13 +225,8 @@
public static final class Builder {
@Nullable
private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
- private int mManufacturerId = -1;
- @Nullable
- private byte[] mManufacturerSpecificData;
- @Nullable
- private ParcelUuid mServiceDataUuid;
- @Nullable
- private byte[] mServiceData;
+ private SparseArray<byte[]> mManufacturerSpecificData = new SparseArray<byte[]>();
+ private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>();
private boolean mIncludeTxPowerLevel;
private boolean mIncludeDeviceName;
@@ -268,18 +252,17 @@
* @throws IllegalArgumentException If the {@code serviceDataUuid} or {@code serviceData} is
* empty.
*/
- public Builder setServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) {
+ public Builder addServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) {
if (serviceDataUuid == null || serviceData == null) {
throw new IllegalArgumentException(
"serviceDataUuid or serviceDataUuid is null");
}
- mServiceDataUuid = serviceDataUuid;
- mServiceData = serviceData;
+ mServiceData.put(serviceDataUuid, serviceData);
return this;
}
/**
- * Set manufacturer specific data.
+ * Add manufacturer specific data.
* <p>
* Please refer to the Bluetooth Assigned Numbers document provided by the <a
* href="https://www.bluetooth.org">Bluetooth SIG</a> for a list of existing company
@@ -290,7 +273,7 @@
* @throws IllegalArgumentException If the {@code manufacturerId} is negative or
* {@code manufacturerSpecificData} is null.
*/
- public Builder setManufacturerData(int manufacturerId, byte[] manufacturerSpecificData) {
+ public Builder addManufacturerData(int manufacturerId, byte[] manufacturerSpecificData) {
if (manufacturerId < 0) {
throw new IllegalArgumentException(
"invalid manufacturerId - " + manufacturerId);
@@ -298,8 +281,7 @@
if (manufacturerSpecificData == null) {
throw new IllegalArgumentException("manufacturerSpecificData is null");
}
- mManufacturerId = manufacturerId;
- mManufacturerSpecificData = manufacturerSpecificData;
+ mManufacturerSpecificData.put(manufacturerId, manufacturerSpecificData);
return this;
}
@@ -324,9 +306,7 @@
* Build the {@link AdvertiseData}.
*/
public AdvertiseData build() {
- return new AdvertiseData(mServiceUuids,
- mServiceDataUuid,
- mServiceData, mManufacturerId, mManufacturerSpecificData,
+ return new AdvertiseData(mServiceUuids, mManufacturerSpecificData, mServiceData,
mIncludeTxPowerLevel, mIncludeDeviceName);
}
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 4d128e7..331ebfc 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -18,6 +18,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallbackWrapper;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothGattCallback;
@@ -209,13 +210,13 @@
num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
}
}
- if (data.getServiceDataUuid() != null) {
+ for (ParcelUuid uuid : data.getServiceData().keySet()) {
size += OVERHEAD_BYTES_PER_FIELD + SERVICE_DATA_UUID_LENGTH
- + byteLength(data.getServiceData());
+ + byteLength(data.getServiceData().get(uuid));
}
- if (data.getManufacturerId() > 0) {
+ for (int i = 0; i < data.getManufacturerSpecificData().size(); ++i) {
size += OVERHEAD_BYTES_PER_FIELD + MANUFACTURER_SPECIFIC_DATA_LENGTH +
- byteLength(data.getManufacturerSpecificData());
+ byteLength(data.getManufacturerSpecificData().valueAt(i));
}
if (data.getIncludeTxPowerLevel()) {
size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte.
@@ -233,7 +234,7 @@
/**
* Bluetooth GATT interface callbacks for advertising.
*/
- private static class AdvertiseCallbackWrapper extends IBluetoothGattCallback.Stub {
+ private static class AdvertiseCallbackWrapper extends BluetoothGattCallbackWrapper {
private static final int LE_CALLBACK_TIMEOUT_MILLIS = 2000;
private final AdvertiseCallback mAdvertiseCallback;
private final AdvertiseData mAdvertisement;
@@ -245,7 +246,7 @@
// -1: scan stopped
// >0: registered and scan started
private int mClientIf;
- private boolean isAdvertising = false;
+ private boolean mIsAdvertising = false;
public AdvertiseCallbackWrapper(AdvertiseCallback advertiseCallback,
AdvertiseData advertiseData, AdvertiseData scanResponse,
@@ -270,7 +271,7 @@
} catch (InterruptedException e) {
Log.e(TAG, "Callback reg wait interrupted: ", e);
}
- started = (mClientIf > 0 && isAdvertising);
+ started = (mClientIf > 0 && mIsAdvertising);
}
return started;
}
@@ -282,7 +283,7 @@
} catch (InterruptedException e) {
Log.e(TAG, "Callback reg wait interrupted: " + e);
}
- return !isAdvertising;
+ return !mIsAdvertising;
}
}
@@ -312,155 +313,35 @@
}
@Override
- public void onClientConnectionState(int status, int clientIf,
- boolean connected, String address) {
- // no op
- }
-
- @Override
- public void onScanResult(String address, int rssi, byte[] advData) {
- // no op
- }
-
- @Override
- public void onGetService(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid) {
- // no op
- }
-
- @Override
- public void onGetIncludedService(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int inclSrvcType, int inclSrvcInstId,
- ParcelUuid inclSrvcUuid) {
- // no op
- }
-
- @Override
- public void onGetCharacteristic(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- int charProps) {
- // no op
- }
-
- @Override
- public void onGetDescriptor(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- int descInstId, ParcelUuid descUuid) {
- // no op
- }
-
- @Override
- public void onSearchComplete(String address, int status) {
- // no op
- }
-
- @Override
- public void onCharacteristicRead(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid, byte[] value) {
- // no op
- }
-
- @Override
- public void onCharacteristicWrite(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid) {
- // no op
- }
-
- @Override
- public void onNotify(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- byte[] value) {
- // no op
- }
-
- @Override
- public void onDescriptorRead(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- int descInstId, ParcelUuid descrUuid, byte[] value) {
- // no op
- }
-
- @Override
- public void onDescriptorWrite(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- int descInstId, ParcelUuid descrUuid) {
- // no op
- }
-
- @Override
- public void onExecuteWrite(String address, int status) {
- // no op
- }
-
- @Override
- public void onReadRemoteRssi(String address, int rssi, int status) {
- // no op
- }
-
- @Override
- public void onMultiAdvertiseCallback(int status) {
- // TODO: This logic needs to be re-visited to account
- // for whether the scan has actually been started
- // or not. Toggling the isAdvertising does not seem
- // correct.
+ public void onMultiAdvertiseCallback(int status, boolean isStart,
+ AdvertiseSettings settings) {
synchronized (this) {
- if (status == AdvertiseCallback.ADVERTISE_SUCCESS) {
- isAdvertising = !isAdvertising;
- if (!isAdvertising) {
- try {
- mBluetoothGatt.unregisterClient(mClientIf);
- mClientIf = -1;
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception when unregistering", e);
- }
+ if (isStart) {
+ if (status == AdvertiseCallback.ADVERTISE_SUCCESS) {
+ // Start success
+ mAdvertiseCallback.onStartSuccess(settings);
+ mIsAdvertising = true;
} else {
- mAdvertiseCallback.onStartSuccess(null);
+ // Start failure.
+ mAdvertiseCallback.onStartFailure(status);
}
} else {
- if (!isAdvertising)
- mAdvertiseCallback.onStartFailure(status);
+ // unregister client for stop.
+ try {
+ mBluetoothGatt.unregisterClient(mClientIf);
+ mClientIf = -1;
+ mIsAdvertising = false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote exception when unregistering", e);
+ }
}
notifyAll();
}
}
-
- /**
- * Callback reporting LE ATT MTU.
- *
- * @hide
- */
- @Override
- public void onConfigureMTU(String address, int mtu, int status) {
- // no op
- }
-
- @Override
- public void onConnectionCongested(String address, boolean congested) {
- // no op
- }
-
- @Override
- public void onBatchScanResults(List<ScanResult> results) {
- // no op
- }
-
- @Override
- public void onFoundOrLost(boolean onFound, String address, int rssi,
- byte[] advData) {
- // no op
- }
}
- //TODO: move this api to a common util class.
+ // TODO: move this api to a common util class.
private void checkAdapterState() {
if (mBluetoothAdapter.getState() != mBluetoothAdapter.STATE_ON) {
throw new IllegalStateException("BT Adapter is not turned ON");
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index f100ddc..45e466f 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -19,6 +19,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallbackWrapper;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothGattCallback;
import android.bluetooth.IBluetoothManager;
@@ -186,7 +187,7 @@
/**
* Bluetooth GATT interface callbacks
*/
- private static class BleScanCallbackWrapper extends IBluetoothGattCallback.Stub {
+ private static class BleScanCallbackWrapper extends BluetoothGattCallbackWrapper {
private static final int REGISTRATION_CALLBACK_TIMEOUT_SECONDS = 5;
private final ScanCallback mScanCallback;
@@ -284,37 +285,26 @@
}
}
- @Override
- public void onClientConnectionState(int status, int clientIf,
- boolean connected, String address) {
- // no op
- }
-
/**
* Callback reporting an LE scan result.
*
* @hide
*/
@Override
- public void onScanResult(String address, int rssi, byte[] advData) {
+ public void onScanResult(final ScanResult scanResult) {
if (DBG)
- Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" + rssi);
+ Log.d(TAG, "onScanResult() - " + scanResult.toString());
// Check null in case the scan has been stopped
synchronized (this) {
if (mClientIf <= 0)
return;
}
- BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
- address);
- long scanNanos = SystemClock.elapsedRealtimeNanos();
- final ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(advData),
- rssi, scanNanos);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
- mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result);
+ mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
}
});
@@ -332,104 +322,6 @@
}
@Override
- public void onGetService(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid) {
- // no op
- }
-
- @Override
- public void onGetIncludedService(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int inclSrvcType, int inclSrvcInstId,
- ParcelUuid inclSrvcUuid) {
- // no op
- }
-
- @Override
- public void onGetCharacteristic(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- int charProps) {
- // no op
- }
-
- @Override
- public void onGetDescriptor(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- int descInstId, ParcelUuid descUuid) {
- // no op
- }
-
- @Override
- public void onSearchComplete(String address, int status) {
- // no op
- }
-
- @Override
- public void onCharacteristicRead(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid, byte[] value) {
- // no op
- }
-
- @Override
- public void onCharacteristicWrite(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid) {
- // no op
- }
-
- @Override
- public void onNotify(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- byte[] value) {
- // no op
- }
-
- @Override
- public void onDescriptorRead(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- int descInstId, ParcelUuid descrUuid, byte[] value) {
- // no op
- }
-
- @Override
- public void onDescriptorWrite(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- int descInstId, ParcelUuid descrUuid) {
- // no op
- }
-
- @Override
- public void onExecuteWrite(String address, int status) {
- // no op
- }
-
- @Override
- public void onReadRemoteRssi(String address, int rssi, int status) {
- // no op
- }
-
- @Override
- public void onMultiAdvertiseCallback(int status) {
- // no op
- }
-
- @Override
- public void onConfigureMTU(String address, int mtu, int status) {
- // no op
- }
-
- @Override
- public void onConnectionCongested(String address, boolean congested) {
- // no op
- }
-
- @Override
public void onFoundOrLost(boolean onFound, String address, int rssi,
byte[] advData) {
if (DBG) {
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 30aaf2e..d1b93d2 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -181,7 +181,7 @@
byte[] serviceDataMask = new byte[serviceDataMaskLength];
in.readByteArray(serviceDataMask);
builder.setServiceData(
- servcieDataUuid, serviceData, serviceDataMask);
+ servcieDataUuid, serviceData, serviceDataMask);
}
}
}
@@ -242,9 +242,6 @@
return mServiceDataMask;
}
- /**
- * @hide
- */
@Nullable
public ParcelUuid getServiceDataUuid() {
return mServiceDataUuid;
@@ -303,19 +300,17 @@
}
// Service data match
- if (mServiceData != null) {
- if (!Objects.equals(mServiceDataUuid, scanRecord.getServiceDataUuid()) ||
- !matchesPartialData(mServiceData, mServiceDataMask,
- scanRecord.getServiceData())) {
+ if (mServiceDataUuid != null) {
+ if (!matchesPartialData(mServiceData, mServiceDataMask,
+ scanRecord.getServiceData(mServiceDataUuid))) {
return false;
}
}
// Manufacturer data match.
- if (mManufacturerData != null) {
- if (mManufacturerId != scanRecord.getManufacturerId() ||
- !matchesPartialData(mManufacturerData,
- mManufacturerDataMask, scanRecord.getManufacturerSpecificData())) {
+ if (mManufacturerId >= 0) {
+ if (!matchesPartialData(mManufacturerData, mManufacturerDataMask,
+ scanRecord.getManufacturerSpecificData(mManufacturerId))) {
return false;
}
}
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index e564c7d..e7f33ff1 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -19,11 +19,14 @@
import android.annotation.Nullable;
import android.bluetooth.BluetoothUuid;
import android.os.ParcelUuid;
+import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseArray;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
/**
* Represents a scan record from Bluetooth LE scan.
@@ -53,14 +56,9 @@
@Nullable
private final List<ParcelUuid> mServiceUuids;
- private final int mManufacturerId;
- @Nullable
- private final byte[] mManufacturerSpecificData;
+ private final SparseArray<byte[]> mManufacturerSpecificData;
- @Nullable
- private final ParcelUuid mServiceDataUuid;
- @Nullable
- private final byte[] mServiceData;
+ private final Map<ParcelUuid, byte[]> mServiceData;
// Transmission power level(in dB).
private final int mTxPowerLevel;
@@ -81,43 +79,49 @@
/**
* Returns a list of service UUIDs within the advertisement that are used to identify the
- * bluetooth gatt services.
+ * bluetooth GATT services.
*/
public List<ParcelUuid> getServiceUuids() {
return mServiceUuids;
}
/**
- * Returns the manufacturer identifier, which is a non-negative number assigned by Bluetooth
- * SIG.
+ * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific
+ * data.
*/
- public int getManufacturerId() {
- return mManufacturerId;
- }
-
- /**
- * Returns the manufacturer specific data which is the content of manufacturer specific data
- * field.
- */
- public byte[] getManufacturerSpecificData() {
+ public SparseArray<byte[]> getManufacturerSpecificData() {
return mManufacturerSpecificData;
}
/**
- * Returns a 16-bit UUID of the service that the service data is associated with.
+ * Returns the manufacturer specific data associated with the manufacturer id. Returns
+ * {@code null} if the {@code manufacturerId} is not found.
*/
- public ParcelUuid getServiceDataUuid() {
- return mServiceDataUuid;
+ @Nullable
+ public byte[] getManufacturerSpecificData(int manufacturerId) {
+ return mManufacturerSpecificData.get(manufacturerId);
}
/**
- * Returns service data.
+ * Returns a map of service UUID and its corresponding service data.
*/
- public byte[] getServiceData() {
+ public Map<ParcelUuid, byte[]> getServiceData() {
return mServiceData;
}
/**
+ * Returns the service data byte array associated with the {@code serviceUuid}. Returns
+ * {@code null} if the {@code serviceDataUuid} is not found.
+ */
+ @Nullable
+ public byte[] getServiceData(ParcelUuid serviceDataUuid) {
+ if (serviceDataUuid == null) {
+ return null;
+ }
+ return mServiceData.get(serviceDataUuid);
+ }
+
+ /**
* Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE}
* if the field is not set. This value can be used to calculate the path loss of a received
* packet using the following equation:
@@ -144,14 +148,12 @@
}
private ScanRecord(List<ParcelUuid> serviceUuids,
- ParcelUuid serviceDataUuid, byte[] serviceData,
- int manufacturerId,
- byte[] manufacturerSpecificData, int advertiseFlags, int txPowerLevel,
+ SparseArray<byte[]> manufacturerData,
+ Map<ParcelUuid, byte[]> serviceData,
+ int advertiseFlags, int txPowerLevel,
String localName, byte[] bytes) {
mServiceUuids = serviceUuids;
- mManufacturerId = manufacturerId;
- mManufacturerSpecificData = manufacturerSpecificData;
- mServiceDataUuid = serviceDataUuid;
+ mManufacturerSpecificData = manufacturerData;
mServiceData = serviceData;
mDeviceName = localName;
mAdvertiseFlags = advertiseFlags;
@@ -168,7 +170,6 @@
* order.
*
* @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response.
- *
* @hide
*/
public static ScanRecord parseFromBytes(byte[] scanRecord) {
@@ -181,10 +182,9 @@
List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
String localName = null;
int txPowerLevel = Integer.MIN_VALUE;
- ParcelUuid serviceDataUuid = null;
- byte[] serviceData = null;
- int manufacturerId = -1;
- byte[] manufacturerSpecificData = null;
+
+ SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();
+ Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();
try {
while (currentPos < scanRecord.length) {
@@ -230,16 +230,20 @@
int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
serviceUuidLength);
- serviceDataUuid = BluetoothUuid.parseUuidFrom(serviceDataUuidBytes);
- serviceData = extractBytes(scanRecord, currentPos + 2, dataLength - 2);
+ ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom(
+ serviceDataUuidBytes);
+ byte[] serviceDataArray = extractBytes(scanRecord,
+ currentPos + serviceUuidLength, dataLength - serviceUuidLength);
+ serviceData.put(serviceDataUuid, serviceDataArray);
break;
case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
// The first two bytes of the manufacturer specific data are
// manufacturer ids in little endian.
- manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +
+ int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +
(scanRecord[currentPos] & 0xFF);
- manufacturerSpecificData = extractBytes(scanRecord, currentPos + 2,
+ byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2,
dataLength - 2);
+ manufacturerData.put(manufacturerId, manufacturerDataBytes);
break;
default:
// Just ignore, we don't handle such data type.
@@ -251,9 +255,8 @@
if (serviceUuids.isEmpty()) {
serviceUuids = null;
}
- return new ScanRecord(serviceUuids, serviceDataUuid, serviceData,
- manufacturerId, manufacturerSpecificData, advertiseFlag, txPowerLevel,
- localName, scanRecord);
+ return new ScanRecord(serviceUuids, manufacturerData, serviceData,
+ advertiseFlag, txPowerLevel, localName, scanRecord);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));
return null;
@@ -263,13 +266,11 @@
@Override
public String toString() {
return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids
- + ", mManufacturerId=" + mManufacturerId + ", mManufacturerSpecificData="
- + Arrays.toString(mManufacturerSpecificData) + ", mServiceDataUuid="
- + mServiceDataUuid + ", mServiceData=" + Arrays.toString(mServiceData)
+ + ", mManufacturerSpecificData=" + Utils.toString(mManufacturerSpecificData)
+ + ", mServiceData=" + Utils.toString(mServiceData)
+ ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]";
}
-
// Parse service UUIDs.
private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength,
int uuidLength, List<ParcelUuid> serviceUuids) {
diff --git a/core/java/android/bluetooth/le/Utils.java b/core/java/android/bluetooth/le/Utils.java
new file mode 100644
index 0000000..8598dd7
--- /dev/null
+++ b/core/java/android/bluetooth/le/Utils.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014 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 android.bluetooth.le;
+
+import android.util.SparseArray;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Helper class for Bluetooth LE utils.
+ *
+ * @hide
+ */
+public class Utils {
+
+ /**
+ * Returns a string composed from a {@link SparseArray}.
+ */
+ static String toString(SparseArray<byte[]> array) {
+ if (array == null) {
+ return "null";
+ }
+ if (array.size() == 0) {
+ return "{}";
+ }
+ StringBuilder buffer = new StringBuilder();
+ buffer.append('{');
+ for (int i = 0; i < array.size(); ++i) {
+ buffer.append(array.keyAt(i)).append("=").append(array.valueAt(i));
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+ /**
+ * Returns a string composed from a {@link Map}.
+ */
+ static <T> String toString(Map<T, byte[]> map) {
+ if (map == null) {
+ return "null";
+ }
+ if (map.isEmpty()) {
+ return "{}";
+ }
+ StringBuilder buffer = new StringBuilder();
+ buffer.append('{');
+ Iterator<Map.Entry<T, byte[]>> it = map.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<T, byte[]> entry = it.next();
+ Object key = entry.getKey();
+ buffer.append(key).append("=").append(Arrays.toString(map.get(key)));
+ if (it.hasNext()) {
+ buffer.append(", ");
+ }
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+ /**
+ * Check whether two {@link SparseArray} equal.
+ */
+ static boolean equals(SparseArray<byte[]> array, SparseArray<byte[]> otherArray) {
+ if (array == otherArray) {
+ return true;
+ }
+ if (array == null || otherArray == null) {
+ return false;
+ }
+ if (array.size() != otherArray.size()) {
+ return false;
+ }
+
+ // Keys are guaranteed in ascending order when indices are in ascending order.
+ for (int i = 0; i < array.size(); ++i) {
+ if (array.keyAt(i) != otherArray.keyAt(i) ||
+ !Arrays.equals(array.valueAt(i), otherArray.valueAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check whether two {@link Map} equal.
+ */
+ static <T> boolean equals(Map<T, byte[]> map, Map<T, byte[]> otherMap) {
+ if (map == otherMap) {
+ return true;
+ }
+ if (map == null || otherMap == null) {
+ return false;
+ }
+ if (map.size() != otherMap.size()) {
+ return false;
+ }
+ Set<T> keys = map.keySet();
+ if (!keys.equals(otherMap.keySet())) {
+ return false;
+ }
+ for (T key : keys) {
+ if (!Objects.deepEquals(map.get(key), otherMap.get(key))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 4498789..adee740 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -524,6 +524,11 @@
/** True if the DSP should capture the trigger sound and make it available for further
* capture. */
public final boolean captureRequested;
+ /**
+ * True if the service should restart listening after the DSP triggers.
+ * Note: This config flag is currently used at the service layer rather than by the DSP.
+ */
+ public final boolean allowMultipleTriggers;
/** List of all keyphrases in the sound model for which recognition should be performed with
* options for each keyphrase. */
public final KeyphraseRecognitionExtra keyphrases[];
@@ -531,9 +536,10 @@
* typically during enrollment. */
public final byte[] data;
- public RecognitionConfig(boolean captureRequested,
+ public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
KeyphraseRecognitionExtra keyphrases[], byte[] data) {
this.captureRequested = captureRequested;
+ this.allowMultipleTriggers = allowMultipleTriggers;
this.keyphrases = keyphrases;
this.data = data;
}
@@ -551,15 +557,17 @@
private static RecognitionConfig fromParcel(Parcel in) {
boolean captureRequested = in.readByte() == 1;
+ boolean allowMultipleTriggers = in.readByte() == 1;
KeyphraseRecognitionExtra[] keyphrases =
in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
byte[] data = in.readBlob();
- return new RecognitionConfig(captureRequested, keyphrases, data);
+ return new RecognitionConfig(captureRequested, allowMultipleTriggers, keyphrases, data);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (captureRequested ? 1 : 0));
+ dest.writeByte((byte) (allowMultipleTriggers ? 1 : 0));
dest.writeTypedArray(keyphrases, flags);
dest.writeBlob(data);
}
@@ -571,9 +579,9 @@
@Override
public String toString() {
- return "RecognitionConfig [captureRequested=" + captureRequested + ", keyphrases="
- + Arrays.toString(keyphrases)
- + ", data=" + (data == null ? 0 : data.length) + "]";
+ return "RecognitionConfig [captureRequested=" + captureRequested
+ + ", allowMultipleTriggers=" + allowMultipleTriggers + ", keyphrases="
+ + Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data) + "]";
}
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index dda6d27..6334f76 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -716,6 +716,19 @@
= "android.os.action.POWER_SAVE_MODE_CHANGED";
/**
+ * Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change.
+ * This broadcast is only sent to registered receivers.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_POWER_SAVE_MODE_CHANGING
+ = "android.os.action.POWER_SAVE_MODE_CHANGING";
+
+ /** @hide */
+ public static final String EXTRA_POWER_SAVE_MODE = "mode";
+
+ /**
* A wake lock is a mechanism to indicate that your application needs
* to have the device stay on.
* <p>
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 6278e69..279bf40 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -16,6 +16,9 @@
package android.service.voice;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Intent;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
@@ -27,6 +30,7 @@
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.media.AudioFormat;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
@@ -35,6 +39,9 @@
import com.android.internal.app.IVoiceInteractionManagerService;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A class that lets a VoiceInteractionService implementation interact with
* always-on keyphrase detection APIs.
@@ -50,14 +57,17 @@
/**
* Indicates that recognition for the given keyphrase is not available on the system
* because of the hardware configuration.
+ * No further interaction should be performed with the detector that returns this availability.
*/
public static final int STATE_HARDWARE_UNAVAILABLE = -2;
/**
* Indicates that recognition for the given keyphrase is not supported.
+ * No further interaction should be performed with the detector that returns this availability.
*/
public static final int STATE_KEYPHRASE_UNSUPPORTED = -1;
/**
* Indicates that the given keyphrase is not enrolled.
+ * The caller may choose to begin an enrollment flow for the keyphrase.
*/
public static final int STATE_KEYPHRASE_UNENROLLED = 1;
/**
@@ -79,7 +89,17 @@
/** Indicates that we need to un-enroll. */
public static final int MANAGE_ACTION_UN_ENROLL = 2;
- //-- Flags for startRecogntion ----//
+ //-- Flags for startRecognition ----//
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ value = {
+ RECOGNITION_FLAG_NONE,
+ RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO,
+ RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
+ })
+ public @interface RecognitionFlags {}
+
/** Empty flag for {@link #startRecognition(int)}. */
public static final int RECOGNITION_FLAG_NONE = 0;
/**
@@ -87,17 +107,37 @@
* whether the trigger audio for hotword needs to be captured.
*/
public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 0x1;
+ /**
+ * Recognition flag for {@link #startRecognition(int)} that indicates
+ * whether the recognition should keep going on even after the keyphrase triggers.
+ * If this flag is specified, it's possible to get multiple triggers after a
+ * call to {@link #startRecognition(int)} if the user speaks the keyphrase multiple times.
+ * When this isn't specified, the default behavior is to stop recognition once the
+ * keyphrase is spoken, till the caller starts recognition again.
+ */
+ public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 0x2;
//---- Recognition mode flags. Return codes for getSupportedRecognitionModes() ----//
// Must be kept in sync with the related attribute defined as searchKeyphraseRecognitionFlags.
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ value = {
+ RECOGNITION_MODE_VOICE_TRIGGER,
+ RECOGNITION_MODE_USER_IDENTIFICATION,
+ })
+ public @interface RecognitionModes {}
+
/**
- * Simple recognition of the key phrase. Returned by {@link #getSupportedRecognitionModes()}
+ * Simple recognition of the key phrase.
+ * Returned by {@link #getSupportedRecognitionModes()}
*/
public static final int RECOGNITION_MODE_VOICE_TRIGGER
= SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER;
/**
- * Trigger only if one user is identified. Returned by {@link #getSupportedRecognitionModes()}
+ * User identification performed with the keyphrase recognition.
+ * Returned by {@link #getSupportedRecognitionModes()}
*/
public static final int RECOGNITION_MODE_USER_IDENTIFICATION
= SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION;
@@ -109,16 +149,9 @@
private static final int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
private static final int STATUS_OK = SoundTrigger.STATUS_OK;
- private static final int MSG_STATE_CHANGED = 1;
+ private static final int MSG_AVAILABILITY_CHANGED = 1;
private static final int MSG_HOTWORD_DETECTED = 2;
- private static final int MSG_DETECTION_STARTED = 3;
- private static final int MSG_DETECTION_STOPPED = 4;
- private static final int MSG_DETECTION_ERROR = 5;
-
- private static final int FLAG_REQUESTED = 0x1;
- private static final int FLAG_STARTED = 0x2;
- private static final int FLAG_CALL_ACTIVE = 0x4;
- private static final int FLAG_MICROPHONE_OPEN = 0x8;
+ private static final int MSG_DETECTION_ERROR = 3;
private final String mText;
private final String mLocale;
@@ -136,8 +169,27 @@
private final Handler mHandler;
private int mAvailability = STATE_NOT_READY;
- private int mInternalState = 0;
- private int mRecognitionFlags = RECOGNITION_FLAG_NONE;
+
+ /**
+ * Details of the audio that triggered the keyphrase.
+ */
+ public static class TriggerAudio {
+ /**
+ * Format of {@code data}.
+ */
+ @NonNull
+ public final AudioFormat audioFormat;
+ /**
+ * Raw audio data that triggered they keyphrase.
+ */
+ @NonNull
+ public final byte[] data;
+
+ private TriggerAudio(AudioFormat _audioFormat, byte[] _data) {
+ audioFormat = _audioFormat;
+ data = _data;
+ }
+ }
/**
* Callbacks for always-on hotword detection.
@@ -150,13 +202,11 @@
*
* Availability implies whether the hardware on this system is capable of listening for
* the given keyphrase or not. <p/>
- * If the return code is one of {@link #STATE_HARDWARE_UNAVAILABLE} or
- * {@link #STATE_KEYPHRASE_UNSUPPORTED},
- * detection is not possible and no further interaction should be
- * performed with this detector. <br/>
- * If it is {@link #STATE_KEYPHRASE_UNENROLLED} the caller may choose to begin
- * an enrollment flow for the keyphrase. <br/>
- * and for {@link #STATE_KEYPHRASE_ENROLLED} a recognition can be started as desired. <p/>
+ *
+ * @see AlwaysOnHotwordDetector#STATE_HARDWARE_UNAVAILABLE
+ * @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_UNSUPPORTED
+ * @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_UNENROLLED
+ * @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_ENROLLED
*/
void onAvailabilityChanged(int status);
/**
@@ -165,22 +215,10 @@
* Clients should start a recognition again once they are done handling this
* detection.
*
- * @param data Optional trigger audio data, if it was requested during
+ * @param triggerAudio Optional trigger audio data, if it was requested during
* {@link AlwaysOnHotwordDetector#startRecognition(int)}.
*/
- void onDetected(byte[] data);
- /**
- * Called when the detection for the associated keyphrase starts.
- * This is called as a result of a successful call to
- * {@link AlwaysOnHotwordDetector#startRecognition(int)}.
- */
- void onDetectionStarted();
- /**
- * Called when the detection for the associated keyphrase stops.
- * This is called as a result of a successful call to
- * {@link AlwaysOnHotwordDetector#stopRecognition()}.
- */
- void onDetectionStopped();
+ void onDetected(@Nullable TriggerAudio triggerAudio);
/**
* Called when the detection fails due to an error.
*/
@@ -215,6 +253,9 @@
/**
* Gets the recognition modes supported by the associated keyphrase.
*
+ * @see #RECOGNITION_MODE_USER_IDENTIFICATION
+ * @see #RECOGNITION_MODE_VOICE_TRIGGER
+ *
* @throws UnsupportedOperationException if the keyphrase itself isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
@@ -222,7 +263,8 @@
* This may happen if another detector has been instantiated or the
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
- public int getSupportedRecognitionModes() {
+ public @RecognitionModes int getSupportedRecognitionModes() {
+ if (DBG) Slog.d(TAG, "getSupportedRecognitionModes()");
synchronized (mLock) {
return getSupportedRecognitionModesLocked();
}
@@ -248,8 +290,10 @@
* Starts recognition for the associated keyphrase.
*
* @param recognitionFlags The flags to control the recognition properties.
- * The allowed flags are {@link #RECOGNITION_FLAG_NONE} and
- * {@link #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO}.
+ * The allowed flags are {@link #RECOGNITION_FLAG_NONE},
+ * {@link #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO} and
+ * {@link #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS}.
+ * @return Indicates whether the call succeeded or not.
* @throws UnsupportedOperationException if the recognition isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
@@ -257,7 +301,8 @@
* This may happen if another detector has been instantiated or the
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
- public void startRecognition(int recognitionFlags) {
+ public boolean startRecognition(@RecognitionFlags int recognitionFlags) {
+ if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")");
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("startRecognition called on an invalid detector");
@@ -269,15 +314,14 @@
"Recognition for the given keyphrase is not supported");
}
- mInternalState |= FLAG_REQUESTED;
- mRecognitionFlags = recognitionFlags;
- updateRecognitionLocked();
+ return startRecognitionLocked(recognitionFlags) == STATUS_OK;
}
}
/**
* Stops recognition for the associated keyphrase.
*
+ * @return Indicates whether the call succeeded or not.
* @throws UnsupportedOperationException if the recognition isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
@@ -285,7 +329,8 @@
* This may happen if another detector has been instantiated or the
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
- public void stopRecognition() {
+ public boolean stopRecognition() {
+ if (DBG) Slog.d(TAG, "stopRecognition()");
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("stopRecognition called on an invalid detector");
@@ -297,9 +342,7 @@
"Recognition for the given keyphrase is not supported");
}
- mInternalState &= ~FLAG_REQUESTED;
- mRecognitionFlags = RECOGNITION_FLAG_NONE;
- updateRecognitionLocked();
+ return stopRecognitionLocked() == STATUS_OK;
}
}
@@ -318,6 +361,7 @@
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
public Intent getManageIntent(int action) {
+ if (DBG) Slog.d(TAG, "getManageIntent(" + action + ")");
synchronized (mLock) {
return getManageIntentLocked(action);
}
@@ -364,7 +408,7 @@
*/
void onSoundModelsChanged() {
synchronized (mLock) {
- // TODO: This should stop the recognition if it was using an enrolled sound model
+ // FIXME: This should stop the recognition if it was using an enrolled sound model
// that's no longer available.
if (mAvailability == STATE_INVALID
|| mAvailability == STATE_HARDWARE_UNAVAILABLE
@@ -378,87 +422,21 @@
}
}
- @SuppressWarnings("unused")
- private void onCallStateChanged(boolean active) {
- synchronized (mLock) {
- if (active) {
- mInternalState |= FLAG_CALL_ACTIVE;
- } else {
- mInternalState &= ~FLAG_CALL_ACTIVE;
- }
-
- updateRecognitionLocked();
- }
- }
-
- @SuppressWarnings("unused")
- private void onMicrophoneStateChanged(boolean open) {
- synchronized (mLock) {
- if (open) {
- mInternalState |= FLAG_MICROPHONE_OPEN;
- } else {
- mInternalState &= ~FLAG_MICROPHONE_OPEN;
- }
-
- updateRecognitionLocked();
- }
- }
-
- private void updateRecognitionLocked() {
- // Don't attempt to update the recognition state if keyphrase isn't enrolled.
- if (mAvailability != STATE_KEYPHRASE_ENROLLED) {
- return;
- }
-
- // Start recognition if requested and not in a call/reading from the microphone
- boolean start = (mInternalState&FLAG_REQUESTED) != 0
- && (mInternalState&FLAG_CALL_ACTIVE) == 0
- && (mInternalState&FLAG_MICROPHONE_OPEN) == 0;
- boolean requested = (mInternalState&FLAG_REQUESTED) != 0;
-
- if (start && (mInternalState&FLAG_STARTED) == 0) {
- // Start recognition.
- if (DBG) Slog.d(TAG, "starting recognition...");
- int status = startRecognitionLocked();
- if (status == STATUS_OK) {
- mHandler.sendEmptyMessage(MSG_DETECTION_STARTED);
- } else {
- if (DBG) Slog.d(TAG, "failed to start recognition: " + status);
- mHandler.sendEmptyMessage(MSG_DETECTION_ERROR);
- }
- // Post the callback
- return;
- }
-
- if (!start && (mInternalState&FLAG_STARTED) != 0) {
- // Stop recognition
- // Only notify the callback if a recognition was *not* requested.
- // For internal stoppages, don't notify the callback.
- if (DBG) Slog.d(TAG, "stopping recognition...");
- int status = stopRecognitionLocked();
- if (status == STATUS_OK) {
- if (!requested) mHandler.sendEmptyMessage(MSG_DETECTION_STOPPED);
- } else {
- if (!requested) mHandler.sendEmptyMessage(MSG_DETECTION_ERROR);
- if (DBG) Slog.d(TAG, "failed to stop recognition: " + status);
- }
- return;
- }
- }
-
- private int startRecognitionLocked() {
+ private int startRecognitionLocked(int recognitionFlags) {
KeyphraseRecognitionExtra[] recognitionExtra = new KeyphraseRecognitionExtra[1];
// TODO: Do we need to do something about the confidence level here?
recognitionExtra[0] = new KeyphraseRecognitionExtra(mKeyphraseMetadata.id,
mKeyphraseMetadata.recognitionModeFlags, new ConfidenceLevel[0]);
boolean captureTriggerAudio =
- (mRecognitionFlags&RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO) != 0;
+ (recognitionFlags&RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO) != 0;
+ boolean allowMultipleTriggers =
+ (recognitionFlags&RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS) != 0;
int code = STATUS_ERROR;
try {
code = mModelManagementService.startRecognition(mVoiceInteractionService,
mKeyphraseMetadata.id, mInternalCallback,
- new RecognitionConfig(
- captureTriggerAudio, recognitionExtra, null /* additional data */));
+ new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
+ recognitionExtra, null /* additional data */));
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in startRecognition!");
}
@@ -484,7 +462,7 @@
}
private void notifyStateChangedLocked() {
- Message message = Message.obtain(mHandler, MSG_STATE_CHANGED);
+ Message message = Message.obtain(mHandler, MSG_AVAILABILITY_CHANGED);
message.arg1 = mAvailability;
message.sendToTarget();
}
@@ -499,9 +477,22 @@
@Override
public void onDetected(KeyphraseRecognitionEvent event) {
- Slog.i(TAG, "onDetected");
+ if (DBG) {
+ Slog.d(TAG, "OnDetected(" + event + ")");
+ } else {
+ Slog.i(TAG, "onDetected");
+ }
Message message = Message.obtain(mHandler, MSG_HOTWORD_DETECTED);
- message.obj = event.data;
+ // FIXME: Check whether the event contains trigger data or not.
+ // FIXME: Read the audio format from the event.
+ if (event.data != null) {
+ AudioFormat audioFormat = new AudioFormat.Builder()
+ .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
+ .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+ .setSampleRate(16000)
+ .build();
+ message.obj = new TriggerAudio(audioFormat, event.data);
+ }
message.sendToTarget();
}
@@ -523,34 +514,13 @@
}
switch (msg.what) {
- case MSG_STATE_CHANGED:
+ case MSG_AVAILABILITY_CHANGED:
mExternalCallback.onAvailabilityChanged(msg.arg1);
break;
case MSG_HOTWORD_DETECTED:
- synchronized (mLock) {
- mInternalState &= ~FLAG_REQUESTED;
- mInternalState &= ~FLAG_STARTED;
- }
- mExternalCallback.onDetected((byte[]) msg.obj);
- break;
- case MSG_DETECTION_STARTED:
- synchronized (mLock) {
- mInternalState |= FLAG_STARTED;
- }
- mExternalCallback.onDetectionStarted();
- break;
- case MSG_DETECTION_STOPPED:
- synchronized (mLock) {
- mInternalState &= ~FLAG_REQUESTED;
- mInternalState &= ~FLAG_STARTED;
- }
- mExternalCallback.onDetectionStopped();
+ mExternalCallback.onDetected((TriggerAudio) msg.obj);
break;
case MSG_DETECTION_ERROR:
- synchronized (mLock) {
- mInternalState &= ~FLAG_REQUESTED;
- mInternalState &= ~FLAG_STARTED;
- }
mExternalCallback.onError();
break;
default:
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 82e23c4..5189404 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -182,6 +182,7 @@
/**
* Called during service de-initialization to tell you when the system is shutting the
* service down.
+ * At this point this service may no longer be the active {@link VoiceInteractionService}.
*/
public void onShutdown() {
}
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index f3a48a6..cb447fda 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -518,7 +518,7 @@
* This class uses generics so methods from this class can return instances
* of its child classes, resulting in a fluent API (CRTP pattern).
*/
- public static abstract class Builder<C extends Builder<C>> {
+ public static class Builder<C extends Builder<?>> {
// Holds the type of this class.
private final String mType;
@@ -580,7 +580,7 @@
* this builder like {@link TtsSpan.TextBuilder} and
* {@link TtsSpan.CardinalBuilder} are likely more useful.
*/
- public static class SemioticClassBuilder<C extends SemioticClassBuilder<C>>
+ public static class SemioticClassBuilder<C extends SemioticClassBuilder<?>>
extends Builder<C> {
public SemioticClassBuilder(String type) {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 2c7b3eb..2e836fb 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -16,16 +16,26 @@
package android.webkit;
+import android.app.ActivityManagerInternal;
+import android.app.Application;
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
+import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.Log;
+import com.android.server.LocalServices;
import dalvik.system.VMRuntime;
import java.io.File;
+import java.util.Arrays;
import com.android.internal.os.Zygote;
@@ -42,17 +52,15 @@
private static final String NULL_WEBVIEW_FACTORY =
"com.android.webview.nullwebview.NullWebViewFactoryProvider";
- // TODO(torne): we need to use a system property instead of hardcoding the library paths to
- // enable it to be changed when a webview update apk is installed.
- private static final String CHROMIUM_WEBVIEW_NATIVE_LIB_32 =
- "/system/lib/libwebviewchromium.so";
- private static final String CHROMIUM_WEBVIEW_NATIVE_LIB_64 =
- "/system/lib64/libwebviewchromium.so";
private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
"/data/misc/shared_relro/libwebviewchromium32.relro";
private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
"/data/misc/shared_relro/libwebviewchromium64.relro";
+ public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
+ "persist.sys.webview.vmsize";
+ private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
+
private static final String LOGTAG = "WebViewFactory";
private static final boolean DEBUG = false;
@@ -64,8 +72,8 @@
private static boolean sAddressSpaceReserved = false;
public static String getWebViewPackageName() {
- // TODO: Make this dynamic based on resource configuration.
- return "com.android.webview";
+ return AppGlobals.getInitialApplication().getString(
+ com.android.internal.R.string.config_webViewPackageName);
}
static WebViewFactoryProvider getProvider() {
@@ -99,10 +107,18 @@
}
private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
+ Application initialApplication = AppGlobals.getInitialApplication();
try {
- return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
- } catch (ClassNotFoundException e) {
- Log.e(LOGTAG, "Chromium WebView does not exist");
+ Context webViewContext = initialApplication.createPackageContext(
+ getWebViewPackageName(),
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ initialApplication.getAssets().addAssetPath(
+ webViewContext.getApplicationInfo().sourceDir);
+ ClassLoader clazzLoader = webViewContext.getClassLoader();
+ return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true,
+ clazzLoader);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOGTAG, "Chromium WebView package does not exist");
return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
}
}
@@ -114,79 +130,197 @@
public static void prepareWebViewInZygote() {
try {
System.loadLibrary("webviewchromium_loader");
- sAddressSpaceReserved = nativeReserveAddressSpace(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
- CHROMIUM_WEBVIEW_NATIVE_LIB_64);
+ long addressSpaceToReserve =
+ SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
+ CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
+ sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
+
if (sAddressSpaceReserved) {
- if (DEBUG) Log.v(LOGTAG, "address space reserved");
+ if (DEBUG) {
+ Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes");
+ }
} else {
- Log.e(LOGTAG, "reserving address space failed");
+ Log.e(LOGTAG, "reserving " + addressSpaceToReserve +
+ " bytes of address space failed");
}
- } catch (Throwable e) {
+ } catch (Throwable t) {
// Log and discard errors at this stage as we must not crash the zygote.
- Log.e(LOGTAG, "error preparing native loader", e);
+ Log.e(LOGTAG, "error preparing native loader", t);
}
}
/**
* Perform any WebView loading preparations that must happen at boot from the system server,
- * after the package manager has started.
+ * after the package manager has started or after an update to the webview is installed.
* This must be called in the system server.
* Currently, this means spawning the child processes which will create the relro files.
*/
public static void prepareWebViewInSystemServer() {
- if (DEBUG) Log.v(LOGTAG, "creating relro files");
- if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_64).exists()) {
- createRelroFile(Build.SUPPORTED_64_BIT_ABIS[0]);
+ String[] nativePaths = null;
+ try {
+ nativePaths = getWebViewNativeLibraryPaths();
+ } catch (PackageManager.NameNotFoundException e) {
}
- if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_32).exists()) {
- createRelroFile(Build.SUPPORTED_32_BIT_ABIS[0]);
+ prepareWebViewInSystemServer(nativePaths);
+ }
+
+ private static void prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
+ if (DEBUG) Log.v(LOGTAG, "creating relro files");
+
+ // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
+ // unexpected values will be handled there to ensure that we trigger notifying any process
+ // waiting on relreo creation.
+ if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
+ if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
+ createRelroFile(false /* is64Bit */, nativeLibraryPaths);
+ }
+
+ if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
+ if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
+ createRelroFile(true /* is64Bit */, nativeLibraryPaths);
}
}
- private static void createRelroFile(String abi) {
+ public static void onWebViewUpdateInstalled() {
+ String[] nativeLibs = null;
try {
- Process.start("android.webkit.WebViewFactory$RelroFileCreator",
- "WebViewLoader-" + abi,
- Process.SHARED_RELRO_UID,
- Process.SHARED_RELRO_UID,
- null,
- 0, // TODO(torne): do we need to set debug flags?
- Zygote.MOUNT_EXTERNAL_NONE,
- Build.VERSION.SDK_INT,
- null,
- abi,
- null);
- } catch (Throwable e) {
+ nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths();
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+
+ if (nativeLibs != null) {
+ long newVmSize = 0L;
+
+ for (String path : nativeLibs) {
+ 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;
+ }
+ }
+ }
+
+ if (DEBUG) {
+ Log.v(LOGTAG, "Based on library size, need " + newVmSize +
+ " bytes of address space.");
+ }
+ // The required memory can be larger than the file on disk (due to .bss), and an
+ // upgraded version of the library will likely be larger, so always attempt to reserve
+ // twice as much as we think to allow for the library to grow during this boot cycle.
+ newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
+ Log.d(LOGTAG, "Setting new address space to " + newVmSize);
+ SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
+ Long.toString(newVmSize));
+ }
+ prepareWebViewInSystemServer(nativeLibs);
+ }
+
+ private static String[] getWebViewNativeLibraryPaths()
+ throws PackageManager.NameNotFoundException {
+ final String NATIVE_LIB_FILE_NAME = "libwebviewchromium.so";
+
+ PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+ ApplicationInfo ai = pm.getApplicationInfo(getWebViewPackageName(), 0);
+
+ String path32;
+ String path64;
+ boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi);
+ if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
+ // Multi-arch case.
+ if (primaryArchIs64bit) {
+ // Primary arch: 64-bit, secondary: 32-bit.
+ path64 = ai.nativeLibraryDir;
+ path32 = ai.secondaryNativeLibraryDir;
+ } else {
+ // Primary arch: 32-bit, secondary: 64-bit.
+ path64 = ai.secondaryNativeLibraryDir;
+ path32 = ai.nativeLibraryDir;
+ }
+ } else if (primaryArchIs64bit) {
+ // Single-arch 64-bit.
+ path64 = ai.nativeLibraryDir;
+ path32 = "";
+ } else {
+ // Single-arch 32-bit.
+ path32 = ai.nativeLibraryDir;
+ path64 = "";
+ }
+ if (!TextUtils.isEmpty(path32)) path32 += "/" + NATIVE_LIB_FILE_NAME;
+ if (!TextUtils.isEmpty(path64)) path64 += "/" + NATIVE_LIB_FILE_NAME;
+ return new String[] { path32, path64 };
+ }
+
+ private static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
+ final String abi =
+ is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
+
+ // crashHandler is invoked by the ActivityManagerService when the isolated process crashes.
+ Runnable crashHandler = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
+ getUpdateService().notifyRelroCreationCompleted(is64Bit, false);
+ } catch (RemoteException e) {
+ Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
+ }
+ }
+ };
+
+ try {
+ if (nativeLibraryPaths == null
+ || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
+ throw new IllegalArgumentException(
+ "Native library paths to the WebView RelRo process must not be null!");
+ }
+ int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
+ RelroFileCreator.class.getName(), nativeLibraryPaths, "WebViewLoader-" + abi, abi,
+ Process.SHARED_RELRO_UID, crashHandler);
+ if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
+ } catch (Throwable t) {
// Log and discard errors as we must not crash the system server.
- Log.e(LOGTAG, "error starting relro file creator for abi " + abi, e);
+ Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t);
+ crashHandler.run();
}
}
private static class RelroFileCreator {
// Called in an unprivileged child process to create the relro file.
public static void main(String[] args) {
- if (!sAddressSpaceReserved) {
- Log.e(LOGTAG, "can't create relro file; address space not reserved");
- return;
- }
- boolean result = nativeCreateRelroFile(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
- CHROMIUM_WEBVIEW_NATIVE_LIB_64,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
- if (!result) {
- Log.e(LOGTAG, "failed to create relro file");
- } else if (DEBUG) {
- Log.v(LOGTAG, "created relro file");
- }
- try {
- getUpdateService().notifyRelroCreationCompleted(VMRuntime.getRuntime().is64Bit(),
- result);
- } catch (RemoteException e) {
- Log.e(LOGTAG, "error notifying update service", e);
- }
+ boolean result = false;
+ boolean is64Bit = VMRuntime.getRuntime().is64Bit();
+ try{
+ if (args.length != 2 || args[0] == null || args[1] == null) {
+ Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
+ return;
+ }
+ Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), " +
+ " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
+ if (!sAddressSpaceReserved) {
+ Log.e(LOGTAG, "can't create relro file; address space not reserved");
+ return;
+ }
+ result = nativeCreateRelroFile(args[0] /* path32 */,
+ args[1] /* path64 */,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+ if (result && DEBUG) Log.v(LOGTAG, "created relro file");
+ } finally {
+ // We must do our best to always notify the update service, even if something fails.
+ try {
+ getUpdateService().notifyRelroCreationCompleted(is64Bit, result);
+ } catch (RemoteException e) {
+ Log.e(LOGTAG, "error notifying update service", e);
+ }
- // Must explicitly exit or else this process will just sit around after we return.
- System.exit(0);
+ if (!result) Log.e(LOGTAG, "failed to create relro file");
+
+ // Must explicitly exit or else this process will just sit around after we return.
+ System.exit(0);
+ }
}
}
@@ -203,14 +337,19 @@
return;
}
- boolean result = nativeLoadWithRelroFile(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
- CHROMIUM_WEBVIEW_NATIVE_LIB_64,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
- if (!result) {
- Log.w(LOGTAG, "failed to load with relro file, proceeding without");
- } else if (DEBUG) {
- Log.v(LOGTAG, "loaded with relro file");
+ try {
+ String[] args = getWebViewNativeLibraryPaths();
+ boolean result = nativeLoadWithRelroFile(args[0] /* path32 */,
+ args[1] /* path64 */,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+ if (!result) {
+ Log.w(LOGTAG, "failed to load with relro file, proceeding without");
+ } else if (DEBUG) {
+ Log.v(LOGTAG, "loaded with relro file");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
}
}
@@ -218,7 +357,7 @@
return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
}
- private static native boolean nativeReserveAddressSpace(String lib32, String lib64);
+ private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
private static native boolean nativeCreateRelroFile(String lib32, String lib64,
String relro32, String relro64);
private static native boolean nativeLoadWithRelroFile(String lib32, String lib64,
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 52618cc..a0f7baf 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -658,6 +658,7 @@
float dx = 0, dy = 0, r = 0;
boolean elegant = false;
float letterSpacing = 0;
+ String fontFeatureSettings = null;
final Resources.Theme theme = context.getTheme();
@@ -742,6 +743,10 @@
case com.android.internal.R.styleable.TextAppearance_letterSpacing:
letterSpacing = appearance.getFloat(attr, 0);
break;
+
+ case com.android.internal.R.styleable.TextAppearance_fontFeatureSettings:
+ fontFeatureSettings = appearance.getString(attr);
+ break;
}
}
@@ -1087,6 +1092,10 @@
case com.android.internal.R.styleable.TextView_letterSpacing:
letterSpacing = a.getFloat(attr, 0);
break;
+
+ case com.android.internal.R.styleable.TextView_fontFeatureSettings:
+ fontFeatureSettings = a.getString(attr);
+ break;
}
}
a.recycle();
@@ -1269,6 +1278,7 @@
setRawTextSize(textSize);
setElegantTextHeight(elegant);
setLetterSpacing(letterSpacing);
+ setFontFeatureSettings(fontFeatureSettings);
if (allCaps) {
setTransformationMethod(new AllCapsTransformationMethod(getContext()));
@@ -2502,6 +2512,11 @@
com.android.internal.R.styleable.TextAppearance_letterSpacing, 0));
}
+ if (appearance.hasValue(com.android.internal.R.styleable.TextAppearance_fontFeatureSettings)) {
+ setFontFeatureSettings(appearance.getString(
+ com.android.internal.R.styleable.TextAppearance_fontFeatureSettings));
+ }
+
appearance.recycle();
}
@@ -2686,6 +2701,7 @@
* This will normally be 0.
*
* @see #setLetterSpacing(float)
+ * @see Paint#setLetterSpacing
* @hide
*/
public float getLetterSpacing() {
@@ -2697,7 +2713,7 @@
* for slight expansion will be around 0.05. Negative values tighten text.
*
* @see #getLetterSpacing()
- * @see Paint#setFlags
+ * @see Paint#getLetterSpacing
*
* @attr ref android.R.styleable#TextView_letterSpacing
* @hide
@@ -2715,6 +2731,41 @@
}
}
+ /**
+ * @return the currently set font feature settings. Default is null.
+ *
+ * @see #setFontFeatureSettings(String)
+ * @see Paint#setFontFeatureSettings
+ * @hide
+ */
+ public String getFontFeatureSettings() {
+ return mTextPaint.getFontFeatureSettings();
+ }
+
+ /**
+ * Sets font feature settings. The format is the same as the CSS
+ * font-feature-settings attribute:
+ * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
+ *
+ * @see #getFontFeatureSettings()
+ * @see Paint#getFontFeatureSettings
+ *
+ * @attr ref android.R.styleable#TextView_fontFeatureSettings
+ * @hide
+ */
+ @android.view.RemotableViewMethod
+ public void setFontFeatureSettings(String fontFeatureSettings) {
+ if (fontFeatureSettings != mTextPaint.getFontFeatureSettings()) {
+ mTextPaint.setFontFeatureSettings(fontFeatureSettings);
+
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+ }
+
/**
* Sets the text color for all the states (normal, selected,
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 235e4f2..f6ced09 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -430,9 +430,9 @@
static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- if (!settings)
+ if (!settings) {
paint->setFontFeatureSettings(std::string());
- else {
+ } else {
ScopedUtfChars settingsChars(env, settings);
paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d7aea39..2a96580 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -75,6 +75,7 @@
<protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
+ <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
diff --git a/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
deleted file mode 100644
index 8148ab8..0000000
--- a/core/res/res/drawable-hdpi/stat_notify_wifi_in_range.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_wifi.png b/core/res/res/drawable-hdpi/stat_sys_tether_wifi.png
deleted file mode 100644
index 7d4df50..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_tether_wifi.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-ldpi/stat_notify_wifi_in_range.png
deleted file mode 100644
index 1ff50ea..0000000
--- a/core/res/res/drawable-ldpi/stat_notify_wifi_in_range.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_tether_wifi.png b/core/res/res/drawable-ldpi/stat_sys_tether_wifi.png
deleted file mode 100644
index b4b3cfd..0000000
--- a/core/res/res/drawable-ldpi/stat_sys_tether_wifi.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png
deleted file mode 100644
index b7e2a6a..0000000
--- a/core/res/res/drawable-mdpi/stat_notify_wifi_in_range.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_tether_wifi.png b/core/res/res/drawable-mdpi/stat_sys_tether_wifi.png
deleted file mode 100644
index 869ad35..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_tether_wifi.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-xhdpi/stat_notify_wifi_in_range.png
deleted file mode 100644
index 0dbae57..0000000
--- a/core/res/res/drawable-xhdpi/stat_notify_wifi_in_range.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_tether_wifi.png b/core/res/res/drawable-xhdpi/stat_sys_tether_wifi.png
deleted file mode 100644
index dc48646..0000000
--- a/core/res/res/drawable-xhdpi/stat_sys_tether_wifi.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_wifi_in_range.png b/core/res/res/drawable-xxhdpi/stat_notify_wifi_in_range.png
deleted file mode 100644
index 47e74fb..0000000
--- a/core/res/res/drawable-xxhdpi/stat_notify_wifi_in_range.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_wifi.png b/core/res/res/drawable-xxhdpi/stat_sys_tether_wifi.png
deleted file mode 100644
index da44e6a..0000000
--- a/core/res/res/drawable-xxhdpi/stat_sys_tether_wifi.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/stat_notify_wifi_in_range.xml b/core/res/res/drawable/stat_notify_wifi_in_range.xml
new file mode 100644
index 0000000..9a5407d
--- /dev/null
+++ b/core/res/res/drawable/stat_notify_wifi_in_range.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2014 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="26.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M19.100000,14.000000l-3.400000,0.000000l0.000000,-1.500000c0.000000,-1.800000 0.800000,-2.800000 1.500000,-3.400000C18.100000,8.300000 19.200001,8.000000 20.600000,8.000000c1.200000,0.000000 2.300000,0.300000 3.100000,0.800000l1.900000,-2.300000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.500000,-8.100000L19.100000,14.000000z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19.500000,17.799999c0.000000,-0.800000 0.100000,-1.300000 0.200000,-1.600000c0.200000,-0.300000 0.500000,-0.700000 1.100000,-1.200000c0.400000,-0.400000 0.700000,-0.800000 1.000000,-1.100000s0.400000,-0.800000 0.400000,-1.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.400000,-1.200000c-0.300000,-0.300000 -0.700000,-0.400000 -1.200000,-0.400000c-0.400000,0.000000 -0.800000,0.100000 -1.100000,0.300000c-0.300000,0.200000 -0.400000,0.600000 -0.400000,1.100000l-1.900000,0.000000c0.000000,-1.000000 0.300000,-1.700000 1.000000,-2.200000c0.600000,-0.500000 1.500000,-0.800000 2.500000,-0.800000c1.100000,0.000000 2.000000,0.300000 2.600000,0.800000c0.600000,0.500000 0.900000,1.300000 0.900000,2.300000c0.000000,0.700000 -0.200000,1.300000 -0.600000,1.800000c-0.400000,0.600000 -0.900000,1.100000 -1.500000,1.600000c-0.300000,0.300000 -0.500000,0.500000 -0.600000,0.700000c-0.100000,0.200000 -0.100000,0.600000 -0.100000,1.000000L19.500000,17.700001zM21.400000,21.000000l-1.900000,0.000000l0.000000,-1.800000l1.900000,0.000000L21.400000,21.000000z"/>
+</vector>
diff --git a/core/res/res/drawable/stat_sys_tether_wifi.xml b/core/res/res/drawable/stat_sys_tether_wifi.xml
new file mode 100644
index 0000000..a816db8
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_tether_wifi.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 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="26.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+</vector>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d07d0ab..2baa599 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3784,6 +3784,8 @@
<attr name="elegantTextHeight" format="boolean" />
<!-- Text letter-spacing. -->
<attr name="letterSpacing" format="float" />
+ <!-- Font feature settings. -->
+ <attr name="fontFeatureSettings" format="string" />
</declare-styleable>
<declare-styleable name="TextClock">
<!-- Specifies the formatting pattern used to show the time and/or date
@@ -4079,6 +4081,8 @@
<attr name="elegantTextHeight" />
<!-- Text letter-spacing. -->
<attr name="letterSpacing" />
+ <!-- Font feature settings. -->
+ <attr name="fontFeatureSettings" />
</declare-styleable>
<declare-styleable name="TextViewAppearance">
<!-- Base text color, typeface, size, and style. -->
@@ -7259,7 +7263,9 @@
<!-- Component name of an activity that allows the user to modify
the settings for this service. -->
<attr name="settingsActivity" />
- <!-- Type of this service. -->
+ <!-- Component name of an xml file that describes the structure of TV content ratings that
+ this service uses. -->
+ <attr name="contentRatingSystemXml" format="reference" />
</declare-styleable>
<declare-styleable name="ResolverDrawerLayout">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 217658c..b9e5c66 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1661,4 +1661,8 @@
<!--Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet
string that's stored in 8-bit unpacked format) characters.-->
<bool translatable="false" name="config_sms_decode_gsm_8bit_data">false</bool>
+
+ <!-- Package name providing WebView implementation. -->
+ <string name="config_webViewPackageName" translatable="false">com.android.webview</string>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d8f9665..08398f0 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2560,4 +2560,6 @@
<public type="raw" name="loaderror" id="0x01100000"/>
<!-- WebView error page for when domain lookup fails. @hide @SystemApi -->
<public type="raw" name="nodomain"/>
+
+ <public type="attr" name="contentRatingSystemXml"/>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 80c74b4..8e626e3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4841,4 +4841,44 @@
<!-- Lock-to-app unlock password string -->
<string name="lock_to_app_unlock_password">password</string>
+ <string name="display_name_ustvpg" translatable="false">US-TV</string>
+ <string name="description_ustvpg">The TV Parental Guidelines</string>
+ <string name="display_name_krtv" translatable="false">KR-TV</string>
+
+ <string name="display_name_ustvpg_d" translatable="false">D</string>
+ <string name="display_name_ustvpg_l" translatable="false">L</string>
+ <string name="display_name_ustvpg_s" translatable="false">S</string>
+ <string name="display_name_ustvpg_v" translatable="false">V</string>
+ <string name="display_name_ustvpg_fv" translatable="false">FV</string>
+ <string name="display_name_ustvpg_y" translatable="false">TV-Y</string>
+ <string name="display_name_ustvpg_y7" translatable="false">TV-Y7</string>
+ <string name="display_name_ustvpg_g" translatable="false">TV-G</string>
+ <string name="display_name_ustvpg_pg" translatable="false">TV-PG</string>
+ <string name="display_name_ustvpg_14" translatable="false">TV-14</string>
+ <string name="display_name_ustvpg_ma" translatable="false">TV-MA</string>
+ <string name="display_name_krtv_all" translatable="false">모든연령시청가</string>
+ <string name="display_name_krtv_7" translatable="false">7세이상시청가</string>
+ <string name="display_name_krtv_12" translatable="false">12세이상시청가</string>
+ <string name="display_name_krtv_15" translatable="false">15세이상시청가</string>
+ <string name="display_name_krtv_19" translatable="false">19세이상시청가</string>
+
+ <string name="description_ustvpg_d">Suggestive dialogue (Usually means talks about sex)</string>
+ <string name="description_ustvpg_l">Coarse language</string>
+ <string name="description_ustvpg_s">Sexual content</string>
+ <string name="description_ustvpg_v">Violence</string>
+ <string name="description_ustvpg_fv">Fantasy violence (Children\'s programming only)</string>
+ <string name="description_ustvpg_y">This program is designed to be appropriate for all children.</string>
+ <string name="description_ustvpg_y7">This program is designed for children age 7 and above.</string>
+ <string name="description_ustvpg_g">Most parents would find this program suitable for all ages.</string>
+ <string name="description_ustvpg_pg">This program contains material that parents may find unsuitable for younger children.</string>
+ <string name="description_ustvpg_14">This program contains some material that many parents would find unsuitable for children under 14 years of age.</string>
+ <string name="description_ustvpg_ma">This program is specifically designed to be viewed by adults and therefore may be unsuitable for children under 17.</string>
+ <string name="description_krtv_all">모든 연령의 시청자가 시청하기에 부적절한 내용이 없는 등급을 말한다.</string>
+ <string name="description_krtv_7">7세미만의 어린이가 시청하기에 부적절한 내용이 포함되어 있어 보호자의 시청지도가 필요한 등급을 말한다.</string>
+ <string name="description_krtv_12">12세미만의 청소년이 시청하기에 부적절한 내용이 포함되어 있어 보호자의 시청지도가 필요한 등급을 말한다.</string>
+ <string name="description_krtv_15">15세미만의 청소년이 시청하기에 부적절한 내용이 포함되어 있어 보호자의 시청지도가 필요한 등급을 말한다.</string>
+ <string name="description_krtv_19">19세미만의 청소년이 시청하기에 부적절한 내용이 포함되어 있어 청소년이 시청할 수 없는 등급을 말한다.</string>
+
+ <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
+ <string name="battery_saver_description">To help improve battery life, battery saver will reduce your device’s performance and restrict background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6e23557..5c8926e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1259,6 +1259,7 @@
<java-symbol type="xml" name="audio_assets" />
<java-symbol type="xml" name="global_keys" />
<java-symbol type="xml" name="default_zen_mode_config" />
+ <java-symbol type="xml" name="tv_content_rating_systems" />
<java-symbol type="raw" name="accessibility_gestures" />
<java-symbol type="raw" name="incognito_mode_start_page" />
@@ -1838,6 +1839,7 @@
<java-symbol type="attr" name="actionModeWebSearchDrawable" />
<java-symbol type="string" name="websearch" />
<java-symbol type="drawable" name="ic_media_video_poster" />
+ <java-symbol type="string" name="config_webViewPackageName" />
<!-- From SubtitleView -->
<java-symbol type="dimen" name="subtitle_corner_radius" />
@@ -1892,6 +1894,7 @@
<java-symbol type="string" name="timepicker_numbers_radius_multiplier_normal" />
<java-symbol type="string" name="timepicker_transition_mid_radius_multiplier" />
<java-symbol type="string" name="timepicker_transition_end_radius_multiplier" />
+ <java-symbol type="string" name="battery_saver_description" />
<java-symbol type="string" name="item_is_selected" />
<java-symbol type="string" name="day_of_week_label_typeface" />
diff --git a/core/res/res/xml/tv_content_rating_systems.xml b/core/res/res/xml/tv_content_rating_systems.xml
new file mode 100644
index 0000000..bd9abb8
--- /dev/null
+++ b/core/res/res/xml/tv_content_rating_systems.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, 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.
+*/
+-->
+<rating-system-definitions>
+ <rating-system-definition id="US_TVPG"
+ displayName="@string/display_name_ustvpg"
+ description="@string/description_ustvpg"
+ country="US">
+ <sub-rating-definition id="US_TVPG_D"
+ displayName="@string/display_name_ustvpg_d"
+ description="@string/description_ustvpg_d" />
+ <sub-rating-definition id="US_TVPG_L"
+ displayName="@string/display_name_ustvpg_l"
+ description="@string/description_ustvpg_l" />
+ <sub-rating-definition id="US_TVPG_S"
+ displayName="@string/display_name_ustvpg_s"
+ description="@string/description_ustvpg_s" />
+ <sub-rating-definition id="US_TVPG_V"
+ displayName="@string/display_name_ustvpg_v"
+ description="@string/description_ustvpg_v" />
+ <sub-rating-definition id="US_TVPG_FV"
+ displayName="@string/display_name_ustvpg_fv"
+ description="@string/description_ustvpg_fv" />
+
+ <rating-definition id="US_TVPG_TV_Y"
+ displayName="@string/display_name_ustvpg_y"
+ description="@string/description_ustvpg_y"
+ ageHint="0" />
+ <rating-definition id="US_TVPG_TV_Y7"
+ displayName="@string/display_name_ustvpg_y7"
+ description="@string/description_ustvpg_y7"
+ ageHint="7">
+ <sub-rating id="US_TVPG_FV" />
+ </rating-definition>
+ <rating-definition id="US_TVPG_TV_G"
+ displayName="@string/display_name_ustvpg_g"
+ description="@string/description_ustvpg_g"
+ ageHint="0" />
+ <rating-definition id="US_TVPG_TV_PG"
+ displayName="@string/display_name_ustvpg_pg"
+ description="@string/description_ustvpg_pg"
+ ageHint="14">
+ <sub-rating id="US_TVPG_D" />
+ <sub-rating id="US_TVPG_L" />
+ <sub-rating id="US_TVPG_S" />
+ <sub-rating id="US_TVPG_V" />
+ </rating-definition>
+ <rating-definition id="US_TVPG_TV_14"
+ displayName="@string/display_name_ustvpg_14"
+ description="@string/description_ustvpg_14"
+ ageHint="14">
+ <sub-rating id="US_TVPG_D" />
+ <sub-rating id="US_TVPG_L" />
+ <sub-rating id="US_TVPG_S" />
+ <sub-rating id="US_TVPG_V" />
+ </rating-definition>
+ <rating-definition id="US_TVPG_TV_MA"
+ displayName="@string/display_name_ustvpg_ma"
+ description="@string/description_ustvpg_ma"
+ ageHint="17">
+ <sub-rating id="US_TVPG_L" />
+ <sub-rating id="US_TVPG_S" />
+ <sub-rating id="US_TVPG_V" />
+ </rating-definition>
+ <order>
+ <rating id="US_TVPG_TV_Y" />
+ <rating id="US_TVPG_TV_Y7" />
+ </order>
+ <order>
+ <rating id="US_TVPG_TV_G" />
+ <rating id="US_TVPG_TV_PG" />
+ <rating id="US_TVPG_TV_14" />
+ <rating id="US_TVPG_TV_MA" />
+ </order>
+ </rating-system-definition>
+
+ <rating-system-definition id="KR_TV"
+ displayName="@string/display_name_krtv"
+ country="KR">
+ <rating-definition id="KR_TV_ALL"
+ displayName="@string/display_name_krtv_all"
+ description="@string/description_krtv_all"
+ ageHint="0" />
+ <rating-definition id="KR_TV_7"
+ displayName="@string/display_name_krtv_7"
+ description="@string/description_krtv_7"
+ ageHint="7">
+ </rating-definition>
+ <rating-definition id="KR_TV_12"
+ displayName="@string/display_name_krtv_12"
+ description="@string/description_krtv_12"
+ ageHint="12">
+ </rating-definition>
+ <rating-definition id="KR_TV_15"
+ displayName="@string/display_name_krtv_15"
+ description="@string/description_krtv_15"
+ ageHint="15">
+ </rating-definition>
+ <rating-definition id="KR_TV_19"
+ displayName="@string/display_name_krtv_19"
+ description="@string/description_krtv_19"
+ ageHint="19">
+ </rating-definition>
+ <order>
+ <rating id="KR_TV_ALL" />
+ <rating id="KR_TV_7" />
+ <rating id="KR_TV_12" />
+ <rating id="KR_TV_15" />
+ <rating id="KR_TV_19" />
+ </order>
+ </rating-system-definition>
+</rating-system-definitions>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
index 5e451ca..e58d905 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
@@ -66,7 +66,7 @@
byte[] manufacturerData = new byte[0];
AdvertiseData data =
mAdvertiseDataBuilder.setIncludeDeviceName(true)
- .setManufacturerData(manufacturerId, manufacturerData).build();
+ .addManufacturerData(manufacturerId, manufacturerData).build();
data.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
AdvertiseData dataFromParcel =
@@ -81,7 +81,7 @@
byte[] serviceData = new byte[0];
AdvertiseData data =
mAdvertiseDataBuilder.setIncludeDeviceName(true)
- .setServiceData(uuid, serviceData).build();
+ .addServiceData(uuid, serviceData).build();
data.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
AdvertiseData dataFromParcel =
@@ -117,7 +117,7 @@
AdvertiseData data =
mAdvertiseDataBuilder.setIncludeDeviceName(true)
.addServiceUuid(uuid).addServiceUuid(uuid2)
- .setManufacturerData(manufacturerId, manufacturerData).build();
+ .addManufacturerData(manufacturerId, manufacturerData).build();
data.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
@@ -134,7 +134,7 @@
(byte) 0xF0, 0x00, 0x02, 0x15 };
AdvertiseData data =
mAdvertiseDataBuilder.setIncludeDeviceName(true)
- .setServiceData(uuid, serviceData).build();
+ .addServiceData(uuid, serviceData).build();
data.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
AdvertiseData dataFromParcel =
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
index ccdd90a..8b3db7e 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
@@ -53,13 +53,13 @@
assertEquals("Ped", data.getDeviceName());
assertEquals(-20, data.getTxPowerLevel());
- assertEquals(0x00e0, data.getManufacturerId());
+ assertTrue(data.getManufacturerSpecificData().get(0x00E0) != null);
assertArrayEquals(new byte[] {
- 0x02, 0x15 }, data.getManufacturerSpecificData());
+ 0x02, 0x15 }, data.getManufacturerSpecificData().get(0x00E0));
- assertEquals(uuid2, data.getServiceDataUuid());
+ assertTrue(data.getServiceData().containsKey(uuid2));
assertArrayEquals(new byte[] {
- 0x50, 0x64 }, data.getServiceData());
+ 0x50, 0x64 }, data.getServiceData().get(uuid2));
}
// Assert two byte arrays are equal.
diff --git a/data/fonts/Roboto-Black.ttf b/data/fonts/Roboto-Black.ttf
index 1eb7cf2..79b5f74 100644
--- a/data/fonts/Roboto-Black.ttf
+++ b/data/fonts/Roboto-Black.ttf
Binary files differ
diff --git a/data/fonts/Roboto-BlackItalic.ttf b/data/fonts/Roboto-BlackItalic.ttf
index 8f9da76..4c58b7b 100644
--- a/data/fonts/Roboto-BlackItalic.ttf
+++ b/data/fonts/Roboto-BlackItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf
index d3a6ed9..58397cc 100644
--- a/data/fonts/Roboto-Bold.ttf
+++ b/data/fonts/Roboto-Bold.ttf
Binary files differ
diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf
index 49bd012..606252c 100644
--- a/data/fonts/Roboto-BoldItalic.ttf
+++ b/data/fonts/Roboto-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf
index da58461..cc3fd40 100644
--- a/data/fonts/Roboto-Italic.ttf
+++ b/data/fonts/Roboto-Italic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Light.ttf b/data/fonts/Roboto-Light.ttf
index 9ca4e92..e65c2d2 100644
--- a/data/fonts/Roboto-Light.ttf
+++ b/data/fonts/Roboto-Light.ttf
Binary files differ
diff --git a/data/fonts/Roboto-LightItalic.ttf b/data/fonts/Roboto-LightItalic.ttf
index 710c14c..d5476e7 100644
--- a/data/fonts/Roboto-LightItalic.ttf
+++ b/data/fonts/Roboto-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Medium.ttf b/data/fonts/Roboto-Medium.ttf
index aaa3723..9263090 100644
--- a/data/fonts/Roboto-Medium.ttf
+++ b/data/fonts/Roboto-Medium.ttf
Binary files differ
diff --git a/data/fonts/Roboto-MediumItalic.ttf b/data/fonts/Roboto-MediumItalic.ttf
index 8c2b101..329aab9 100644
--- a/data/fonts/Roboto-MediumItalic.ttf
+++ b/data/fonts/Roboto-MediumItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf
index e5b0c83..c515eca 100644
--- a/data/fonts/Roboto-Regular.ttf
+++ b/data/fonts/Roboto-Regular.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Thin.ttf b/data/fonts/Roboto-Thin.ttf
index 781ef3d..35ab525 100644
--- a/data/fonts/Roboto-Thin.ttf
+++ b/data/fonts/Roboto-Thin.ttf
Binary files differ
diff --git a/data/fonts/Roboto-ThinItalic.ttf b/data/fonts/Roboto-ThinItalic.ttf
index 0ed5203..edada2e 100644
--- a/data/fonts/Roboto-ThinItalic.ttf
+++ b/data/fonts/Roboto-ThinItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Bold.ttf b/data/fonts/RobotoCondensed-Bold.ttf
index 9f34ffe..bcbeece 100644
--- a/data/fonts/RobotoCondensed-Bold.ttf
+++ b/data/fonts/RobotoCondensed-Bold.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-BoldItalic.ttf b/data/fonts/RobotoCondensed-BoldItalic.ttf
index c8dea7a..7680d0a 100644
--- a/data/fonts/RobotoCondensed-BoldItalic.ttf
+++ b/data/fonts/RobotoCondensed-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Italic.ttf b/data/fonts/RobotoCondensed-Italic.ttf
index 09f4f5b..04c83a0 100644
--- a/data/fonts/RobotoCondensed-Italic.ttf
+++ b/data/fonts/RobotoCondensed-Italic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Light.ttf b/data/fonts/RobotoCondensed-Light.ttf
index c33a3e1..9f57418 100644
--- a/data/fonts/RobotoCondensed-Light.ttf
+++ b/data/fonts/RobotoCondensed-Light.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-LightItalic.ttf b/data/fonts/RobotoCondensed-LightItalic.ttf
index adfefc4..f9eac04 100644
--- a/data/fonts/RobotoCondensed-LightItalic.ttf
+++ b/data/fonts/RobotoCondensed-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Regular.ttf b/data/fonts/RobotoCondensed-Regular.ttf
index d750454..3a06286 100644
--- a/data/fonts/RobotoCondensed-Regular.ttf
+++ b/data/fonts/RobotoCondensed-Regular.ttf
Binary files differ
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index ec862f8..ca8d736 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1305,10 +1305,13 @@
* @hide
*/
public void setFontFeatureSettings(String settings) {
- if (settings != null && settings.equals(""))
+ if (settings != null && settings.equals("")) {
settings = null;
+ }
if ((settings == null && mFontFeatureSettings == null)
- || (settings != null && settings.equals(mFontFeatureSettings))) return;
+ || (settings != null && settings.equals(mFontFeatureSettings))) {
+ return;
+ }
mFontFeatureSettings = settings;
native_setFontFeatureSettings(mNativePaint, settings);
}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 099cd3f..1225fd1 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -257,12 +258,7 @@
aa.mSource = mSource;
aa.mFlags = mFlags;
aa.mTags = (HashSet<String>) mTags.clone();
- final Iterator<String> tagIterator = mTags.iterator();
- String allTagsInOne = new String();
- while (tagIterator.hasNext()) {
- allTagsInOne += tagIterator.next() + ";";
- }
- aa.mFormattedTags = allTagsInOne;
+ aa.mFormattedTags = TextUtils.join(";", mTags);
return aa;
}
@@ -503,12 +499,14 @@
boolean hasFlattenedTags = ((in.readInt() & FLATTEN_TAGS) == FLATTEN_TAGS);
mTags = new HashSet<String>();
if (hasFlattenedTags) {
- mTags.add(in.readString());
+ mFormattedTags = new String(in.readString());
+ mTags.add(mFormattedTags);
} else {
String[] tagsArray = in.readStringArray();
for (int i = tagsArray.length - 1 ; i >= 0 ; i--) {
mTags.add(tagsArray[i]);
}
+ mFormattedTags = TextUtils.join(";", mTags);
}
}
@@ -535,7 +533,7 @@
+ " usage=" + mUsage
+ " content=" + mContentType
+ " flags=0x" + Integer.toHexString(mFlags).toUpperCase()
- + " tags=" + mTags);
+ + " tags=" + mFormattedTags);
}
/** @hide */
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 2a612e8..8d99d6a1 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -263,18 +263,39 @@
private int mChannelMask;
private int mPropertySetMask;
- /** @hide */
+ /**
+ * Return the encoding.
+ * @return one of the values that can be set in {@link Builder#setEncoding(int)} or
+ * {@link AudioFormat#ENCODING_INVALID} if not set.
+ */
public int getEncoding() {
+ if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_ENCODING) == 0) {
+ return ENCODING_INVALID;
+ }
return mEncoding;
}
- /** @hide */
+ /**
+ * Return the sample rate.
+ * @return one of the values that can be set in {@link Builder#setSampleRate(int)} or
+ * 0 if not set.
+ */
public int getSampleRate() {
+ if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) == 0) {
+ return 0;
+ }
return mSampleRate;
}
- /** @hide */
+ /**
+ * Return the channel mask.
+ * @return one of the values that can be set in {@link Builder#setChannelMask(int)} or
+ * {@link AudioFormat#CHANNEL_INVALID} if not set.
+ */
public int getChannelMask() {
+ if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) == 0) {
+ return CHANNEL_INVALID;
+ }
return mChannelMask;
}
diff --git a/media/java/android/media/tv/ITvInputHardware.aidl b/media/java/android/media/tv/ITvInputHardware.aidl
index f35e8f3..3a04161 100644
--- a/media/java/android/media/tv/ITvInputHardware.aidl
+++ b/media/java/android/media/tv/ITvInputHardware.aidl
@@ -33,6 +33,7 @@
* trigger CEC commands for adjusting active HDMI source. Returns true on success.
*/
boolean setSurface(in Surface surface, in TvStreamConfig config);
+
/**
* Set volume for this stream via AudioGain. (TBD)
*/
@@ -43,4 +44,21 @@
* HDMI CEC commands. If the hardware is not representing an HDMI port, this method will fail.
*/
boolean dispatchKeyEventToHdmi(in KeyEvent event);
+
+ /**
+ * Override default audio sink from audio policy. When override is on, it is
+ * TvInputService's responsibility to adjust to audio configuration change
+ * (for example, when the audio sink becomes unavailable or more desirable
+ * audio sink is detected).
+ *
+ * @param audioType one of AudioManager.DEVICE_* values. When it's * DEVICE_NONE, override
+ * becomes off.
+ * @param audioAddress audio address of the overriding device.
+ * @param samplingRate desired sampling rate. Use default when it's 0.
+ * @param channelMask desired channel mask. Use default when it's
+ * AudioFormat.CHANNEL_OUT_DEFAULT.
+ * @param format desired format. Use default when it's AudioFormat.ENCODING_DEFAULT.
+ */
+ void overrideAudioSink(int audioType, String audioAddress, int samplingRate, int channelMask,
+ int format);
}
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 1939c56..a2b7d6b 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -38,6 +38,8 @@
List<TvInputInfo> getTvInputList(int userId);
TvInputInfo getTvInputInfo(in String inputId, int userId);
+ List<Uri> getTvContentRatingSystemXmls(int userId);
+
void registerCallback(in ITvInputManagerCallback callback, int userId);
void unregisterCallback(in ITvInputManagerCallback callback, int userId);
diff --git a/media/java/android/media/tv/TvContentRating.java b/media/java/android/media/tv/TvContentRating.java
index 986a7d9..1ace775 100644
--- a/media/java/android/media/tv/TvContentRating.java
+++ b/media/java/android/media/tv/TvContentRating.java
@@ -17,149 +17,275 @@
package android.media.tv;
import android.annotation.SystemApi;
+import android.net.Uri;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Log;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
/**
* A class representing a TV content rating.
+ * When a TV input service provides the content rating information of a program into TV provider,
+ * TvContentRating class will be used for generating the value of {@link
+ * TvContract.Programs#COLUMN_CONTENT_RATING}. To create an object of {@link TvContentRating}, use
+ * the {@link #createRating} method with valid arguments. The arguments could be a system defined
+ * strings, or a TV input service defined strings.
+ * TV input service defined strings are in an xml file defined in <code><{@link
+ * android.R.styleable#TvInputService tv-input}></code> with the {@link
+ * android.R.attr#contentRatingSystemXml contentRatingSystemXml} attribute by the TV input service.
+ *
+ * <h3> Content Rating System XML format </h3>
+ * The XML file for publishing content rating system should follow the DTD bellow:
+ * <p><pre class="prettyprint">
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <!DOCTYPE rating-systems [
+ * <!ELEMENT rating-system-definitions (rating-system-definition+)>
+ * <!ELEMENT rating-system-definition (
+ * (sub-rating-definition*, rating-definition, sub-rating-definition*)+, order*)>
+ * <!ATTLIST rating-system-definition
+ * id ID #REQUIRED
+ * displayName CDATA #IMPLIED
+ * description CDATA #IMPLIED
+ * country CDATA #IMPLIED>
+ * <!ELEMENT sub-rating-definition EMPTY>
+ * <!ATTLIST sub-rating-definition
+ * id ID #REQUIRED
+ * displayName CDATA #IMPLIED
+ * icon CDATA #IMPLIED
+ * description CDATA #IMPLIED>
+ * <!ELEMENT rating-definition (sub-rating*))>
+ * <!ATTLIST rating-definition
+ * id ID #REQUIRED
+ * displayName CDATA #IMPLIED
+ * icon CDATA #IMPLIED
+ * description CDATA #IMPLIED>
+ * <!ELEMENT sub-rating EMPTY>
+ * <!ATTLIST sub-rating id IDREF #REQUIRED>
+ * <!ELEMENT order (rating, rating+)>
+ * <!ELEMENT rating EMPTY>
+ * <!ATTLIST rating id IDREF #REQUIRED>
+ * ]>
+ * </pre></p>
+ *
+ * <h3>System defined rating strings</h3>
+ *
+ * <u>System defined string for {@code domain}</u>
+ * <table border="0" cellspacing="0" cellpadding="0">
+ * <tr>
+ * <td>String value</td>
+ * <td>Comments</td>
+ * </tr>
+ * <tr>
+ * <td>android.media.tv</td>
+ * <td>Used for creating system defined content ratings</td>
+ * </tr>
+ * </table>
+ * <u>System defined string for {@code ratingSystem}</u>
+ * <table border="0" cellspacing="0" cellpadding="0">
+ * <tr>
+ * <td>String value</td>
+ * <td>Comments</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG</td>
+ * <td>The TV Parental Guidelines for US TV content ratings</td>
+ * </tr>
+ * <tr>
+ * <td>KR_TV</td>
+ * <td>The South Korean television rating system</td>
+ * </tr>
+ * </table>
+ *
+ * <u>System defined string for {@code rating}</u>
+ * <table border="0" cellspacing="0" cellpadding="0">
+ * <tr>
+ * <td>String value</td>
+ * <td>Comments</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_TV_Y</td>
+ * <td>A rating string for the US_TVPG domain. Programs rated this are designed to be
+ * appropriate for all children. Whether animated or live-action, the themes and elements
+ * in this program are specifically designed for a very young audience, including children
+ * from ages 2-6. This program is not expected to frighten younger children.</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_TV_Y7</td>
+ * <td>A rating string for the US_TVPG domain. Programs rated this are designed for children
+ * age 7 and above. It may be more appropriate for children who have acquired the
+ * developmental skills needed to distinguish between make-believe and reality. Themes and
+ * elements in this program may include mild fantasy violence or comedic violence, or may
+ * frighten children under the age of 7. Therefore, parents may wish to consider the
+ * suitability of this program for their very young children. This rating may contain
+ * fantasy violence (US_TVPG_FV) when programs are generally more intense or more combative
+ * than other programs in this category.</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_TV_G</td>
+ * <td>A rating string for the US_TVPG domain. Most parents would find this program suitable
+ * for all ages. Although this rating does not signify a program designed specifically for
+ * children, most parents may let younger children watch this program unattended. It
+ * contains little or no violence, no strong language and little or no sexual dialogue or
+ * situations.</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_TV_PG</td>
+ * <td>A rating string for the US_TVPG domain. Programs rated this contain material that
+ * parents may find unsuitable for younger children. Many parents may want to watch it with
+ * their younger children. The theme itself may call for parental guidance and/or the
+ * program may contain one or more of the following: some suggestive dialogue (US_TVPG_D),
+ * infrequent coarse language (US_TVPG_L), some sexual situations (US_TVPG_S), or moderate
+ * violence (US_TVPG_V).</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_TV_14</td>
+ * <td>A rating string for the US_TVPG domain. Programs rated this contains some material
+ * that many parents would find unsuitable for children under 14 years of age. Parents are
+ * strongly urged to exercise greater care in monitoring this program and are cautioned
+ * against letting children under the age of 14 watch unattended. This program may contain
+ * one or more of the following: intensely suggestive dialogue (US_TVPG_D), strong coarse
+ * language (US_TVPG_L), intense sexual situations (US_TVPG_S), or intense violence
+ * (US_TVPG_V).</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_TV_MA</td>
+ * <td>A rating string for the US_TVPG domain. Programs rated TV-MA are specifically
+ * designed to be viewed by adults and therefore may be unsuitable for children under 17.
+ * This program may contain one or more of the following: crude indecent language
+ * (US_TVPG_L), explicit sexual activity (US_TVPG_S), or graphic violence (US_TVPG_V).</td>
+ * </tr>
+ * <tr>
+ * <td>KR_TV_ALL</td>
+ * <td>A rating string for the KR_TV domain. This rating is for programs that are
+ * appropriate for all ages. This program usually involves programs designed for children or
+ * families. This rating does not have an icon.</td>
+ * </tr>
+ * <tr>
+ * <td>KR_TV_7</td>
+ * <td>A rating string for the KR_TV domain. This rating is for programs that may contain
+ * material inappropriate for children younger than 7, and parental discretion should be
+ * used. Some cartoon programs not deemed strictly as "educational", and films rated "G" or
+ * "PG" in North America may fall into the 7 category.</td>
+ * </tr>
+ * <tr>
+ * <td>KR_TV_12</td>
+ * <td>A rating string for the KR_TV domain. This rating is for programs that may deemed
+ * inappropriate for those younger than 12, and parental discretion should be used. Usually
+ * used for animations that have stronger themes or violence then those designed for
+ * children, or for reality shows that have mild violence, themes, or language.</td>
+ * </tr>
+ * <tr>
+ * <td>KR_TV_15</td>
+ * <td>A rating string for the KR_TV domain. This rating is for programs that contain
+ * material that may be inappropriate for children under 15, and that parental discretion
+ * should be used. Examples include most dramas, and talk shows on OTA (over-the-air) TV
+ * (KBS, MBC, SBS), and many American TV shows/dramas on Cable TV channels like OCN and
+ * OnStyle. The programs that have this rating may include moderate or strong adult themes,
+ * language, sexual inference, and violence. As with the TV-14 rating in North America, this
+ * rating is commonly applied to live events where the occurrence of inappropriate dialogue
+ * is unpredictable. Since 2007, this rating is the most used rating for TV.</td>
+ * </tr>
+ * <tr>
+ * <td>KR_TV_19</td>
+ * <td>A rating string for the KR_TV domain. This rating is for programs that are intended
+ * for adults only. 19-rated programs cannot air during the hours of 7:00AM to 9:00AM, and
+ * 1:00PM to 10:00PM. Programs that receive this rating will almost certainly have adult
+ * themes, sexual situations, frequent use of strong language and disturbing scenes of
+ * violence.</td>
+ * </tr>
+ * </table>
+ *
+ * <u>System defined string for {@code subRating}</u>
+ * <table border="0" cellspacing="0" cellpadding="0">
+ * <tr>
+ * <td>String value</td>
+ * <td>Comments</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_D</td>
+ * <td>Suggestive dialogue (Not used with US_TVPG_TV_MA)</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_L</td>
+ * <td>Coarse language</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_S</td>
+ * <td>Sexual content</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_V</td>
+ * <td>Violence</td>
+ * </tr>
+ * <tr>
+ * <td>US_TVPG_FV</td>
+ * <td>Fantasy violence (exclusive to US_TVPG_TV_Y7)</td>
+ * </tr>
+ * </table>
*/
public final class TvContentRating {
private static final String TAG = "TvContentRating";
- private static final int RATING_PREFIX_LENGTH = 10;
- private static final String PREFIX_RATING_US = "RATING_US_";
- private static final String PREFIX_SUBRATING_US = "SUBRATING_US_";
+ /** @hide */
+ public static final Uri SYSTEM_CONTENT_RATING_SYSTEM_XML = Uri.parse(
+ "android.resource://system/" + com.android.internal.R.xml.tv_content_rating_systems);
- /**
- * Rating constant for TV-Y from the TV Parental Guidelines system in US. This program is
- * designed to be appropriate for all children.
- */
- public static final String RATING_US_TV_Y = PREFIX_RATING_US + "TV_Y";
- /**
- * Rating constant for TV-Y7 from the TV Parental Guidelines system in US. This program is
- * designed for children age 7 and above.
- */
- public static final String RATING_US_TV_Y7 = PREFIX_RATING_US + "TV_Y7";
- /**
- * Rating constant for TV-G from the TV Parental Guidelines system in US. Most parents would
- * find this program suitable for all ages.
- */
- public static final String RATING_US_TV_G = PREFIX_RATING_US + "TV_G";
- /**
- * Rating constant for TV-PG from the TV Parental Guidelines system in US. This program contains
- * material that parents may find unsuitable for younger children.
- */
- public static final String RATING_US_TV_PG = PREFIX_RATING_US + "TV_PG";
- /**
- * Rating constant for TV-14 from the TV Parental Guidelines system in US. This program contains
- * some material that many parents would find unsuitable for children under 14 years of age.
- */
- public static final String RATING_US_TV_14 = PREFIX_RATING_US + "TV_14";
- /**
- * Rating constant for TV-MA from the TV Parental Guidelines system in US. This program is
- * specifically designed to be viewed by adults and therefore may be unsuitable for children
- * under 17.
- */
- public static final String RATING_US_TV_MA = PREFIX_RATING_US + "TV_MA";
-
- /**
- * Sub-rating constant for D (Suggestive dialogue) from the TV Parental Guidelines system in US.
- */
- public static final String SUBRATING_US_D = PREFIX_SUBRATING_US + "D";
- /**
- * Sub-rating constant for L (Coarse language) from the TV Parental Guidelines system in US.
- */
- public static final String SUBRATING_US_L = PREFIX_SUBRATING_US + "L";
- /**
- * Sub-rating constant for S (Sexual content) from the TV Parental Guidelines system in US.
- */
- public static final String SUBRATING_US_S = PREFIX_SUBRATING_US + "S";
- /**
- * Sub-rating constant for V (Violence) from the TV Parental Guidelines system in US.
- */
- public static final String SUBRATING_US_V = PREFIX_SUBRATING_US + "V";
- /**
- * Sub-rating constant for FV (Fantasy violence) from the TV Parental Guidelines system in US.
- */
- public static final String SUBRATING_US_FV = PREFIX_SUBRATING_US + "FV";
-
- private static final String PREFIX_RATING_KR = "RATING_KR_";
-
- /**
- * Rating constant for 'ALL' from the South Korean television rating system. This rating is for
- * programming that is appropriate for all ages.
- */
- public static final String RATING_KR_ALL = PREFIX_RATING_KR + "ALL";
- /**
- * Rating constant for '7' from the South Korean television rating system. This rating is for
- * programming that may contain material inappropriate for children younger than 7, and parental
- * discretion should be used.
- */
- public static final String RATING_KR_7 = PREFIX_RATING_KR + "7";
- /**
- * Rating constant for '12' from the South Korean television rating system. This rating is for
- * programs that may deemed inappropriate for those younger than 12, and parental discretion
- * should be used.
- */
- public static final String RATING_KR_12 = PREFIX_RATING_KR + "12";
- /**
- * Rating constant for '15' from the South Korean television rating system. This rating is for
- * programs that contain material that may be inappropriate for children under 15, and that
- * parental discretion should be used.
- */
- public static final String RATING_KR_15 = PREFIX_RATING_KR + "15";
- /**
- * Rating constant for '19' from the South Korean television rating system. This rating is for
- * programs that are intended for adults only. 19-rated programming cannot air during the hours
- * of 7:00AM to 9:00AM, and 1:00PM to 10:00PM.
- */
- public static final String RATING_KR_19 = PREFIX_RATING_KR + "19";
-
+ // TODO: Consider to use other DELIMITER. In some countries such as India may use this delimiter
+ // in the main ratings.
private static final String DELIMITER = "/";
- // A mapping from two-letter country code (ISO 3166-1 alpha-2) to its rating-to-sub-ratings map.
- // This is used for validating the builder parameters.
- private static final Map<String, Map<String, String[]>> sRatings
- = new ArrayMap<String, Map<String, String[]>>();
-
- static {
- Map<String, String[]> usRatings = new ArrayMap<String, String[]>();
- usRatings.put(RATING_US_TV_Y, null);
- usRatings.put(RATING_US_TV_Y7, new String[] { SUBRATING_US_FV });
- usRatings.put(RATING_US_TV_G, null);
- usRatings.put(RATING_US_TV_PG, new String[] {
- SUBRATING_US_D, SUBRATING_US_L, SUBRATING_US_S, SUBRATING_US_V });
- usRatings.put(RATING_US_TV_14, new String[] {
- SUBRATING_US_D, SUBRATING_US_L, SUBRATING_US_S, SUBRATING_US_V });
- usRatings.put(RATING_US_TV_MA, new String[] {
- SUBRATING_US_L, SUBRATING_US_S, SUBRATING_US_V });
- sRatings.put(PREFIX_RATING_US, usRatings);
-
- Map<String, String[]> krRatings = new ArrayMap<String, String[]>();
- krRatings.put(RATING_KR_ALL, null);
- krRatings.put(RATING_KR_7, null);
- krRatings.put(RATING_KR_12, null);
- krRatings.put(RATING_KR_15, null);
- krRatings.put(RATING_KR_19, null);
- sRatings.put(PREFIX_RATING_KR, krRatings);
- }
-
+ private final String mDomain;
+ private final String mCountryCode;
+ private final String mRatingSystem;
private final String mRating;
private final String[] mSubRatings;
/**
- * Constructs a TvContentRating object from a given rating constant.
+ * Creates a TvContentRating object.
*
- * @param rating The rating constant defined in this class.
+ * @param domain The domain name.
+ * @param countryCode The country code in ISO 3166-2 format or {@code null}.
+ * @param ratingSystem The rating system id.
+ * @param rating The content rating string.
+ * @param subRatings The string array of sub-ratings.
+ * @return A TvContentRating object, or null if creation failed.
*/
- public TvContentRating(String rating) {
- this(rating, null);
+ public static TvContentRating createRating(String domain, String countryCode,
+ String ratingSystem, String rating, String... subRatings) {
+ if (TextUtils.isEmpty(domain)) {
+ throw new IllegalArgumentException("domain cannot be empty");
+ }
+ if (TextUtils.isEmpty(rating)) {
+ throw new IllegalArgumentException("rating cannot be empty");
+ }
+ return new TvContentRating(domain, countryCode, ratingSystem, rating, subRatings);
+ }
+
+ /**
+ * Recovers a TvContentRating from a String that was previously created with
+ * {@link #flattenToString}.
+ *
+ * @param ratingString The String that was returned by flattenToString().
+ * @return a new TvContentRating containing the domain, countryCode, rating system, rating and
+ * sub-ratings information was encoded in {@code ratingString}.
+ * @see #flattenToString
+ */
+ public static TvContentRating unflattenFromString(String ratingString) {
+ if (TextUtils.isEmpty(ratingString)) {
+ throw new IllegalArgumentException("ratingString cannot be empty");
+ }
+ String[] strs = ratingString.split(DELIMITER);
+ if (strs.length < 4) {
+ throw new IllegalArgumentException("Invalid rating string: " + ratingString);
+ }
+ if (strs.length > 4) {
+ String[] subRatings = new String[strs.length - 4];
+ System.arraycopy(strs, 4, subRatings, 0, subRatings.length);
+ return new TvContentRating(strs[0], strs[1], strs[2], strs[3], subRatings);
+ }
+ return new TvContentRating(strs[0], strs[1], strs[2], strs[3], null);
}
/**
@@ -168,57 +294,45 @@
* @param rating The rating constant defined in this class.
* @param subRatings The String array of sub-rating constants defined in this class.
*/
- public TvContentRating(String rating, String[] subRatings) {
- if (TextUtils.isEmpty(rating)) {
- throw new IllegalArgumentException("rating cannot be null");
- }
+ private TvContentRating(String domain, String countryCode,
+ String ratingSystem, String rating, String[] subRatings) {
+ mDomain = domain;
+ mCountryCode = countryCode;
+ mRatingSystem = ratingSystem;
mRating = rating;
mSubRatings = subRatings;
- String prefix = "";
- if (mRating.length() > RATING_PREFIX_LENGTH) {
- prefix = mRating.substring(0, RATING_PREFIX_LENGTH);
- }
- Map<String, String[]> ratings = sRatings.get(prefix);
- if (ratings != null) {
- if (!ratings.keySet().contains(mRating)) {
- Log.w(TAG, "Unknown rating: " + mRating);
- } else if (mSubRatings != null) {
- String[] validSubRatings = ratings.get(mRating);
- if (validSubRatings == null) {
- Log.w(TAG, "Invalid subratings: " + mSubRatings);
- } else {
- List<String> validSubRatingList = Arrays.asList(subRatings);
- for (String sr : mSubRatings) {
- if (TextUtils.isEmpty(sr)) {
- throw new IllegalArgumentException(
- "subRatings cannot contain empty elements");
- }
- if (!validSubRatingList.contains(sr)) {
- Log.w(TAG, "Invalid subrating: " + sr);
- break;
- }
- }
- }
- }
- } else {
- Log.w(TAG, "Rating undefined for " + mRating);
- }
}
/**
- * Returns the main rating constant.
- *
- * @return the rating string that starts with "RATING_" prefix as defined in this class.
+ * Returns the domain.
+ */
+ public String getDomain() {
+ return mDomain;
+ }
+
+ /**
+ * Returns the country code in ISO 3166-2 format or {@code null}.
+ */
+ public String getCountry() {
+ return mCountryCode;
+ }
+
+ /**
+ * Returns the rating system id.
+ */
+ public String getRatingSystem() {
+ return mRatingSystem;
+ }
+
+ /**
+ * Returns the main rating.
*/
public String getMainRating() {
return mRating;
}
/**
- * Returns the list of sub-rating constants.
- *
- * @return the unmodifiable {@code List} of sub-rating strings that start with "SUBRATING_"
- * prefix as defined in this class.
+ * Returns the unmodifiable {@code List} of sub-rating strings.
*/
public List<String> getSubRatings() {
if (mSubRatings == null) {
@@ -238,10 +352,14 @@
* @see #unflattenFromString
*/
public String flattenToString() {
- // TODO: Consider removing all obvious/redundant sub-strings including "RATING" and
- // "SUBRATING" and find out a storage-efficient string format such as:
- // <country>-<primary>/<sub1>/<sub2>/<sub3>
- StringBuilder builder = new StringBuilder(mRating);
+ StringBuilder builder = new StringBuilder();
+ builder.append(mDomain);
+ builder.append(DELIMITER);
+ builder.append(mCountryCode);
+ builder.append(DELIMITER);
+ builder.append(mRatingSystem);
+ builder.append(DELIMITER);
+ builder.append(mRating);
if (mSubRatings != null) {
for (String subRating : mSubRatings) {
builder.append(DELIMITER);
@@ -252,31 +370,6 @@
}
/**
- * Recovers a TvContentRating from a String that was previously created with
- * {@link #flattenToString}.
- *
- * @param ratingString The String that was returned by flattenToString().
- * @return a new TvContentRating containing the rating and sub-ratings information was encoded
- * in {@code ratingString}.
- * @see #flattenToString
- */
- public static TvContentRating unflattenFromString(String ratingString) {
- if (TextUtils.isEmpty(ratingString)) {
- throw new IllegalArgumentException("Empty rating string");
- }
- String[] strs = ratingString.split(DELIMITER);
- if (strs.length < 1) {
- throw new IllegalArgumentException("Invalid rating string: " + ratingString);
- }
- if (strs.length > 1) {
- String[] subRatings = new String[strs.length - 1];
- System.arraycopy(strs, 1, subRatings, 0, subRatings.length);
- return new TvContentRating(strs[0], subRatings);
- }
- return new TvContentRating(strs[0]);
- }
-
- /**
* Returns true if this rating has the same main rating as the specified rating and when this
* rating's sub-ratings contain the other's.
* <p>
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index e48b805..bc0538c 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -18,6 +18,7 @@
import android.annotation.SystemApi;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -118,6 +119,7 @@
private String mLabel;
private Uri mIconUri;
private boolean mIsConnectedToHdmiSwitch;
+ private Uri mRatingSystemXmlUri;
static {
sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_OTHER_HARDWARE,
@@ -237,6 +239,19 @@
Log.d(TAG, "Settings activity loaded. [" + input.mSettingsActivity + "] for "
+ si.name);
}
+ int contentRatingSystemXml = sa.getResourceId(
+ com.android.internal.R.styleable.TvInputService_contentRatingSystemXml, -1);
+ if (contentRatingSystemXml != -1) {
+ input.mRatingSystemXmlUri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
+ .authority(si.packageName)
+ .appendPath(Integer.toString(contentRatingSystemXml))
+ .build();
+ if (DEBUG) {
+ Log.d(TAG, "Content rating xml loaded. [" + contentRatingSystemXml + "] for "
+ + si.name);
+ }
+ }
sa.recycle();
input.mLabel = label;
@@ -346,6 +361,15 @@
}
/**
+ * Returns the resource uri for the rating system xml of this TV input service.
+ * @hide
+ */
+ @SystemApi
+ public Uri getRatingSystemXmlUri() {
+ return mRatingSystemXmlUri;
+ }
+
+ /**
* Returns {@code true} if this TV input is pass-though which does not have any real channels
* in TvProvider. {@code false} otherwise.
*
@@ -449,9 +473,10 @@
dest.writeString(mSetupActivity);
dest.writeString(mSettingsActivity);
dest.writeInt(mType);
- dest.writeString(mIconUri == null ? null : mIconUri.toString());
+ dest.writeParcelable(mIconUri, flags);
dest.writeString(mLabel);
dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
+ dest.writeParcelable(mRatingSystemXmlUri, flags);
}
private Drawable loadDefaultIcon(Context context) {
@@ -521,11 +546,9 @@
mSetupActivity = in.readString();
mSettingsActivity = in.readString();
mType = in.readInt();
- String mIconUriString = in.readString();
- if (mIconUriString != null) {
- mIconUri = Uri.parse(mIconUriString);
- }
+ mIconUri = in.readParcelable(null);
mLabel = in.readString();
mIsConnectedToHdmiSwitch = in.readByte() == 1 ? true : false;
+ mRatingSystemXmlUri = in.readParcelable(null);
}
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 7bb353c..0334083 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -800,6 +800,19 @@
}
/**
+ * Returns the list of xml resource uris for TV content rating systems.
+ * @hide
+ */
+ @SystemApi
+ public List<Uri> getTvContentRatingSystemXmls() {
+ try {
+ return mService.getTvContentRatingSystemXmls(mUserId);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* Creates a {@link Session} for a given TV input.
* <p>
* The number of sessions that can be created at the same time is limited by the capability of
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index dd7a828..91199c1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -190,33 +190,34 @@
String localeString = loc.getLanguage();
String country = loc.getCountry();
if (!TextUtils.isEmpty(country)) {
- localeString += "_" + country;
+ localeString += "-" + country;
}
return localeString.getBytes();
}
/**
- * Sets the locale specified. Input data is the equivalent of "ll_cc".getBytes(), where
- * "ll" is the language code and "cc" is the country code.
+ * Sets the locale specified. Input data is the byte representation of a
+ * BCP-47 language tag. For backwards compatibility, strings of the form
+ * {@code ll_CC} are also accepted, where {@code ll} is a two letter language
+ * code and {@code CC} is a two letter country code.
+ *
* @param data the locale string in bytes.
*/
void setLocaleData(byte[] data, int size) {
// Check if locale was set by the user:
Configuration conf = mContext.getResources().getConfiguration();
- Locale loc = conf.locale;
// TODO: The following is not working as intended because the network is forcing a locale
// change after registering. Need to find some other way to detect if the user manually
// changed the locale
if (conf.userSetLocale) return; // Don't change if user set it in the SetupWizard
final String[] availableLocales = mContext.getAssets().getLocales();
- String localeCode = new String(data, 0, size);
- String language = new String(data, 0, 2);
- String country = size > 4 ? new String(data, 3, 2) : "";
- loc = null;
+ // Replace "_" with "-" to deal with older backups.
+ String localeCode = new String(data, 0, size).replace('_', '-');
+ Locale loc = null;
for (int i = 0; i < availableLocales.length; i++) {
if (availableLocales[i].equals(localeCode)) {
- loc = new Locale(language, country);
+ loc = Locale.forLanguageTag(localeCode);
break;
}
}
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png
deleted file mode 100644
index 250653b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png
deleted file mode 100644
index 497c69f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png
deleted file mode 100644
index d750726..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png
deleted file mode 100644
index 250653b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png
deleted file mode 100644
index 497c69f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png
deleted file mode 100644
index d750726..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_in.png
deleted file mode 100644
index 64c6723..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_inout.png
deleted file mode 100644
index 2338122..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_out.png
deleted file mode 100644
index 29df6d7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_in.png
deleted file mode 100644
index 3fba731..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_inout.png
deleted file mode 100644
index eb5fcd0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_out.png
deleted file mode 100644
index a91c7c7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_in.png
deleted file mode 100644
index 521de12..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_inout.png
deleted file mode 100644
index 4d015da..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_out.png
deleted file mode 100644
index d8209e6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_in.png
deleted file mode 100644
index 3725b3f0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_inout.png
deleted file mode 100644
index b72a274..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_out.png
deleted file mode 100644
index aa2de43..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png
deleted file mode 100644
index 4a2119f..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png
deleted file mode 100644
index a53d764..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png
deleted file mode 100644
index 8b7251b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png
deleted file mode 100644
index 4a2119f..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png
deleted file mode 100644
index a53d764..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png
deleted file mode 100644
index 8b7251b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png
deleted file mode 100644
index 1664688..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png
deleted file mode 100644
index b38e3ef..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png
deleted file mode 100644
index c645859..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png
deleted file mode 100644
index 1664688..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png
deleted file mode 100644
index b38e3ef..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png
deleted file mode 100644
index c645859..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_in.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_in.png
deleted file mode 100644
index 3725b3f0..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_inout.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_inout.png
deleted file mode 100644
index b72a274..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_out.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_out.png
deleted file mode 100644
index aa2de43..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_signal_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_in.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_in.png
deleted file mode 100644
index 5b80893..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_in.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_inout.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_inout.png
deleted file mode 100644
index 21b2118..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_inout.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_out.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_out.png
deleted file mode 100644
index 3f0447df..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_wifi_out.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
index 6872a33..94b3a6b 100644
--- a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
@@ -18,14 +18,7 @@
android:height="64dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
-
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M10.25,1.75c-0.6,-0.6 -1.5,-0.6 -2.1,0.0l-6.4,6.4c-0.6,0.6 -0.6,1.5 0.0,2.1l12.0,12.0c0.6,0.6 1.5,0.6 2.1,0.0l6.4,-6.4c0.6,-0.6 0.6,-1.5 0.0,-2.1L10.25,1.75zM14.85,21.25l-12.0,-12.0l6.4,-6.4l12.0,12.0L14.85,21.25z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M16.55,2.5c3.3,1.5 5.6,4.7 6.0,8.5l1.5,0.0c-0.6,-6.2 -5.7,-11.0 -12.0,-11.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.55,2.5z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M7.55,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5l-1.4,0.0c0.5,6.2 5.6,11.0 11.9,11.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.55,21.5z"/>
+ android:pathData="M16.600000,2.500000c3.300000,1.500000 5.600000,4.700000 6.000000,8.500000l1.500000,0.000000c-0.600000,-6.200000 -5.700000,-11.000000 -12.000000,-11.000000c-0.200000,0.000000 -0.400000,0.000000 -0.700000,0.000000l3.800000,3.800000L16.600000,2.500000zM10.300000,1.700000c-0.600000,-0.600000 -1.500000,-0.600000 -2.100000,0.000000L1.800000,8.100000c-0.600000,0.600000 -0.600000,1.500000 0.000000,2.100000l12.000000,12.000000c0.600000,0.600000 1.500000,0.600000 2.100000,0.000000l6.400000,-6.400000c0.600000,-0.600000 0.600000,-1.500000 0.000000,-2.100000L10.300000,1.700000zM13.400000,19.700001l-9.200000,-9.200000l6.400000,-6.400000l9.200000,9.200000L13.400000,19.700001zM7.600000,21.500000C4.300000,20.000000 2.000000,16.799999 1.600000,13.000000L0.200000,13.000000c0.500000,6.200000 5.600000,11.000000 11.900000,11.000000c0.200000,0.000000 0.400000,0.000000 0.700000,0.000000L9.000000,20.200001L7.600000,21.500000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
index 8775264..71c40df 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
@@ -14,15 +14,14 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32dp"
+ android:width="16.0dp"
android:height="32dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="12.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M4.300000,11.000000L2.700000,11.000000L2.700000,4.400000L1.000000,5.100000L1.000000,3.700000l3.100000,-1.300000l0.200000,0.000000L4.300000,11.000000z"/>
+ android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/>
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M9.500000,5.500000l1.200000,-3.000000l1.900000,0.000000l-2.100000,4.200000l2.200000,4.300000l-1.900000,0.000000L9.500000,7.900000L8.300000,11.000000L6.300000,11.000000l2.100000,-4.300000L6.400000,2.500000l1.900000,0.000000L9.500000,5.500000z"/>
+ android:pathData="M8.600000,5.500000l1.200000,-3.000000l1.900000,0.000000L9.700000,6.700000l2.200000,4.300000L9.900000,11.000000L8.700000,7.900000L7.400000,11.000000L5.500000,11.000000l2.100000,-4.300000L5.600000,2.500000l1.900000,0.000000L8.600000,5.500000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
index 4b4e2e5..e9a57ea 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
@@ -14,15 +14,14 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32dp"
+ android:width="17.333334dp"
android:height="32dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="13.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M2.600000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.700000,3.700000 3.500000,3.700000C3.200000,3.700000 3.000000,3.800000 2.900000,4.000000S2.600000,4.400000 2.600000,4.700000L1.000000,4.700000C1.000000,4.000000 1.200000,3.400000 1.700000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000S6.000000,4.000000 6.000000,4.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S5.200000,6.500000 4.800000,6.600000c0.400000,0.200000 0.700000,0.400000 0.900000,0.800000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000l1.700000,0.000000c0.000000,0.300000 0.100000,0.600000 0.300000,0.800000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S4.400000,9.000000 4.400000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.700000,7.300000 3.400000,7.300000L2.600000,7.300000L2.600000,6.000000z"/>
+ android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/>
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M13.100000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S7.300000,9.000000 7.300000,7.900000L7.300000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000S13.000000,4.200000 13.000000,5.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.900000,5.000000 8.900000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L11.299999,7.800000l-1.300000,0.000000L9.999999,6.600000l2.900000,0.000000L12.900000,9.900000z"/>
+ android:pathData="M12.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.700000,9.000000 6.700000,7.900000L6.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.400000,5.000000 8.400000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.799999,7.800000L9.600000,7.800000L9.600000,6.600000l2.900000,0.000000L12.500000,9.900000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
index 920692f..42045d1 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
@@ -14,15 +14,14 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32dp"
+ android:width="16.0dp"
android:height="32dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="12.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M5.700000,7.800000l0.700000,0.000000l0.000000,1.300000L5.700000,9.100000L5.700000,11.000000L4.000000,11.000000L4.000000,9.200000L1.200000,9.200000l-0.100000,-1.000000L4.000000,2.500000l1.700000,0.000000L5.700000,7.800000zM2.700000,7.800000L4.000000,7.800000l0.000000,-3.000000L4.000000,5.000000L2.700000,7.800000z"/>
+ android:pathData="M4.600000,7.800000l0.700000,0.000000l0.000000,1.300000L4.600000,9.100000L4.600000,11.000000L3.000000,11.000000L3.000000,9.200000L0.100000,9.200000L0.000000,8.100000L3.000000,2.500000l1.700000,0.000000L4.700000,7.800000zM1.600000,7.800000L3.000000,7.800000l0.000000,-3.000000L2.900000,5.000000L1.600000,7.800000z"/>
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M13.000000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S7.200000,9.000000 7.200000,7.900000L7.200000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.800000,5.000000 8.800000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L11.200000,7.800000l-1.300000,0.000000L9.900000,6.600000L13.000000,6.600000L13.000000,9.900000z"/>
+ android:pathData="M11.900000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.100000,9.000000 6.100000,7.900000L6.100000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000S8.100000,2.400000 9.000000,2.400000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S9.500000,3.700000 9.000000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S7.700000,5.000000 7.700000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.099999,7.800000L9.000000,7.800000L9.000000,6.600000l2.900000,0.000000L11.900000,9.900000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml
new file mode 100644
index 0000000..4f253e3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 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:autoMirrored="true"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M21.799999,22.299999l-1.199999,-1.299999 0.000000,0.000000 -9.600000,-10.000000 0.000000,0.000000 -6.400000,-6.700000 -1.300000,1.300000 6.400000,6.700000 -8.700000,8.700000 16.900000,0.000000 2.600000,2.700001z"/>
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M21.000000,1.000000l-8.600000,8.600000 8.600000,9.100000z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml b/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
index 737f2d8..e49a409 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
@@ -14,12 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32dp"
+ android:width="6.6666665dp"
android:height="32dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="5.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M5.900000,7.300000L3.100000,7.300000l0.000000,2.400000l3.300000,0.000000L6.400000,11.000000L1.400000,11.000000L1.400000,2.500000l4.900000,0.000000l0.000000,1.300000L3.100000,3.800000l0.000000,2.100000l2.800000,0.000000L5.900000,7.300000z"/>
+ android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
index b0f3c0f..9d42a44 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
@@ -14,12 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32dp"
+ android:width="9.333333dp"
android:height="32dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="7.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M7.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S1.700000,9.000000 1.700000,7.900000L1.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L5.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S5.000000,3.700000 4.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S3.300000,5.000000 3.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L5.700000,7.800000L4.500000,7.800000L4.500000,6.600000l2.900000,0.000000L7.400000,9.900000z"/>
+ android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml b/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
index 8532b27..f509d71 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
@@ -14,12 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32dp"
+ android:width="8.0dp"
android:height="32dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="6.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M7.700000,11.000000L6.000000,11.000000L6.000000,7.500000L3.400000,7.500000L3.400000,11.000000L1.700000,11.000000L1.700000,2.500000l1.700000,0.000000l0.000000,3.700000L6.000000,6.200000L6.000000,2.500000l1.600000,0.000000L7.600000,11.000000z"/>
+ android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_in.xml b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml
new file mode 100644
index 0000000..236fdac
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 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="6.0dp"
+ android:height="32dp"
+ android:viewportWidth="6.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M6.000000,15.700000l-3.000000,5.599999 -3.000000,-5.599999z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml b/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
index ec273ed..b7242e6 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
@@ -14,10 +14,9 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32dp"
+ android:width="17.333334dp"
android:height="32dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="13.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_out.xml b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml
new file mode 100644
index 0000000..c510972
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 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="6.0dp"
+ android:height="32dp"
+ android:viewportWidth="6.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.000000,13.700000l3.000000,-5.700000 3.000000,5.700000z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_r.xml b/packages/SystemUI/res/drawable/ic_qs_signal_r.xml
index bbf2761..66f64c9 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_r.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_r.xml
@@ -14,12 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32dp"
+ android:width="8.0dp"
android:height="32dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="6.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M4.100000,7.900000l-1.000000,0.000000L3.100000,11.000000L1.400000,11.000000L1.400000,2.500000l2.700000,0.000000c0.900000,0.000000 1.500000,0.200000 2.000000,0.700000s0.700000,1.100000 0.700000,1.900000c0.000000,0.600000 -0.100000,1.100000 -0.300000,1.500000S6.000000,7.200000 5.600000,7.400000l1.500000,3.500000L7.100000,11.000000L5.400000,11.000000L4.100000,7.900000zM3.100000,6.500000l1.100000,0.000000c0.400000,0.000000 0.600000,-0.100000 0.800000,-0.400000s0.300000,-0.600000 0.300000,-1.000000c0.000000,-0.400000 -0.100000,-0.800000 -0.300000,-1.000000S4.600000,3.800000 4.200000,3.800000L3.100000,3.800000L3.100000,6.500000z"/>
+ android:pathData="M2.800000,7.900000l-1.000000,0.000000L1.800000,11.000000L0.200000,11.000000L0.200000,2.500000l2.700000,0.000000c0.900000,0.000000 1.500000,0.200000 2.000000,0.700000s0.700000,1.100000 0.700000,1.900000c0.000000,0.600000 -0.100000,1.100000 -0.300000,1.500000S4.800000,7.200000 4.400000,7.400000l1.500000,3.500000L5.900000,11.000000L4.100000,11.000000L2.800000,7.900000zM1.800000,6.500000l1.100000,0.000000c0.400000,0.000000 0.600000,-0.100000 0.800000,-0.400000S4.000000,5.600000 4.000000,5.200000c0.000000,-0.400000 -0.100000,-0.800000 -0.300000,-1.000000S3.300000,3.800000 2.900000,3.800000L1.800000,3.800000L1.800000,6.500000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
new file mode 100644
index 0000000..c505783
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2014 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="32.0dp"
+ android:height="29.5dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M17.500000,16.500000L5.800000,3.400000c0.000000,0.000000 0.000000,0.000000 0.000000,0.000000l-2.700000,-3.000000L1.600000,1.800000l2.200000,2.500000c-2.000000,1.000000 -3.200000,2.000000 -3.400000,2.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l3.200000,-3.900000l2.400000,2.700000l1.500000,-1.400000L17.500000,16.500000L17.500000,16.500000z"/>
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000c-1.900000,0.000000 -3.600000,0.300000 -5.200000,0.700000L18.700001,15.000000L25.600000,6.500000z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/qs_detail_background.xml b/packages/SystemUI/res/drawable/qs_detail_background.xml
new file mode 100644
index 0000000..692cd44
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_detail_background.xml
@@ -0,0 +1,19 @@
+<!--
+Copyright (C) 2014 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.
+-->
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/qs_detail_transition" />
+ <item android:drawable="@color/system_primary_color" />
+</transition>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml
index c0252fa..26d2632 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_1x.xml
@@ -14,15 +14,14 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="18dp"
+ android:width="9.0dp"
android:height="18dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="12.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M4.300000,11.000000L2.700000,11.000000L2.700000,4.400000L1.000000,5.100000L1.000000,3.700000l3.100000,-1.300000l0.200000,0.000000L4.300000,11.000000z"/>
+ android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/>
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M9.500000,5.500000l1.200000,-3.000000l1.900000,0.000000l-2.100000,4.200000l2.200000,4.300000l-1.900000,0.000000L9.500000,7.900000L8.300000,11.000000L6.300000,11.000000l2.100000,-4.300000L6.400000,2.500000l1.900000,0.000000L9.500000,5.500000z"/>
+ android:pathData="M8.600000,5.500000l1.200000,-3.000000l1.900000,0.000000L9.700000,6.700000l2.200000,4.300000L9.900000,11.000000L8.700000,7.900000L7.400000,11.000000L5.500000,11.000000l2.100000,-4.300000L5.600000,2.500000l1.900000,0.000000L8.600000,5.500000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml
index 9a6a032..5aaf93b 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_3g.xml
@@ -14,15 +14,14 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="18dp"
+ android:width="9.75dp"
android:height="18dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="13.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M2.600000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.700000,3.700000 3.500000,3.700000C3.200000,3.700000 3.000000,3.800000 2.900000,4.000000S2.600000,4.400000 2.600000,4.700000L1.000000,4.700000C1.000000,4.000000 1.200000,3.400000 1.700000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000S6.000000,4.000000 6.000000,4.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S5.200000,6.500000 4.800000,6.600000c0.400000,0.200000 0.700000,0.400000 0.900000,0.800000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000l1.700000,0.000000c0.000000,0.300000 0.100000,0.600000 0.300000,0.800000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S4.400000,9.000000 4.400000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.700000,7.300000 3.400000,7.300000L2.600000,7.300000L2.600000,6.000000z"/>
+ android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/>
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M13.100000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S7.300000,9.000000 7.300000,7.900000L7.300000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000S13.000000,4.200000 13.000000,5.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.900000,5.000000 8.900000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L11.299999,7.800000l-1.300000,0.000000L9.999999,6.600000l2.900000,0.000000L12.900000,9.900000z"/>
+ android:pathData="M12.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.700000,9.000000 6.700000,7.900000L6.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.400000,5.000000 8.400000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.799999,7.800000L9.600000,7.800000L9.600000,6.600000l2.900000,0.000000L12.500000,9.900000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml
index 44f8cb1..b7d84f0 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_4g.xml
@@ -14,15 +14,14 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="18dp"
+ android:width="9.0dp"
android:height="18dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="12.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M5.700000,7.800000l0.700000,0.000000l0.000000,1.300000L5.700000,9.100000L5.700000,11.000000L4.000000,11.000000L4.000000,9.200000L1.200000,9.200000l-0.100000,-1.000000L4.000000,2.500000l1.700000,0.000000L5.700000,7.800000zM2.700000,7.800000L4.000000,7.800000l0.000000,-3.000000L4.000000,5.000000L2.700000,7.800000z"/>
+ android:pathData="M4.600000,7.800000l0.700000,0.000000l0.000000,1.300000L4.600000,9.100000L4.600000,11.000000L3.000000,11.000000L3.000000,9.200000L0.100000,9.200000L0.000000,8.100000L3.000000,2.500000l1.700000,0.000000L4.700000,7.800000zM1.600000,7.800000L3.000000,7.800000l0.000000,-3.000000L2.900000,5.000000L1.600000,7.800000z"/>
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M13.000000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S7.200000,9.000000 7.200000,7.900000L7.200000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000s-0.500000,-0.300000 -0.900000,-0.300000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S8.800000,5.000000 8.800000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L11.200000,7.800000l-1.300000,0.000000L9.900000,6.600000L13.000000,6.600000L13.000000,9.900000z"/>
+ android:pathData="M11.900000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S6.100000,9.000000 6.100000,7.900000L6.100000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000S8.100000,2.400000 9.000000,2.400000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000l-1.600000,0.000000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S9.500000,3.700000 9.000000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S7.700000,5.000000 7.700000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L10.099999,7.800000L9.000000,7.800000L9.000000,6.600000l2.900000,0.000000L11.900000,9.900000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml
index e9014ee..7111457 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_e.xml
@@ -14,12 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="18dp"
+ android:width="3.75dp"
android:height="18dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="5.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M5.900000,7.300000L3.100000,7.300000l0.000000,2.400000l3.300000,0.000000L6.400000,11.000000L1.400000,11.000000L1.400000,2.500000l4.900000,0.000000l0.000000,1.300000L3.100000,3.800000l0.000000,2.100000l2.800000,0.000000L5.900000,7.300000z"/>
+ android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml
index fcda0ad..97962b2 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_g.xml
@@ -14,12 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="18dp"
+ android:width="5.25dp"
android:height="18dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="7.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M7.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S1.700000,9.000000 1.700000,7.900000L1.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L5.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S5.000000,3.700000 4.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S3.300000,5.000000 3.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L5.700000,7.800000L4.500000,7.800000L4.500000,6.600000l2.900000,0.000000L7.400000,9.900000z"/>
+ android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml
index b5e9695..4859c14 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_h.xml
@@ -14,12 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="18dp"
+ android:width="4.5dp"
android:height="18dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="6.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M7.700000,11.000000L6.000000,11.000000L6.000000,7.500000L3.400000,7.500000L3.400000,11.000000L1.700000,11.000000L1.700000,2.500000l1.700000,0.000000l0.000000,3.700000L6.000000,6.200000L6.000000,2.500000l1.600000,0.000000L7.600000,11.000000z"/>
+ android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml
index a0cbe5f..d6446db 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_lte.xml
@@ -14,10 +14,9 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="18dp"
+ android:width="9.75dp"
android:height="18dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="13.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_roam.xml b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_roam.xml
index 4a542f9..7f7d5fc 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_roam.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_fully_connected_roam.xml
@@ -14,12 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="18dp"
+ android:width="4.5dp"
android:height="18dp"
- android:viewportWidth="24.0"
+ android:viewportWidth="6.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M4.100000,7.900000l-1.000000,0.000000L3.100000,11.000000L1.400000,11.000000L1.400000,2.500000l2.700000,0.000000c0.900000,0.000000 1.500000,0.200000 2.000000,0.700000s0.700000,1.100000 0.700000,1.900000c0.000000,0.600000 -0.100000,1.100000 -0.300000,1.500000S6.000000,7.200000 5.600000,7.400000l1.500000,3.500000L7.100000,11.000000L5.400000,11.000000L4.100000,7.900000zM3.100000,6.500000l1.100000,0.000000c0.400000,0.000000 0.600000,-0.100000 0.800000,-0.400000s0.300000,-0.600000 0.300000,-1.000000c0.000000,-0.400000 -0.100000,-0.800000 -0.300000,-1.000000S4.600000,3.800000 4.200000,3.800000L3.100000,3.800000L3.100000,6.500000z"/>
+ android:pathData="M2.800000,7.900000l-1.000000,0.000000L1.800000,11.000000L0.200000,11.000000L0.200000,2.500000l2.700000,0.000000c0.900000,0.000000 1.500000,0.200000 2.000000,0.700000s0.700000,1.100000 0.700000,1.900000c0.000000,0.600000 -0.100000,1.100000 -0.300000,1.500000S4.800000,7.200000 4.400000,7.400000l1.500000,3.500000L5.900000,11.000000L4.100000,11.000000L2.800000,7.900000zM1.800000,6.500000l1.100000,0.000000c0.400000,0.000000 0.600000,-0.100000 0.800000,-0.400000S4.000000,5.600000 4.000000,5.200000c0.000000,-0.400000 -0.100000,-0.800000 -0.300000,-1.000000S3.300000,3.800000 2.900000,3.800000L1.800000,3.800000L1.800000,6.500000z"/>
</vector>
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index ca46437..c6a7368 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -17,7 +17,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/system_primary_color"
+ android:background="@drawable/qs_detail_background"
android:padding="16dp" >
<TextView
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a718f4f..a63deb0 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -44,6 +44,7 @@
<color name="qs_tile_text">#B3FFFFFF</color><!-- 70% white -->
<color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
<color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200-->
+ <color name="qs_detail_transition">#66FFFFFF</color>
<color name="data_usage_secondary">#99FFFFFF</color><!-- 60% white -->
<color name="data_usage_graph_track">#33FFFFFF</color><!-- 20% white -->
<color name="data_usage_graph_warning">#FFFFFFFF</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 127bdbe..32425ad 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -395,4 +395,8 @@
<!-- Margin on the left side of the battery % when on Keyguard. -->
<dimen name="header_battery_margin_keyguard">6dp</dimen>
+
+ <!-- Additional translation (downwards) for appearing notifications when going to the full shade
+ from Keyguard. -->
+ <dimen name="go_to_full_shade_appearing_translation">200dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 085d2f9..296cdad 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -86,16 +86,13 @@
<string name="battery_low_why">Settings</string>
<!-- Battery saver confirmation dialog title [CHAR LIMIT=NONE]-->
- <string name="battery_saver_confirmation_title">Start battery saver?</string>
+ <string name="battery_saver_confirmation_title">Turn on battery saver?</string>
<!-- Battery saver confirmation dialog ok text [CHAR LIMIT=40]-->
- <string name="battery_saver_confirmation_ok">Start</string>
+ <string name="battery_saver_confirmation_ok">Turn on</string>
<!-- Battery saver notification action [CHAR LIMIT=NONE]-->
- <string name="battery_saver_start_action">Start battery saver</string>
-
- <!-- Battery saver confirmation dialog text [CHAR LIMIT=NONE]-->
- <string name="battery_saver_confirmation_text">To help improve battery life, Battery saver will reduce your device’s performance.\n\nBattery saver will be disabled when your device is plugged in.</string>
+ <string name="battery_saver_start_action">Turn on battery saver</string>
<!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] -->
<string name="status_bar_settings_settings_button">Settings</string>
@@ -719,10 +716,10 @@
<string name="battery_saver_notification_title">Battery saver is on</string>
<!-- Battery saver notification text. [CHAR LIMIT=60] -->
- <string name="battery_saver_notification_text">Device performance is reduced.</string>
+ <string name="battery_saver_notification_text">Reduces performance and background data</string>
<!-- Battery saver notification action text. [CHAR LIMIT=60] -->
- <string name="battery_saver_notification_action_text">Open battery saver settings</string>
+ <string name="battery_saver_notification_action_text">Turn off battery saver</string>
<!-- Battery level for expanded quick settings [CHAR LIMIT=2] -->
<string name="battery_level_template"><xliff:g id="level" example="45">%d</xliff:g>%%</string>
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
index aa32e9c..5f2c348 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
+++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
@@ -6,6 +6,7 @@
# PhoneStatusBar.java
# ---------------------------
36000 sysui_statusbar_touch (type|1),(x|1),(y|1),(enabled|1)
+36001 sysui_heads_up_status (key|3),(visible|1)
# ---------------------------
# PhoneStatusBarView.java
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
index 2943494..79fadbd 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
@@ -48,7 +48,6 @@
private int mBucket;
private long mScreenOffTime;
private boolean mSaver;
- private int mSaverTriggerLevel;
private AlertDialog mInvalidChargerDialog;
private AlertDialog mLowBatteryDialog;
@@ -222,9 +221,4 @@
public void showSaverMode(boolean mode) {
mSaver = mode;
}
-
- @Override
- public void setSaverTrigger(int level) {
- mSaverTriggerLevel = level;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 186b570..9ffe0ef 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -16,7 +16,6 @@
package com.android.systemui.power;
-import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -25,9 +24,10 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.IntentFilter;
-import android.media.AudioManager;
+import android.media.AudioAttributes;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
@@ -35,11 +35,10 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
-import android.view.ContextThemeWrapper;
import android.view.View;
-import android.view.WindowManager;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
import java.io.PrintWriter;
@@ -66,9 +65,14 @@
private static final String ACTION_SHOW_FALLBACK_CHARGER = "PNW.chargerFallback";
private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
private static final String ACTION_START_SAVER = "PNW.startSaver";
+ private static final String ACTION_STOP_SAVER = "PNW.stopSaver";
+
+ private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .build();
private final Context mContext;
- private final Context mLightContext;
private final NotificationManager mNoMan;
private final Handler mHandler = new Handler();
private final PowerDialogWarnings mFallbackDialogs;
@@ -84,15 +88,13 @@
private long mBucketDroppedNegativeTimeMs;
private boolean mSaver;
- private int mSaverTriggerLevel;
private boolean mWarning;
private boolean mPlaySound;
private boolean mInvalidCharger;
+ private SystemUIDialog mSaverConfirmation;
public PowerNotificationWarnings(Context context) {
mContext = context;
- mLightContext = new ContextThemeWrapper(mContext,
- android.R.style.Theme_DeviceDefault_Light);
mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mFallbackDialogs = new PowerDialogWarnings(context);
mReceiver.init();
@@ -105,6 +107,7 @@
pw.print("mPlaySound="); pw.println(mPlaySound);
pw.print("mInvalidCharger="); pw.println(mInvalidCharger);
pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]);
+ pw.print("mSaverConfirmation="); pw.println(mSaverConfirmation != null ? "not null" : null);
}
@Override
@@ -123,12 +126,9 @@
@Override
public void showSaverMode(boolean mode) {
mSaver = mode;
- updateNotification();
- }
-
- @Override
- public void setSaverTrigger(int level) {
- mSaverTriggerLevel = level;
+ if (mSaver && mSaverConfirmation != null) {
+ mSaverConfirmation.dismiss();
+ }
updateNotification();
}
@@ -180,6 +180,7 @@
.setContentTitle(mContext.getString(R.string.battery_low_title))
.setContentText(mContext.getString(textRes, mBatteryLevel))
.setOngoing(true)
+ .setOnlyAlertOnce(true)
.setPriority(Notification.PRIORITY_MAX)
.setCategory(Notification.CATEGORY_SYSTEM)
.setVisibility(Notification.VISIBILITY_PUBLIC)
@@ -187,10 +188,12 @@
if (hasBatterySettings()) {
nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
}
- if (!mSaver && mSaverTriggerLevel <= 0) {
+ if (!mSaver) {
nb.addAction(R.drawable.ic_power_saver,
mContext.getString(R.string.battery_saver_start_action),
pendingBroadcast(ACTION_START_SAVER));
+ } else {
+ addStopSaverAction(nb);
}
if (mPlaySound) {
attachLowBatterySound(nb);
@@ -208,19 +211,28 @@
.setContentTitle(mContext.getString(R.string.battery_saver_notification_title))
.setContentText(mContext.getString(R.string.battery_saver_notification_text))
.setOngoing(true)
- .setWhen(0)
.setShowWhen(false)
.setCategory(Notification.CATEGORY_SYSTEM)
.setVisibility(Notification.VISIBILITY_PUBLIC);
+ addStopSaverAction(nb);
if (hasSaverSettings()) {
- nb.addAction(0,
- mContext.getString(R.string.battery_saver_notification_action_text),
- pendingActivity(mOpenSaverSettings));
nb.setContentIntent(pendingActivity(mOpenSaverSettings));
}
mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.CURRENT);
}
+ private void addStopSaverAction(Notification.Builder nb) {
+ nb.addAction(R.drawable.ic_power_saver,
+ mContext.getString(R.string.battery_saver_notification_action_text),
+ pendingBroadcast(ACTION_STOP_SAVER));
+ }
+
+ private void dismissSaverNotification() {
+ if (mSaver) Slog.i(TAG, "dismissing saver notification");
+ mSaver = false;
+ updateNotification();
+ }
+
private PendingIntent pendingActivity(Intent intent) {
return PendingIntent.getActivityAsUser(mContext,
0, intent, 0, null, UserHandle.CURRENT);
@@ -307,8 +319,8 @@
if (soundPath != null) {
final Uri soundUri = Uri.parse("file://" + soundPath);
if (soundUri != null) {
- b.setSound(soundUri, AudioManager.STREAM_SYSTEM);
- Slog.d(TAG, "playing sound " + soundUri);
+ b.setSound(soundUri, AUDIO_ATTRIBUTES);
+ if (DEBUG) Slog.d(TAG, "playing sound " + soundUri);
}
}
}
@@ -333,17 +345,21 @@
}
private void showStartSaverConfirmation() {
- final AlertDialog d = new AlertDialog.Builder(mLightContext)
- .setTitle(R.string.battery_saver_confirmation_title)
- .setMessage(R.string.battery_saver_confirmation_text)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(R.string.battery_saver_confirmation_ok, mStartSaverMode)
- .create();
-
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
- d.getWindow().getAttributes().privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ if (mSaverConfirmation != null) return;
+ final SystemUIDialog d = new SystemUIDialog(mContext);
+ d.setTitle(R.string.battery_saver_confirmation_title);
+ d.setMessage(com.android.internal.R.string.battery_saver_description);
+ d.setNegativeButton(android.R.string.cancel, null);
+ d.setPositiveButton(R.string.battery_saver_confirmation_ok, mStartSaverMode);
+ d.setShowForAllUsers(true);
+ d.setOnDismissListener(new OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ mSaverConfirmation = null;
+ }
+ });
d.show();
+ mSaverConfirmation = d;
}
private void setSaverSetting(boolean mode) {
@@ -359,6 +375,7 @@
filter.addAction(ACTION_SHOW_FALLBACK_CHARGER);
filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
filter.addAction(ACTION_START_SAVER);
+ filter.addAction(ACTION_STOP_SAVER);
mContext.registerReceiver(this, filter, null, mHandler);
}
@@ -378,6 +395,10 @@
} else if (action.equals(ACTION_START_SAVER)) {
dismissLowBatteryNotification();
showStartSaverConfirmation();
+ } else if (action.equals(ACTION_STOP_SAVER)) {
+ dismissSaverNotification();
+ dismissLowBatteryNotification();
+ setSaverSetting(false);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 1bb7edb..ccef8eb 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -22,13 +22,13 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
-import android.net.Uri;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.Log;
import android.util.Slog;
import com.android.systemui.SystemUI;
@@ -39,11 +39,9 @@
public class PowerUI extends SystemUI {
static final String TAG = "PowerUI";
- static final boolean DEBUG = false;
-
+ static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Handler mHandler = new Handler();
- private final SettingsObserver mObserver = new SettingsObserver(mHandler);
private final Receiver mReceiver = new Receiver();
private PowerManager mPowerManager;
@@ -75,17 +73,12 @@
false, obs, UserHandle.USER_ALL);
updateBatteryWarningLevels();
mReceiver.init();
- mObserver.init();
}
private void setSaverMode(boolean mode) {
mWarnings.showSaverMode(mode);
}
- private void setSaverTrigger(int level) {
- mWarnings.setSaverTrigger(level);
- }
-
void updateBatteryWarningLevels() {
int critLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
@@ -143,6 +136,7 @@
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
mContext.registerReceiver(this, filter, null, mHandler);
updateSaverMode();
@@ -214,6 +208,8 @@
mScreenOffTime = -1;
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
updateSaverMode();
+ } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) {
+ setSaverMode(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
} else {
Slog.w(TAG, "unknown intent: " + intent);
}
@@ -251,7 +247,6 @@
public interface WarningsUI {
void update(int batteryLevel, int bucket, long screenOffTime);
- void setSaverTrigger(int level);
void showSaverMode(boolean mode);
void dismissLowBatteryWarning();
void showLowBatteryWarning(boolean playSound);
@@ -261,29 +256,5 @@
boolean isInvalidChargerWarningShowing();
void dump(PrintWriter pw);
}
-
- private final class SettingsObserver extends ContentObserver {
- private final Uri LOW_POWER_MODE_TRIGGER_LEVEL_URI =
- Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL);
-
- public SettingsObserver(Handler handler) {
- super(handler);
- }
-
- public void init() {
- onChange(true, LOW_POWER_MODE_TRIGGER_LEVEL_URI);
- final ContentResolver cr = mContext.getContentResolver();
- cr.registerContentObserver(LOW_POWER_MODE_TRIGGER_LEVEL_URI, false, this);
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (LOW_POWER_MODE_TRIGGER_LEVEL_URI.equals(uri)) {
- final int level = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
- setSaverTrigger(level);
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java b/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java
deleted file mode 100644
index 90275c1..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2014 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.qs;
-
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
-import android.view.View;
-import android.view.ViewAnimationUtils;
-
-/** Helper for view-level circular clip animations. **/
-public class CircularClipper {
-
- private final View mTarget;
-
- private Animator mAnimator;
-
- public CircularClipper(View target) {
- mTarget = target;
- }
-
- public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- final int w = mTarget.getWidth() - x;
- final int h = mTarget.getHeight() - y;
- int r = (int) Math.ceil(Math.sqrt(x * x + y * y));
- r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + y * y)));
- r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + h * h)));
- r = (int) Math.max(r, Math.ceil(Math.sqrt(x * x + h * h)));
-
- mAnimator = ViewAnimationUtils.createCircularReveal(mTarget, x, y, 0, r);
- mAnimator.removeAllListeners();
- if (listener != null) {
- mAnimator.addListener(listener);
- }
- if (in) {
- mAnimator.addListener(mVisibleOnStart);
- mAnimator.start();
- } else {
- mAnimator.addListener(mGoneOnEnd);
- mAnimator.reverse();
- }
- }
-
- private final AnimatorListenerAdapter mVisibleOnStart = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mTarget.setVisibility(View.VISIBLE);
- }
- };
-
- private final AnimatorListenerAdapter mGoneOnEnd = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mTarget.setVisibility(View.GONE);
- };
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
new file mode 100644
index 0000000..9c1ff9d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 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.qs;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.graphics.drawable.TransitionDrawable;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+
+/** Helper for quick settings detail panel clip animations. **/
+public class QSDetailClipper {
+
+ private final View mDetail;
+ private final TransitionDrawable mBackground;
+
+ private Animator mAnimator;
+
+ public QSDetailClipper(View detail) {
+ mDetail = detail;
+ mBackground = (TransitionDrawable) detail.getBackground();
+ }
+
+ public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ final int w = mDetail.getWidth() - x;
+ final int h = mDetail.getHeight() - y;
+ int r = (int) Math.ceil(Math.sqrt(x * x + y * y));
+ r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + y * y)));
+ r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + h * h)));
+ r = (int) Math.max(r, Math.ceil(Math.sqrt(x * x + h * h)));
+ mAnimator = ViewAnimationUtils.createCircularReveal(mDetail, x, y, 0, r);
+ mAnimator.setDuration((long)(mAnimator.getDuration() * 1.5));
+ if (listener != null) {
+ mAnimator.addListener(listener);
+ }
+ mDetail.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ if (in) {
+ mBackground.startTransition((int)(mAnimator.getDuration() * 0.6));
+ mAnimator.addListener(mVisibleOnStart);
+ mAnimator.start();
+ } else {
+ mDetail.postDelayed(mReverseBackground, (long)(mAnimator.getDuration() * 0.65));
+ mAnimator.addListener(mGoneOnEnd);
+ mAnimator.reverse();
+ }
+ }
+
+ private final Runnable mReverseBackground = new Runnable() {
+ @Override
+ public void run() {
+ if (mAnimator != null) {
+ mBackground.reverseTransition((int)(mAnimator.getDuration() * 0.35));
+ }
+ }
+ };
+
+ private final AnimatorListenerAdapter mVisibleOnStart = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mDetail.setVisibility(View.VISIBLE);
+ }
+
+ public void onAnimationEnd(Animator animation) {
+ mDetail.setLayerType(View.LAYER_TYPE_NONE, null);
+ mAnimator = null;
+ }
+ };
+
+ private final AnimatorListenerAdapter mGoneOnEnd = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDetail.setLayerType(View.LAYER_TYPE_NONE, null);
+ mDetail.setVisibility(View.GONE);
+ mBackground.resetTransition();
+ mAnimator = null;
+ };
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 4901f40..1173053 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -49,7 +49,7 @@
private final View mDetailSettingsButton;
private final View mDetailDoneButton;
private final View mBrightnessView;
- private final CircularClipper mClipper;
+ private final QSDetailClipper mClipper;
private final H mHandler = new H();
private int mColumns;
@@ -85,7 +85,7 @@
R.layout.quick_settings_brightness_dialog, this, false);
addView(mDetail);
addView(mBrightnessView);
- mClipper = new CircularClipper(mDetail);
+ mClipper = new QSDetailClipper(mDetail);
updateResources();
mBrightnessController = new BrightnessController(getContext(),
@@ -95,7 +95,7 @@
mDetailDoneButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- showDetail(false, mDetailRecord);
+ closeDetail();
}
});
}
@@ -134,7 +134,7 @@
if (mExpanded == expanded) return;
mExpanded = expanded;
if (!mExpanded) {
- showDetail(false /*show*/, mDetailRecord);
+ closeDetail();
}
}
@@ -226,6 +226,14 @@
addView(r.tileView);
}
+ public boolean isShowingDetail() {
+ return mDetailRecord != null;
+ }
+
+ public void closeDetail() {
+ showDetail(false, mDetailRecord);
+ }
+
private void handleShowDetail(Record r, boolean show) {
if (r instanceof TileRecord) {
handleShowDetailTile((TileRecord) r, show);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index 6697751..1a555f1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -57,7 +57,7 @@
mSignal = new ImageView(mContext);
mIconFrame.addView(mSignal);
mOverlay = new ImageView(mContext);
- mIconFrame.addView(mOverlay);
+ mIconFrame.addView(mOverlay, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
return mIconFrame;
}
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 42da282..ce42d47 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -91,10 +91,9 @@
if (cb == null) return;
final Resources r = mContext.getResources();
- state.iconId = cb.noSim
- ? R.drawable.stat_sys_no_sim
- : cb.enabled && (cb.mobileSignalIconId > 0) && !cb.airplaneModeEnabled
- ? cb.mobileSignalIconId
+ state.iconId = cb.noSim ? R.drawable.stat_sys_no_sim
+ : !cb.enabled || cb.airplaneModeEnabled ? R.drawable.ic_qs_signal_disabled
+ : cb.mobileSignalIconId > 0 ? cb.mobileSignalIconId
: R.drawable.ic_qs_signal_no_signal;
state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiConnected
? cb.dataTypeIconId
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 1707b32..5651d49 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -113,7 +113,11 @@
state.filter = true;
final String signalContentDescription;
final Resources r = mContext.getResources();
- if (wifiConnected) {
+ if (!state.enabled) {
+ state.iconId = R.drawable.ic_qs_wifi_disabled;
+ state.label = r.getString(R.string.quick_settings_wifi_label);
+ signalContentDescription = r.getString(R.string.accessibility_wifi_off);
+ } else if (wifiConnected) {
state.iconId = cb.wifiSignalIconId;
state.label = removeDoubleQuotes(cb.enabledDesc);
signalContentDescription = cb.wifiSignalContentDescription;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 4534897..75fbad8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -383,9 +383,6 @@
filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
registerReceiver(mSystemBroadcastReceiver, filter);
- // Register any broadcast receivers for the task loader
- RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView);
-
// Private API calls to make the shadows look better
try {
Utilities.setShadowProperty("ambientShadowStrength", String.valueOf(35f));
@@ -451,6 +448,9 @@
filter.addAction(ACTION_TOGGLE_RECENTS_ACTIVITY);
filter.addAction(ACTION_START_ENTER_ANIMATION);
registerReceiver(mServiceBroadcastReceiver, filter);
+
+ // Register any broadcast receivers for the task loader
+ RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView);
}
@Override
@@ -481,9 +481,15 @@
protected void onStop() {
super.onStop();
+ // Remove all the views
+ mRecentsView.removeAllTaskStacks();
+
// Unregister the RecentsService receiver
unregisterReceiver(mServiceBroadcastReceiver);
+ // Unregister any broadcast receivers for the task loader
+ RecentsTaskLoader.getInstance().unregisterReceivers();
+
// Stop listening for widget package changes if there was one bound
if (mAppWidgetHost.isListening()) {
mAppWidgetHost.stopListening();
@@ -496,7 +502,6 @@
// Unregister the system broadcast receivers
unregisterReceiver(mSystemBroadcastReceiver);
- RecentsTaskLoader.getInstance().unregisterReceivers();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index cd2cbe7..1a32b81 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -121,6 +121,17 @@
}
}
+ /** Removes all the task stack views from this recents view. */
+ public void removeAllTaskStacks() {
+ int childCount = getChildCount();
+ for (int i = childCount - 1; i >= 0; i--) {
+ View child = getChildAt(i);
+ if (child != mSearchBar) {
+ removeViewAt(i);
+ }
+ }
+ }
+
/** Launches the focused task from the first stack if possible */
public boolean launchFocusedTask() {
// Get the first stack view
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 5771299..c559253 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -74,6 +74,8 @@
Runnable finisher;
int iconSize;
int result;
+ int previewWidth;
+ int previewheight;
void clearImage() {
image = null;
@@ -131,17 +133,19 @@
mImageWidth = data.image.getWidth();
mImageHeight = data.image.getHeight();
int iconSize = data.iconSize;
+ int previewWidth = data.previewWidth;
+ int previewHeight = data.previewheight;
final int shortSide = mImageWidth < mImageHeight ? mImageWidth : mImageHeight;
- Bitmap preview = Bitmap.createBitmap(shortSide, shortSide, data.image.getConfig());
+ Bitmap preview = Bitmap.createBitmap(previewWidth, previewHeight, data.image.getConfig());
Canvas c = new Canvas(preview);
Paint paint = new Paint();
ColorMatrix desat = new ColorMatrix();
desat.setSaturation(0.25f);
paint.setColorFilter(new ColorMatrixColorFilter(desat));
Matrix matrix = new Matrix();
- matrix.postTranslate((shortSide - mImageWidth) / 2,
- (shortSide - mImageHeight) / 2);
+ matrix.postTranslate((previewWidth - mImageWidth) / 2,
+ (previewHeight - mImageHeight) / 2);
c.drawBitmap(data.image, matrix, paint);
c.drawColor(0x40FFFFFF);
c.setBitmap(null);
@@ -343,6 +347,8 @@
private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f;
private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f;
private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f;
+ private final int mPreviewWidth;
+ private final int mPreviewHeight;
private Context mContext;
private WindowManager mWindowManager;
@@ -418,6 +424,16 @@
mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);
mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;
+ // determine the optimal preview size
+ int panelWidth = 0;
+ try {
+ panelWidth = r.getDimensionPixelSize(R.dimen.notification_panel_width);
+ } catch (Resources.NotFoundException e) {
+ panelWidth = mDisplayMetrics.widthPixels;
+ }
+ mPreviewWidth = panelWidth;
+ mPreviewHeight = r.getDimensionPixelSize(R.dimen.notification_max_height);
+
// Setup the Camera shutter sound
mCameraSound = new MediaActionSound();
mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
@@ -432,6 +448,8 @@
data.image = mScreenBitmap;
data.iconSize = mNotificationIconSize;
data.finisher = finisher;
+ data.previewWidth = mPreviewWidth;
+ data.previewheight = mPreviewHeight;
if (mSaveInBgTask != null) {
mSaveInBgTask.cancel(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 4d7698a..1cd18a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -43,7 +43,6 @@
import android.view.animation.PathInterpolator;
import com.android.systemui.R;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -449,19 +448,20 @@
}
@Override
- public void performRemoveAnimation(float translationDirection, Runnable onFinishedRunnable) {
+ public void performRemoveAnimation(long duration, float translationDirection,
+ Runnable onFinishedRunnable) {
enableAppearDrawing(true);
if (mDrawingAppearAnimation) {
startAppearAnimation(false /* isAppearing */, translationDirection,
- 0, onFinishedRunnable);
+ 0, duration, onFinishedRunnable);
}
}
@Override
- public void performAddAnimation(long delay) {
+ public void performAddAnimation(long delay, long duration) {
enableAppearDrawing(true);
if (mDrawingAppearAnimation) {
- startAppearAnimation(true /* isAppearing */, -1.0f, delay, null);
+ startAppearAnimation(true /* isAppearing */, -1.0f, delay, duration, null);
}
}
@@ -470,8 +470,8 @@
mScrimView.setAlpha(scrimAmount);
}
- private void startAppearAnimation(boolean isAppearing,
- float translationDirection, long delay, final Runnable onFinishedRunnable) {
+ private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
+ long duration, final Runnable onFinishedRunnable) {
if (mAppearAnimator != null) {
mAppearAnimator.cancel();
}
@@ -501,8 +501,7 @@
targetValue);
mAppearAnimator.setInterpolator(mLinearInterpolator);
mAppearAnimator.setDuration(
- (long) (StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR
- * Math.abs(mAppearAnimationFraction - targetValue)));
+ (long) (duration * Math.abs(mAppearAnimationFraction - targetValue)));
mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 4b037d2..03508ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1324,31 +1324,30 @@
return entry.notification;
}
- protected NotificationData.Entry createNotificationViews(StatusBarNotification notification) {
+ protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
if (DEBUG) {
- Log.d(TAG, "createNotificationViews(notification=" + notification);
+ Log.d(TAG, "createNotificationViews(notification=" + sbn);
}
// Construct the icon.
+ Notification n = sbn.getNotification();
final StatusBarIconView iconView = new StatusBarIconView(mContext,
- notification.getPackageName() + "/0x" + Integer.toHexString(notification.getId()),
- notification.getNotification());
+ sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
- final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
- notification.getUser(),
- notification.getNotification().icon,
- notification.getNotification().iconLevel,
- notification.getNotification().number,
- notification.getNotification().tickerText);
+ final StatusBarIcon ic = new StatusBarIcon(sbn.getPackageName(),
+ sbn.getUser(),
+ n.icon,
+ n.iconLevel,
+ n.number,
+ n.tickerText);
if (!iconView.set(ic)) {
- handleNotificationError(notification, "Couldn't create icon: " + ic);
+ handleNotificationError(sbn, "Couldn't create icon: " + ic);
return null;
}
// Construct the expanded view.
- NotificationData.Entry entry = new NotificationData.Entry(notification, iconView);
+ NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
if (!inflateViews(entry, mStackScroller)) {
- handleNotificationError(notification, "Couldn't expand RemoteViews for: "
- + notification);
+ handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
return null;
}
return entry;
@@ -1464,15 +1463,16 @@
// XXX: modify when we do something more intelligent with the two content views
final RemoteViews oldContentView = oldNotification.getNotification().contentView;
- final RemoteViews contentView = notification.getNotification().contentView;
+ Notification n = notification.getNotification();
+ final RemoteViews contentView = n.contentView;
final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView;
- final RemoteViews bigContentView = notification.getNotification().bigContentView;
+ final RemoteViews bigContentView = n.bigContentView;
final RemoteViews oldHeadsUpContentView = oldNotification.getNotification().headsUpContentView;
- final RemoteViews headsUpContentView = notification.getNotification().headsUpContentView;
+ final RemoteViews headsUpContentView = n.headsUpContentView;
final Notification oldPublicNotification = oldNotification.getNotification().publicVersion;
final RemoteViews oldPublicContentView = oldPublicNotification != null
? oldPublicNotification.contentView : null;
- final Notification publicNotification = notification.getNotification().publicVersion;
+ final Notification publicNotification = n.publicVersion;
final RemoteViews publicContentView = publicNotification != null
? publicNotification.contentView : null;
@@ -1484,7 +1484,7 @@
+ " bigContentView=" + oldBigContentView
+ " publicView=" + oldPublicContentView
+ " rowParent=" + oldEntry.row.getParent());
- Log.d(TAG, "new notification: when=" + notification.getNotification().when
+ Log.d(TAG, "new notification: when=" + n.when
+ " ongoing=" + oldNotification.isOngoing()
+ " contentView=" + contentView
+ " bigContentView=" + bigContentView
@@ -1521,8 +1521,8 @@
&& oldPublicContentView.getPackage() != null
&& oldPublicContentView.getPackage().equals(publicContentView.getPackage())
&& oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
- boolean updateTicker = notification.getNotification().tickerText != null
- && !TextUtils.equals(notification.getNotification().tickerText,
+ boolean updateTicker = n.tickerText != null
+ && !TextUtils.equals(n.tickerText,
oldEntry.notification.getNotification().tickerText);
final boolean shouldInterrupt = shouldInterrupt(notification);
@@ -1537,10 +1537,11 @@
// Update the icon
final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
notification.getUser(),
- notification.getNotification().icon,
- notification.getNotification().iconLevel,
- notification.getNotification().number,
- notification.getNotification().tickerText);
+ n.icon,
+ n.iconLevel,
+ n.number,
+ n.tickerText);
+ oldEntry.icon.setNotification(n);
if (!oldEntry.icon.set(ic)) {
handleNotificationError(notification, "Couldn't update icon: " + ic);
return;
@@ -1607,10 +1608,11 @@
oldEntry.notification = notification;
final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
notification.getUser(),
- notification.getNotification().icon,
- notification.getNotification().iconLevel,
- notification.getNotification().number,
- notification.getNotification().tickerText);
+ n.icon,
+ n.iconLevel,
+ n.number,
+ n.tickerText);
+ oldEntry.icon.setNotification(n);
oldEntry.icon.set(ic);
inflateViews(oldEntry, mStackScroller, wasHeadsUp);
mNotificationData.updateRanking(ranking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
index d60c17f..9712ee2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
@@ -116,12 +116,15 @@
}
@Override
- public void performRemoveAnimation(float translationDirection, Runnable onFinishedRunnable) {
+ public void performRemoveAnimation(long duration, float translationDirection,
+ Runnable onFinishedRunnable) {
+ // TODO: Use duration
performVisibilityAnimation(false);
}
@Override
- public void performAddAnimation(long delay) {
+ public void performAddAnimation(long delay, long duration) {
+ // TODO: use delay and duration
performVisibilityAnimation(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index e9989ab..df475d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -127,9 +127,7 @@
return true;
case MotionEvent.ACTION_UP:
if (mDraggedFarEnough && mDragDownCallback.onDraggedDown(mStartingChild)) {
- if (mStartingChild != null) {
- mCallback.setUserLockedChild(mStartingChild, false);
- } else {
+ if (mStartingChild == null) {
mDragDownCallback.setEmptyDragAmount(0f);
}
mDraggingDown = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 4b0af11..0960c00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -37,6 +37,9 @@
private boolean mUserLocked;
/** Are we showing the "public" version */
private boolean mShowingPublic;
+ private boolean mSensitive;
+ private boolean mShowingPublicInitialized;
+ private boolean mShowingPublicForIntrinsicHeight;
/**
* Is this notification expanded by the system. The expansion state can be overridden by the
@@ -78,6 +81,8 @@
mHasUserChangedExpansion = false;
mUserLocked = false;
mShowingPublic = false;
+ mSensitive = false;
+ mShowingPublicInitialized = false;
mIsSystemExpanded = false;
mExpansionDisabled = false;
mPublicLayout.reset();
@@ -222,7 +227,7 @@
return mRowMinHeight;
}
- return mShowingPublic ? mRowMinHeight : getMaxExpandHeight();
+ return mShowingPublicForIntrinsicHeight ? mRowMinHeight : getMaxExpandHeight();
}
/**
@@ -248,17 +253,64 @@
}
}
- public void setShowingPublic(boolean show) {
- mShowingPublic = show;
+ public void setSensitive(boolean sensitive) {
+ mSensitive = sensitive;
+ }
+
+ public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
+ mShowingPublicForIntrinsicHeight = mSensitive && hideSensitive;
+ }
+
+ public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
+ long duration) {
+ boolean oldShowingPublic = mShowingPublic;
+ mShowingPublic = mSensitive && hideSensitive;
+ if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
+ return;
+ }
// bail out if no public version
if (mPublicLayout.getChildCount() == 0) return;
- // TODO: animation?
- mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
- mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
+ if (!animated) {
+ mPublicLayout.animate().cancel();
+ mPrivateLayout.animate().cancel();
+ mPublicLayout.setAlpha(1f);
+ mPrivateLayout.setAlpha(1f);
+ mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
+ mPrivateLayout.setVisibility(mShowingPublic ? View.INVISIBLE : View.VISIBLE);
+ } else {
+ animateShowingPublic(delay, duration);
+ }
updateVetoButton();
+ mShowingPublicInitialized = true;
+ }
+
+ private void animateShowingPublic(long delay, long duration) {
+ final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
+ View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
+ source.setVisibility(View.VISIBLE);
+ target.setVisibility(View.VISIBLE);
+ target.setAlpha(0f);
+ source.animate().cancel();
+ target.animate().cancel();
+ source.animate()
+ .alpha(0f)
+ .withLayer()
+ .setStartDelay(delay)
+ .setDuration(duration)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ source.setVisibility(View.INVISIBLE);
+ }
+ });
+ target.animate()
+ .alpha(1f)
+ .withLayer()
+ .setStartDelay(delay)
+ .setDuration(duration);
}
private void updateVetoButton() {
@@ -267,7 +319,7 @@
}
public int getMaxExpandHeight() {
- return mShowingPublic ? mRowMinHeight : mMaxExpandHeight;
+ return mShowingPublicForIntrinsicHeight ? mRowMinHeight : mMaxExpandHeight;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index b71cd77..46d4a9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -176,6 +176,23 @@
}
/**
+ * See {@link #setHideSensitive}. This is a variant which notifies this view in advance about
+ * the upcoming state of hiding sensitive notifications. It gets called at the very beginning
+ * of a stack scroller update such that the updated intrinsic height (which is dependent on
+ * whether private or public layout is showing) gets taken into account into all layout
+ * calculations.
+ */
+ public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
+ }
+
+ /**
+ * Sets whether the notification should hide its private contents if it is sensitive.
+ */
+ public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
+ long duration) {
+ }
+
+ /**
* @return The desired notification height.
*/
public int getIntrinsicHeight() {
@@ -220,6 +237,7 @@
/**
* Perform a remove animation on this view.
*
+ * @param duration The duration of the remove animation.
* @param translationDirection The direction value from [-1 ... 1] indicating in which the
* animation should be performed. A value of -1 means that The
* remove animation should be performed upwards,
@@ -227,10 +245,10 @@
* Should mean the opposite.
* @param onFinishedRunnable A runnable which should be run when the animation is finished.
*/
- public abstract void performRemoveAnimation(float translationDirection,
+ public abstract void performRemoveAnimation(long duration, float translationDirection,
Runnable onFinishedRunnable);
- public abstract void performAddAnimation(long delay);
+ public abstract void performAddAnimation(long delay, long duration);
public abstract void setScrimAmount(float scrimAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
index dfeadc5..816612b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -76,23 +76,25 @@
return true;
}
- public void performVisibilityAnimation(boolean nowVisible) {
- animateDivider(nowVisible, null /* onFinishedRunnable */);
+ public void performVisibilityAnimation(boolean nowVisible, long delay) {
+ animateDivider(nowVisible, delay, null /* onFinishedRunnable */);
}
/**
* Animate the divider to a new visibility.
*
* @param nowVisible should it now be visible
+ * @param delay the delay after the animation should start
* @param onFinishedRunnable A runnable which should be run when the animation is
* finished.
*/
- public void animateDivider(boolean nowVisible, Runnable onFinishedRunnable) {
+ public void animateDivider(boolean nowVisible, long delay, Runnable onFinishedRunnable) {
if (nowVisible != mIsVisible) {
// Animate dividers
float endValue = nowVisible ? 1.0f : 0.0f;
mLine.animate()
.alpha(endValue)
+ .setStartDelay(delay)
.scaleX(endValue)
.scaleY(endValue)
.setInterpolator(mFastOutSlowInInterpolator)
@@ -113,13 +115,16 @@
}
@Override
- public void performRemoveAnimation(float translationDirection, Runnable onFinishedRunnable) {
- performVisibilityAnimation(false);
+ public void performRemoveAnimation(long duration, float translationDirection,
+ Runnable onFinishedRunnable) {
+ // TODO: Use duration
+ performVisibilityAnimation(false, 0 /* delay */);
}
@Override
- public void performAddAnimation(long delay) {
- performVisibilityAnimation(true);
+ public void performAddAnimation(long delay, long duration) {
+ // TODO: Use duration
+ performVisibilityAnimation(true, delay);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 6f839bd..20dd3e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -57,8 +57,7 @@
mNumberPain.setTextAlign(Paint.Align.CENTER);
mNumberPain.setColor(res.getColor(R.drawable.notification_number_text_color));
mNumberPain.setAntiAlias(true);
- mNotification = notification;
- setContentDescription(notification);
+ setNotification(notification);
// We do not resize and scale system icons (on the right), only notification icons (on the
// left).
@@ -73,6 +72,11 @@
setScaleType(ImageView.ScaleType.CENTER);
}
+ public void setNotification(Notification notification) {
+ mNotification = notification;
+ setContentDescription(notification);
+ }
+
public StatusBarIconView(Context context, AttributeSet attrs) {
super(context, attrs);
final Resources res = context.getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index e6ffde0..8996197 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -47,7 +47,6 @@
private StatusBarWindowManager mWindowManager;
private KeyguardViewBase mKeyguardView;
private ViewGroup mRoot;
- private Interpolator mFadeOutInterpolator = new LinearInterpolator();
private boolean mFadingOut;
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
@@ -101,7 +100,7 @@
// Make it disappear faster, as the focus should be on the activity behind.
.setDuration(duration / 2)
- .setInterpolator(mFadeOutInterpolator)
+ .setInterpolator(PhoneStatusBar.ALPHA_OUT)
.setStartDelay(delay)
.withEndAction(new Runnable() {
@Override
@@ -109,7 +108,8 @@
mFadingOut = false;
hide(true /* destroyView */);
}
- });
+ })
+ .start();
} else {
hide(true /* destroyView */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 602b914..53c4740 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
@@ -92,6 +93,8 @@
private boolean mQsExpandedWhenExpandingStarted;
private boolean mQsFullyExpanded;
private boolean mKeyguardShowing;
+ private boolean mDozing;
+ private boolean mKeyguardStatusBarTransparent;
private int mStatusBarState;
private float mInitialHeightOnTouch;
private float mInitialTouchX;
@@ -115,6 +118,7 @@
private Interpolator mFastOutSlowInInterpolator;
private Interpolator mFastOutLinearInterpolator;
+ private Interpolator mLinearOutSlowInInterpolator;
private ObjectAnimator mClockAnimator;
private int mClockAnimationTarget = -1;
private int mTopPaddingAdjustment;
@@ -139,7 +143,9 @@
private boolean mIsLaunchTransitionRunning;
private Runnable mLaunchAnimationEndRunnable;
private boolean mOnlyAffordanceInThisMotion;
- private boolean mKeyguardStatusBarAnimatingIn;
+ private boolean mKeyguardStatusViewAnimating;
+ private boolean mHeaderAnimatingIn;
+ private ObjectAnimator mQsContainerAnimator;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -172,6 +178,8 @@
android.R.interpolator.fast_out_slow_in);
mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_linear_in);
+ mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+ android.R.interpolator.linear_out_slow_in);
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
}
@@ -285,14 +293,16 @@
}
private void updateClock(float alpha, float scale) {
- mKeyguardStatusView.setAlpha(alpha);
+ if (!mKeyguardStatusViewAnimating) {
+ mKeyguardStatusView.setAlpha(alpha);
+ }
mKeyguardStatusView.setScaleX(scale);
mKeyguardStatusView.setScaleY(scale);
}
- public void animateToFullShade() {
+ public void animateToFullShade(long delay) {
mAnimateNextTopPaddingChange = true;
- mNotificationStackScroller.goToFullShade();
+ mNotificationStackScroller.goToFullShade(delay);
requestLayout();
}
@@ -671,18 +681,191 @@
}
}
- public void setBarState(int statusBarState) {
+ public void setBarState(int statusBarState, boolean keyguardFadingAway,
+ boolean goingToFullShade) {
boolean keyguardShowing = statusBarState == StatusBarState.KEYGUARD
|| statusBarState == StatusBarState.SHADE_LOCKED;
- mKeyguardStatusBar.setAlpha(1f);
- mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
if (!mKeyguardShowing && keyguardShowing) {
setQsTranslation(mQsExpansionHeight);
mHeader.setTranslationY(0f);
}
+ setKeyguardStatusViewVisibility(statusBarState, keyguardFadingAway, goingToFullShade);
+ setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
+ if (goingToFullShade) {
+ animateKeyguardStatusBarOut();
+ } else {
+ mKeyguardStatusBar.setAlpha(1f);
+ mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
+ }
mStatusBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
updateQsState();
+ if (goingToFullShade) {
+ animateHeaderSlidingIn();
+ }
+ }
+
+ private final Runnable mAnimateKeyguardStatusViewInvisibleEndRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mKeyguardStatusViewAnimating = false;
+ mKeyguardStatusView.setVisibility(View.GONE);
+ }
+ };
+
+ private final Runnable mAnimateKeyguardStatusViewVisibleEndRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mKeyguardStatusViewAnimating = false;
+ }
+ };
+
+ private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
+ = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHeaderAnimatingIn = false;
+ mQsContainerAnimator = null;
+ mQsContainer.removeOnLayoutChangeListener(mQsContainerAnimatorUpdater);
+ }
+ };
+
+ private final OnLayoutChangeListener mQsContainerAnimatorUpdater
+ = new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ int oldHeight = oldBottom - oldTop;
+ int height = bottom - top;
+ if (height != oldHeight && mQsContainerAnimator != null) {
+ PropertyValuesHolder[] values = mQsContainerAnimator.getValues();
+ float newEndValue = mHeader.getCollapsedHeight() + mQsPeekHeight - height - top;
+ float newStartValue = -height - top;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ mQsContainerAnimator.setCurrentPlayTime(mQsContainerAnimator.getCurrentPlayTime());
+ }
+ }
+ };
+
+ private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
+ = new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ mHeader.setTranslationY(-mHeader.getCollapsedHeight() - mQsPeekHeight);
+ mHeader.animate()
+ .translationY(0f)
+ .setStartDelay(mStatusBar.calculateGoingToFullShadeDelay())
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .start();
+ mQsContainer.setY(-mQsContainer.getHeight());
+ mQsContainerAnimator = ObjectAnimator.ofFloat(mQsContainer, View.TRANSLATION_Y,
+ mQsContainer.getTranslationY(),
+ mHeader.getCollapsedHeight() + mQsPeekHeight - mQsContainer.getHeight()
+ - mQsContainer.getTop());
+ mQsContainerAnimator.setStartDelay(mStatusBar.calculateGoingToFullShadeDelay());
+ mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
+ mQsContainerAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
+ mQsContainerAnimator.start();
+ mQsContainer.addOnLayoutChangeListener(mQsContainerAnimatorUpdater);
+ return true;
+ }
+ };
+
+ private void animateHeaderSlidingIn() {
+ mHeaderAnimatingIn = true;
+ getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+
+ }
+
+ private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mKeyguardStatusBar.setVisibility(View.INVISIBLE);
+ }
+ };
+
+ private void animateKeyguardStatusBarOut() {
+ mKeyguardStatusBar.animate()
+ .alpha(0f)
+ .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
+ .setDuration(mStatusBar.getKeyguardFadingAwayDuration()/2)
+ .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .withEndAction(mAnimateKeyguardStatusBarInvisibleEndRunnable)
+ .start();
+ }
+
+ private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mKeyguardBottomArea.setVisibility(View.GONE);
+ }
+ };
+
+ private void setKeyguardBottomAreaVisibility(int statusBarState,
+ boolean goingToFullShade) {
+ if (goingToFullShade) {
+ mKeyguardBottomArea.animate().cancel();
+ mKeyguardBottomArea.animate()
+ .alpha(0f)
+ .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
+ .setDuration(mStatusBar.getKeyguardFadingAwayDuration()/2)
+ .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable)
+ .start();
+ } else if (statusBarState == StatusBarState.KEYGUARD
+ || statusBarState == StatusBarState.SHADE_LOCKED) {
+ mKeyguardBottomArea.animate().cancel();
+ mKeyguardBottomArea.setVisibility(View.VISIBLE);
+ mKeyguardBottomArea.setAlpha(1f);
+ } else {
+ mKeyguardBottomArea.animate().cancel();
+ mKeyguardBottomArea.setVisibility(View.GONE);
+ mKeyguardBottomArea.setAlpha(1f);
+ }
+ }
+
+ private void setKeyguardStatusViewVisibility(int statusBarState, boolean keyguardFadingAway,
+ boolean goingToFullShade) {
+ if ((!keyguardFadingAway && mStatusBarState == StatusBarState.KEYGUARD
+ && statusBarState != StatusBarState.KEYGUARD) || goingToFullShade) {
+ mKeyguardStatusView.animate().cancel();
+ mKeyguardStatusViewAnimating = true;
+ mKeyguardStatusView.animate()
+ .alpha(0f)
+ .setStartDelay(0)
+ .setDuration(160)
+ .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable);
+ if (keyguardFadingAway) {
+ mKeyguardStatusView.animate()
+ .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
+ .setDuration(mStatusBar.getKeyguardFadingAwayDuration()/2)
+ .start();
+ }
+ } else if (mStatusBarState == StatusBarState.SHADE_LOCKED
+ && statusBarState == StatusBarState.KEYGUARD) {
+ mKeyguardStatusView.animate().cancel();
+ mKeyguardStatusView.setVisibility(View.VISIBLE);
+ mKeyguardStatusViewAnimating = true;
+ mKeyguardStatusView.setAlpha(0f);
+ mKeyguardStatusView.animate()
+ .alpha(1f)
+ .setStartDelay(0)
+ .setDuration(320)
+ .setInterpolator(PhoneStatusBar.ALPHA_IN)
+ .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable);
+ } else if (statusBarState == StatusBarState.KEYGUARD) {
+ mKeyguardStatusView.animate().cancel();
+ mKeyguardStatusView.setVisibility(View.VISIBLE);
+ mKeyguardStatusView.setAlpha(1f);
+ } else {
+ mKeyguardStatusView.animate().cancel();
+ mKeyguardStatusView.setVisibility(View.GONE);
+ mKeyguardStatusView.setAlpha(1f);
+ }
}
private void updateQsState() {
@@ -716,10 +899,9 @@
alpha *= 2;
alpha = Math.min(1, alpha);
alpha = 1 - alpha;
- if (alpha == 0f) {
- mKeyguardStatusBar.setVisibility(View.INVISIBLE);
- } else {
- mKeyguardStatusBar.setVisibility(View.VISIBLE);
+ mKeyguardStatusBarTransparent = alpha == 0f;
+ updateKeyguardStatusBarVisibility();
+ if (!mKeyguardStatusBarTransparent) {
mKeyguardStatusBar.setAlpha(alpha);
}
}
@@ -741,7 +923,9 @@
}
private void setQsTranslation(float height) {
- mQsContainer.setY(height - mQsContainer.getHeight() + getHeaderTranslation());
+ if (!mHeaderAnimatingIn) {
+ mQsContainer.setY(height - mQsContainer.getHeight() + getHeaderTranslation());
+ }
if (mKeyguardShowing) {
mHeader.setY(interpolate(getQsExpansionFraction(), -mHeader.getHeight(), 0));
}
@@ -1039,7 +1223,9 @@
}
private void updateHeaderShade() {
- mHeader.setTranslationY(getHeaderTranslation());
+ if (!mHeaderAnimatingIn) {
+ mHeader.setTranslationY(getHeaderTranslation());
+ }
setQsTranslation(mQsExpansionHeight);
}
@@ -1076,7 +1262,7 @@
}
alpha = Math.max(0, Math.min(alpha, 1));
alpha = (float) Math.pow(alpha, 0.75);
- if (!mQsExpanded && !mKeyguardStatusBarAnimatingIn) {
+ if (!mQsExpanded) {
mKeyguardStatusBar.setAlpha(alpha);
}
mKeyguardBottomArea.setAlpha(alpha);
@@ -1374,6 +1560,14 @@
return mQsExpanded;
}
+ public boolean isQsDetailShowing() {
+ return mQsPanel.isShowingDetail();
+ }
+
+ public void closeQsDetail() {
+ mQsPanel.closeDetail();
+ }
+
@Override
public boolean shouldDelayChildPressedState() {
return true;
@@ -1405,4 +1599,20 @@
private static float interpolate(float t, float start, float end) {
return (1 - t) * start + t * end;
}
+
+ private void updateKeyguardStatusBarVisibility() {
+ mKeyguardStatusBar.setVisibility(mKeyguardShowing && !mKeyguardStatusBarTransparent
+ && !mDozing ? VISIBLE : INVISIBLE);
+ }
+
+ public void setDozing(boolean dozing) {
+ if (dozing == mDozing) return;
+ mDozing = dozing;
+ if (mDozing) {
+ setBackgroundColor(0xff000000);
+ } else {
+ setBackground(null);
+ }
+ updateKeyguardStatusBarVisibility();
+ }
}
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 0284036..fe9ea50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -455,6 +455,7 @@
private int mDrawCount;
private Runnable mLaunchTransitionEndRunnable;
private boolean mLaunchTransitionFadingAway;
+ private ExpandableNotificationRow mDraggedDownRow;
private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD
| ViewState.LOCATION_TOP_STACK_PEEKING
@@ -1361,10 +1362,15 @@
int vis = ent.notification.getNotification().visibility;
// Display public version of the notification if we need to redact.
- final boolean hideSensitive = shouldHideSensitiveContents(ent.notification.getUserId());
- boolean showingPublic = vis == Notification.VISIBILITY_PRIVATE && hideSensitive;
- ent.row.setShowingPublic(showingPublic);
+ final boolean hideSensitive =
+ !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
+ boolean sensitive = vis == Notification.VISIBILITY_PRIVATE;
+ boolean showingPublic = sensitive && hideSensitive && isLockscreenPublicMode();
+ ent.row.setSensitive(sensitive && hideSensitive);
if (ent.autoRedacted && ent.legacy) {
+
+ // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
+ // for legacy auto redacted notifications.
if (showingPublic) {
ent.row.setShowingLegacyBackground(false);
} else {
@@ -2436,7 +2442,7 @@
final boolean powerSave = mBatteryController.isPowerSave();
final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN
&& !powerSave;
- if (powerSave && getBarState() != StatusBarState.KEYGUARD) {
+ if (powerSave && getBarState() == StatusBarState.SHADE) {
mode = MODE_WARNING;
}
transitions.transitionTo(mode, anim);
@@ -2969,6 +2975,9 @@
private void setHeadsUpVisibility(boolean vis) {
if (!ENABLE_HEADS_UP) return;
if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window");
+ EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_STATUS,
+ vis ? mHeadsUpNotificationView.getKey() : "",
+ vis ? 1 : 0);
mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
}
@@ -3287,9 +3296,14 @@
public void showKeyguard() {
setBarState(StatusBarState.KEYGUARD);
- updateKeyguardState();
+ updateKeyguardState(false /* goingToFullShade */);
instantExpandNotificationsPanel();
mLeaveOpenOnKeyguardHide = false;
+ if (mDraggedDownRow != null) {
+ mDraggedDownRow.setUserLocked(false);
+ mDraggedDownRow.notifyHeightChanged();
+ mDraggedDownRow = null;
+ }
}
public boolean isInLaunchTransition() {
@@ -3338,15 +3352,28 @@
}
}
- public void hideKeyguard() {
+ /**
+ * @return true if we would like to stay in the shade, false if it should go away entirely
+ */
+ public boolean hideKeyguard() {
+ boolean staying = mLeaveOpenOnKeyguardHide;
setBarState(StatusBarState.SHADE);
if (mLeaveOpenOnKeyguardHide) {
mLeaveOpenOnKeyguardHide = false;
- mNotificationPanel.animateToFullShade();
+ mNotificationPanel.animateToFullShade(calculateGoingToFullShadeDelay());
+ if (mDraggedDownRow != null) {
+ mDraggedDownRow.setUserLocked(false);
+ mDraggedDownRow = null;
+ }
} else {
instantCollapseNotificationPanel();
}
- updateKeyguardState();
+ updateKeyguardState(staying);
+ return staying;
+ }
+
+ public long calculateGoingToFullShadeDelay() {
+ return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
}
/**
@@ -3377,28 +3404,24 @@
&& mStatusBarKeyguardViewManager.isSecure());
}
- private void updateKeyguardState() {
+ private void updateKeyguardState(boolean goingToFullShade) {
if (mState == StatusBarState.KEYGUARD) {
- mKeyguardStatusView.setVisibility(View.VISIBLE);
mKeyguardIndicationController.setVisible(true);
mNotificationPanel.resetViews();
mKeyguardUserSwitcher.setKeyguard(true);
} else {
- mKeyguardStatusView.setVisibility(View.GONE);
mKeyguardIndicationController.setVisible(false);
mKeyguardUserSwitcher.setKeyguard(false);
}
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
- mKeyguardBottomArea.setVisibility(View.VISIBLE);
mScrimController.setKeyguardShowing(true);
} else {
- mKeyguardBottomArea.setVisibility(View.GONE);
mScrimController.setKeyguardShowing(false);
}
- mNotificationPanel.setBarState(mState);
+ mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
updateDozingState();
- updateStackScrollerState();
updatePublicMode();
+ updateStackScrollerState(goingToFullShade);
updateNotifications();
checkBarModes();
updateCarrierLabelVisibility(false);
@@ -3411,23 +3434,21 @@
if (mState != StatusBarState.KEYGUARD) {
return;
}
+ mNotificationPanel.setDozing(mDozing);
if (mDozing) {
- mNotificationPanel.setBackgroundColor(0xff000000);
- mKeyguardStatusBar.setVisibility(View.INVISIBLE);
mKeyguardBottomArea.setVisibility(View.INVISIBLE);
mStackScroller.setDark(true, false /*animate*/);
} else {
- mNotificationPanel.setBackground(null);
- mKeyguardStatusBar.setVisibility(View.VISIBLE);
- mKeyguardBottomArea.setVisibility(View.VISIBLE);
+ mKeyguardBottomArea.setVisibility(View.VISIBLE);
mStackScroller.setDark(false, false /*animate*/);
}
mScrimController.setDozing(mDozing);
}
- public void updateStackScrollerState() {
+ public void updateStackScrollerState(boolean goingToFullShade) {
if (mStackScroller == null) return;
boolean onKeyguard = mState == StatusBarState.KEYGUARD;
+ mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
mStackScroller.setDimmed(onKeyguard, false /* animate */);
mStackScroller.setExpandingEnabled(!onKeyguard);
ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
@@ -3457,7 +3478,11 @@
return true;
}
if (mNotificationPanel.isQsExpanded()) {
- mNotificationPanel.animateCloseQs();
+ if (mNotificationPanel.isQsDetailShowing()) {
+ mNotificationPanel.closeQsDetail();
+ } else {
+ mNotificationPanel.animateCloseQs();
+ }
return true;
}
if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
@@ -3604,17 +3629,22 @@
* @param expandView The view to expand after going to the shade.
*/
public void goToLockedShade(View expandView) {
+ ExpandableNotificationRow row = null;
if (expandView instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) expandView;
+ row = (ExpandableNotificationRow) expandView;
row.setUserExpanded(true);
}
if (isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(mCurrentUserId)) {
mLeaveOpenOnKeyguardHide = true;
showBouncer();
+ mDraggedDownRow = row;
} else {
- mNotificationPanel.animateToFullShade();
+ mNotificationPanel.animateToFullShade(0 /* delay */);
setBarState(StatusBarState.SHADE_LOCKED);
- updateKeyguardState();
+ updateKeyguardState(false /* goingToFullShade */);
+ if (row != null) {
+ row.setUserLocked(false);
+ }
}
}
@@ -3624,7 +3654,7 @@
public void goToKeyguard() {
if (mState == StatusBarState.SHADE_LOCKED) {
setBarState(StatusBarState.KEYGUARD);
- updateKeyguardState();
+ updateKeyguardState(false /* goingToFullShade */);
}
}
@@ -3635,6 +3665,14 @@
return mNotificationPanel;
}
+ public long getKeyguardFadingAwayDelay() {
+ return mKeyguardFadingAwayDelay;
+ }
+
+ public long getKeyguardFadingAwayDuration() {
+ return mKeyguardFadingAwayDuration;
+ }
+
public LinearLayout getSystemIcons() {
return mSystemIcons;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index eb42401..7bce6647 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -115,6 +115,13 @@
scheduleUpdate();
}
+ public void animateGoingToFullShade(long delay, long duration) {
+ mDurationOverride = duration;
+ mAnimationDelay = delay;
+ mAnimateChange = true;
+ scheduleUpdate();
+ }
+
public void setDozing(boolean dozing) {
if (mDozing == dozing) return;
mDozing = dozing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index af21f25..6831933 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -230,17 +230,22 @@
});
} else {
mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration);
- mPhoneStatusBar.hideKeyguard();
- mStatusBarWindowManager.setKeyguardFadingAway(true);
+ boolean staying = mPhoneStatusBar.hideKeyguard();
+ if (!staying) {
+ mStatusBarWindowManager.setKeyguardFadingAway(true);
+ mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() {
+ @Override
+ public void run() {
+ mStatusBarWindowManager.setKeyguardFadingAway(false);
+ mPhoneStatusBar.finishKeyguardFadingAway();
+ }
+ });
+ } else {
+ mScrimController.animateGoingToFullShade(delay, fadeoutDuration);
+ mPhoneStatusBar.finishKeyguardFadingAway();
+ }
mStatusBarWindowManager.setKeyguardShowing(false);
mBouncer.animateHide(delay, fadeoutDuration);
- mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() {
- @Override
- public void run() {
- mStatusBarWindowManager.setKeyguardFadingAway(false);
- mPhoneStatusBar.finishKeyguardFadingAway();
- }
- });
mViewMediatorCallback.keyguardGone();
updateStates();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 86a6622..d701b3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -27,8 +27,12 @@
*/
public class SystemUIDialog extends AlertDialog {
+ private final Context mContext;
+
public SystemUIDialog(Context context) {
super(context, R.style.Theme_SystemUI_Dialog);
+ mContext = context;
+
getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
@@ -36,4 +40,26 @@
attrs.setTitle(getClass().getSimpleName());
getWindow().setAttributes(attrs);
}
+
+ public void setShowForAllUsers(boolean show) {
+ if (show) {
+ getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ } else {
+ getWindow().getAttributes().privateFlags &=
+ ~WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ }
+ }
+
+ public void setMessage(int resId) {
+ setMessage(mContext.getString(resId));
+ }
+
+ public void setPositiveButton(int resId, OnClickListener onClick) {
+ setButton(BUTTON_POSITIVE, mContext.getString(resId), onClick);
+ }
+
+ public void setNegativeButton(int resId, OnClickListener onClick) {
+ setButton(BUTTON_NEGATIVE, mContext.getString(resId), onClick);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 1e65543..d1b69ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -47,6 +47,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
context.registerReceiver(this, filter);
updatePowerSave();
@@ -86,6 +87,8 @@
fireBatteryLevelChanged();
} else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) {
updatePowerSave();
+ } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)) {
+ setPowerSave(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
}
}
@@ -94,7 +97,10 @@
}
private void updatePowerSave() {
- final boolean powerSave = mPowerManager.isPowerSaveMode();
+ setPowerSave(mPowerManager.isPowerSaveMode());
+ }
+
+ private void setPowerSave(boolean powerSave) {
if (powerSave == mPowerSave) return;
mPowerSave = powerSave;
if (DEBUG) Log.d(TAG, "Power save is " + (mPowerSave ? "on" : "off"));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index ac260db..2aceb95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -91,7 +91,9 @@
if (mHeadsUp != null) {
mHeadsUp.row.setSystemExpanded(true);
- mHeadsUp.row.setShowingPublic(false);
+ mHeadsUp.row.setSensitive(false);
+ mHeadsUp.row.setHideSensitive(
+ false, false /* animated */, 0 /* delay */, 0 /* duration */);
if (mContentHolder == null) {
// too soon!
return false;
@@ -338,6 +340,10 @@
mBar.scheduleHeadsUpEscalation();
}
+ public String getKey() {
+ return mHeadsUp == null ? null : mHeadsUp.notification.getKey();
+ }
+
private class EdgeSwipeHelper implements Gefingerpoken {
private static final boolean DEBUG_EDGE_SWIPE = false;
private final float mTouchSlop;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 6795842..a0312bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -36,8 +36,6 @@
private static final String TAG = "KeyguardUserSwitcher";
private static final boolean ALWAYS_ON = false;
- private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
- "lockscreenSimpleUserSwitcher";
private final ViewGroup mUserSwitcher;
private final KeyguardStatusBarView mStatusBarView;
@@ -52,8 +50,7 @@
mStatusBarView.setKeyguardUserSwitcher(this);
mAdapter = new Adapter(context, userSwitcherController);
mAdapter.registerDataSetObserver(mDataSetObserver);
- mSimpleUserSwitcher = Settings.Global.getInt(context.getContentResolver(),
- SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
+ mSimpleUserSwitcher = userSwitcherController.isSimpleUserSwitcher();
} else {
mUserSwitcher = null;
mStatusBarView = null;
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 70fe85f..4e9f37d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -34,7 +34,6 @@
import android.os.Messenger;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
-import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -471,8 +470,8 @@
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
- if (true/*DEBUG*/) {
- Rlog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
+ if (DEBUG) {
+ Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
}
mSignalStrength = signalStrength;
@@ -482,8 +481,8 @@
@Override
public void onServiceStateChanged(ServiceState state) {
- if (true/*DEBUG*/) {
- Rlog.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
+ if (DEBUG) {
+ Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
+ " dataState=" + state.getDataRegState());
}
mServiceState = state;
@@ -495,8 +494,8 @@
@Override
public void onCallStateChanged(int state, String incomingNumber) {
- if (true/*DEBUG*/) {
- Rlog.d(TAG, "onCallStateChanged state=" + state);
+ if (DEBUG) {
+ Log.d(TAG, "onCallStateChanged state=" + state);
}
// In cdma, if a voice call is made, RSSI should switch to 1x.
if (isCdma()) {
@@ -507,8 +506,8 @@
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
- if (true/*DEBUG*/) {
- Rlog.d(TAG, "onDataConnectionStateChanged: state=" + state
+ if (DEBUG) {
+ Log.d(TAG, "onDataConnectionStateChanged: state=" + state
+ " type=" + networkType);
}
mDataState = state;
@@ -520,8 +519,8 @@
@Override
public void onDataActivity(int direction) {
- if (true/*DEBUG*/) {
- Rlog.d(TAG, "onDataActivity: direction=" + direction);
+ if (DEBUG) {
+ Log.d(TAG, "onDataActivity: direction=" + direction);
}
mDataActivity = direction;
updateDataIcon();
@@ -552,7 +551,7 @@
} else {
mSimState = IccCardConstants.State.UNKNOWN;
}
- Rlog.d(TAG, "updateSimState: mSimState=" + mSimState);
+ if (DEBUG) Log.d(TAG, "updateSimState: mSimState=" + mSimState);
}
private boolean isCdma() {
@@ -580,7 +579,7 @@
} else {
retVal = false;
}
- Rlog.d(TAG, "hasService: mServiceState=" + mServiceState + " retVal=" + retVal);
+ if (DEBUG) Log.d(TAG, "hasService: mServiceState=" + mServiceState + " retVal=" + retVal);
return retVal;
}
@@ -594,21 +593,18 @@
}
private final void updateTelephonySignalStrength() {
- Rlog.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService() + " ss=" + mSignalStrength);
- if (mDemoMode) {
- mQSPhoneSignalIconId = mDemoMobileLevel < 0 ? R.drawable.ic_qs_signal_no_signal :
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mDemoInetCondition][mDemoMobileLevel];
- mQSDataTypeIconId = mDemoQSDataTypeIconId;
- return;
+ if (DEBUG) {
+ Log.d(TAG, "updateTelephonySignalStrength: hasService=" + hasService()
+ + " ss=" + mSignalStrength);
}
if (!hasService()) {
- if (true/*CHATTY*/) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
+ if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
mDataSignalIconId = R.drawable.stat_sys_signal_null;
} else {
if (mSignalStrength == null) {
- if (true/*CHATTY*/) Rlog.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
+ if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
mDataSignalIconId = R.drawable.stat_sys_signal_null;
@@ -619,9 +615,12 @@
int[] iconList;
if (isCdma() && mAlwaysShowCdmaRssi) {
mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
- if(true/*DEBUG*/) Rlog.d(TAG, "updateTelephonySignalStrength: mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
+ if (DEBUG) {
+ Log.d(TAG, "updateTelephonySignalStrength:"
+ + " mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
+ " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
+ " instead of level=" + mSignalStrength.getLevel());
+ }
} else {
mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
}
@@ -646,7 +645,7 @@
mContentDescriptionPhoneSignal = mContext.getString(
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
- Rlog.d(TAG, "updateTelephonySignalStrength: iconLevel=" + iconLevel);
+ if (DEBUG) Log.d(TAG, "updateTelephonySignalStrength: iconLevel=" + iconLevel);
}
}
}
@@ -950,11 +949,6 @@
}
private void updateWifiIcons() {
- if (mDemoMode) {
- mQSWifiIconId = mDemoWifiLevel < 0 ? R.drawable.ic_qs_wifi_no_network
- : WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
- return;
- }
if (mWifiConnected) {
mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
@@ -1209,6 +1203,14 @@
}
}
+ if (mDemoMode) {
+ mQSWifiIconId = mDemoWifiLevel < 0 ? R.drawable.ic_qs_wifi_no_network
+ : WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
+ mQSPhoneSignalIconId = mDemoMobileLevel < 0 ? R.drawable.ic_qs_signal_no_signal :
+ TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mDemoInetCondition][mDemoMobileLevel];
+ mQSDataTypeIconId = mDemoQSDataTypeIconId;
+ }
+
if (DEBUG) {
Log.d(TAG, "refreshViews connected={"
+ (mWifiConnected?" wifi":"")
@@ -1497,8 +1499,6 @@
for (SignalCluster cluster : mSignalClusters) {
refreshSignalCluster(cluster);
}
- updateWifiIcons();
- updateTelephonySignalStrength();
refreshViews();
} else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
String airplane = args.getString("airplane");
@@ -1528,7 +1528,6 @@
iconId,
"Demo");
}
- updateWifiIcons();
refreshViews();
}
String mobile = args.getString("mobile");
@@ -1574,7 +1573,6 @@
"Demo",
"Demo");
}
- updateTelephonySignalStrength();
refreshViews();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 7c00c7f..6e3656d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -32,11 +32,14 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.os.AsyncTask;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
@@ -57,12 +60,15 @@
private static final String TAG = "UserSwitcherController";
private static final boolean DEBUG = false;
+ private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
+ "lockscreenSimpleUserSwitcher";
private final Context mContext;
private final UserManager mUserManager;
private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
private final GuestResumeSessionReceiver mGuestResumeSessionReceiver
= new GuestResumeSessionReceiver();
+ private boolean mSimpleUserSwitcher;
private ArrayList<UserRecord> mUsers = new ArrayList<>();
private Dialog mExitGuestDialog;
@@ -80,6 +86,13 @@
filter.addAction(Intent.ACTION_USER_STOPPING);
mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter,
null /* permission */, null /* scheduler */);
+
+ mSimpleUserSwitcher = Settings.Global.getInt(context.getContentResolver(),
+ SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
+ mSimpleUserSwitcherObserver);
+
refreshUsers(UserHandle.USER_NULL);
}
@@ -136,11 +149,13 @@
}
}
- if (guestRecord == null) {
- records.add(new UserRecord(null /* info */, null /* picture */,
- true /* isGuest */, false /* isCurrent */));
- } else {
- records.add(guestRecord);
+ if (!mSimpleUserSwitcher) {
+ if (guestRecord == null) {
+ records.add(new UserRecord(null /* info */, null /* picture */,
+ true /* isGuest */, false /* isCurrent */));
+ } else {
+ records.add(guestRecord);
+ }
}
return records;
@@ -167,6 +182,10 @@
}
}
+ public boolean isSimpleUserSwitcher() {
+ return mSimpleUserSwitcher;
+ }
+
public void switchTo(UserRecord record) {
int id;
if (record.isGuest && record.info == null) {
@@ -253,6 +272,14 @@
}
};
+ private final ContentObserver mSimpleUserSwitcherObserver = new ContentObserver(new Handler()) {
+ public void onChange(boolean selfChange) {
+ mSimpleUserSwitcher = Settings.Global.getInt(mContext.getContentResolver(),
+ SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
+ refreshUsers(UserHandle.USER_NULL);
+ };
+ };
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("UserSwitcherController state:");
pw.println(" mLastNonGuestUser=" + mLastNonGuestUser);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 0582140..ddb5cb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -34,6 +34,7 @@
private int mSpeedBumpIndex = -1;
private float mScrimAmount;
private boolean mDark;
+ private boolean mHideSensitive;
public int getScrollY() {
return mScrollY;
@@ -68,6 +69,10 @@
mDark = dark;
}
+ public void setHideSensitive(boolean hideSensitive) {
+ mHideSensitive = hideSensitive;
+ }
+
/**
* In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
* interaction. This child is then scaled normally and its background is fully opaque.
@@ -84,6 +89,10 @@
return mDark;
}
+ public boolean isHideSensitive() {
+ return mHideSensitive;
+ }
+
public ActivatableNotificationView getActivatedChild() {
return mActivatedChild;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 99d3a01..3c93b19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -30,7 +30,9 @@
boolean animateTopInset;
boolean animateDimmed;
boolean animateDark;
+ boolean animateHideSensitive;
boolean hasDelays;
+ boolean hasGoToFullShadeEvent;
public AnimationFilter animateAlpha() {
animateAlpha = true;
@@ -77,6 +79,11 @@
return this;
}
+ public AnimationFilter animateHideSensitive() {
+ animateHideSensitive = true;
+ return this;
+ }
+
/**
* Combines multiple filters into {@code this} filter, using or as the operand .
*
@@ -87,6 +94,10 @@
int size = events.size();
for (int i = 0; i < size; i++) {
combineFilter(events.get(i).filter);
+ if (events.get(i).animationType ==
+ NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_GO_TO_FULL_SHADE) {
+ hasGoToFullShadeEvent = true;
+ }
}
}
@@ -99,6 +110,7 @@
animateTopInset |= filter.animateTopInset;
animateDimmed |= filter.animateDimmed;
animateDark |= filter.animateDark;
+ animateHideSensitive |= filter.animateHideSensitive;
hasDelays |= filter.hasDelays;
}
@@ -111,6 +123,8 @@
animateTopInset = false;
animateDimmed = false;
animateDark = false;
+ animateHideSensitive = false;
hasDelays = false;
+ hasGoToFullShadeEvent = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index e0167e9..a4d2021 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -131,8 +131,10 @@
private boolean mNeedsAnimation;
private boolean mTopPaddingNeedsAnimation;
private boolean mDimmedNeedsAnimation;
+ private boolean mHideSensitiveNeedsAnimation;
private boolean mDarkNeedsAnimation;
private boolean mActivateNeedsAnimation;
+ private boolean mGoToFullShadeNeedsAnimation;
private boolean mIsExpanded = true;
private boolean mChildrenUpdateRequested;
private SpeedBumpView mSpeedBumpView;
@@ -175,6 +177,7 @@
private boolean mInterceptDelegateEnabled;
private boolean mDelegateToScrollView;
private boolean mDisallowScrollingInThisMotion;
+ private long mGoToFullShadeDelay;
private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@@ -1214,6 +1217,9 @@
count++;
}
}
+ if (mDismissView.willBeGone()) {
+ count--;
+ }
return count;
}
@@ -1556,11 +1562,13 @@
mNeedsAnimation = false;
}
if (!mAnimationEvents.isEmpty() || isCurrentlyAnimating()) {
- mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState);
+ mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState,
+ mGoToFullShadeDelay);
mAnimationEvents.clear();
} else {
applyCurrentState();
}
+ mGoToFullShadeDelay = 0;
}
private void generateChildHierarchyEvents() {
@@ -1572,7 +1580,9 @@
generateTopPaddingEvent();
generateActivateEvent();
generateDimmedEvent();
+ generateHideSensitiveEvent();
generateDarkEvent();
+ generateGoToFullShadeEvent();
mNeedsAnimation = false;
}
@@ -1648,6 +1658,14 @@
mDimmedNeedsAnimation = false;
}
+ private void generateHideSensitiveEvent() {
+ if (mHideSensitiveNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_HIDE_SENSITIVE));
+ }
+ mHideSensitiveNeedsAnimation = false;
+ }
+
private void generateDarkEvent() {
if (mDarkNeedsAnimation) {
mAnimationEvents.add(
@@ -1656,6 +1674,14 @@
mDarkNeedsAnimation = false;
}
+ private void generateGoToFullShadeEvent() {
+ if (mGoToFullShadeNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_GO_TO_FULL_SHADE));
+ }
+ mGoToFullShadeNeedsAnimation = false;
+ }
+
private boolean onInterceptTouchEventScroll(MotionEvent ev) {
if (!isScrollingEnabled()) {
return false;
@@ -1883,6 +1909,22 @@
requestChildrenUpdate();
}
+ public void setHideSensitive(boolean hideSensitive, boolean animate) {
+ if (hideSensitive != mAmbientState.isHideSensitive()) {
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ ExpandableView v = (ExpandableView) getChildAt(i);
+ v.setHideSensitiveForIntrinsicHeight(hideSensitive);
+ }
+ mAmbientState.setHideSensitive(hideSensitive);
+ if (animate && mAnimationsEnabled) {
+ mHideSensitiveNeedsAnimation = true;
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ }
+ }
+
/**
* See {@link AmbientState#setActivatedChild}.
*/
@@ -1919,19 +1961,20 @@
if (visible) {
// Make invisible to ensure that the appear animation is played.
mSpeedBumpView.setInvisible();
- if (!mIsExpansionChanging) {
- generateAddAnimation(mSpeedBumpView);
- }
} else {
- mSpeedBumpView.performVisibilityAnimation(false);
+ // TODO: This doesn't really work, because the view is already set to GONE above.
generateRemoveAnimation(mSpeedBumpView);
}
}
}
- public void goToFullShade() {
+ public void goToFullShade(long delay) {
updateSpeedBump(true /* visibility */);
mDismissView.setInvisible();
+ mGoToFullShadeNeedsAnimation = true;
+ mGoToFullShadeDelay = delay;
+ mNeedsAnimation = true;
+ requestChildrenUpdate();
}
public void cancelExpandHelper() {
@@ -2104,7 +2147,8 @@
// ANIMATION_TYPE_SNAP_BACK
new AnimationFilter()
- .animateAlpha(),
+ .animateAlpha()
+ .animateHeight(),
// ANIMATION_TYPE_ACTIVATED_CHILD
new AnimationFilter()
@@ -2128,6 +2172,21 @@
// ANIMATION_TYPE_DARK
new AnimationFilter()
.animateDark(),
+
+ // ANIMATION_TYPE_GO_TO_FULL_SHADE
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateTopInset()
+ .animateY()
+ .animateDimmed()
+ .animateScale()
+ .animateZ()
+ .hasDelays(),
+
+ // ANIMATION_TYPE_HIDE_SENSITIVE
+ new AnimationFilter()
+ .animateHideSensitive(),
};
static int[] LENGTHS = new int[] {
@@ -2161,6 +2220,12 @@
// ANIMATION_TYPE_DARK
StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_GO_TO_FULL_SHADE
+ StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE,
+
+ // ANIMATION_TYPE_HIDE_SENSITIVE
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
};
static final int ANIMATION_TYPE_ADD = 0;
@@ -2173,6 +2238,8 @@
static final int ANIMATION_TYPE_DIMMED = 7;
static final int ANIMATION_TYPE_CHANGE_POSITION = 8;
static final int ANIMATION_TYPE_DARK = 9;
+ static final int ANIMATION_TYPE_GO_TO_FULL_SHADE = 10;
+ static final int ANIMATION_TYPE_HIDE_SENSITIVE = 11;
final long eventStartTime;
final View changingView;
@@ -2193,13 +2260,18 @@
* Combines the length of several animation events into a single value.
*
* @param events The events of the lengths to combine.
- * @return The combined length. This is just the maximum of all length.
+ * @return The combined length. Depending on the event types, this might be the maximum of
+ * all events or the length of a specific event.
*/
static long combineLength(ArrayList<AnimationEvent> events) {
long length = 0;
int size = events.size();
for (int i = 0; i < size; i++) {
- length = Math.max(length, events.get(i).length);
+ AnimationEvent event = events.get(i);
+ length = Math.max(length, event.length);
+ if (event.animationType == ANIMATION_TYPE_GO_TO_FULL_SHADE) {
+ return event.length;
+ }
}
return length;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index fe2733b..ba3f339 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -159,7 +159,7 @@
updateZValuesForState(resultState, algorithmState);
handleDraggedViews(ambientState, resultState, algorithmState);
- updateDimmedActivated(ambientState, resultState, algorithmState);
+ updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState);
updateClipping(resultState, algorithmState);
updateScrimAmount(resultState, algorithmState, ambientState.getScrimAmount());
updateSpeedBumpState(resultState, algorithmState, ambientState.getSpeedBumpIndex());
@@ -251,12 +251,13 @@
}
/**
- * Updates the dimmed and activated states of the children.
+ * Updates the dimmed, activated and hiding sensitive states of the children.
*/
- private void updateDimmedActivated(AmbientState ambientState, StackScrollState resultState,
- StackScrollAlgorithmState algorithmState) {
+ private void updateDimmedActivatedHideSensitive(AmbientState ambientState,
+ StackScrollState resultState, StackScrollAlgorithmState algorithmState) {
boolean dimmed = ambientState.isDimmed();
boolean dark = ambientState.isDark();
+ boolean hideSensitive = ambientState.isHideSensitive();
View activatedChild = ambientState.getActivatedChild();
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
@@ -264,6 +265,7 @@
StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
childViewState.dimmed = dimmed;
childViewState.dark = dark;
+ childViewState.hideSensitive = hideSensitive;
boolean isActivatedChild = activatedChild == child;
childViewState.scale = !dimmed || isActivatedChild
? 1.0f
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 7b90a351..a174952 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -157,6 +157,10 @@
// apply dark
child.setDark(state.dark, false /* animate */);
+ // apply hiding sensitive
+ child.setHideSensitive(
+ state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
+
// apply speed bump state
child.setBelowSpeedBump(state.belowSpeedBump);
@@ -171,8 +175,7 @@
updateChildClip(child, newHeight, state.topOverLap);
if(child instanceof SpeedBumpView) {
- float lineEnd = newYTranslation + newHeight / 2;
- performSpeedBumpAnimation(i, (SpeedBumpView) child, lineEnd);
+ performSpeedBumpAnimation(i, (SpeedBumpView) child, state, 0);
} else if (child instanceof DismissView) {
DismissView dismissView = (DismissView) child;
boolean visible = state.topOverLap < mClearAllTopPadding;
@@ -197,12 +200,14 @@
child.setClipBounds(mClipRect);
}
- private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd) {
+ public void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, ViewState state,
+ long delay) {
View nextChild = getNextChildNotGone(i);
if (nextChild != null) {
+ float lineEnd = state.yTranslation + state.height / 2;
ViewState nextState = getViewStateForView(nextChild);
- boolean startIsAboveNext = nextState.yTranslation > speedBumpEnd;
- speedBump.animateDivider(startIsAboveNext, null /* onFinishedRunnable */);
+ boolean startIsAboveNext = nextState.yTranslation > lineEnd;
+ speedBump.animateDivider(startIsAboveNext, delay, null /* onFinishedRunnable */);
}
}
@@ -237,6 +242,7 @@
float scale;
boolean dimmed;
boolean dark;
+ boolean hideSensitive;
boolean belowSpeedBump;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 71524ec..afd7216 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -27,6 +27,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.SpeedBumpView;
import java.util.ArrayList;
import java.util.HashSet;
@@ -39,10 +40,12 @@
public class StackStateAnimator {
public static final int ANIMATION_DURATION_STANDARD = 360;
+ public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448;
public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464;
public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80;
public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32;
+ public static final int ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE = 48;
private static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
@@ -65,15 +68,19 @@
private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
private final Interpolator mFastOutSlowInInterpolator;
+ private final int mGoToFullShadeAppearingTranslation;
public NotificationStackScrollLayout mHostLayout;
private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
new ArrayList<>();
private ArrayList<View> mNewAddChildren = new ArrayList<>();
- private Set<Animator> mAnimatorSet = new HashSet<Animator>();
- private Stack<AnimatorListenerAdapter> mAnimationListenerPool
- = new Stack<AnimatorListenerAdapter>();
+ private Set<Animator> mAnimatorSet = new HashSet<>();
+ private Stack<AnimatorListenerAdapter> mAnimationListenerPool = new Stack<>();
private AnimationFilter mAnimationFilter = new AnimationFilter();
private long mCurrentLength;
+ private long mCurrentAdditionalDelay;
+
+ /** The current index for the last child which was not added in this event set. */
+ private int mCurrentLastNotAddedIndex;
private ValueAnimator mTopOverScrollAnimator;
private ValueAnimator mBottomOverScrollAnimator;
@@ -82,6 +89,9 @@
mHostLayout = hostLayout;
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(hostLayout.getContext(),
android.R.interpolator.fast_out_slow_in);
+ mGoToFullShadeAppearingTranslation =
+ hostLayout.getContext().getResources().getDimensionPixelSize(
+ R.dimen.go_to_full_shade_appearing_translation);
}
public boolean isRunning() {
@@ -90,13 +100,15 @@
public void startAnimationForEvents(
ArrayList<NotificationStackScrollLayout.AnimationEvent> mAnimationEvents,
- StackScrollState finalState) {
+ StackScrollState finalState, long additionalDelay) {
processAnimationEvents(mAnimationEvents, finalState);
int childCount = mHostLayout.getChildCount();
mAnimationFilter.applyCombination(mNewEvents);
+ mCurrentAdditionalDelay = additionalDelay;
mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents);
+ mCurrentLastNotAddedIndex = findLastNotAddedIndex(finalState);
for (int i = 0; i < childCount; i++) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
@@ -106,7 +118,7 @@
}
child.setClipBounds(null);
- startAnimations(child, viewState, finalState);
+ startAnimations(child, viewState, finalState, i);
}
if (!isRunning()) {
// no child has preformed any animation, lets finish
@@ -116,11 +128,27 @@
mNewAddChildren.clear();
}
+ private int findLastNotAddedIndex(StackScrollState finalState) {
+ int childCount = mHostLayout.getChildCount();
+ for (int i = childCount - 1; i >= 0; i--) {
+ final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
+
+ StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
+ if (viewState == null || child.getVisibility() == View.GONE) {
+ continue;
+ }
+ if (!mNewAddChildren.contains(child)) {
+ return viewState.notGoneIndex;
+ }
+ }
+ return -1;
+ }
+
/**
* Start an animation to the given viewState
*/
private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState,
- StackScrollState finalState) {
+ StackScrollState finalState, int i) {
int childVisibility = child.getVisibility();
boolean wasVisible = childVisibility == View.VISIBLE;
final float alpha = viewState.alpha;
@@ -139,38 +167,48 @@
boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging ||
alphaChanging || heightChanging || topInsetChanging;
long delay = 0;
+ long duration = mCurrentLength;
if (hasDelays && isDelayRelevant || wasAdded) {
- delay = calculateChildAnimationDelay(viewState, finalState);
+ delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, finalState);
+ }
+
+ if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
+ child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
+ yTranslationChanging = true;
+ float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
+ longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
+ duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
+ (long) (100 * longerDurationFactor);
}
// start translationY animation
if (yTranslationChanging) {
- startYTranslationAnimation(child, viewState, delay);
+ startYTranslationAnimation(child, viewState, duration, delay);
}
// start translationZ animation
if (zTranslationChanging) {
- startZTranslationAnimation(child, viewState, delay);
+ startZTranslationAnimation(child, viewState, duration, delay);
}
// start scale animation
if (scaleChanging) {
- startScaleAnimation(child, viewState);
+ startScaleAnimation(child, viewState, duration);
}
// start alpha animation
if (alphaChanging && child.getTranslationX() == 0) {
- startAlphaAnimation(child, viewState, delay);
+ startAlphaAnimation(child, viewState, duration, delay);
}
// start height animation
if (heightChanging) {
- startHeightAnimation(child, viewState, delay);
+ startHeightAnimation(child, viewState, duration, delay);
}
// start top inset animation
if (topInsetChanging) {
- startInsetAnimation(child, viewState, delay);
+ startInsetAnimation(child, viewState, duration, delay);
}
// start dimmed animation
@@ -182,16 +220,27 @@
// apply speed bump state
child.setBelowSpeedBump(viewState.belowSpeedBump);
+ // start hiding sensitive animation
+ child.setHideSensitive(viewState.hideSensitive,
+ mAnimationFilter.animateHideSensitive && !wasAdded, delay, duration);
+
// apply scrimming
child.setScrimAmount(viewState.scrimAmount);
if (wasAdded) {
- child.performAddAnimation(delay);
+ child.performAddAnimation(delay, mCurrentLength);
+ }
+ if (child instanceof SpeedBumpView) {
+ finalState.performSpeedBumpAnimation(i, (SpeedBumpView) child, viewState,
+ delay + duration);
}
}
private long calculateChildAnimationDelay(StackScrollState.ViewState viewState,
StackScrollState finalState) {
+ if (mAnimationFilter.hasGoToFullShadeEvent) {
+ return calculateDelayGoToFullShade(viewState);
+ }
long minDelay = 0;
for (NotificationStackScrollLayout.AnimationEvent event : mNewEvents) {
long delayPerElement = ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING;
@@ -236,8 +285,14 @@
return minDelay;
}
+ private long calculateDelayGoToFullShade(StackScrollState.ViewState viewState) {
+ float index = viewState.notGoneIndex;
+ index = (float) Math.pow(index, 0.7f);
+ return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
+ }
+
private void startHeightAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState, long delay) {
+ StackScrollState.ViewState viewState, long duration, long delay) {
Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
int newEndValue = viewState.height;
@@ -274,7 +329,7 @@
}
});
animator.setInterpolator(mFastOutSlowInInterpolator);
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
animator.setStartDelay(delay);
@@ -296,7 +351,7 @@
}
private void startInsetAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState, long delay) {
+ StackScrollState.ViewState viewState, long duration, long delay) {
Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
int newEndValue = viewState.clipTopAmount;
@@ -332,7 +387,7 @@
}
});
animator.setInterpolator(mFastOutSlowInInterpolator);
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
animator.setStartDelay(delay);
@@ -354,7 +409,7 @@
}
private void startAlphaAnimation(final ExpandableView child,
- final StackScrollState.ViewState viewState, long delay) {
+ final StackScrollState.ViewState viewState, long duration, long delay) {
Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
final float newEndValue = viewState.alpha;
@@ -413,7 +468,7 @@
mWasCancelled = false;
}
});
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
animator.setStartDelay(delay);
@@ -433,7 +488,7 @@
}
private void startZTranslationAnimation(final ExpandableView child,
- final StackScrollState.ViewState viewState, long delay) {
+ final StackScrollState.ViewState viewState, long duration, long delay) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
float newEndValue = viewState.zTranslation;
@@ -463,7 +518,7 @@
ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
child.getTranslationZ(), newEndValue);
animator.setInterpolator(mFastOutSlowInInterpolator);
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
animator.setStartDelay(delay);
@@ -485,7 +540,7 @@
}
private void startYTranslationAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState, long delay) {
+ StackScrollState.ViewState viewState, long duration, long delay) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
float newEndValue = viewState.yTranslation;
@@ -516,7 +571,7 @@
ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
child.getTranslationY(), newEndValue);
animator.setInterpolator(mFastOutSlowInInterpolator);
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
animator.setStartDelay(delay);
@@ -538,7 +593,7 @@
}
private void startScaleAnimation(final ExpandableView child,
- StackScrollState.ViewState viewState) {
+ StackScrollState.ViewState viewState, long duration) {
Float previousStartValue = getChildTag(child, TAG_START_SCALE);
Float previousEndValue = getChildTag(child, TAG_END_SCALE);
float newEndValue = viewState.scale;
@@ -573,7 +628,7 @@
PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), newEndValue);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(child, holderX, holderY);
animator.setInterpolator(mFastOutSlowInInterpolator);
- long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
animator.addListener(getGlobalAnimationFinishedListener());
// remove the tag when the animation is finished
@@ -637,11 +692,12 @@
/**
* Cancel the previous animator and get the duration of the new animation.
*
+ * @param duration the new duration
* @param previousAnimator the animator which was running before
* @return the new duration
*/
- private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator) {
- long newDuration = mCurrentLength;
+ private long cancelAnimatorAndGetNewDuration(long duration, ValueAnimator previousAnimator) {
+ long newDuration = duration;
if (previousAnimator != null) {
// We take either the desired length of the new animation or the remaining time of
// the previous animator, whichever is longer.
@@ -710,7 +766,8 @@
translationDirection = Math.max(Math.min(translationDirection, 1.0f),-1.0f);
}
- changingView.performRemoveAnimation(translationDirection, new Runnable() {
+ changingView.performRemoveAnimation(ANIMATION_DURATION_APPEAR_DISAPPEAR,
+ translationDirection, new Runnable() {
@Override
public void run() {
// remove the temporary overlay
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 149d09a..984a5f4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -45,6 +45,7 @@
import android.util.Log;
import android.util.SparseArray;
import android.view.Gravity;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -249,6 +250,8 @@
private final VolumePanel mVolumePanel;
private final AudioManager mAudioManager;
+ private boolean mNewVolumeUp;
+
SafetyWarning(Context context, VolumePanel volumePanel, AudioManager audioManager) {
super(context);
mContext = context;
@@ -267,6 +270,24 @@
}
@Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && event.getRepeatCount() == 0) {
+ mNewVolumeUp = true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mNewVolumeUp) {
+ if (LOGD) Log.d(TAG, "Confirmed warning via VOLUME_UP");
+ mAudioManager.disableSafeMediaVolume();
+ dismiss();
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
public void onClick(DialogInterface dialog, int which) {
mAudioManager.disableSafeMediaVolume();
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5382489..a00fbf3 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -465,6 +465,11 @@
* changes.
*/
private class LegacyTypeTracker {
+
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+ private static final String TAG = "CSLegacyTypeTracker";
+
/**
* Array of lists, one per legacy network type (e.g., TYPE_MOBILE_MMS).
* Each list holds references to all NetworkAgentInfos that are used to
@@ -508,6 +513,15 @@
}
}
+ private void maybeLogBroadcast(NetworkAgentInfo nai, boolean connected, int type) {
+ if (DBG) {
+ log("Sending " + (connected ? "connected" : "disconnected") +
+ " broadcast for type " + type + " " + nai.name() +
+ " isDefaultNetwork=" + isDefaultNetwork(nai));
+ }
+ }
+
+ /** Adds the given network to the specified legacy type list. */
public void add(int type, NetworkAgentInfo nai) {
if (!isTypeSupported(type)) {
return; // Invalid network type.
@@ -521,42 +535,54 @@
}
if (list.isEmpty() || isDefaultNetwork(nai)) {
- if (VDBG) log("Sending connected broadcast for type " + type +
- "isDefaultNetwork=" + isDefaultNetwork(nai));
+ maybeLogBroadcast(nai, true, type);
sendLegacyNetworkBroadcast(nai, true, type);
}
list.add(nai);
}
+ /** Removes the given network from the specified legacy type list. */
+ public void remove(int type, NetworkAgentInfo nai) {
+ ArrayList<NetworkAgentInfo> list = mTypeLists[type];
+ if (list == null || list.isEmpty()) {
+ return;
+ }
+
+ boolean wasFirstNetwork = list.get(0).equals(nai);
+
+ if (!list.remove(nai)) {
+ return;
+ }
+
+ if (wasFirstNetwork || isDefaultNetwork(nai)) {
+ maybeLogBroadcast(nai, false, type);
+ sendLegacyNetworkBroadcast(nai, false, type);
+ }
+
+ if (!list.isEmpty() && wasFirstNetwork) {
+ if (DBG) log("Other network available for type " + type +
+ ", sending connected broadcast");
+ maybeLogBroadcast(list.get(0), false, type);
+ sendLegacyNetworkBroadcast(list.get(0), false, type);
+ }
+ }
+
+ /** Removes the given network from all legacy type lists. */
public void remove(NetworkAgentInfo nai) {
if (VDBG) log("Removing agent " + nai);
for (int type = 0; type < mTypeLists.length; type++) {
- ArrayList<NetworkAgentInfo> list = mTypeLists[type];
- if (list == null || list.isEmpty()) {
- continue;
- }
-
- boolean wasFirstNetwork = false;
- if (list.get(0).equals(nai)) {
- // This network was the first in the list. Send broadcast.
- wasFirstNetwork = true;
- }
- list.remove(nai);
-
- if (wasFirstNetwork || isDefaultNetwork(nai)) {
- if (VDBG) log("Sending disconnected broadcast for type " + type +
- "isDefaultNetwork=" + isDefaultNetwork(nai));
- sendLegacyNetworkBroadcast(nai, false, type);
- }
-
- if (!list.isEmpty() && wasFirstNetwork) {
- if (VDBG) log("Other network available for type " + type +
- ", sending connected broadcast");
- sendLegacyNetworkBroadcast(list.get(0), false, type);
- }
+ remove(type, nai);
}
}
+ private String naiToString(NetworkAgentInfo nai) {
+ String name = (nai != null) ? nai.name() : "null";
+ String state = (nai.networkInfo != null) ?
+ nai.networkInfo.getState() + "/" + nai.networkInfo.getDetailedState() :
+ "???/???";
+ return name + " " + state;
+ }
+
public void dump(IndentingPrintWriter pw) {
for (int type = 0; type < mTypeLists.length; type++) {
if (mTypeLists[type] == null) continue;
@@ -564,11 +590,17 @@
pw.increaseIndent();
if (mTypeLists[type].size() == 0) pw.println("none");
for (NetworkAgentInfo nai : mTypeLists[type]) {
- pw.println(nai.name());
+ pw.println(naiToString(nai));
}
pw.decreaseIndent();
}
}
+
+ // This class needs its own log method because it has a different TAG.
+ private void log(String s) {
+ Slog.d(TAG, s);
+ }
+
}
private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker();
@@ -806,9 +838,11 @@
// network is blocked; clone and override state
info = new NetworkInfo(info);
info.setDetailedState(DetailedState.BLOCKED, null, null);
+ if (VDBG) log("returning Blocked NetworkInfo");
}
if (mLockdownTracker != null) {
info = mLockdownTracker.augmentNetworkInfo(info);
+ if (VDBG) log("returning Locked NetworkInfo");
}
return info;
}
@@ -1693,7 +1727,16 @@
pw.println();
pw.decreaseIndent();
- pw.println("mActiveDefaultNetwork:" + mActiveDefaultNetwork);
+ pw.print("mActiveDefaultNetwork: " + mActiveDefaultNetwork);
+ if (mActiveDefaultNetwork != TYPE_NONE) {
+ NetworkInfo activeNetworkInfo = getActiveNetworkInfo();
+ if (activeNetworkInfo != null) {
+ pw.print(" " + activeNetworkInfo.getState() +
+ "/" + activeNetworkInfo.getDetailedState());
+ }
+ }
+ pw.println();
+
pw.println("mLegacyTypeTracker:");
pw.increaseIndent();
mLegacyTypeTracker.dump(pw);
@@ -1986,6 +2029,7 @@
synchronized (mNetworkForNetId) {
mNetworkForNetId.remove(nai.network.netId);
}
+ // Just in case.
mLegacyTypeTracker.remove(nai);
}
}
@@ -2087,15 +2131,14 @@
}
bestNetwork.addRequest(nri.request);
mNetworkForRequestId.put(nri.request.requestId, bestNetwork);
- int legacyType = nri.request.legacyType;
- if (legacyType != TYPE_NONE) {
- mLegacyTypeTracker.add(legacyType, bestNetwork);
- }
notifyNetworkCallback(bestNetwork, nri);
score = bestNetwork.currentScore;
+ if (nri.isRequest && nri.request.legacyType != TYPE_NONE) {
+ mLegacyTypeTracker.add(nri.request.legacyType, bestNetwork);
+ }
}
mNetworkRequests.put(nri.request, nri);
- if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) {
+ if (nri.isRequest) {
if (DBG) log("sending new NetworkRequest to factories");
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
@@ -2123,6 +2166,9 @@
log(" Removing from current network " + affectedNetwork.name() + ", leaving " +
affectedNetwork.networkRequests.size() + " requests.");
}
+ if (nri.isRequest && nri.request.legacyType != TYPE_NONE) {
+ mLegacyTypeTracker.remove(nri.request.legacyType, affectedNetwork);
+ }
}
if (nri.isRequest) {
@@ -4454,9 +4500,8 @@
}
mNetworkForRequestId.put(nri.request.requestId, newNetwork);
newNetwork.addRequest(nri.request);
- int legacyType = nri.request.legacyType;
- if (legacyType != TYPE_NONE) {
- mLegacyTypeTracker.add(legacyType, newNetwork);
+ if (nri.isRequest && nri.request.legacyType != TYPE_NONE) {
+ mLegacyTypeTracker.add(nri.request.legacyType, newNetwork);
}
keep = true;
// TODO - this could get expensive if we have alot of requests for this
@@ -4472,6 +4517,14 @@
} else {
setDefaultDnsSystemProperties(new ArrayList<InetAddress>());
}
+ // Maintain the illusion: since the legacy API only
+ // understands one network at a time, we must pretend
+ // that the current default network disconnected before
+ // the new one connected.
+ if (currentNetwork != null) {
+ mLegacyTypeTracker.remove(currentNetwork.networkInfo.getType(),
+ currentNetwork);
+ }
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
}
}
@@ -4665,13 +4718,19 @@
}
private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, boolean connected, int type) {
+ // The NetworkInfo we actually send out has no bearing on the real
+ // state of affairs. For example, if the default connection is mobile,
+ // and a request for HIPRI has just gone away, we need to pretend that
+ // HIPRI has just disconnected. So we need to set the type to HIPRI and
+ // the state to DISCONNECTED, even though the network is of type MOBILE
+ // and is still connected.
+ NetworkInfo info = new NetworkInfo(nai.networkInfo);
+ info.setType(type);
if (connected) {
- NetworkInfo info = new NetworkInfo(nai.networkInfo);
- info.setType(type);
+ info.setDetailedState(DetailedState.CONNECTED, null, info.getExtraInfo());
sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
} else {
- NetworkInfo info = new NetworkInfo(nai.networkInfo);
- info.setType(type);
+ info.setDetailedState(DetailedState.DISCONNECTED, null, info.getExtraInfo());
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 2fad73e..898b6f1 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -49,6 +49,11 @@
private static final int MSG_TRY_CONNECTING = 1;
+ private static final Uri FAKE_SMS_SENT_URI = Uri.parse("content://sms/sent/0");
+ private static final Uri FAKE_MMS_SENT_URI = Uri.parse("content://mms/sent/0");
+ private static final Uri FAKE_SMS_DRAFT_URI = Uri.parse("content://sms/draft/0");
+ private static final Uri FAKE_MMS_DRAFT_URI = Uri.parse("content://mms/draft/0");
+
private Context mContext;
// The actual MMS service instance to invoke
private volatile IMms mService;
@@ -275,7 +280,9 @@
mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Import SMS message");
if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
callingPkg) != AppOpsManager.MODE_ALLOWED) {
- return null;
+ // Silently fail AppOps failure due to not being the default SMS app
+ // while writing the TelephonyProvider
+ return FAKE_SMS_SENT_URI;
}
return getServiceGuarded().importTextMessage(
callingPkg, address, type, text, timestampMillis, seen, read);
@@ -287,7 +294,9 @@
mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Import MMS message");
if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
callingPkg) != AppOpsManager.MODE_ALLOWED) {
- return null;
+ // Silently fail AppOps failure due to not being the default SMS app
+ // while writing the TelephonyProvider
+ return FAKE_MMS_SENT_URI;
}
return getServiceGuarded().importMultimediaMessage(
callingPkg, pdu, messageId, timestampSecs, seen, read);
@@ -340,7 +349,9 @@
mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Add SMS draft");
if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
callingPkg) != AppOpsManager.MODE_ALLOWED) {
- return null;
+ // Silently fail AppOps failure due to not being the default SMS app
+ // while writing the TelephonyProvider
+ return FAKE_SMS_DRAFT_URI;
}
return getServiceGuarded().addTextMessageDraft(callingPkg, address, text);
}
@@ -350,7 +361,9 @@
mContext.enforceCallingPermission(Manifest.permission.WRITE_SMS, "Add MMS draft");
if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
callingPkg) != AppOpsManager.MODE_ALLOWED) {
- return null;
+ // Silently fail AppOps failure due to not being the default SMS app
+ // while writing the TelephonyProvider
+ return FAKE_MMS_DRAFT_URI;
}
return getServiceGuarded().addMultimediaMessageDraft(callingPkg, pdu);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index cb410ef..7624314 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -80,9 +80,9 @@
*/
class TelephonyRegistry extends ITelephonyRegistry.Stub {
private static final String TAG = "TelephonyRegistry";
- private static final boolean DBG = true; // STOPSHIP if true
+ private static final boolean DBG = false; // STOPSHIP if true
private static final boolean DBG_LOC = false; // STOPSHIP if true
- private static final boolean VDBG = true; // STOPSHIP if true
+ private static final boolean VDBG = false; // STOPSHIP if true
private static class Record {
String pkgForDebug;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9a58c56..0ad36fc 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1206,9 +1206,13 @@
}
return;
}
- if (!showBackground && UserHandle.getAppId(proc.uid)
- >= Process.FIRST_APPLICATION_UID && proc.userId != mCurrentUserId
- && proc.pid != MY_PID) {
+ boolean isBackground = (UserHandle.getAppId(proc.uid)
+ >= Process.FIRST_APPLICATION_UID
+ && proc.pid != MY_PID);
+ for (int userId : mCurrentProfileIds) {
+ isBackground &= (proc.userId != userId);
+ }
+ if (isBackground && !showBackground) {
Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
if (res != null) {
res.set(0);
@@ -2030,7 +2034,7 @@
mSystemThread.installSystemApplicationInfo(info);
synchronized (this) {
- ProcessRecord app = newProcessRecordLocked(info, info.processName, false);
+ ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
app.persistent = true;
app.pid = MY_PID;
app.maxAdj = ProcessList.SYSTEM_ADJ;
@@ -2830,10 +2834,45 @@
|| transit == AppTransition.TRANSIT_TASK_TO_FRONT;
}
+ int startIsolatedProcess(String entryPoint, String[] entryPointArgs,
+ String processName, String abiOverride, int uid, Runnable crashHandler) {
+ synchronized(this) {
+ ApplicationInfo info = new ApplicationInfo();
+ // In general the ApplicationInfo.uid isn't neccesarily equal to ProcessRecord.uid.
+ // For isolated processes, the former contains the parent's uid and the latter the
+ // actual uid of the isolated process.
+ // In the special case introduced by this method (which is, starting an isolated
+ // process directly from the SystemServer without an actual parent app process) the
+ // closest thing to a parent's uid is SYSTEM_UID.
+ // The only important thing here is to keep AI.uid != PR.uid, in order to trigger
+ // the |isolated| logic in the ProcessRecord constructor.
+ info.uid = Process.SYSTEM_UID;
+ info.processName = processName;
+ info.className = entryPoint;
+ info.packageName = "android";
+ ProcessRecord proc = startProcessLocked(processName, info /* info */,
+ false /* knownToBeDead */, 0 /* intentFlags */, "" /* hostingType */,
+ null /* hostingName */, true /* allowWhileBooting */, true /* isolated */,
+ uid, true /* keepIfLarge */, abiOverride, entryPoint, entryPointArgs,
+ crashHandler);
+ return proc != null ? proc.pid : 0;
+ }
+ }
+
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
+ return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
+ hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
+ null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
+ null /* crashHandler */);
+ }
+
+ final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
+ boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
+ boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
+ String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
@@ -2901,7 +2940,8 @@
}
if (app == null) {
- app = newProcessRecordLocked(info, processName, isolated);
+ app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
+ app.crashHandler = crashHandler;
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
@@ -2928,7 +2968,8 @@
return app;
}
- startProcessLocked(app, hostingType, hostingNameStr, null /* ABI override */);
+ startProcessLocked(
+ app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
return (app.pid != 0) ? app : null;
}
@@ -2937,7 +2978,13 @@
}
private final void startProcessLocked(ProcessRecord app,
- String hostingType, String hostingNameStr, String abiOverride) {
+ String hostingType, String hostingNameStr) {
+ startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */,
+ null /* entryPoint */, null /* entryPointArgs */);
+ }
+
+ private final void startProcessLocked(ProcessRecord app, String hostingType,
+ String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
if (app.pid > 0 && app.pid != MY_PID) {
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
@@ -3030,9 +3077,11 @@
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
- Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
+ boolean isActivityProcess = (entryPoint == null);
+ if (entryPoint == null) entryPoint = "android.app.ActivityThread";
+ Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
- app.info.targetSdkVersion, app.info.seinfo, requiredAbi, null);
+ app.info.targetSdkVersion, app.info.seinfo, requiredAbi, entryPointArgs);
if (app.isolated) {
mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);
@@ -3052,6 +3101,11 @@
buf.setLength(0);
buf.append("Start proc ");
buf.append(app.processName);
+ if (!isActivityProcess) {
+ buf.append(" [");
+ buf.append(entryPoint);
+ buf.append("]");
+ }
buf.append(" for ");
buf.append(hostingType);
if (hostingNameStr != null) {
@@ -3082,10 +3136,12 @@
app.killedByAm = false;
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app);
- Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
- msg.obj = app;
- mHandler.sendMessageDelayed(msg, startResult.usingWrapper
- ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
+ if (isActivityProcess) {
+ Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+ msg.obj = app;
+ mHandler.sendMessageDelayed(msg, startResult.usingWrapper
+ ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
+ }
}
} catch (RuntimeException e) {
// XXX do better error recovery.
@@ -5355,7 +5411,7 @@
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
- startProcessLocked(app, "link fail", processName, null /* ABI override */);
+ startProcessLocked(app, "link fail", processName);
return false;
}
@@ -5448,7 +5504,7 @@
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
- startProcessLocked(app, "bind fail", processName, null /* ABI override */);
+ startProcessLocked(app, "bind fail", processName);
return false;
}
@@ -5603,7 +5659,7 @@
for (int ip=0; ip<NP; ip++) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: "
+ procs.get(ip));
- startProcessLocked(procs.get(ip), "on-hold", null, null /* ABI override */);
+ startProcessLocked(procs.get(ip), "on-hold", null);
}
}
@@ -8951,29 +9007,35 @@
// =========================================================
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
- boolean isolated) {
+ boolean isolated, int isolatedUid) {
String proc = customProcess != null ? customProcess : info.processName;
BatteryStatsImpl.Uid.Proc ps = null;
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
int uid = info.uid;
if (isolated) {
- int userId = UserHandle.getUserId(uid);
- int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
- while (true) {
- if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
- || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
- mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
+ if (isolatedUid == 0) {
+ int userId = UserHandle.getUserId(uid);
+ int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
+ while (true) {
+ if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
+ || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
+ mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
+ }
+ uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
+ mNextIsolatedProcessUid++;
+ if (mIsolatedProcesses.indexOfKey(uid) < 0) {
+ // No process for this uid, use it.
+ break;
+ }
+ stepsLeft--;
+ if (stepsLeft <= 0) {
+ return null;
+ }
}
- uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
- mNextIsolatedProcessUid++;
- if (mIsolatedProcesses.indexOfKey(uid) < 0) {
- // No process for this uid, use it.
- break;
- }
- stepsLeft--;
- if (stepsLeft <= 0) {
- return null;
- }
+ } else {
+ // Special case for startIsolatedProcess (internal only), where
+ // the uid of the isolated process is specified by the caller.
+ uid = isolatedUid;
}
}
return new ProcessRecord(stats, info, proc, uid);
@@ -8989,7 +9051,7 @@
}
if (app == null) {
- app = newProcessRecordLocked(info, null, isolated);
+ app = newProcessRecordLocked(info, null, isolated, 0);
mProcessNames.put(info.processName, app.uid, app);
if (isolated) {
mIsolatedProcesses.put(app.uid, app);
@@ -9015,8 +9077,8 @@
}
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
- startProcessLocked(app, "added application", app.processName,
- abiOverride);
+ startProcessLocked(app, "added application", app.processName, abiOverride,
+ null /* entryPoint */, null /* entryPointArgs */);
}
return app;
@@ -10515,6 +10577,7 @@
mProcessCrashTimes.put(app.info.processName, app.uid, now);
}
+ if (app.crashHandler != null) mHandler.post(app.crashHandler);
return true;
}
@@ -13513,7 +13576,7 @@
// We have components that still need to be running in the
// process, so re-launch it.
mProcessNames.put(app.processName, app.uid, app);
- startProcessLocked(app, "restart", app.processName, null /* ABI override */);
+ startProcessLocked(app, "restart", app.processName);
} else if (app.pid > 0 && app.pid != MY_PID) {
// Goodbye!
boolean removed;
@@ -17845,6 +17908,13 @@
public void wakingUp() {
ActivityManagerService.this.wakingUp();
}
+
+ @Override
+ public int startIsolatedProcess(String entryPoint, String[] entryPointArgs,
+ String processName, String abiOverride, int uid, Runnable crashHandler) {
+ return ActivityManagerService.this.startIsolatedProcess(entryPoint, entryPointArgs,
+ processName, abiOverride, uid, crashHandler);
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b33f7b7..f1bcb60 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -127,7 +127,8 @@
Object adjSource; // Debugging: option dependent object.
int adjSourceProcState; // Debugging: proc state of adjSource's process.
Object adjTarget; // Debugging: target component impacting oom_adj.
-
+ Runnable crashHandler; // Optional local handler to be invoked in the process crash.
+
// contains HistoryRecord objects
final ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
// all ServiceRecord running in this process
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8c52fad..d1182e9 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -422,6 +422,9 @@
// Current state of whether the settings are allowing auto low power mode.
private boolean mAutoLowPowerModeEnabled;
+ // The user turned off low power mode below the trigger level
+ private boolean mAutoLowPowerModeSnoozing;
+
// True if the battery level is currently considered low.
private boolean mBatteryLevelLow;
@@ -650,9 +653,23 @@
final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
final boolean autoLowPowerModeEnabled = Settings.Global.getInt(resolver,
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 15) != 0;
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) != 0;
if (lowPowerModeEnabled != mLowPowerModeSetting
|| autoLowPowerModeEnabled != mAutoLowPowerModeEnabled) {
+ if (lowPowerModeEnabled != mLowPowerModeSetting) {
+ if (!mAutoLowPowerModeSnoozing && !lowPowerModeEnabled && !mIsPowered
+ && mAutoLowPowerModeEnabled) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "updateSettingsLocked: snoozing low power mode");
+ }
+ mAutoLowPowerModeSnoozing = true;
+ } else if (mAutoLowPowerModeSnoozing && lowPowerModeEnabled) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "updateSettingsLocked: no longer snoozing low power mode");
+ }
+ mAutoLowPowerModeSnoozing = true;
+ }
+ }
mLowPowerModeSetting = lowPowerModeEnabled;
mAutoLowPowerModeEnabled = autoLowPowerModeEnabled;
updateLowPowerModeLocked();
@@ -662,8 +679,25 @@
}
void updateLowPowerModeLocked() {
- final boolean lowPowerModeEnabled = !mIsPowered
- && (mLowPowerModeSetting || (mAutoLowPowerModeEnabled && mBatteryLevelLow));
+ if (mIsPowered && mLowPowerModeSetting) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "updateLowPowerModeLocked: powered, turning setting off");
+ }
+ // Turn setting off if powered
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.LOW_POWER_MODE, 0);
+ mLowPowerModeSetting = false;
+ } else if (!mIsPowered && mAutoLowPowerModeEnabled && !mAutoLowPowerModeSnoozing
+ && mBatteryLevelLow && !mLowPowerModeSetting) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "updateLowPowerModeLocked: trigger level reached, turning setting on");
+ }
+ // Turn setting on if trigger level is enabled, and we're now below it
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.LOW_POWER_MODE, 1);
+ mLowPowerModeSetting = true;
+ }
+ final boolean lowPowerModeEnabled = mLowPowerModeSetting;
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
@@ -672,6 +706,10 @@
BackgroundThread.getHandler().post(new Runnable() {
@Override
public void run() {
+ Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
+ .putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, mLowPowerModeEnabled)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcast(intent);
ArrayList<PowerManagerInternal.LowPowerModeListener> listeners;
synchronized (mLock) {
listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(
@@ -680,7 +718,7 @@
for (int i=0; i<listeners.size(); i++) {
listeners.get(i).onLowPowerModeChanged(lowPowerModeEnabled);
}
- Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcast(intent);
}
@@ -1218,6 +1256,12 @@
}
if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
+ if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "updateIsPoweredLocked: resetting low power snooze");
+ }
+ mAutoLowPowerModeSnoozing = false;
+ }
updateLowPowerModeLocked();
}
}
@@ -2265,6 +2309,7 @@
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
pw.println(" mLowPowerModeSetting=" + mLowPowerModeSetting);
pw.println(" mAutoLowPowerModeEnabled=" + mAutoLowPowerModeEnabled);
+ pw.println(" mAutoLowPowerModeSnoozing=" + mAutoLowPowerModeSnoozing);
pw.println(" mMinimumScreenOffTimeoutConfig=" + mMinimumScreenOffTimeoutConfig);
pw.println(" mMaximumScreenDimDurationConfig=" + mMaximumScreenDimDurationConfig);
pw.println(" mMaximumScreenDimRatioConfig=" + mMaximumScreenDimRatioConfig);
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 80ea2c8..4d375ee 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -28,6 +28,7 @@
import android.hardware.hdmi.IHdmiHotplugEventListener;
import android.hardware.hdmi.IHdmiInputChangeListener;
import android.media.AudioDevicePort;
+import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioPatch;
import android.media.AudioPort;
@@ -556,41 +557,54 @@
private final Object mImplLock = new Object();
private final AudioDevicePort mAudioSource;
- private final AudioDevicePort mAudioSink;
+ private AudioDevicePort mAudioSink;
private AudioPatch mAudioPatch = null;
private TvStreamConfig mActiveConfig = null;
+ private int mDesiredSamplingRate = 0;
+ private int mDesiredChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT;
+ private int mDesiredFormat = AudioFormat.ENCODING_DEFAULT;
+
public TvInputHardwareImpl(TvInputHardwareInfo info) {
mInfo = info;
AudioDevicePort audioSource = null;
- AudioDevicePort audioSink = null;
if (mInfo.getAudioType() != AudioManager.DEVICE_NONE) {
- ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>();
- if (mAudioManager.listAudioDevicePorts(devicePorts) == AudioManager.SUCCESS) {
- // Find source
- for (AudioPort port : devicePorts) {
- AudioDevicePort devicePort = (AudioDevicePort) port;
- if (devicePort.type() == mInfo.getAudioType() &&
- devicePort.address().equals(mInfo.getAudioAddress())) {
- audioSource = devicePort;
- break;
- }
- }
- // Find sink
- // TODO: App may want to specify sink device?
- int sinkDevices = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
- for (AudioPort port : devicePorts) {
- AudioDevicePort devicePort = (AudioDevicePort) port;
- if (devicePort.type() == sinkDevices) {
- audioSink = devicePort;
- break;
- }
+ audioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress());
+ mAudioSink = findAudioSinkFromAudioPolicy();
+ }
+ mAudioSource = audioSource;
+ }
+
+ private AudioDevicePort findAudioSinkFromAudioPolicy() {
+ ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>();
+ if (mAudioManager.listAudioDevicePorts(devicePorts) == AudioManager.SUCCESS) {
+ int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
+ for (AudioPort port : devicePorts) {
+ AudioDevicePort devicePort = (AudioDevicePort) port;
+ if (devicePort.type() == sinkDevice) {
+ return devicePort;
}
}
}
- mAudioSource = audioSource;
- mAudioSink = audioSink;
+ return null;
+ }
+
+ private AudioDevicePort findAudioDevicePort(int type, String address) {
+ if (type == AudioManager.DEVICE_NONE) {
+ return null;
+ }
+ ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>();
+ if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) {
+ return null;
+ }
+ for (AudioPort port : devicePorts) {
+ AudioDevicePort devicePort = (AudioDevicePort) port;
+ if (devicePort.type() == type && devicePort.address().equals(address)) {
+ return devicePort;
+ }
+ }
+ return null;
}
public void release() {
@@ -621,15 +635,7 @@
}
if (mAudioSource != null && mAudioSink != null) {
if (surface != null) {
- AudioPortConfig sourceConfig = mAudioSource.activeConfig();
- AudioPortConfig sinkConfig = mAudioSink.activeConfig();
- AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch };
- // TODO: build config if activeConfig() == null
- mAudioManager.createAudioPatch(
- audioPatchArray,
- new AudioPortConfig[] { sourceConfig },
- new AudioPortConfig[] { sinkConfig });
- mAudioPatch = audioPatchArray[0];
+ updateAudioPatchLocked();
} else {
mAudioManager.releaseAudioPatch(mAudioPatch);
mAudioPatch = null;
@@ -656,6 +662,31 @@
}
}
+ private void updateAudioPatchLocked() {
+ AudioPortConfig sourceConfig = mAudioSource.activeConfig();
+ AudioPortConfig sinkConfig = mAudioSink.activeConfig();
+ AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch };
+ if (sinkConfig == null
+ || (mDesiredSamplingRate != 0
+ && sinkConfig.samplingRate() != mDesiredSamplingRate)
+ || (mDesiredChannelMask != AudioFormat.CHANNEL_OUT_DEFAULT
+ && sinkConfig.channelMask() != mDesiredChannelMask)
+ || (mDesiredFormat != AudioFormat.ENCODING_DEFAULT
+ && sinkConfig.format() != mDesiredFormat)) {
+ sinkConfig = mAudioSource.buildConfig(mDesiredSamplingRate, mDesiredChannelMask,
+ mDesiredFormat, null);
+ }
+ if (sourceConfig == null) {
+ sourceConfig = mAudioSource.buildConfig(sinkConfig.samplingRate(),
+ sinkConfig.channelMask(), sinkConfig.format(), null);
+ }
+ mAudioManager.createAudioPatch(
+ audioPatchArray,
+ new AudioPortConfig[] { sourceConfig },
+ new AudioPortConfig[] { sinkConfig });
+ mAudioPatch = audioPatchArray[0];
+ }
+
@Override
public void setVolume(float volume) throws RemoteException {
synchronized (mImplLock) {
@@ -710,6 +741,28 @@
return result == TvInputHal.SUCCESS;
}
}
+
+ @Override
+ public void overrideAudioSink(int audioType, String audioAddress, int samplingRate,
+ int channelMask, int format) {
+ synchronized (mImplLock) {
+ if (audioType == AudioManager.DEVICE_NONE) {
+ mAudioSink = findAudioSinkFromAudioPolicy();
+ } else {
+ AudioDevicePort audioSink = findAudioDevicePort(audioType, audioAddress);
+ if (audioSink != null) {
+ mAudioSink = audioSink;
+ }
+ }
+ mDesiredSamplingRate = samplingRate;
+ mDesiredChannelMask = channelMask;
+ mDesiredFormat = format;
+
+ if (mAudioPatch != null) {
+ updateAudioPatchLocked();
+ }
+ }
+ }
}
interface Listener {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index e9a3c4e..e11b6a7 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -35,6 +35,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Rect;
import android.hardware.hdmi.HdmiCecDeviceInfo;
@@ -282,6 +283,18 @@
userState.inputMap.clear();
userState.inputMap = inputMap;
+
+ Resources r = Resources.getSystem();
+ userState.ratingSystemXmlUriSet.clear();
+ userState.ratingSystemXmlUriSet.add(TvContentRating.SYSTEM_CONTENT_RATING_SYSTEM_XML);
+ for (TvInputState state : userState.inputMap.values()) {
+ Uri ratingSystemXmlUri = state.mInfo.getRatingSystemXmlUri();
+ if (ratingSystemXmlUri != null) {
+ // TODO: need to check the validation of xml format and the duplication of rating
+ // systems.
+ userState.ratingSystemXmlUriSet.add(state.mInfo.getRatingSystemXmlUri());
+ }
+ }
}
private void switchUser(int userId) {
@@ -815,6 +828,23 @@
}
@Override
+ public List<Uri> getTvContentRatingSystemXmls(int userId) {
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, "getTvContentRatingSystemXmls");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ UserState userState = getUserStateLocked(resolvedUserId);
+ List<Uri> ratingSystemXmlUriList = new ArrayList<Uri>();
+ ratingSystemXmlUriList.addAll(userState.ratingSystemXmlUriSet);
+ return ratingSystemXmlUriList;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void registerCallback(final ITvInputManagerCallback callback, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "registerCallback");
@@ -1643,6 +1673,9 @@
// A set of all TV input packages.
private final Set<String> packageSet = new HashSet<String>();
+ // A set of all TV content rating system xml uris.
+ private final Set<Uri> ratingSystemXmlUriSet = new HashSet<Uri>();
+
// A mapping from the token of a client to its state.
private final Map<IBinder, ClientState> clientStateMap =
new HashMap<IBinder, ClientState>();
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 60724e7..d4c5f87 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -22,17 +22,20 @@
import android.content.IntentFilter;
import android.os.Binder;
import android.os.Process;
-import android.util.Log;
+import android.util.Slog;
import android.webkit.IWebViewUpdateService;
import android.webkit.WebViewFactory;
+import com.android.server.SystemService;
+
/**
* Private service to wait for the updatable WebView to be ready for use.
* @hide
*/
-public class WebViewUpdateService extends IWebViewUpdateService.Stub {
+public class WebViewUpdateService extends SystemService {
private static final String TAG = "WebViewUpdateService";
+ private static final int WAIT_TIMEOUT_MS = 5000; // Same as KEY_DISPATCHING_TIMEOUT.
private boolean mRelroReady32Bit = false;
private boolean mRelroReady64Bit = false;
@@ -40,6 +43,11 @@
private BroadcastReceiver mWebViewUpdatedReceiver;
public WebViewUpdateService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
mWebViewUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -52,57 +60,76 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addDataScheme("package");
- context.registerReceiver(mWebViewUpdatedReceiver, filter);
- }
+ getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
- /**
- * The shared relro process calls this to notify us that it's done trying to create a relro
- * file.
- */
- public void notifyRelroCreationCompleted(boolean is64Bit, boolean success) {
- // Verify that the caller is the shared relro process.
- if (Binder.getCallingUid() != Process.SHARED_RELRO_UID) {
- return;
- }
-
- synchronized (this) {
- if (is64Bit) {
- mRelroReady64Bit = true;
- } else {
- mRelroReady32Bit = true;
- }
- this.notifyAll();
- }
- }
-
- /**
- * WebViewFactory calls this to block WebView loading until the relro file is created.
- */
- public void waitForRelroCreationCompleted(boolean is64Bit) {
- synchronized (this) {
- if (is64Bit) {
- while (!mRelroReady64Bit) {
- try {
- this.wait();
- } catch (InterruptedException e) {}
- }
- } else {
- while (!mRelroReady32Bit) {
- try {
- this.wait();
- } catch (InterruptedException e) {}
- }
- }
- }
+ publishBinderService("webviewupdate", new BinderService());
}
private void onWebViewUpdateInstalled() {
- Log.d(TAG, "WebView Package updated!");
+ Slog.d(TAG, "WebView Package updated!");
synchronized (this) {
mRelroReady32Bit = false;
mRelroReady64Bit = false;
}
- WebViewFactory.prepareWebViewInSystemServer();
+ WebViewFactory.onWebViewUpdateInstalled();
}
+
+ private class BinderService extends IWebViewUpdateService.Stub {
+
+ /**
+ * The shared relro process calls this to notify us that it's done trying to create a relro
+ * file. This method gets called even if the relro creation has failed or the process
+ * crashed.
+ */
+ @Override // Binder call
+ public void notifyRelroCreationCompleted(boolean is64Bit, boolean success) {
+ // Verify that the caller is either the shared relro process (nominal case) or the
+ // system server (only in the case the relro process crashes and we get here via the
+ // crashHandler).
+ if (Binder.getCallingUid() != Process.SHARED_RELRO_UID &&
+ Binder.getCallingUid() != Process.SYSTEM_UID) {
+ return;
+ }
+
+ synchronized (WebViewUpdateService.this) {
+ if (is64Bit) {
+ mRelroReady64Bit = true;
+ } else {
+ mRelroReady32Bit = true;
+ }
+ WebViewUpdateService.this.notifyAll();
+ }
+ }
+
+ /**
+ * WebViewFactory calls this to block WebView loading until the relro file is created.
+ */
+ @Override // Binder call
+ public void waitForRelroCreationCompleted(boolean is64Bit) {
+ // The WebViewUpdateService depends on the prepareWebViewInSystemServer call, which
+ // happens later (during the PHASE_ACTIVITY_MANAGER_READY) in SystemServer.java. If
+ // another service there tries to bring up a WebView in the between, the wait below
+ // would deadlock without the check below.
+ if (Binder.getCallingPid() == Process.myPid()) {
+ throw new IllegalStateException("Cannot create a WebView from the SystemServer");
+ }
+
+ final long NS_PER_MS = 1000000;
+ final long timeoutTimeMs = System.nanoTime() / NS_PER_MS + WAIT_TIMEOUT_MS;
+ boolean relroReady = (is64Bit ? mRelroReady64Bit : mRelroReady32Bit);
+ synchronized (WebViewUpdateService.this) {
+ while (!relroReady) {
+ final long timeNowMs = System.nanoTime() / NS_PER_MS;
+ if (timeNowMs >= timeoutTimeMs) break;
+ try {
+ WebViewUpdateService.this.wait(timeoutTimeMs - timeNowMs);
+ } catch (InterruptedException e) {}
+ relroReady = (is64Bit ? mRelroReady64Bit : mRelroReady32Bit);
+ }
+ }
+ if (!relroReady) Slog.w(TAG, "creating relro file timed out");
+ }
+ }
+
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d955354..e8d6773 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -376,6 +376,9 @@
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
+
+ // Tracks whether the updatable WebView is in a ready state and watches for update installs.
+ mSystemServiceManager.startService(WebViewUpdateService.class);
}
/**
@@ -422,12 +425,6 @@
Slog.i(TAG, "Reading configuration...");
SystemConfig.getInstance();
- Slog.i(TAG, "WebView Update Service");
- ServiceManager.addService("webviewupdate", new WebViewUpdateService(context));
-
- Slog.i(TAG, "WebViewFactory preparation");
- WebViewFactory.prepareWebViewInSystemServer();
-
Slog.i(TAG, "Scheduling Policy");
ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
@@ -1080,6 +1077,10 @@
} catch (Throwable e) {
reportWtf("observing native crashes", e);
}
+
+ Slog.i(TAG, "WebViewFactory preparation");
+ WebViewFactory.prepareWebViewInSystemServer();
+
try {
startSystemUi(context);
} catch (Throwable e) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
index 0eac1c4..f3ede88 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
@@ -65,6 +65,8 @@
private int mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
private UUID mCurrentSoundModelUuid = null;
+ // FIXME: Ideally this should not be stored if allowMultipleTriggers happens at a lower layer.
+ private RecognitionConfig mRecognitionConfig = null;
SoundTriggerHelper() {
ArrayList <ModuleProperties> modules = new ArrayList<>();
@@ -174,6 +176,7 @@
// Everything went well!
mCurrentSoundModelHandle = soundModelHandle;
mCurrentSoundModelUuid = soundModel.uuid;
+ mRecognitionConfig = recognitionConfig;
// Register the new listener. This replaces the old one.
// There can only be a maximum of one active listener for a keyphrase
// at any given time.
@@ -221,12 +224,12 @@
int status = mModule.stopRecognition(mCurrentSoundModelHandle);
if (status != SoundTrigger.STATUS_OK) {
Slog.w(TAG, "stopRecognition call failed with " + status);
- return STATUS_ERROR;
+ return status;
}
status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
if (status != SoundTrigger.STATUS_OK) {
Slog.w(TAG, "unloadSoundModel call failed with " + status);
- return STATUS_ERROR;
+ return status;
}
mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
@@ -237,6 +240,30 @@
}
}
+ synchronized void stopAllRecognitions() {
+ if (moduleProperties == null || mModule == null) {
+ return;
+ }
+
+ if (mCurrentSoundModelHandle == INVALID_SOUND_MODEL_HANDLE) {
+ return;
+ }
+
+ int status = mModule.stopRecognition(mCurrentSoundModelHandle);
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "stopRecognition call failed with " + status);
+ }
+ status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "unloadSoundModel call failed with " + status);
+ }
+
+ mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE;
+ mCurrentSoundModelUuid = null;
+
+ mActiveListeners.clear();
+ }
+
//---- SoundTrigger.StatusListener methods
@Override
public void onRecognition(RecognitionEvent event) {
@@ -284,6 +311,17 @@
Slog.w(TAG, "received onRecognition event without any listener for it");
return;
}
+
+ // FIXME: Remove this block if the lower layer supports multiple triggers.
+ if (mRecognitionConfig != null
+ && mRecognitionConfig.allowMultipleTriggers) {
+ int status = mModule.startRecognition(
+ mCurrentSoundModelHandle, mRecognitionConfig);
+ if (status != STATUS_OK) {
+ Slog.w(TAG, "Error in restarting recognition after a trigger");
+ listener.onError(status);
+ }
+ }
}
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onDetectionStopped");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index a3d578a..75d41aa 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -49,9 +49,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.List;
-import java.util.UUID;
-
/**
* SystemService that publishes an IVoiceInteractionManagerService.
@@ -151,6 +148,7 @@
}
if (force || mImpl == null || mImpl.mUser != mCurUser
|| !mImpl.mComponent.equals(serviceComponent)) {
+ mSoundTriggerHelper.stopAllRecognitions();
if (mImpl != null) {
mImpl.shutdownLocked();
}
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 8845821..b55f62a 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -19,6 +19,9 @@
import android.app.PendingIntent;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
import java.util.HashSet;
@@ -30,6 +33,32 @@
*/
public abstract class Connection {
+ private static final int MSG_ADD_CONNECTION_LISTENER = 1;
+ private static final int MSG_REMOVE_CONNECTION_LISTENER = 2;
+ private static final int MSG_SET_AUDIO_STATE = 3;
+ private static final int MSG_SET_PARENT_CONNECTION = 4;
+ private static final int MSG_SET_HANDLE = 5;
+ private static final int MSG_SET_CALLER_DISPLAY_NAME = 6;
+ private static final int MSG_SET_CANCELED = 7;
+ private static final int MSG_SET_FAILED = 8;
+ private static final int MSG_SET_VIDEO_STATE = 9;
+ private static final int MSG_SET_ACTIVE = 10;
+ private static final int MSG_SET_RINGING = 11;
+ private static final int MSG_SET_INITIALIZING = 12;
+ private static final int MSG_SET_INITIALIZED = 13;
+ private static final int MSG_SET_DIALING = 14;
+ private static final int MSG_SET_ON_HOLD = 15;
+ private static final int MSG_SET_VIDEO_CALL_PROVIDER = 16;
+ private static final int MSG_SET_DISCONNECTED = 17;
+ private static final int MSG_SET_POST_DIAL_WAIT = 18;
+ private static final int MSG_SET_REQUESTING_RINGBACK = 19;
+ private static final int MSG_SET_CALL_CAPABILITIES = 20;
+ private static final int MSG_DESTROY = 21;
+ private static final int MSG_SET_SIGNAL = 22;
+ private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 23;
+ private static final int MSG_SET_STATUS_HINTS = 24;
+ private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 25;
+
/** @hide */
public abstract static class Listener {
public void onStateChanged(Connection c, int state) {}
@@ -49,7 +78,6 @@
public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
public void onStatusHintsChanged(Connection c, StatusHints statusHints) {}
public void onStartActivityFromInCall(Connection c, PendingIntent intent) {}
- public void onFailed(Connection c, int code, String msg) {}
}
public final class State {
@@ -87,6 +115,220 @@
private String mFailureMessage;
private boolean mIsCanceled;
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ADD_CONNECTION_LISTENER: {
+ Listener listener = (Listener) msg.obj;
+ mListeners.add(listener);
+ }
+ break;
+ case MSG_REMOVE_CONNECTION_LISTENER: {
+ Listener listener = (Listener) msg.obj;
+ mListeners.remove(listener);
+ }
+ break;
+ case MSG_SET_AUDIO_STATE: {
+ CallAudioState state = (CallAudioState) msg.obj;
+ mCallAudioState = state;
+ onSetAudioState(state);
+ }
+ break;
+ case MSG_SET_PARENT_CONNECTION: {
+ Connection parentConnection = (Connection) msg.obj;
+ if (mParentConnection != parentConnection) {
+ if (mParentConnection != null) {
+ mParentConnection.removeChild(Connection.this);
+ }
+ mParentConnection = parentConnection;
+ if (mParentConnection != null) {
+ mParentConnection.addChild(Connection.this);
+ // do something if the child connections goes down to ZERO.
+ }
+ for (Listener l : mListeners) {
+ l.onParentConnectionChanged(Connection.this, mParentConnection);
+ }
+ }
+ }
+ break;
+ case MSG_SET_HANDLE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ Uri handle = (Uri) args.arg1;
+ int presentation = args.argi1;
+ mHandle = handle;
+ mHandlePresentation = presentation;
+ for (Listener l : mListeners) {
+ l.onHandleChanged(Connection.this, handle, presentation);
+ }
+ } finally {
+ args.recycle();
+ }
+ }
+ break;
+ case MSG_SET_CALLER_DISPLAY_NAME: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callerDisplayName = (String) args.arg1;
+ int presentation = args.argi1;
+ mCallerDisplayName = callerDisplayName;
+ mCallerDisplayNamePresentation = presentation;
+ for (Listener l : mListeners) {
+ l.onCallerDisplayNameChanged(Connection.this, callerDisplayName,
+ presentation);
+ }
+ } finally {
+ args.recycle();
+ }
+ }
+ break;
+ case MSG_SET_CANCELED: {
+ setState(State.CANCELED);
+ }
+ break;
+ case MSG_SET_FAILED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ int code = args.argi1;
+ String message = (String) args.arg1;
+ mFailureCode = code;
+ mFailureMessage = message;
+ setState(State.FAILED);
+ } finally {
+ args.recycle();
+ }
+ }
+ break;
+ case MSG_SET_VIDEO_STATE: {
+ int videoState = ((Integer) msg.obj).intValue();
+ mVideoState = videoState;
+ for (Listener l : mListeners) {
+ l.onVideoStateChanged(Connection.this, mVideoState);
+ }
+ }
+ break;
+ case MSG_SET_ACTIVE: {
+ setRequestingRingback(false);
+ setState(State.ACTIVE);
+ }
+ break;
+ case MSG_SET_RINGING: {
+ setState(State.RINGING);
+ }
+ break;
+ case MSG_SET_INITIALIZING: {
+ setState(State.INITIALIZING);
+ }
+ break;
+ case MSG_SET_INITIALIZED: {
+ setState(State.NEW);
+ }
+ break;
+ case MSG_SET_DIALING: {
+ setState(State.DIALING);
+ }
+ break;
+ case MSG_SET_ON_HOLD: {
+ setState(State.HOLDING);
+ }
+ break;
+ case MSG_SET_VIDEO_CALL_PROVIDER: {
+ ConnectionService.VideoCallProvider videoCallProvider =
+ (ConnectionService.VideoCallProvider) msg.obj;
+ mVideoCallProvider = videoCallProvider;
+ for (Listener l : mListeners) {
+ l.onVideoCallProviderChanged(Connection.this, videoCallProvider);
+ }
+ }
+ break;
+ case MSG_SET_DISCONNECTED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ int cause = args.argi1;
+ String message = (String) args.arg1;
+ setState(State.DISCONNECTED);
+ Log.d(this, "Disconnected with cause %d message %s", cause, message);
+ for (Listener l : mListeners) {
+ l.onDisconnected(Connection.this, cause, message);
+ }
+ } finally {
+ args.recycle();
+ }
+ }
+ break;
+ case MSG_SET_POST_DIAL_WAIT: {
+ String remaining = (String) msg.obj;
+ for (Listener l : mListeners) {
+ l.onPostDialWait(Connection.this, remaining);
+ }
+ }
+ break;
+ case MSG_SET_REQUESTING_RINGBACK: {
+ boolean ringback = ((Boolean) msg.obj).booleanValue();
+ if (mRequestingRingback != ringback) {
+ mRequestingRingback = ringback;
+ for (Listener l : mListeners) {
+ l.onRequestingRingback(Connection.this, ringback);
+ }
+ }
+ } break;
+ case MSG_SET_CALL_CAPABILITIES: {
+ int callCapabilities = ((Integer) msg.obj).intValue();
+ if (mCallCapabilities != callCapabilities) {
+ mCallCapabilities = callCapabilities;
+ for (Listener l : mListeners) {
+ l.onCallCapabilitiesChanged(Connection.this, mCallCapabilities);
+ }
+ }
+ }
+ break;
+ case MSG_DESTROY: {
+ // TODO: Is this still relevant because everything is on the main thread now.
+ // It is possible that onDestroy() will trigger the listener to remove itself
+ // which will result in a concurrent modification exception. To counteract
+ // this we make a copy of the listeners and iterate on that.
+ for (Listener l : new ArrayList<>(mListeners)) {
+ if (mListeners.contains(l)) {
+ l.onDestroyed(Connection.this);
+ }
+ }
+ }
+ break;
+ case MSG_SET_SIGNAL: {
+ Bundle details = (Bundle) msg.obj;
+ for (Listener l : mListeners) {
+ l.onSignalChanged(Connection.this, details);
+ }
+ }
+ break;
+ case MSG_SET_AUDIO_MODE_IS_VOIP: {
+ boolean isVoip = ((Boolean) msg.obj).booleanValue();
+ mAudioModeIsVoip = isVoip;
+ for (Listener l : mListeners) {
+ l.onAudioModeIsVoipChanged(Connection.this, isVoip);
+ }
+ }
+ break;
+ case MSG_SET_STATUS_HINTS: {
+ StatusHints statusHints = (StatusHints) msg.obj;
+ mStatusHints = statusHints;
+ for (Listener l : mListeners) {
+ l.onStatusHintsChanged(Connection.this, statusHints);
+ }
+ }
+ break;
+ case MSG_START_ACTIVITY_FROM_IN_CALL: {
+ PendingIntent intent = (PendingIntent) msg.obj;
+ for (Listener l : mListeners) {
+ l.onStartActivityFromInCall(Connection.this, intent);
+ }
+ }
+ break;
+ }
+ }
+ };
+
/**
* Create a new Connection.
*/
@@ -188,7 +430,7 @@
* @hide
*/
public final Connection addConnectionListener(Listener l) {
- mListeners.add(l);
+ mHandler.obtainMessage(MSG_ADD_CONNECTION_LISTENER, l).sendToTarget();
return this;
}
@@ -201,7 +443,7 @@
* @hide
*/
public final Connection removeConnectionListener(Listener l) {
- mListeners.remove(l);
+ mHandler.obtainMessage(MSG_REMOVE_CONNECTION_LISTENER, l).sendToTarget();
return this;
}
@@ -227,8 +469,7 @@
*/
final void setAudioState(CallAudioState state) {
Log.d(this, "setAudioState %s", state);
- mCallAudioState = state;
- onSetAudioState(state);
+ mHandler.obtainMessage(MSG_SET_AUDIO_STATE, state).sendToTarget();
}
/**
@@ -266,19 +507,7 @@
*/
public final void setParentConnection(Connection parentConnection) {
Log.d(this, "parenting %s to %s", this, parentConnection);
- if (mParentConnection != parentConnection) {
- if (mParentConnection != null) {
- mParentConnection.removeChild(this);
- }
- mParentConnection = parentConnection;
- if (mParentConnection != null) {
- mParentConnection.addChild(this);
- // do something if the child connections goes down to ZERO.
- }
- for (Listener l : mListeners) {
- l.onParentConnectionChanged(this, mParentConnection);
- }
- }
+ mHandler.obtainMessage(MSG_SET_PARENT_CONNECTION, parentConnection).sendToTarget();
}
public final Connection getParentConnection() {
@@ -305,11 +534,10 @@
*/
public final void setHandle(Uri handle, int presentation) {
Log.d(this, "setHandle %s", handle);
- mHandle = handle;
- mHandlePresentation = presentation;
- for (Listener l : mListeners) {
- l.onHandleChanged(this, handle, presentation);
- }
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = handle;
+ args.argi1 = presentation;
+ mHandler.obtainMessage(MSG_SET_HANDLE, args).sendToTarget();
}
/**
@@ -321,11 +549,10 @@
*/
public final void setCallerDisplayName(String callerDisplayName, int presentation) {
Log.d(this, "setCallerDisplayName %s", callerDisplayName);
- mCallerDisplayName = callerDisplayName;
- mCallerDisplayNamePresentation = presentation;
- for (Listener l : mListeners) {
- l.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
- }
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callerDisplayName;
+ args.argi1 = presentation;
+ mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
}
/**
@@ -334,7 +561,7 @@
*/
public final void setCanceled() {
Log.d(this, "setCanceled");
- setState(State.CANCELED);
+ mHandler.obtainMessage(MSG_SET_CANCELED).sendToTarget();
}
/**
@@ -350,9 +577,10 @@
*/
public final void setFailed(int code, String message) {
Log.d(this, "setFailed (%d: %s)", code, message);
- mFailureCode = code;
- mFailureMessage = message;
- setState(State.FAILED);
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = code;
+ args.arg1 = message;
+ mHandler.obtainMessage(MSG_SET_FAILED, args).sendToTarget();
}
/**
@@ -366,10 +594,7 @@
*/
public final void setVideoState(int videoState) {
Log.d(this, "setVideoState %d", videoState);
- mVideoState = videoState;
- for (Listener l : mListeners) {
- l.onVideoStateChanged(this, mVideoState);
- }
+ mHandler.obtainMessage(MSG_SET_VIDEO_STATE, Integer.valueOf(videoState)).sendToTarget();
}
/**
@@ -377,28 +602,28 @@
* communicate).
*/
public final void setActive() {
- setRequestingRingback(false);
- setState(State.ACTIVE);
+ mHandler.obtainMessage(MSG_SET_ACTIVE).sendToTarget();
}
/**
* Sets state to ringing (e.g., an inbound ringing call).
*/
public final void setRinging() {
- setState(State.RINGING);
+ mHandler.obtainMessage(MSG_SET_RINGING).sendToTarget();
}
/**
* Sets state to initializing (this Connection is not yet ready to be used).
*/
public final void setInitializing() {
- setState(State.INITIALIZING);
+ mHandler.obtainMessage(MSG_SET_INITIALIZING).sendToTarget();
}
/**
* Sets state to initialized (the Connection has been set up and is now ready to be used).
*/
public final void setInitialized() {
+ mHandler.obtainMessage(MSG_SET_INITIALIZED).sendToTarget();
setState(State.NEW);
}
@@ -406,14 +631,14 @@
* Sets state to dialing (e.g., dialing an outbound call).
*/
public final void setDialing() {
- setState(State.DIALING);
+ mHandler.obtainMessage(MSG_SET_DIALING).sendToTarget();
}
/**
* Sets state to be on hold.
*/
public final void setOnHold() {
- setState(State.HOLDING);
+ mHandler.obtainMessage(MSG_SET_ON_HOLD).sendToTarget();
}
/**
@@ -421,10 +646,7 @@
* @param videoCallProvider The video call provider.
*/
public final void setVideoCallProvider(ConnectionService.VideoCallProvider videoCallProvider) {
- mVideoCallProvider = videoCallProvider;
- for (Listener l : mListeners) {
- l.onVideoCallProviderChanged(this, videoCallProvider);
- }
+ mHandler.obtainMessage(MSG_SET_VIDEO_CALL_PROVIDER, videoCallProvider).sendToTarget();
}
public final ConnectionService.VideoCallProvider getVideoCallProvider() {
@@ -439,20 +661,17 @@
* @param message Optional call-service-provided message about the disconnect.
*/
public final void setDisconnected(int cause, String message) {
- setState(State.DISCONNECTED);
- Log.d(this, "Disconnected with cause %d message %s", cause, message);
- for (Listener l : mListeners) {
- l.onDisconnected(this, cause, message);
- }
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = cause;
+ args.arg1 = message;
+ mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
}
/**
* TODO(santoscordon): Needs documentation.
*/
public final void setPostDialWait(String remaining) {
- for (Listener l : mListeners) {
- l.onPostDialWait(this, remaining);
- }
+ mHandler.obtainMessage(MSG_SET_POST_DIAL_WAIT, remaining).sendToTarget();
}
/**
@@ -462,12 +681,8 @@
* @param ringback Whether the ringback tone is to be played.
*/
public final void setRequestingRingback(boolean ringback) {
- if (mRequestingRingback != ringback) {
- mRequestingRingback = ringback;
- for (Listener l : mListeners) {
- l.onRequestingRingback(this, ringback);
- }
- }
+ mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, Boolean.valueOf(ringback))
+ .sendToTarget();
}
/**
@@ -476,26 +691,15 @@
* @param callCapabilities The new call capabilities.
*/
public final void setCallCapabilities(int callCapabilities) {
- if (mCallCapabilities != callCapabilities) {
- mCallCapabilities = callCapabilities;
- for (Listener l : mListeners) {
- l.onCallCapabilitiesChanged(this, mCallCapabilities);
- }
- }
+ mHandler.obtainMessage(MSG_SET_CALL_CAPABILITIES, Integer.valueOf(callCapabilities))
+ .sendToTarget();
}
/**
* TODO(santoscordon): Needs documentation.
*/
public final void destroy() {
- // It is possible that onDestroy() will trigger the listener to remove itself which will
- // result in a concurrent modification exception. To counteract this we make a copy of the
- // listeners and iterate on that.
- for (Listener l : new ArrayList<>(mListeners)) {
- if (mListeners.contains(l)) {
- l.onDestroyed(this);
- }
- }
+ mHandler.obtainMessage(MSG_DESTROY).sendToTarget();
}
/**
@@ -504,9 +708,7 @@
* @param details A {@link android.os.Bundle} containing details of the current level.
*/
public final void setSignal(Bundle details) {
- for (Listener l : mListeners) {
- l.onSignalChanged(this, details);
- }
+ mHandler.obtainMessage(MSG_SET_SIGNAL, details).sendToTarget();
}
/**
@@ -515,10 +717,7 @@
* @param isVoip True if the audio mode is VOIP.
*/
public final void setAudioModeIsVoip(boolean isVoip) {
- mAudioModeIsVoip = isVoip;
- for (Listener l : mListeners) {
- l.onAudioModeIsVoipChanged(this, isVoip);
- }
+ mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, Boolean.valueOf(isVoip)).sendToTarget();
}
/**
@@ -527,10 +726,7 @@
* @param statusHints The status label and icon to set.
*/
public final void setStatusHints(StatusHints statusHints) {
- mStatusHints = statusHints;
- for (Listener l : mListeners) {
- l.onStatusHintsChanged(this, statusHints);
- }
+ mHandler.obtainMessage(MSG_SET_STATUS_HINTS, statusHints).sendToTarget();
}
/**
@@ -542,13 +738,13 @@
if (!intent.isActivity()) {
throw new IllegalArgumentException("Activity intent required.");
}
- for (Listener l : mListeners) {
- l.onStartActivityFromInCall(this, intent);
- }
+ mHandler.obtainMessage(MSG_START_ACTIVITY_FROM_IN_CALL, intent).sendToTarget();
}
/**
* Notifies this Connection that the {@link #getCallAudioState()} property has a new value.
+ * <p>
+ * This callback will happen on the main thread.
*
* @param state The new call audio state.
*/
@@ -557,6 +753,8 @@
/**
* Notifies this Connection of an internal state change. This method is called after the
* state is changed.
+ * <p>
+ * This callback will happen on the main thread.
*
* @param state The new state, a {@link Connection.State} member.
*/
@@ -564,6 +762,8 @@
/**
* Notifies this Connection of a request to play a DTMF tone.
+ * <p>
+ * This callback will happen on the main thread.
*
* @param c A DTMF character.
*/
@@ -571,61 +771,81 @@
/**
* Notifies this Connection of a request to stop any currently playing DTMF tones.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onStopDtmfTone() {}
/**
* Notifies this Connection of a request to disconnect.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onDisconnect() {}
/**
* Notifies this Connection of a request to disconnect.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onSeparate() {}
/**
* Notifies this Connection of a request to abort.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onAbort() {}
/**
* Notifies this Connection of a request to hold.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onHold() {}
/**
* Notifies this Connection of a request to exit a hold state.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onUnhold() {}
/**
- * Notifies this Connection, which is in {@link State#RINGING}, of
- * a request to accept.
+ * Notifies this Connection, which is in {@link State#RINGING}, of a request to accept.
+ * <p>
+ * This callback will happen on the main thread.
*
* @param videoState The video state in which to answer the call.
*/
public void onAnswer(int videoState) {}
/**
- * Notifies this Connection, which is in {@link State#RINGING}, of
- * a request to reject.
+ * Notifies this Connection, which is in {@link State#RINGING}, of a request to reject.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onReject() {}
/**
* Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onPostDialContinue(boolean proceed) {}
/**
* Swap this call with a background call. This is used for calls that don't support hold,
* e.g. CDMA.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onSwapWithBackgroundCall() {}
/**
* TODO(santoscordon): Needs documentation.
+ * <p>
+ * This callback will happen on the main thread.
*/
public void onChildrenChanged(List<Connection> children) {}
@@ -634,12 +854,14 @@
*/
public void onPhoneAccountClicked() {}
+ /** This must be called from the main thread. */
private void addChild(Connection connection) {
Log.d(this, "adding child %s", connection);
mChildConnections.add(connection);
onChildrenChanged(mChildConnections);
}
+ /** This must be called from the main thread. */
private void removeChild(Connection connection) {
Log.d(this, "removing child %s", connection);
mChildConnections.remove(connection);
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index c8c3063..350c27e 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -50,7 +50,8 @@
* appropriate LISTEN_ flags.
*/
public class PhoneStateListener {
- private static final String TAG = "PhoneStateListener";
+ private static final String LOG_TAG = "PhoneStateListener";
+ private static final boolean DBG = false; // STOPSHIP if true
/**
* Stop listening for updates.
@@ -233,12 +234,14 @@
/** @hide */
public PhoneStateListener(long subId, Looper looper) {
- Rlog.d(TAG, "ctor: subId=" + subId + " looper=" + looper);
+ if (DBG) log("ctor: subId=" + subId + " looper=" + looper);
mSubId = subId;
mHandler = new Handler(looper) {
public void handleMessage(Message msg) {
- Rlog.d(TAG, "mSubId=" + mSubId + " what=0x" + Integer.toHexString(msg.what)
- + " msg=" + msg);
+ if (DBG) {
+ log("mSubId=" + mSubId + " what=0x" + Integer.toHexString(msg.what)
+ + " msg=" + msg);
+ }
switch (msg.what) {
case LISTEN_SERVICE_STATE:
PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
@@ -528,4 +531,8 @@
Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget();
}
};
+
+ private void log(String s) {
+ Rlog.d(LOG_TAG, s);
+ }
}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 99faba6..d2b6725 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -218,7 +218,10 @@
public static final int CODE_UT_OPERATION_NOT_ALLOWED = 803;
public static final int CODE_UT_CB_PASSWORD_MISMATCH = 821;
-
+ /**
+ * ECBM
+ */
+ public static final int CODE_ECBM_NOT_SUPPORTED = 901;
// For reason type
public int mReasonType;
diff --git a/telephony/java/com/android/ims/internal/IImsEcbm.aidl b/telephony/java/com/android/ims/internal/IImsEcbm.aidl
new file mode 100644
index 0000000..f890bc2
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsEcbm.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.ims.internal;
+
+import com.android.ims.internal.IImsEcbmListener;
+
+/**
+ * Provides the ECBM interface
+ *
+ * {@hide}
+ */
+interface IImsEcbm {
+ /**
+ * Sets the listener.
+ */
+ void setListener(in IImsEcbmListener listener);
+
+ /**
+ * Requests Modem to come out of ECBM mode
+ */
+ void exitEmergencyCallbackMode();
+}
diff --git a/telephony/java/com/android/ims/internal/IImsEcbmListener.aidl b/telephony/java/com/android/ims/internal/IImsEcbmListener.aidl
new file mode 100644
index 0000000..d866ecb
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsEcbmListener.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.ims.internal;
+
+/**
+ * A listener type for receiving notifications about the changes to
+ * Emergency Callback Mode through IMS.
+ *
+ * {@hide}
+ */
+interface IImsEcbmListener {
+ /**
+ * Notifies the application when the device enters Emergency Callback Mode.
+ */
+ void enteredECBM();
+
+ /**
+ * Notifies the application when the device exits Emergency Callback Mode.
+ */
+ void exitedECBM();
+}
diff --git a/telephony/java/com/android/ims/internal/IImsService.aidl b/telephony/java/com/android/ims/internal/IImsService.aidl
index 869cd9f..5138305 100644
--- a/telephony/java/com/android/ims/internal/IImsService.aidl
+++ b/telephony/java/com/android/ims/internal/IImsService.aidl
@@ -22,6 +22,7 @@
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsEcbm;
import com.android.ims.internal.IImsUt;
import com.android.ims.internal.IImsConfig;
@@ -62,4 +63,11 @@
* When IMS is OFF, device will behave as CSFB'ed.
*/
void turnOffIms();
+
+
+ /**
+ * ECBM interface for Emergency Callback mode mechanism.
+ */
+ IImsEcbm getEcbmInterface(int serviceId);
+
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 5ec4247..41b6b76 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -209,4 +209,14 @@
* Set to the sim count.
*/
static final String PROPERTY_SIM_COUNT = "ro.telephony.sim.count";
+
+ /**
+ * Enable VoLTE/VT over IMS: debug option
+ * If 1: use IMS if provisioned/registered etc (i.e. standard operation)
+ * If 0: use CS.
+ * If missing: use PROPERTY_DBG_IMS_VOLTE_ENABLE_DEAFULT
+ */
+ static final String PROPERTY_DBG_IMS_VOLTE_ENABLE = "persist.dbg.ims_volte_enable";
+
+ static final int PROPERTY_DBG_IMS_VOLTE_ENABLE_DEAFULT = 0;
}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index b43ad6f..02610f8 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -20,6 +20,7 @@
import android.os.Bundle;
import android.service.voice.AlwaysOnHotwordDetector;
import android.service.voice.AlwaysOnHotwordDetector.Callback;
+import android.service.voice.AlwaysOnHotwordDetector.TriggerAudio;
import android.service.voice.VoiceInteractionService;
import android.util.Log;
@@ -36,21 +37,11 @@
}
@Override
- public void onDetected(byte[] data) {
+ public void onDetected(TriggerAudio triggerAudio) {
Log.i(TAG, "onDetected");
}
@Override
- public void onDetectionStarted() {
- Log.i(TAG, "onDetectionStarted");
- }
-
- @Override
- public void onDetectionStopped() {
- Log.i(TAG, "onDetectionStopped");
- }
-
- @Override
public void onError() {
Log.i(TAG, "onError");
}
@@ -95,8 +86,12 @@
break;
case AlwaysOnHotwordDetector.STATE_KEYPHRASE_ENROLLED:
Log.i(TAG, "STATE_KEYPHRASE_ENROLLED - starting recognition");
- mHotwordDetector.startRecognition(
- AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE);
+ if (mHotwordDetector.startRecognition(
+ AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE)) {
+ Log.i(TAG, "startRecognition succeeded");
+ } else {
+ Log.i(TAG, "startRecognition failed");
+ }
break;
}
}