Merge "Remove TODO in statsd AnomalyTracker_test"
diff --git a/api/system-current.txt b/api/system-current.txt
index 44f0588..6850f8f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -385,16 +385,16 @@
public final class StatsManager {
method public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException;
- method public boolean addConfiguration(long, byte[]);
- method public byte[] getData(long);
- method public byte[] getMetadata();
+ method public deprecated boolean addConfiguration(long, byte[]);
+ method public deprecated byte[] getData(long);
+ method public deprecated byte[] getMetadata();
method public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
method public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
method public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
- method public boolean removeConfiguration(long);
+ method public deprecated boolean removeConfiguration(long);
method public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
- method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
- method public boolean setDataFetchOperation(long, android.app.PendingIntent);
+ method public deprecated boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
+ method public deprecated boolean setDataFetchOperation(long, android.app.PendingIntent);
method public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
field public static final java.lang.String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
@@ -538,6 +538,7 @@
method public long getAvailableRestoreToken(java.lang.String);
method public android.content.Intent getConfigurationIntent(java.lang.String);
method public java.lang.String getCurrentTransport();
+ method public android.content.ComponentName getCurrentTransportComponent();
method public android.content.Intent getDataManagementIntent(java.lang.String);
method public java.lang.String getDataManagementLabel(java.lang.String);
method public java.lang.String getDestinationString(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index db42186..54604a5 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1332,6 +1332,7 @@
public class KeyEvent extends android.view.InputEvent implements android.os.Parcelable {
method public static java.lang.String actionToString(int);
+ field public static final int LAST_KEYCODE = 285; // 0x11d
}
public final class KeyboardShortcutGroup implements android.os.Parcelable {
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index d3ec320..74edffb 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -91,9 +91,6 @@
if (args.length > start) {
for (int i = start; i < args.length; i++) {
int keyCode = KeyEvent.keyCodeFromString(args[i]);
- if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
- keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
- }
sendKeyEvent(inputSource, keyCode, longpress);
}
return;
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index f352e5f..8db7de3 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1029,6 +1029,7 @@
Landroid/bluetooth/BluetoothA2dp;->setOptionalCodecsEnabled(Landroid/bluetooth/BluetoothDevice;I)V
Landroid/bluetooth/BluetoothA2dp;->stateToString(I)Ljava/lang/String;
Landroid/bluetooth/BluetoothA2dp;->supportsOptionalCodecs(Landroid/bluetooth/BluetoothDevice;)I
+Landroid/bluetooth/BluetoothA2dpSink;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
Landroid/bluetooth/BluetoothAdapter;->disable(Z)Z
Landroid/bluetooth/BluetoothAdapter;->factoryReset()Z
Landroid/bluetooth/BluetoothAdapter;->getBluetoothManager()Landroid/bluetooth/IBluetoothManager;
@@ -1104,6 +1105,7 @@
Landroid/bluetooth/BluetoothDevice;->EXTRA_SDP_SEARCH_STATUS:Ljava/lang/String;
Landroid/bluetooth/BluetoothDevice;->getAlias()Ljava/lang/String;
Landroid/bluetooth/BluetoothDevice;->getAliasName()Ljava/lang/String;
+Landroid/bluetooth/BluetoothDevice;->getBatteryLevel()I
Landroid/bluetooth/BluetoothDevice;->getMessageAccessPermission()I
Landroid/bluetooth/BluetoothDevice;->getPhonebookAccessPermission()I
Landroid/bluetooth/BluetoothDevice;->getService()Landroid/bluetooth/IBluetooth;
@@ -1164,6 +1166,7 @@
Landroid/bluetooth/BluetoothHearingAid;->ACTION_ACTIVE_DEVICE_CHANGED:Ljava/lang/String;
Landroid/bluetooth/BluetoothHearingAid;->getActiveDevices()Ljava/util/List;
Landroid/bluetooth/BluetoothHearingAid;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
+Landroid/bluetooth/BluetoothMap;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
Landroid/bluetooth/BluetoothMapClient;->sendMessage(Landroid/bluetooth/BluetoothDevice;[Landroid/net/Uri;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)Z
Landroid/bluetooth/BluetoothPan;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
Landroid/bluetooth/BluetoothPan;->close()V
@@ -1175,11 +1178,13 @@
Landroid/bluetooth/BluetoothPan;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
Landroid/bluetooth/BluetoothPan;->log(Ljava/lang/String;)V
Landroid/bluetooth/BluetoothPan;->setBluetoothTethering(Z)V
+Landroid/bluetooth/BluetoothPbap;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
Landroid/bluetooth/BluetoothProfile;->A2DP_SINK:I
Landroid/bluetooth/BluetoothProfile;->AVRCP_CONTROLLER:I
Landroid/bluetooth/BluetoothProfile;->PAN:I
Landroid/bluetooth/BluetoothProfile;->PRIORITY_AUTO_CONNECT:I
Landroid/bluetooth/BluetoothProfile;->PRIORITY_UNDEFINED:I
+Landroid/bluetooth/BluetoothSap;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
Landroid/bluetooth/BluetoothServerSocket;->mSocket:Landroid/bluetooth/BluetoothSocket;
Landroid/bluetooth/BluetoothSocket;->EADDRINUSE:I
Landroid/bluetooth/BluetoothSocket;->flush()V
@@ -1311,6 +1316,7 @@
Landroid/content/Context;->checkPermission(Ljava/lang/String;IILandroid/os/IBinder;)I
Landroid/content/Context;->COUNTRY_DETECTOR:Ljava/lang/String;
Landroid/content/Context;->createApplicationContext(Landroid/content/pm/ApplicationInfo;I)Landroid/content/Context;
+Landroid/content/Context;->ETHERNET_SERVICE:Ljava/lang/String;
Landroid/content/Context;->getBasePackageName()Ljava/lang/String;
Landroid/content/Context;->getDisplay()Landroid/view/Display;
Landroid/content/Context;->getSharedPrefsFile(Ljava/lang/String;)Ljava/io/File;
@@ -1389,6 +1395,7 @@
Landroid/content/ISyncAdapter$Stub;-><init>()V
Landroid/content/ISyncAdapter$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/ISyncAdapter;
Landroid/content/ISyncAdapter;->cancelSync(Landroid/content/ISyncContext;)V
+Landroid/content/ISyncAdapter;->onUnsyncableAccount(Landroid/content/ISyncAdapterUnsyncableAccountCallback;)V
Landroid/content/ISyncAdapter;->startSync(Landroid/content/ISyncContext;Ljava/lang/String;Landroid/accounts/Account;Landroid/os/Bundle;)V
Landroid/content/ISyncContext$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/ISyncContext$Stub$Proxy;->mRemote:Landroid/os/IBinder;
@@ -1434,6 +1441,8 @@
Landroid/content/pm/ApplicationInfo;->secondaryCpuAbi:Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->secondaryNativeLibraryDir:Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->versionCode:I
+Landroid/content/pm/BaseParceledListSlice;->getList()Ljava/util/List;
+Landroid/content/pm/BaseParceledListSlice;->writeParcelableCreator(Ljava/lang/Object;Landroid/os/Parcel;)V
Landroid/content/pm/ComponentInfo;->getComponentName()Landroid/content/ComponentName;
Landroid/content/pm/IPackageDataObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/pm/IPackageDataObserver$Stub$Proxy;->mRemote:Landroid/os/IBinder;
@@ -1707,6 +1716,8 @@
Landroid/content/pm/PackageStats;->userHandle:I
Landroid/content/pm/PackageUserState;-><init>()V
Landroid/content/pm/ParceledListSlice;-><init>(Ljava/util/List;)V
+Landroid/content/pm/ParceledListSlice;->CREATOR:Landroid/os/Parcelable$ClassLoaderCreator;
+Landroid/content/pm/ParceledListSlice;->writeParcelableCreator(Landroid/os/Parcelable;Landroid/os/Parcel;)V
Landroid/content/pm/PermissionInfo;->protectionToString(I)Ljava/lang/String;
Landroid/content/pm/RegisteredServicesCache$ServiceInfo;->componentName:Landroid/content/ComponentName;
Landroid/content/pm/RegisteredServicesCache$ServiceInfo;->type:Ljava/lang/Object;
@@ -2183,6 +2194,7 @@
Landroid/graphics/drawable/VectorDrawable;->mTintFilter:Landroid/graphics/PorterDuffColorFilter;
Landroid/graphics/drawable/VectorDrawable;->setAllowCaching(Z)V
Landroid/graphics/FontFamily;-><init>()V
+Landroid/graphics/FontFamily;-><init>([Ljava/lang/String;I)V
Landroid/graphics/FontFamily;->abortCreation()V
Landroid/graphics/FontFamily;->addFontFromAssetManager(Landroid/content/res/AssetManager;Ljava/lang/String;IZIII[Landroid/graphics/fonts/FontVariationAxis;)Z
Landroid/graphics/FontFamily;->addFontFromBuffer(Ljava/nio/ByteBuffer;I[Landroid/graphics/fonts/FontVariationAxis;II)Z
@@ -2260,6 +2272,7 @@
Landroid/graphics/TableMaskFilter;->CreateClipTable(II)Landroid/graphics/TableMaskFilter;
Landroid/graphics/TemporaryBuffer;->obtain(I)[C
Landroid/graphics/TemporaryBuffer;->recycle([C)V
+Landroid/graphics/Typeface;-><init>(J)V
Landroid/graphics/Typeface;->createFromFamilies([Landroid/graphics/FontFamily;)Landroid/graphics/Typeface;
Landroid/graphics/Typeface;->createFromFamiliesWithDefault([Landroid/graphics/FontFamily;II)Landroid/graphics/Typeface;
Landroid/graphics/Typeface;->createFromFamiliesWithDefault([Landroid/graphics/FontFamily;Ljava/lang/String;II)Landroid/graphics/Typeface;
@@ -2269,6 +2282,7 @@
Landroid/graphics/Typeface;->native_instance:J
Landroid/graphics/Typeface;->sDefaults:[Landroid/graphics/Typeface;
Landroid/graphics/Typeface;->setDefault(Landroid/graphics/Typeface;)V
+Landroid/graphics/Typeface;->sSystemFallbackMap:Ljava/util/Map;
Landroid/graphics/Typeface;->sSystemFontMap:Ljava/util/Map;
Landroid/graphics/Xfermode;->porterDuffMode:I
Landroid/hardware/biometrics/BiometricConstants;->BIOMETRIC_ACQUIRED_GOOD:I
@@ -3220,6 +3234,14 @@
Landroid/net/ConnectivityManager;->TYPE_PROXY:I
Landroid/net/ConnectivityManager;->TYPE_WIFI_P2P:I
Landroid/net/ConnectivityManager;->unregisterNetworkFactory(Landroid/os/Messenger;)V
+Landroid/net/EthernetManager$Listener;->onAvailabilityChanged(Ljava/lang/String;Z)V
+Landroid/net/EthernetManager;->addListener(Landroid/net/EthernetManager$Listener;)V
+Landroid/net/EthernetManager;->getAvailableInterfaces()[Ljava/lang/String;
+Landroid/net/EthernetManager;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration;
+Landroid/net/EthernetManager;->isAvailable()Z
+Landroid/net/EthernetManager;->isAvailable(Ljava/lang/String;)Z
+Landroid/net/EthernetManager;->removeListener(Landroid/net/EthernetManager$Listener;)V
+Landroid/net/EthernetManager;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V
Landroid/net/http/SslCertificate;->getDigest(Ljava/security/cert/X509Certificate;Ljava/lang/String;)Ljava/lang/String;
Landroid/net/http/SslCertificate;->getSerialNumber(Ljava/security/cert/X509Certificate;)Ljava/lang/String;
Landroid/net/http/SslCertificate;->inflateCertificateView(Landroid/content/Context;)Landroid/view/View;
@@ -4108,6 +4130,7 @@
Landroid/os/storage/StorageManager;->getVolumes()Ljava/util/List;
Landroid/os/storage/StorageManager;->getVolumeState(Ljava/lang/String;)Ljava/lang/String;
Landroid/os/storage/StorageManager;->isFileEncryptedNativeOnly()Z
+Landroid/os/storage/StorageManager;->isUsbMassStorageConnected()Z
Landroid/os/storage/StorageManager;->isUsbMassStorageEnabled()Z
Landroid/os/storage/StorageManager;->partitionPublic(Ljava/lang/String;)V
Landroid/os/storage/StorageManager;->unmount(Ljava/lang/String;)V
@@ -4510,6 +4533,7 @@
Landroid/provider/Settings$System;->LOCKSCREEN_SOUNDS_ENABLED:Ljava/lang/String;
Landroid/provider/Settings$System;->LOCK_SOUND:Ljava/lang/String;
Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String;
+Landroid/provider/Settings$System;->NOTIFICATION_LIGHT_PULSE:Ljava/lang/String;
Landroid/provider/Settings$System;->POINTER_LOCATION:Ljava/lang/String;
Landroid/provider/Settings$System;->POINTER_SPEED:Ljava/lang/String;
Landroid/provider/Settings$System;->PRIVATE_SETTINGS:Ljava/util/Set;
@@ -5369,6 +5393,7 @@
Landroid/telephony/SubscriptionManager;->setDataRoaming(II)I
Landroid/telephony/SubscriptionManager;->setDefaultDataSubId(I)V
Landroid/telephony/SubscriptionManager;->setDefaultSmsSubId(I)V
+Landroid/telephony/SubscriptionManager;->setDisplayNumber(Ljava/lang/String;I)I
Landroid/telephony/TelephonyManager$MultiSimVariants;->TSTS:Landroid/telephony/TelephonyManager$MultiSimVariants;
Landroid/telephony/TelephonyManager$MultiSimVariants;->UNKNOWN:Landroid/telephony/TelephonyManager$MultiSimVariants;
Landroid/telephony/TelephonyManager$MultiSimVariants;->values()[Landroid/telephony/TelephonyManager$MultiSimVariants;
@@ -8778,7 +8803,6 @@
Ljava/util/ArrayList;->elementData:[Ljava/lang/Object;
Ljava/util/ArrayList;->size:I
Ljava/util/Arrays$ArrayList;->a:[Ljava/lang/Object;
-Ljava/util/Arrays;->checkOffsetAndCount(III)V
Ljava/util/Arrays;->deepToString([Ljava/lang/Object;Ljava/lang/StringBuilder;Ljava/util/Set;)V
Ljava/util/Calendar;->zone:Ljava/util/TimeZone;
Ljava/util/Collections$EmptyList;-><init>()V
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 494ea39..37bf21a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -939,7 +939,8 @@
}
public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
- final ConnectivityManager cm = ConnectivityManager.from(getSystemContext());
+ final ConnectivityManager cm = ConnectivityManager.from(
+ getApplication() != null ? getApplication() : getSystemContext());
final Network network = cm.getBoundNetworkForProcess();
if (network != null) {
Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8f0617b..c2ac923 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4924,7 +4924,8 @@
CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
if (!p.ambient && validRemoteInput && replyText != null
- && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) {
+ && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])
+ && p.maxRemoteInputHistory > 0) {
boolean showSpinner = mN.extras.getBoolean(EXTRA_SHOW_REMOTE_INPUT_SPINNER);
big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
big.setViewVisibility(R.id.notification_material_reply_text_1_container,
@@ -4939,13 +4940,15 @@
ColorStateList.valueOf(
isColorized() ? getPrimaryTextColor() : resolveContrastColor()));
- if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])) {
+ if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])
+ && p.maxRemoteInputHistory > 1) {
big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_2,
processTextSpans(replyText[1]));
setTextViewColorSecondary(big, R.id.notification_material_reply_text_2);
- if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])) {
+ if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])
+ && p.maxRemoteInputHistory > 2) {
big.setViewVisibility(
R.id.notification_material_reply_text_3, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_3,
@@ -5108,7 +5111,13 @@
return null;
}
- return applyStandardTemplateWithActions(getBigBaseLayoutResource(), null /* result */);
+ // We only want at most a single remote input history to be shown here, otherwise
+ // the content would become squished.
+ StandardTemplateParams p = mParams.reset().fillTextsFrom(this)
+ .setMaxRemoteInputHistory(1);
+ return applyStandardTemplateWithActions(getBigBaseLayoutResource(),
+ p,
+ null /* result */);
}
/**
@@ -5977,6 +5986,12 @@
* object.
*/
public static abstract class Style {
+
+ /**
+ * The number of items allowed simulatanously in the remote input history.
+ * @hide
+ */
+ static final int MAX_REMOTE_INPUT_HISTORY_LINES = 3;
private CharSequence mBigContentTitle;
/**
@@ -7378,7 +7393,14 @@
return messages;
}
- static Message getMessageFromBundle(Bundle bundle) {
+ /**
+ * @return The message that is stored in the bundle or null if the message couldn't be
+ * resolved.
+ *
+ * @hide
+ */
+ @Nullable
+ public static Message getMessageFromBundle(Bundle bundle) {
try {
if (!bundle.containsKey(KEY_TEXT) || !bundle.containsKey(KEY_TIMESTAMP)) {
return null;
@@ -7436,6 +7458,11 @@
* @see Notification#bigContentView
*/
public static class InboxStyle extends Style {
+
+ /**
+ * The number of lines of remote input history allowed until we start reducing lines.
+ */
+ private static final int NUMBER_OF_HISTORY_ALLOWED_UNTIL_REDUCTION = 1;
private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5);
public InboxStyle() {
@@ -7535,6 +7562,28 @@
if (mBuilder.mActions.size() > 0) {
maxRows--;
}
+ CharSequence[] remoteInputHistory = mBuilder.mN.extras.getCharSequenceArray(
+ EXTRA_REMOTE_INPUT_HISTORY);
+ if (remoteInputHistory != null
+ && remoteInputHistory.length > NUMBER_OF_HISTORY_ALLOWED_UNTIL_REDUCTION) {
+ // Let's remove some messages to make room for the remote input history.
+ // 1 is always able to fit, but let's remove them if they are 2 or 3
+ int numRemoteInputs = Math.min(remoteInputHistory.length,
+ MAX_REMOTE_INPUT_HISTORY_LINES);
+ int totalNumRows = mTexts.size() + numRemoteInputs
+ - NUMBER_OF_HISTORY_ALLOWED_UNTIL_REDUCTION;
+ if (totalNumRows > maxRows) {
+ int overflow = totalNumRows - maxRows;
+ if (mTexts.size() > maxRows) {
+ // Heuristic: if the Texts don't fit anyway, we'll rather drop the last
+ // few messages, even with the remote input
+ maxRows -= overflow;
+ } else {
+ // otherwise we drop the first messages
+ i = overflow;
+ }
+ }
+ }
while (i < mTexts.size() && i < maxRows) {
CharSequence str = mTexts.get(i);
if (!TextUtils.isEmpty(str)) {
@@ -9605,6 +9654,7 @@
CharSequence title;
CharSequence text;
CharSequence headerTextSecondary;
+ int maxRemoteInputHistory = Style.MAX_REMOTE_INPUT_HISTORY_LINES;
boolean hideLargeIcon;
boolean hideReplyIcon;
@@ -9614,6 +9664,7 @@
title = null;
text = null;
headerTextSecondary = null;
+ maxRemoteInputHistory = Style.MAX_REMOTE_INPUT_HISTORY_LINES;
return this;
}
@@ -9665,5 +9716,15 @@
this.text = b.processLegacyText(text, ambient);
return this;
}
+
+ /**
+ * Set the maximum lines of remote input history lines allowed.
+ * @param maxRemoteInputHistory The number of lines.
+ * @return The builder for method chaining.
+ */
+ public StandardTemplateParams setMaxRemoteInputHistory(int maxRemoteInputHistory) {
+ this.maxRemoteInputHistory = maxRemoteInputHistory;
+ return this;
+ }
}
}
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 45754ae..32fc0dc 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -115,8 +115,9 @@
}
}
+ // TODO: Temporary for backwards compatibility. Remove.
/**
- * TODO: Temporary for backwards compatibility. Remove.
+ * @deprecated Use {@link #addConfig(long, byte[])}
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean addConfiguration(long configKey, byte[] config) {
@@ -149,8 +150,9 @@
}
}
+ // TODO: Temporary for backwards compatibility. Remove.
/**
- * TODO: Temporary for backwards compatibility. Remove.
+ * @deprecated Use {@link #removeConfig(long)}
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean removeConfiguration(long configKey) {
@@ -216,8 +218,9 @@
}
}
+ // TODO: Temporary for backwards compatibility. Remove.
/**
- * TODO: Temporary for backwards compatibility. Remove.
+ * @deprecated Use {@link #setBroadcastSubscriber(PendingIntent, long, long)}
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean setBroadcastSubscriber(
@@ -268,8 +271,9 @@
}
}
+ // TODO: Temporary for backwards compatibility. Remove.
/**
- * TODO: Temporary for backwards compatibility. Remove.
+ * @deprecated Use {@link #setFetchReportsOperation(PendingIntent, long)}
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
@@ -304,8 +308,9 @@
}
}
+ // TODO: Temporary for backwards compatibility. Remove.
/**
- * TODO: Temporary for backwards compatibility. Remove.
+ * @deprecated Use {@link #getReports(long)}
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public @Nullable byte[] getData(long configKey) {
@@ -339,12 +344,9 @@
}
}
+ // TODO: Temporary for backwards compatibility. Remove.
/**
- * Clients can request metadata for statsd. Will contain stats across all configurations but not
- * the actual metrics themselves (metrics must be collected via {@link #getReports(long)}.
- * This getter is not destructive and will not reset any metrics/counters.
- *
- * @return Serialized StatsdStatsReport proto. Returns null on failure (eg, if statsd crashed).
+ * @deprecated Use {@link #getStatsMetadata()}
*/
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public @Nullable byte[] getMetadata() {
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 30f340c..d445965 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -255,7 +255,7 @@
/**
* @deprecated Since Android P app can no longer request restoring of its backup.
*
- * Restore the calling application from backup. The data will be restored from the
+ * <p>Restore the calling application from backup. The data will be restored from the
* current backup dataset if the application has stored data there, or from
* the dataset used during the last full device setup operation if the current
* backup dataset has no matching data. If no backup data exists for this application
@@ -282,7 +282,7 @@
/**
* @deprecated Since Android P app can no longer request restoring of its backup.
*
- * Restore the calling application from backup. The data will be restored from the
+ * <p>Restore the calling application from backup. The data will be restored from the
* current backup dataset if the application has stored data there, or from
* the dataset used during the last full device setup operation if the current
* backup dataset has no matching data. If no backup data exists for this application
@@ -443,6 +443,27 @@
}
/**
+ * Returns the {@link ComponentName} of the host service of the selected transport or {@code
+ * null} if no transport selected or if the transport selected is not registered.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
+ @Nullable
+ public ComponentName getCurrentTransportComponent() {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ return sService.getCurrentTransportComponent();
+ } catch (RemoteException e) {
+ Log.e(TAG, "getCurrentTransportComponent() couldn't connect");
+ }
+ }
+ return null;
+ }
+
+ /**
* Request a list of all available backup transports' names.
*
* @hide
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index f3ca746..1c55d8a 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -244,8 +244,6 @@
* {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
* @throws SecurityException If the UID of the calling process differs from the package UID of
* {@code transportComponent} or if the caller does NOT have BACKUP permission.
- *
- * @hide
*/
void updateTransportAttributes(in ComponentName transportComponent, in String name,
in Intent configurationIntent, in String currentDestinationString,
@@ -257,6 +255,13 @@
*/
String getCurrentTransport();
+ /**
+ * Returns the {@link ComponentName} of the host service of the selected transport or {@code
+ * null} if no transport selected or if the transport selected is not registered. Callers must
+ * hold the android.permission.BACKUP permission to use this method.
+ */
+ ComponentName getCurrentTransportComponent();
+
/**
* Request a list of all available backup transports' names. Callers must
* hold the android.permission.BACKUP permission to use this method.
@@ -296,8 +301,6 @@
* the transport's name that is returned by {@link BackupTransport#name()}.
* @param listener A listener object to get a callback on the transport being selected. It may
* be {@code null}.
- *
- * @hide
*/
void selectBackupTransportAsync(in ComponentName transport, ISelectBackupTransportCallback listener);
@@ -364,7 +367,6 @@
* @param result In the case of a full backup measure operation, the estimated
* total file size that would result from the operation. Unused in all other
* cases.
- * {@hide}
*/
void opComplete(int token, long result);
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 503ca6c..3e90af3 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -399,16 +399,20 @@
* {@hide}
*/
public UsageEvents(Parcel in) {
- mEventCount = in.readInt();
- mIndex = in.readInt();
+ byte[] bytes = in.readBlob();
+ Parcel data = Parcel.obtain();
+ data.unmarshall(bytes, 0, bytes.length);
+ data.setDataPosition(0);
+ mEventCount = data.readInt();
+ mIndex = data.readInt();
if (mEventCount > 0) {
- mStringPool = in.createStringArray();
+ mStringPool = data.createStringArray();
- final int listByteLength = in.readInt();
- final int positionInParcel = in.readInt();
+ final int listByteLength = data.readInt();
+ final int positionInParcel = data.readInt();
mParcel = Parcel.obtain();
mParcel.setDataPosition(0);
- mParcel.appendFrom(in, in.dataPosition(), listByteLength);
+ mParcel.appendFrom(data, data.dataPosition(), listByteLength);
mParcel.setDataSize(mParcel.dataPosition());
mParcel.setDataPosition(positionInParcel);
}
@@ -586,10 +590,11 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mEventCount);
- dest.writeInt(mIndex);
+ Parcel data = Parcel.obtain();
+ data.writeInt(mEventCount);
+ data.writeInt(mIndex);
if (mEventCount > 0) {
- dest.writeStringArray(mStringPool);
+ data.writeStringArray(mStringPool);
if (mEventsToWrite != null) {
// Write out the events
@@ -604,31 +609,34 @@
final int listByteLength = p.dataPosition();
// Write the total length of the data.
- dest.writeInt(listByteLength);
+ data.writeInt(listByteLength);
// Write our current position into the data.
- dest.writeInt(0);
+ data.writeInt(0);
// Write the data.
- dest.appendFrom(p, 0, listByteLength);
+ data.appendFrom(p, 0, listByteLength);
} finally {
p.recycle();
}
} else if (mParcel != null) {
// Write the total length of the data.
- dest.writeInt(mParcel.dataSize());
+ data.writeInt(mParcel.dataSize());
// Write out current position into the data.
- dest.writeInt(mParcel.dataPosition());
+ data.writeInt(mParcel.dataPosition());
// Write the data.
- dest.appendFrom(mParcel, 0, mParcel.dataSize());
+ data.appendFrom(mParcel, 0, mParcel.dataSize());
} else {
throw new IllegalStateException(
"Either mParcel or mEventsToWrite must not be null");
}
}
+ // Data can be too large for a transact. Write the data as a Blob, which will be written to
+ // ashmem if too large.
+ dest.writeBlob(data.marshall());
}
public static final Creator<UsageEvents> CREATOR = new Creator<UsageEvents>() {
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 2306e5f..16c1f6d 100644
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -21,18 +21,15 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Paint.Align;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Typeface;
-import android.graphics.Paint.Align;
-import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard.Key;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
-import android.os.UserHandle;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.GestureDetector;
@@ -662,11 +659,13 @@
invalidateAllKeys();
mKeyboardChanged = false;
}
- final Canvas canvas = mCanvas;
- canvas.clipRect(mDirtyRect, Op.REPLACE);
if (mKeyboard == null) return;
+ mCanvas.save();
+ final Canvas canvas = mCanvas;
+ canvas.clipRect(mDirtyRect);
+
final Paint paint = mPaint;
final Drawable keyBackground = mKeyBackground;
final Rect clipRegion = mClipRegion;
@@ -758,7 +757,7 @@
paint.setColor(0xFF00FF00);
canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint);
}
-
+ mCanvas.restore();
mDrawPending = false;
mDirtyRect.setEmpty();
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index c3b8f39..c5cb1f5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -238,6 +238,14 @@
public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
/**
+ * Key for passing a {@link android.net.captiveportal.CaptivePortalProbeSpec} to the captive
+ * portal login activity.
+ * {@hide}
+ */
+ public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC =
+ "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
+
+ /**
* Key for passing a user agent string to the captive portal login activity.
* {@hide}
*/
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 15a0ee5..d75d439 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -85,6 +85,21 @@
private static final long HANDLE_MAGIC = 0xcafed00dL;
private static final int HANDLE_MAGIC_SIZE = 32;
+ // A boolean to control how getAllByName()/getByName() behaves in the face
+ // of Private DNS.
+ //
+ // When true, these calls will request that DNS resolution bypass any
+ // Private DNS that might otherwise apply. Use of this feature is restricted
+ // and permission checks are made by netd (attempts to bypass Private DNS
+ // without appropriate permission are silently turned into vanilla DNS
+ // requests). This only affects DNS queries made using this network object.
+ //
+ // It it not parceled to receivers because (a) it can be set or cleared at
+ // anytime and (b) receivers should be explicit about attempts to bypass
+ // Private DNS so that the intent of the code is easily determined and
+ // code search audits are possible.
+ private boolean mPrivateDnsBypass = false;
+
/**
* @hide
*/
@@ -108,7 +123,7 @@
* @throws UnknownHostException if the address lookup fails.
*/
public InetAddress[] getAllByName(String host) throws UnknownHostException {
- return InetAddress.getAllByNameOnNet(host, netId);
+ return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
}
/**
@@ -122,7 +137,32 @@
* if the address lookup fails.
*/
public InetAddress getByName(String host) throws UnknownHostException {
- return InetAddress.getByNameOnNet(host, netId);
+ return InetAddress.getByNameOnNet(host, getNetIdForResolv());
+ }
+
+ /**
+ * Specify whether or not Private DNS should be bypassed when attempting
+ * to use {@link getAllByName()}/{@link getByName()} methods on the given
+ * instance for hostname resolution.
+ *
+ * @hide
+ */
+ public void setPrivateDnsBypass(boolean bypass) {
+ mPrivateDnsBypass = bypass;
+ }
+
+ /**
+ * Returns a netid marked with the Private DNS bypass flag.
+ *
+ * This flag must be kept in sync with the NETID_USE_LOCAL_NAMESERVERS flag
+ * in system/netd/include/NetdClient.h.
+ *
+ * @hide
+ */
+ public int getNetIdForResolv() {
+ return mPrivateDnsBypass
+ ? (int) (0x80000000L | (long) netId) // Non-portable DNS resolution flag.
+ : netId;
}
/**
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index f0dd262..edf9bc1 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -1100,6 +1100,8 @@
public interface NonMonotonicObserver<C> {
public void foundNonMonotonic(
NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
+ public void foundNonMonotonic(
+ NetworkStats stats, int statsIndex, C cookie);
}
/**
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index 66cdc99..ddf63ca 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -84,6 +84,10 @@
* @return true if the transaction was successful.
*/
public boolean requestTime(String host, int timeout, Network network) {
+ // This flag only affects DNS resolution and not other socket semantics,
+ // therefore it's safe to set unilaterally rather than take more
+ // defensive measures like making a copy.
+ network.setPrivateDnsBypass(true);
InetAddress address = null;
try {
address = network.getByName(host);
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
index 614c0b8..1634694 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
@@ -16,6 +16,8 @@
package android.net.captiveportal;
+import android.annotation.Nullable;
+
/**
* Result of calling isCaptivePortal().
* @hide
@@ -23,6 +25,7 @@
public final class CaptivePortalProbeResult {
public static final int SUCCESS_CODE = 204;
public static final int FAILED_CODE = 599;
+ public static final int PORTAL_CODE = 302;
public static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(FAILED_CODE);
public static final CaptivePortalProbeResult SUCCESS =
@@ -32,15 +35,23 @@
public final String redirectUrl; // Redirect destination returned from Internet probe.
public final String detectUrl; // URL where a 204 response code indicates
// captive portal has been appeased.
+ @Nullable
+ public final CaptivePortalProbeSpec probeSpec;
public CaptivePortalProbeResult(int httpResponseCode) {
this(httpResponseCode, null, null);
}
public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl, String detectUrl) {
+ this(httpResponseCode, redirectUrl, detectUrl, null);
+ }
+
+ public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl, String detectUrl,
+ CaptivePortalProbeSpec probeSpec) {
mHttpResponseCode = httpResponseCode;
this.redirectUrl = redirectUrl;
this.detectUrl = detectUrl;
+ this.probeSpec = probeSpec;
}
public boolean isSuccessful() {
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
new file mode 100644
index 0000000..57a926a
--- /dev/null
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2018 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.net.captiveportal;
+
+import static android.net.captiveportal.CaptivePortalProbeResult.PORTAL_CODE;
+import static android.net.captiveportal.CaptivePortalProbeResult.SUCCESS_CODE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/** @hide */
+public abstract class CaptivePortalProbeSpec {
+ public static final String HTTP_LOCATION_HEADER_NAME = "Location";
+
+ private static final String TAG = CaptivePortalProbeSpec.class.getSimpleName();
+ private static final String REGEX_SEPARATOR = "@@/@@";
+ private static final String SPEC_SEPARATOR = "@@,@@";
+
+ private final String mEncodedSpec;
+ private final URL mUrl;
+
+ CaptivePortalProbeSpec(String encodedSpec, URL url) {
+ mEncodedSpec = encodedSpec;
+ mUrl = url;
+ }
+
+ /**
+ * Parse a {@link CaptivePortalProbeSpec} from a {@link String}.
+ *
+ * <p>The valid format is a URL followed by two regular expressions, each separated by "@@/@@".
+ * @throws MalformedURLException The URL has invalid format for {@link URL#URL(String)}.
+ * @throws ParseException The string is empty, does not match the above format, or a regular
+ * expression is invalid for {@link Pattern#compile(String)}.
+ */
+ @NonNull
+ public static CaptivePortalProbeSpec parseSpec(String spec) throws ParseException,
+ MalformedURLException {
+ if (TextUtils.isEmpty(spec)) {
+ throw new ParseException("Empty probe spec", 0 /* errorOffset */);
+ }
+
+ String[] splits = TextUtils.split(spec, REGEX_SEPARATOR);
+ if (splits.length != 3) {
+ throw new ParseException("Probe spec does not have 3 parts", 0 /* errorOffset */);
+ }
+
+ final int statusRegexPos = splits[0].length() + REGEX_SEPARATOR.length();
+ final int locationRegexPos = statusRegexPos + splits[1].length() + REGEX_SEPARATOR.length();
+ final Pattern statusRegex = parsePatternIfNonEmpty(splits[1], statusRegexPos);
+ final Pattern locationRegex = parsePatternIfNonEmpty(splits[2], locationRegexPos);
+
+ return new RegexMatchProbeSpec(spec, new URL(splits[0]), statusRegex, locationRegex);
+ }
+
+ @Nullable
+ private static Pattern parsePatternIfNonEmpty(String pattern, int pos) throws ParseException {
+ if (TextUtils.isEmpty(pattern)) {
+ return null;
+ }
+ try {
+ return Pattern.compile(pattern);
+ } catch (PatternSyntaxException e) {
+ throw new ParseException(
+ String.format("Invalid status pattern [%s]: %s", pattern, e),
+ pos /* errorOffset */);
+ }
+ }
+
+ /**
+ * Parse a {@link CaptivePortalProbeSpec} from a {@link String}, or return a fallback spec
+ * based on the status code of the provided URL if the spec cannot be parsed.
+ */
+ @Nullable
+ public static CaptivePortalProbeSpec parseSpecOrNull(@Nullable String spec) {
+ if (spec != null) {
+ try {
+ return parseSpec(spec);
+ } catch (ParseException | MalformedURLException e) {
+ Log.e(TAG, "Invalid probe spec: " + spec, e);
+ // Fall through
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Parse a config String to build an array of {@link CaptivePortalProbeSpec}.
+ *
+ * <p>Each spec is separated by @@,@@ and follows the format for {@link #parseSpec(String)}.
+ * <p>This method does not throw but ignores any entry that could not be parsed.
+ */
+ public static CaptivePortalProbeSpec[] parseCaptivePortalProbeSpecs(String settingsVal) {
+ List<CaptivePortalProbeSpec> specs = new ArrayList<>();
+ if (settingsVal != null) {
+ for (String spec : TextUtils.split(settingsVal, SPEC_SEPARATOR)) {
+ try {
+ specs.add(parseSpec(spec));
+ } catch (ParseException | MalformedURLException e) {
+ Log.e(TAG, "Invalid probe spec: " + spec, e);
+ }
+ }
+ }
+
+ if (specs.isEmpty()) {
+ Log.e(TAG, String.format("could not create any validation spec from %s", settingsVal));
+ }
+ return specs.toArray(new CaptivePortalProbeSpec[specs.size()]);
+ }
+
+ /**
+ * Get the probe result from HTTP status and location header.
+ */
+ public abstract CaptivePortalProbeResult getResult(int status, @Nullable String locationHeader);
+
+ public String getEncodedSpec() {
+ return mEncodedSpec;
+ }
+
+ public URL getUrl() {
+ return mUrl;
+ }
+
+ /**
+ * Implementation of {@link CaptivePortalProbeSpec} that is based on configurable regular
+ * expressions for the HTTP status code and location header (if any). Matches indicate that
+ * the page is not a portal.
+ * This probe cannot fail: it always returns SUCCESS_CODE or PORTAL_CODE
+ */
+ private static class RegexMatchProbeSpec extends CaptivePortalProbeSpec {
+ @Nullable
+ final Pattern mStatusRegex;
+ @Nullable
+ final Pattern mLocationHeaderRegex;
+
+ RegexMatchProbeSpec(
+ String spec, URL url, Pattern statusRegex, Pattern locationHeaderRegex) {
+ super(spec, url);
+ mStatusRegex = statusRegex;
+ mLocationHeaderRegex = locationHeaderRegex;
+ }
+
+ @Override
+ public CaptivePortalProbeResult getResult(int status, String locationHeader) {
+ final boolean statusMatch = safeMatch(String.valueOf(status), mStatusRegex);
+ final boolean locationMatch = safeMatch(locationHeader, mLocationHeaderRegex);
+ final int returnCode = statusMatch && locationMatch ? SUCCESS_CODE : PORTAL_CODE;
+ return new CaptivePortalProbeResult(
+ returnCode, locationHeader, getUrl().toString(), this);
+ }
+ }
+
+ private static boolean safeMatch(@Nullable String value, @Nullable Pattern pattern) {
+ // No value is a match ("no location header" passes the location rule for non-redirects)
+ return pattern == null || TextUtils.isEmpty(value) || pattern.matcher(value).matches();
+ }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 619ec23..221abed 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -245,8 +245,10 @@
* New in version 31:
* - New cellular network types.
* - Deferred job metrics.
+ * New in version 32:
+ * - Ambient display properly output in data dump.
*/
- static final int CHECKIN_VERSION = 31;
+ static final int CHECKIN_VERSION = 32;
/**
* Old version, we hit 9 and ran out of room, need to remove.
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 5e23932..3017f25 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -45,6 +45,7 @@
in String[] disallowedPackages);
UserInfo createRestrictedProfile(String name, int parentUserHandle);
void setUserEnabled(int userHandle);
+ void setUserAdmin(int userId);
void evictCredentialEncryptionKey(int userHandle);
boolean removeUser(int userHandle);
boolean removeUserEvenWhenDisallowed(int userHandle);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 48e019d..bc3d870 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2091,12 +2091,33 @@
* Also ephemeral users can be disabled to indicate that their removal is in progress and they
* shouldn't be re-entered. Therefore ephemeral users should not be re-enabled once disabled.
*
- * @param userHandle the id of the profile to enable
+ * @param userId the id of the profile to enable
* @hide
*/
- public void setUserEnabled(@UserIdInt int userHandle) {
+ public void setUserEnabled(@UserIdInt int userId) {
try {
- mService.setUserEnabled(userHandle);
+ mService.setUserEnabled(userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Assigns admin privileges to the user, if such a user exists.
+ *
+ * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} and
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permissions.
+ *
+ * @param userHandle the id of the user to become admin
+ * @hide
+ */
+ @RequiresPermission(allOf = {
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ Manifest.permission.MANAGE_USERS
+ })
+ public void setUserAdmin(@UserIdInt int userHandle) {
+ try {
+ mService.setUserAdmin(userHandle);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 62359ec..91c69fb 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.content.ContentResolver;
import android.content.Context;
import android.hardware.vibrator.V1_0.EffectStrength;
import android.hardware.vibrator.V1_2.Effect;
@@ -277,7 +278,12 @@
if (uris[i] == null) {
continue;
}
- if (Uri.parse(uris[i]).equals(uri)) {
+ ContentResolver cr = context.getContentResolver();
+ Uri mappedUri = cr.uncanonicalize(Uri.parse(uris[i]));
+ if (mappedUri == null) {
+ continue;
+ }
+ if (mappedUri.equals(uri)) {
return get(RINGTONES[i]);
}
}
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 576ea52..8d4c3c3 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -407,8 +407,12 @@
* {@link #TYPE_EMULATED} or {@link #TYPE_PUBLIC}.
*/
public @Nullable Intent buildBrowseIntent() {
+ return buildBrowseIntentForUser(UserHandle.myUserId());
+ }
+
+ public @Nullable Intent buildBrowseIntentForUser(int userId) {
final Uri uri;
- if (type == VolumeInfo.TYPE_PUBLIC && mountUserId == UserHandle.myUserId()) {
+ if (type == VolumeInfo.TYPE_PUBLIC && mountUserId == userId) {
uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, fsUuid);
} else if (type == VolumeInfo.TYPE_EMULATED && isPrimary()) {
uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 931ac92..fe77dc4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -23,6 +23,7 @@
import static android.provider.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
import static android.provider.SettingsValidators.LOCALE_VALIDATOR;
import static android.provider.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
+import static android.provider.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
import static android.provider.SettingsValidators.PACKAGE_NAME_VALIDATOR;
import static android.provider.SettingsValidators.URI_VALIDATOR;
@@ -5461,7 +5462,8 @@
@TestApi
public static final String AUTOFILL_SERVICE = "autofill_service";
- private static final Validator AUTOFILL_SERVICE_VALIDATOR = COMPONENT_NAME_VALIDATOR;
+ private static final Validator AUTOFILL_SERVICE_VALIDATOR =
+ NULLABLE_COMPONENT_NAME_VALIDATOR;
/**
* Boolean indicating if Autofill supports field classification.
@@ -5959,7 +5961,7 @@
"accessibility_shortcut_target_service";
private static final Validator ACCESSIBILITY_SHORTCUT_TARGET_SERVICE_VALIDATOR =
- COMPONENT_NAME_VALIDATOR;
+ NULLABLE_COMPONENT_NAME_VALIDATOR;
/**
* Setting specifying the accessibility service or feature to be toggled via the
@@ -7119,6 +7121,35 @@
public static final String UI_NIGHT_MODE = "ui_night_mode";
/**
+ * The current device UI theme mode effect SystemUI and Launcher.<br/>
+ * <b>Values:</b><br/>
+ * 0 - The mode that theme will controlled by wallpaper color.<br/>
+ * 1 - The mode that will always light theme.<br/>
+ * 2 - The mode that will always dark theme.<br/>
+ *
+ * @hide
+ */
+ public static final String THEME_MODE = "theme_mode";
+
+ /**
+ * THEME_MODE value for wallpaper mode.
+ * @hide
+ */
+ public static final int THEME_MODE_WALLPAPER = 0;
+
+ /**
+ * THEME_MODE value for light theme mode.
+ * @hide
+ */
+ public static final int THEME_MODE_LIGHT = 1;
+
+ /**
+ * THEME_MODE value for dark theme mode.
+ * @hide
+ */
+ public static final int THEME_MODE_DARK = 2;
+
+ /**
* Whether screensavers are enabled.
* @hide
*/
@@ -10256,6 +10287,15 @@
"captive_portal_other_fallback_urls";
/**
+ * A list of captive portal detection specifications used in addition to the fallback URLs.
+ * Each spec has the format url@@/@@statusCodeRegex@@/@@contentRegex. Specs are separated
+ * by "@@,@@".
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
+ "captive_portal_fallback_probe_specs";
+
+ /**
* Whether to use HTTPS for network validation. This is enabled by default and the setting
* needs to be set to 0 to disable it. This setting is a misnomer because captive portals
* don't actually use HTTPS, but it's consistent with the other settings.
@@ -11570,6 +11610,13 @@
/** @hide */ public static final int EMULATE_DISPLAY_CUTOUT_ON = 1;
/**
+ * A colon separated list of keys for Settings Slices.
+ *
+ * @hide
+ */
+ public static final String BLOCKED_SLICES = "blocked_slices";
+
+ /**
* Defines global zen mode. ZEN_MODE_OFF, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
* or ZEN_MODE_NO_INTERRUPTIONS.
*
diff --git a/core/java/android/provider/SettingsValidators.java b/core/java/android/provider/SettingsValidators.java
index b53b0f0..25e77867 100644
--- a/core/java/android/provider/SettingsValidators.java
+++ b/core/java/android/provider/SettingsValidators.java
@@ -77,6 +77,11 @@
}
};
+ /**
+ * Does not allow a setting to have a null {@link ComponentName}. Use {@link
+ * SettingsValidators#NULLABLE_COMPONENT_NAME_VALIDATOR} instead if a setting can have a
+ * nullable {@link ComponentName}.
+ */
public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() {
@Override
public boolean validate(@Nullable String value) {
@@ -84,6 +89,16 @@
}
};
+ /**
+ * Allows a setting to have a null {@link ComponentName}.
+ */
+ public static final Validator NULLABLE_COMPONENT_NAME_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(@Nullable String value) {
+ return value == null || COMPONENT_NAME_VALIDATOR.validate(value);
+ }
+ };
+
public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() {
@Override
public boolean validate(@Nullable String value) {
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 5ebd28c..92f7a47 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1004,7 +1004,33 @@
return TextUtils.packRangeInLong(0, getLineEnd(line));
}
- /** @hide */
+ /**
+ * Checks if the trailing BiDi level should be used for an offset
+ *
+ * This method is useful when the offset is at the BiDi level transition point and determine
+ * which run need to be used. For example, let's think about following input: (L* denotes
+ * Left-to-Right characters, R* denotes Right-to-Left characters.)
+ * Input (Logical Order): L1 L2 L3 R1 R2 R3 L4 L5 L6
+ * Input (Display Order): L1 L2 L3 R3 R2 R1 L4 L5 L6
+ *
+ * Then, think about selecting the range (3, 6). The offset=3 and offset=6 are ambiguous here
+ * since they are at the BiDi transition point. In Android, the offset is considered to be
+ * associated with the trailing run if the BiDi level of the trailing run is higher than of the
+ * previous run. In this case, the BiDi level of the input text is as follows:
+ *
+ * Input (Logical Order): L1 L2 L3 R1 R2 R3 L4 L5 L6
+ * BiDi Run: [ Run 0 ][ Run 1 ][ Run 2 ]
+ * BiDi Level: 0 0 0 1 1 1 0 0 0
+ *
+ * Thus, offset = 3 is part of Run 1 and this method returns true for offset = 3, since the BiDi
+ * level of Run 1 is higher than the level of Run 0. Similarly, the offset = 6 is a part of Run
+ * 1 and this method returns false for the offset = 6 since the BiDi level of Run 1 is higher
+ * than the level of Run 2.
+ *
+ * @returns true if offset is at the BiDi level transition point and trailing BiDi level is
+ * higher than previous BiDi level. See above for the detail.
+ * @hide
+ */
@VisibleForTesting
public boolean primaryIsTrailingPrevious(int offset) {
int line = getLineForOffset(offset);
@@ -1056,6 +1082,43 @@
}
/**
+ * Computes in linear time the results of calling
+ * #primaryIsTrailingPrevious for all offsets on a line.
+ * @param line The line giving the offsets we compute the information for
+ * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
+ * @hide
+ */
+ @VisibleForTesting
+ public boolean[] primaryIsTrailingPreviousAllLineOffsets(int line) {
+ int lineStart = getLineStart(line);
+ int lineEnd = getLineEnd(line);
+ int[] runs = getLineDirections(line).mDirections;
+
+ boolean[] trailing = new boolean[lineEnd - lineStart + 1];
+
+ byte[] level = new byte[lineEnd - lineStart + 1];
+ for (int i = 0; i < runs.length; i += 2) {
+ int start = lineStart + runs[i];
+ int limit = start + (runs[i + 1] & RUN_LENGTH_MASK);
+ if (limit > lineEnd) {
+ limit = lineEnd;
+ }
+ level[limit - lineStart - 1] =
+ (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
+ }
+
+ for (int i = 0; i < runs.length; i += 2) {
+ int start = lineStart + runs[i];
+ byte currentLevel = (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
+ trailing[start - lineStart] = currentLevel > (start == lineStart
+ ? (getParagraphDirection(line) == 1 ? 0 : 1)
+ : level[start - lineStart - 1]);
+ }
+
+ return trailing;
+ }
+
+ /**
* Get the primary horizontal position for the specified text offset.
* This is the location where a new character would be inserted in
* the paragraph's primary direction.
@@ -1135,6 +1198,60 @@
}
/**
+ * Computes in linear time the results of calling
+ * #getHorizontal for all offsets on a line.
+ * @param line The line giving the offsets we compute information for
+ * @param clamped Whether to clamp the results to the width of the layout
+ * @param primary Whether the results should be the primary or the secondary horizontal
+ * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
+ */
+ private float[] getLineHorizontals(int line, boolean clamped, boolean primary) {
+ int start = getLineStart(line);
+ int end = getLineEnd(line);
+ int dir = getParagraphDirection(line);
+ boolean hasTab = getLineContainsTab(line);
+ Directions directions = getLineDirections(line);
+
+ TabStops tabStops = null;
+ if (hasTab && mText instanceof Spanned) {
+ // Just checking this line should be good enough, tabs should be
+ // consistent across all lines in a paragraph.
+ TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class);
+ if (tabs.length > 0) {
+ tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
+ }
+ }
+
+ TextLine tl = TextLine.obtain();
+ tl.set(mPaint, mText, start, end, dir, directions, hasTab, tabStops);
+ boolean[] trailings = primaryIsTrailingPreviousAllLineOffsets(line);
+ if (!primary) {
+ for (int offset = 0; offset < trailings.length; ++offset) {
+ trailings[offset] = !trailings[offset];
+ }
+ }
+ float[] wid = tl.measureAllOffsets(trailings, null);
+ TextLine.recycle(tl);
+
+ if (clamped) {
+ for (int offset = 0; offset <= wid.length; ++offset) {
+ if (wid[offset] > mWidth) {
+ wid[offset] = mWidth;
+ }
+ }
+ }
+ int left = getParagraphLeft(line);
+ int right = getParagraphRight(line);
+
+ int lineStartPos = getLineStartPos(line, left, right);
+ float[] horizontal = new float[end - start + 1];
+ for (int offset = 0; offset < horizontal.length; ++offset) {
+ horizontal[offset] = lineStartPos + wid[offset];
+ }
+ return horizontal;
+ }
+
+ /**
* Get the leftmost position that should be exposed for horizontal
* scrolling on the specified line.
*/
@@ -1362,6 +1479,8 @@
// XXX: we don't care about tabs as we just use TextLine#getOffsetToLeftRightOf here.
tl.set(mPaint, mText, lineStartOffset, lineEndOffset, getParagraphDirection(line), dirs,
false, null);
+ final HorizontalMeasurementProvider horizontal =
+ new HorizontalMeasurementProvider(line, primary);
final int max;
if (line == getLineCount() - 1) {
@@ -1371,7 +1490,7 @@
!isRtlCharAt(lineEndOffset - 1)) + lineStartOffset;
}
int best = lineStartOffset;
- float bestdist = Math.abs(getHorizontal(best, primary) - horiz);
+ float bestdist = Math.abs(horizontal.get(lineStartOffset) - horiz);
for (int i = 0; i < dirs.mDirections.length; i += 2) {
int here = lineStartOffset + dirs.mDirections[i];
@@ -1387,7 +1506,7 @@
guess = (high + low) / 2;
int adguess = getOffsetAtStartOf(guess);
- if (getHorizontal(adguess, primary) * swap >= horiz * swap) {
+ if (horizontal.get(adguess) * swap >= horiz * swap) {
high = guess;
} else {
low = guess;
@@ -1401,9 +1520,9 @@
int aft = tl.getOffsetToLeftRightOf(low - lineStartOffset, isRtl) + lineStartOffset;
low = tl.getOffsetToLeftRightOf(aft - lineStartOffset, !isRtl) + lineStartOffset;
if (low >= here && low < there) {
- float dist = Math.abs(getHorizontal(low, primary) - horiz);
+ float dist = Math.abs(horizontal.get(low) - horiz);
if (aft < there) {
- float other = Math.abs(getHorizontal(aft, primary) - horiz);
+ float other = Math.abs(horizontal.get(aft) - horiz);
if (other < dist) {
dist = other;
@@ -1418,7 +1537,7 @@
}
}
- float dist = Math.abs(getHorizontal(here, primary) - horiz);
+ float dist = Math.abs(horizontal.get(here) - horiz);
if (dist < bestdist) {
bestdist = dist;
@@ -1426,7 +1545,7 @@
}
}
- float dist = Math.abs(getHorizontal(max, primary) - horiz);
+ float dist = Math.abs(horizontal.get(max) - horiz);
if (dist <= bestdist) {
best = max;
@@ -1437,6 +1556,46 @@
}
/**
+ * Responds to #getHorizontal queries, by selecting the better strategy between:
+ * - calling #getHorizontal explicitly for each query
+ * - precomputing all #getHorizontal measurements, and responding to any query in constant time
+ * The first strategy is used for LTR-only text, while the second is used for all other cases.
+ * The class is currently only used in #getOffsetForHorizontal, so reuse with care in other
+ * contexts.
+ */
+ private class HorizontalMeasurementProvider {
+ private final int mLine;
+ private final boolean mPrimary;
+
+ private float[] mHorizontals;
+ private int mLineStartOffset;
+
+ HorizontalMeasurementProvider(final int line, final boolean primary) {
+ mLine = line;
+ mPrimary = primary;
+ init();
+ }
+
+ private void init() {
+ final Directions dirs = getLineDirections(mLine);
+ if (dirs == DIRS_ALL_LEFT_TO_RIGHT) {
+ return;
+ }
+
+ mHorizontals = getLineHorizontals(mLine, false, mPrimary);
+ mLineStartOffset = getLineStart(mLine);
+ }
+
+ float get(final int offset) {
+ if (mHorizontals == null) {
+ return getHorizontal(offset, mPrimary);
+ } else {
+ return mHorizontals[offset - mLineStartOffset];
+ }
+ }
+ }
+
+ /**
* Return the text offset after the last character on the specified line.
*/
public final int getLineEnd(int line) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 64365fa..b9f93e5 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -388,6 +388,99 @@
}
/**
+ * @see #measure(int, boolean, FontMetricsInt)
+ * @return The measure results for all possible offsets
+ */
+ @VisibleForTesting
+ public float[] measureAllOffsets(boolean[] trailing, FontMetricsInt fmi) {
+ float[] measurement = new float[mLen + 1];
+
+ int[] target = new int[mLen + 1];
+ for (int offset = 0; offset < target.length; ++offset) {
+ target[offset] = trailing[offset] ? offset - 1 : offset;
+ }
+ if (target[0] < 0) {
+ measurement[0] = 0;
+ }
+
+ float h = 0;
+
+ if (!mHasTabs) {
+ if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
+ for (int offset = 0; offset <= mLen; ++offset) {
+ measurement[offset] = measureRun(0, offset, mLen, false, fmi);
+ }
+ return measurement;
+ }
+ if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
+ for (int offset = 0; offset <= mLen; ++offset) {
+ measurement[offset] = measureRun(0, offset, mLen, true, fmi);
+ }
+ return measurement;
+ }
+ }
+
+ char[] chars = mChars;
+ int[] runs = mDirections.mDirections;
+ for (int i = 0; i < runs.length; i += 2) {
+ int runStart = runs[i];
+ int runLimit = runStart + (runs[i + 1] & Layout.RUN_LENGTH_MASK);
+ if (runLimit > mLen) {
+ runLimit = mLen;
+ }
+ boolean runIsRtl = (runs[i + 1] & Layout.RUN_RTL_FLAG) != 0;
+
+ int segstart = runStart;
+ for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; ++j) {
+ int codept = 0;
+ if (mHasTabs && j < runLimit) {
+ codept = chars[j];
+ if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) {
+ codept = Character.codePointAt(chars, j);
+ if (codept > 0xFFFF) {
+ ++j;
+ continue;
+ }
+ }
+ }
+
+ if (j == runLimit || codept == '\t') {
+ float oldh = h;
+ boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
+ float w = measureRun(segstart, j, j, runIsRtl, fmi);
+ h += advance ? w : -w;
+
+ float baseh = advance ? oldh : h;
+ FontMetricsInt crtfmi = advance ? fmi : null;
+ for (int offset = segstart; offset <= j && offset <= mLen; ++offset) {
+ if (target[offset] >= segstart && target[offset] < j) {
+ measurement[offset] =
+ baseh + measureRun(segstart, offset, j, runIsRtl, crtfmi);
+ }
+ }
+
+ if (codept == '\t') {
+ if (target[j] == j) {
+ measurement[j] = h;
+ }
+ h = mDir * nextTab(h * mDir);
+ if (target[j + 1] == j) {
+ measurement[j + 1] = h;
+ }
+ }
+
+ segstart = j + 1;
+ }
+ }
+ }
+ if (target[mLen] == mLen) {
+ measurement[mLen] = h;
+ }
+
+ return measurement;
+ }
+
+ /**
* Draws a unidirectional (but possibly multi-styled) run of text.
*
*
@@ -824,6 +917,9 @@
wp.setColor(previousColor);
}
+ drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl,
+ leftX, y + wp.baselineShift);
+
if (numDecorations != 0) {
for (int i = 0; i < numDecorations; i++) {
final DecorationInfo info = decorations.get(i);
@@ -866,8 +962,6 @@
}
}
- drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl,
- leftX, y + wp.baselineShift);
}
return runIsRtl ? -totalWidth : totalWidth;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 378bb1a..dd5abaa 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -810,7 +811,12 @@
/** Key code constant: Refresh key. */
public static final int KEYCODE_REFRESH = 285;
- private static final int LAST_KEYCODE = KEYCODE_REFRESH;
+ /**
+ * Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent.
+ * @hide
+ */
+ @TestApi
+ public static final int LAST_KEYCODE = KEYCODE_REFRESH;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -2889,25 +2895,34 @@
/**
* Gets a keycode by its symbolic name such as "KEYCODE_A" or an equivalent
- * numeric constant such as "1001".
+ * numeric constant such as "29". For symbolic names,
+ * starting in {@link android.os.Build.VERSION_CODES#Q} the prefix "KEYCODE_" is optional.
*
* @param symbolicName The symbolic name of the keycode.
* @return The keycode or {@link #KEYCODE_UNKNOWN} if not found.
* @see #keycodeToString(int)
*/
- public static int keyCodeFromString(String symbolicName) {
- if (symbolicName.startsWith(LABEL_PREFIX)) {
- symbolicName = symbolicName.substring(LABEL_PREFIX.length());
- int keyCode = nativeKeyCodeFromString(symbolicName);
- if (keyCode > 0) {
+ public static int keyCodeFromString(@NonNull String symbolicName) {
+ try {
+ int keyCode = Integer.parseInt(symbolicName);
+ if (keyCodeIsValid(keyCode)) {
return keyCode;
}
- }
- try {
- return Integer.parseInt(symbolicName, 10);
} catch (NumberFormatException ex) {
- return KEYCODE_UNKNOWN;
}
+
+ if (symbolicName.startsWith(LABEL_PREFIX)) {
+ symbolicName = symbolicName.substring(LABEL_PREFIX.length());
+ }
+ int keyCode = nativeKeyCodeFromString(symbolicName);
+ if (keyCodeIsValid(keyCode)) {
+ return keyCode;
+ }
+ return KEYCODE_UNKNOWN;
+ }
+
+ private static boolean keyCodeIsValid(int keyCode) {
+ return keyCode >= KEYCODE_UNKNOWN && keyCode <= LAST_KEYCODE;
}
/**
diff --git a/core/java/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 537065d..1d5c6f1 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -36,6 +36,10 @@
/**
* Proceed with the SSL certificate.
+ * <p>
+ * It is not recommended to proceed past SSL errors and this method should
+ * generally not be used; see {@link WebViewClient#onReceivedSslError} for
+ * more information.
*/
public void proceed() {}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 4aa1c4a..95fe963 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -113,6 +113,20 @@
* the new WebView as an argument. If the host application chooses not to
* honor the request, it should return {@code false} from this method. The default
* implementation of this method does nothing and hence returns {@code false}.
+ * <p>
+ * Applications should typically not allow windows to be created when the
+ * {@code isUserGesture} flag is false, as this may be an unwanted popup.
+ * <p>
+ * Applications should be careful how they display the new window: don't simply
+ * overlay it over the existing WebView as this may mislead the user about which
+ * site they are viewing. If your application displays the URL of the main page,
+ * make sure to also display the URL of the new window in a similar fashion. If
+ * your application does not display URLs, consider disallowing the creation of
+ * new windows entirely.
+ * <p class="note"><b>Note:</b> There is no trustworthy way to tell which page
+ * requested the new window: the request might originate from a third-party iframe
+ * inside the WebView.
+ *
* @param view The WebView from which the request for a new window
* originated.
* @param isDialog {@code true} if the new window should be a dialog, rather than
@@ -149,6 +163,11 @@
* from the view system if necessary. At this point, WebCore has stopped
* any loading in this window and has removed any cross-scripting ability
* in javascript.
+ * <p>
+ * As with {@link #onCreateWindow}, the application should ensure that any
+ * URL or security indicator displayed is updated so that the user can tell
+ * that the page they were interacting with has been closed.
+ *
* @param window The WebView that needs to be closed.
*/
public void onCloseWindow(WebView window) {}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index bd000f6..4eb85ac 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1019,11 +1019,21 @@
* If {@code null}, defaults to 'text/html'.
* <p>
* The 'data' scheme URL formed by this method uses the default US-ASCII
- * charset. If you need need to set a different charset, you should form a
+ * charset. If you need to set a different charset, you should form a
* 'data' scheme URL which explicitly specifies a charset parameter in the
* mediatype portion of the URL and call {@link #loadUrl(String)} instead.
* Note that the charset obtained from the mediatype portion of a data URL
* always overrides that specified in the HTML or XML document itself.
+ * <p>
+ * Content loaded using this method will have a {@code window.origin} value
+ * of {@code "null"}. This must not be considered to be a trusted origin
+ * by the application or by any JavaScript code running inside the WebView
+ * (for example, event sources in DOM event handlers or web messages),
+ * because malicious content can also create frames with a null origin. If
+ * you need to identify the main frame's origin in a trustworthy way, you
+ * should use {@link #loadDataWithBaseURL(String,String,String,String,String)
+ * loadDataWithBaseURL()} with a valid HTTP or HTTPS base URL to set the
+ * origin.
*
* @param data a String of data in the given encoding
* @param mimeType the MIME type of the data, e.g. 'text/html'.
@@ -1057,6 +1067,15 @@
* <p>
* Note that the baseUrl is sent in the 'Referer' HTTP header when
* requesting subresources (images, etc.) of the page loaded using this method.
+ * <p>
+ * If a valid HTTP or HTTPS base URL is not specified in {@code baseUrl}, then
+ * content loaded using this method will have a {@code window.origin} value
+ * of {@code "null"}. This must not be considered to be a trusted origin
+ * by the application or by any JavaScript code running inside the WebView
+ * (for example, event sources in DOM event handlers or web messages),
+ * because malicious content can also create frames with a null origin. If
+ * you need to identify the main frame's origin in a trustworthy way, you
+ * should use a valid HTTP or HTTPS base URL to set the origin.
*
* @param baseUrl the URL to use as the page's base URL. If {@code null} defaults to
* 'about:blank'.
@@ -2053,6 +2072,13 @@
* <p>
* A target origin can be set as a wildcard ("*"). However this is not recommended.
* See the page above for security issues.
+ * <p>
+ * Content loaded via {@link #loadData(String,String,String)} will not have a
+ * valid origin, and thus cannot be sent messages securely. If you need to send
+ * messages using this function, you should use
+ * {@link #loadDataWithBaseURL(String,String,String,String,String)} with a valid
+ * HTTP or HTTPS {@code baseUrl} to define a valid origin that can be used for
+ * messaging.
*
* @param message the WebMessage
* @param targetOrigin the target origin.
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 6df1655..f686b66 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -368,6 +368,15 @@
* handler.proceed(). Note that the decision may be retained for use in
* response to future SSL errors. The default behavior is to cancel the
* load.
+ * <p>
+ * Applications are advised not to prompt the user about SSL errors, as
+ * the user is unlikely to be able to make an informed security decision
+ * and WebView does not provide any UI for showing the details of the
+ * error in a meaningful way.
+ * <p>
+ * Application overrides of this method may display custom error pages or
+ * silently log issues, but it is strongly recommended to always call
+ * handler.cancel() and never allow proceeding past errors.
*
* @param view The WebView that is initiating the callback.
* @param handler An SslErrorHandler object that will handle the user's
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 97043c7..571878d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -21,6 +21,7 @@
import android.animation.ObjectAnimator;
import android.annotation.NonNull;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.usage.UsageStatsManager;
import android.content.ComponentName;
import android.content.Context;
@@ -1022,6 +1023,11 @@
@Override
public void onListRebuilt() {
+ // don't support direct share on low ram devices
+ if (ActivityManager.isLowRamDeviceStatic()) {
+ return;
+ }
+
if (mServiceTargets != null) {
pruneServiceTargets();
}
diff --git a/core/java/com/android/internal/app/ColorDisplayController.java b/core/java/com/android/internal/app/ColorDisplayController.java
index 6cc964b..ba6cf26 100644
--- a/core/java/com/android/internal/app/ColorDisplayController.java
+++ b/core/java/com/android/internal/app/ColorDisplayController.java
@@ -335,7 +335,7 @@
if (colorTemperature == -1) {
if (DEBUG) {
Slog.d(TAG, "Using default value for setting: "
- + Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE);
+ + Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE);
}
colorTemperature = getDefaultColorTemperature();
}
@@ -358,7 +358,7 @@
*/
public boolean setColorTemperature(int colorTemperature) {
return Secure.putIntForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, colorTemperature, mUserId);
+ Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, colorTemperature, mUserId);
}
/**
@@ -367,10 +367,10 @@
* See com.android.server.display.DisplayTransformManager.
*/
private @ColorMode int getCurrentColorModeFromSystemProperties() {
- int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
+ final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
if (displayColorSetting == 0) {
return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
- ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
+ ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
} else if (displayColorSetting == 1) {
return COLOR_MODE_SATURATED;
} else if (displayColorSetting == 2) {
@@ -381,16 +381,13 @@
}
private boolean isColorModeAvailable(@ColorMode int colorMode) {
- // SATURATED is always allowed
- if (colorMode == COLOR_MODE_SATURATED) {
- return true;
- }
-
final int[] availableColorModes = mContext.getResources().getIntArray(
R.array.config_availableColorModes);
- for (int mode : availableColorModes) {
- if (mode == colorMode) {
- return true;
+ if (availableColorModes != null) {
+ for (int mode : availableColorModes) {
+ if (mode == colorMode) {
+ return true;
+ }
}
}
return false;
@@ -401,14 +398,18 @@
*/
public int getColorMode() {
if (getAccessibilityTransformActivated()) {
- return COLOR_MODE_SATURATED;
+ if (isColorModeAvailable(COLOR_MODE_SATURATED)) {
+ return COLOR_MODE_SATURATED;
+ } else if (isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
+ return COLOR_MODE_AUTOMATIC;
+ }
}
int colorMode = System.getIntForUser(mContext.getContentResolver(),
- System.DISPLAY_COLOR_MODE, -1, mUserId);
+ System.DISPLAY_COLOR_MODE, -1, mUserId);
if (colorMode == -1) {
- // There still might be a legacy system property controlling color mode that we need to
- // respect.
+ // There might be a system property controlling color mode that we need to respect; if
+ // not, this will set a suitable default.
colorMode = getCurrentColorModeFromSystemProperties();
}
@@ -418,10 +419,13 @@
if (colorMode == COLOR_MODE_BOOSTED && isColorModeAvailable(COLOR_MODE_NATURAL)) {
colorMode = COLOR_MODE_NATURAL;
} else if (colorMode == COLOR_MODE_SATURATED
- && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
+ && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
colorMode = COLOR_MODE_AUTOMATIC;
- } else {
+ } else if (colorMode == COLOR_MODE_AUTOMATIC
+ && isColorModeAvailable(COLOR_MODE_SATURATED)) {
colorMode = COLOR_MODE_SATURATED;
+ } else {
+ colorMode = -1;
}
}
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index f42a195..a8edfb6 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -60,7 +60,7 @@
if (resolvedInfo != null && resolvedInfo.activityInfo != null
&& requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
return moreDetailsIntent;
}
return null;
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 7116f3a..d135040 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -207,6 +207,8 @@
mAvatarView.setTranslationY(0.0f);
mSenderName.setAlpha(1.0f);
mSenderName.setTranslationY(0.0f);
+ mIsolatedMessage = null;
+ mMessages = null;
sInstancePool.release(MessagingGroup.this);
}
};
@@ -267,6 +269,11 @@
@Override
public int getMeasuredType() {
+ if (mIsolatedMessage != null) {
+ // We only want to show one group if we have an inline image, so let's return shortened
+ // to avoid displaying the other ones.
+ return MEASURED_SHORTENED;
+ }
boolean hasNormal = false;
for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
View child = mMessageContainer.getChildAt(i);
@@ -292,9 +299,6 @@
}
}
}
- if (mMessageContainer.getChildCount() == 0 && mIsolatedMessage != null) {
- return mIsolatedMessage.getMeasuredType();
- }
return MEASURED_NORMAL;
}
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 9048f87..c7ea781 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -206,7 +206,17 @@
final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
int childTop;
- int childLeft = centerAligned ? left + (right - left) / 2 - mTotalWidth / 2 : 0;
+ int childLeft;
+ if (centerAligned) {
+ childLeft = mPaddingLeft + left + (right - left) / 2 - mTotalWidth / 2;
+ } else {
+ childLeft = mPaddingLeft;
+ int absoluteGravity = Gravity.getAbsoluteGravity(Gravity.START, getLayoutDirection());
+ if (absoluteGravity == Gravity.RIGHT) {
+ childLeft += right - left - mTotalWidth;
+ }
+ }
+
// Where bottom of child should go
final int height = bottom - top;
@@ -216,18 +226,6 @@
final int count = getChildCount();
- final int layoutDirection = getLayoutDirection();
- switch (Gravity.getAbsoluteGravity(Gravity.START, layoutDirection)) {
- case Gravity.RIGHT:
- childLeft += mPaddingLeft + right - left - mTotalWidth;
- break;
-
- case Gravity.LEFT:
- default:
- childLeft += mPaddingLeft;
- break;
- }
-
int start = 0;
int dir = 1;
//In case of RTL, start drawing from the last child.
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index d7d8228..a72363c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1294,11 +1294,8 @@
handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
}
- struct audio_patch nPatch;
+ struct audio_patch nPatch = { .id = handle };
- nPatch.id = handle;
- nPatch.num_sources = 0;
- nPatch.num_sinks = 0;
jobject jSource = NULL;
jobject jSink = NULL;
@@ -1584,7 +1581,7 @@
if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
return AUDIO_JAVA_BAD_VALUE;
}
- struct audio_port_config nAudioPortConfig;
+ struct audio_port_config nAudioPortConfig = {};
jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig, true);
if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index da206b7..642f4ed 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4287,21 +4287,6 @@
</intent-filter>
</receiver>
- <receiver android:name="com.android.server.stats.StatsCompanionService$AnomalyAlarmReceiver"
- android:permission="android.permission.STATSCOMPANION"
- android:exported="false">
- </receiver>
-
- <receiver android:name="com.android.server.stats.StatsCompanionService$PullingAlarmReceiver"
- android:permission="android.permission.STATSCOMPANION"
- android:exported="false">
- </receiver>
-
- <receiver android:name="com.android.server.stats.StatsCompanionService$PeriodicAlarmReceiver"
- android:permission="android.permission.STATSCOMPANION"
- android:exported="false">
- </receiver>
-
<service android:name="android.hardware.location.GeofenceHardwareService"
android:permission="android.permission.LOCATION_HARDWARE"
android:exported="false" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2e8c7f9..471170b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -55,7 +55,7 @@
<!-- Width of the navigation bar when it is placed vertically on the screen in car mode -->
<dimen name="navigation_bar_width_car_mode">96dp</dimen>
<!-- Height of notification icons in the status bar -->
- <dimen name="status_bar_icon_size">24dip</dimen>
+ <dimen name="status_bar_icon_size">22dip</dimen>
<!-- Size of the giant number (unread count) in the notifications -->
<dimen name="status_bar_content_number_size">48sp</dimen>
<!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index c6ada7a..51049fe 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -132,6 +132,7 @@
Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
Settings.Global.BLE_SCAN_BACKGROUND_MODE,
+ Settings.Global.BLOCKED_SLICES,
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
@@ -155,6 +156,7 @@
Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
Settings.Global.CAPTIVE_PORTAL_MODE,
Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
+ Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS,
Settings.Global.CAPTIVE_PORTAL_SERVER,
Settings.Global.CAPTIVE_PORTAL_USE_HTTPS,
Settings.Global.CAPTIVE_PORTAL_USER_AGENT,
@@ -592,6 +594,7 @@
Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
Settings.Secure.SKIP_FIRST_USE_HINTS, // candidate?
Settings.Secure.SMS_DEFAULT_APPLICATION,
+ Settings.Secure.THEME_MODE,
Settings.Secure.TRUST_AGENTS_INITIALIZED,
Settings.Secure.TV_INPUT_CUSTOM_LABELS,
Settings.Secure.TV_INPUT_HIDDEN_INPUTS,
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index 50f24d3..8909293 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -88,6 +88,23 @@
}
@Test
+ public void testNullableComponentNameValidator_onValidComponentName_returnsTrue() {
+ assertTrue(SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR.validate(
+ "android/com.android.internal.backup.LocalTransport"));
+ }
+
+ @Test
+ public void testNullableComponentNameValidator_onInvalidComponentName_returnsFalse() {
+ assertFalse(SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR.validate(
+ "rectangle"));
+ }
+
+ @Test
+ public void testNullableComponentNameValidator_onNullValue_returnsTrue() {
+ assertTrue(SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR.validate(null));
+ }
+
+ @Test
public void testLocaleValidator() {
assertTrue(SettingsValidators.LOCALE_VALIDATOR.validate("en_US"));
assertTrue(SettingsValidators.LOCALE_VALIDATOR.validate("es"));
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 5570bac..97937a4 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -711,6 +711,7 @@
actual[i] = layout.primaryIsTrailingPrevious(i);
}
assertArrayEquals(expected, actual);
+ assertArrayEquals(actual, layout.primaryIsTrailingPreviousAllLineOffsets(0));
}
@Test
@@ -741,7 +742,6 @@
assertPrimaryIsTrailingPrevious(
RTL + LRI + RTL + LTR + PDI + RTL,
new boolean[]{false, false, true, false, false, false, false});
-
}
}
diff --git a/core/tests/coretests/src/android/text/TextLineTest.java b/core/tests/coretests/src/android/text/TextLineTest.java
index b2fa2cf..d1e12fa 100644
--- a/core/tests/coretests/src/android/text/TextLineTest.java
+++ b/core/tests/coretests/src/android/text/TextLineTest.java
@@ -16,6 +16,7 @@
package android.text;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -32,6 +33,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -90,8 +93,9 @@
"fonts/StaticLayoutLineBreakingTestFont.ttf");
private TextLine getTextLine(String str, TextPaint paint, TabStops tabStops) {
- Layout layout = StaticLayout.Builder.obtain(str, 0, str.length(), paint, Integer.MAX_VALUE)
- .build();
+ Layout layout =
+ StaticLayout.Builder.obtain(str, 0, str.length(), paint, Integer.MAX_VALUE)
+ .build();
TextLine tl = TextLine.obtain();
tl.set(paint, str, 0, str.length(),
TextDirectionHeuristics.FIRSTSTRONG_LTR.isRtl(str, 0, str.length()) ? -1 : 1,
@@ -103,6 +107,18 @@
return getTextLine(str, paint, null);
}
+ private void assertMeasurements(final TextLine tl, final int length, boolean trailing,
+ final float[] expected) {
+ for (int offset = 0; offset <= length; ++offset) {
+ assertEquals(expected[offset], tl.measure(offset, trailing, null), 0.0f);
+ }
+
+ final boolean[] trailings = new boolean[length + 1];
+ Arrays.fill(trailings, trailing);
+ final float[] allMeasurements = tl.measureAllOffsets(trailings, null);
+ assertArrayEquals(expected, allMeasurements, 0.0f);
+ }
+
@Test
public void testMeasure_LTR() {
final TextPaint paint = new TextPaint();
@@ -110,21 +126,10 @@
paint.setTextSize(10.0f); // make 1em = 10px
TextLine tl = getTextLine("IIIIIV", paint);
- assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
- assertEquals(10.0f, tl.measure(1, false, null), 0.0f);
- assertEquals(20.0f, tl.measure(2, false, null), 0.0f);
- assertEquals(30.0f, tl.measure(3, false, null), 0.0f);
- assertEquals(40.0f, tl.measure(4, false, null), 0.0f);
- assertEquals(50.0f, tl.measure(5, false, null), 0.0f);
- assertEquals(100.0f, tl.measure(6, false, null), 0.0f);
-
- assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
- assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
- assertEquals(20.0f, tl.measure(2, true, null), 0.0f);
- assertEquals(30.0f, tl.measure(3, true, null), 0.0f);
- assertEquals(40.0f, tl.measure(4, true, null), 0.0f);
- assertEquals(50.0f, tl.measure(5, true, null), 0.0f);
- assertEquals(100.0f, tl.measure(6, true, null), 0.0f);
+ assertMeasurements(tl, 6, false,
+ new float[]{0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 100.0f});
+ assertMeasurements(tl, 6, true,
+ new float[]{0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 100.0f});
}
@Test
@@ -134,21 +139,10 @@
paint.setTextSize(10.0f); // make 1em = 10px
TextLine tl = getTextLine("\u05D0\u05D0\u05D0\u05D0\u05D0\u05D1", paint);
- assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
- assertEquals(-10.0f, tl.measure(1, false, null), 0.0f);
- assertEquals(-20.0f, tl.measure(2, false, null), 0.0f);
- assertEquals(-30.0f, tl.measure(3, false, null), 0.0f);
- assertEquals(-40.0f, tl.measure(4, false, null), 0.0f);
- assertEquals(-50.0f, tl.measure(5, false, null), 0.0f);
- assertEquals(-100.0f, tl.measure(6, false, null), 0.0f);
-
- assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
- assertEquals(-10.0f, tl.measure(1, true, null), 0.0f);
- assertEquals(-20.0f, tl.measure(2, true, null), 0.0f);
- assertEquals(-30.0f, tl.measure(3, true, null), 0.0f);
- assertEquals(-40.0f, tl.measure(4, true, null), 0.0f);
- assertEquals(-50.0f, tl.measure(5, true, null), 0.0f);
- assertEquals(-100.0f, tl.measure(6, true, null), 0.0f);
+ assertMeasurements(tl, 6, false,
+ new float[]{0.0f, -10.0f, -20.0f, -30.0f, -40.0f, -50.0f, -100.0f});
+ assertMeasurements(tl, 6, true,
+ new float[]{0.0f, -10.0f, -20.0f, -30.0f, -40.0f, -50.0f, -100.0f});
}
@Test
@@ -158,21 +152,10 @@
paint.setTextSize(10.0f); // make 1em = 10px
TextLine tl = getTextLine("II\u05D0\u05D0II", paint);
- assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
- assertEquals(10.0f, tl.measure(1, false, null), 0.0f);
- assertEquals(40.0f, tl.measure(2, false, null), 0.0f);
- assertEquals(30.0f, tl.measure(3, false, null), 0.0f);
- assertEquals(40.0f, tl.measure(4, false, null), 0.0f);
- assertEquals(50.0f, tl.measure(5, false, null), 0.0f);
- assertEquals(60.0f, tl.measure(6, false, null), 0.0f);
-
- assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
- assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
- assertEquals(20.0f, tl.measure(2, true, null), 0.0f);
- assertEquals(30.0f, tl.measure(3, true, null), 0.0f);
- assertEquals(20.0f, tl.measure(4, true, null), 0.0f);
- assertEquals(50.0f, tl.measure(5, true, null), 0.0f);
- assertEquals(60.0f, tl.measure(6, true, null), 0.0f);
+ assertMeasurements(tl, 6, false,
+ new float[]{0.0f, 10.0f, 40.0f, 30.0f, 40.0f, 50.0f, 60.0f});
+ assertMeasurements(tl, 6, true,
+ new float[]{0.0f, 10.0f, 20.0f, 30.0f, 20.0f, 50.0f, 60.0f});
}
private static final String LRI = "\u2066"; // LEFT-TO-RIGHT ISOLATE
@@ -186,23 +169,10 @@
paint.setTextSize(10.0f); // make 1em = 10px
TextLine tl = getTextLine("I" + RLI + "I\u05D0\u05D0" + PDI + "I", paint);
- assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
- assertEquals(10.0f, tl.measure(1, false, null), 0.0f);
- assertEquals(30.0f, tl.measure(2, false, null), 0.0f);
- assertEquals(30.0f, tl.measure(3, false, null), 0.0f);
- assertEquals(20.0f, tl.measure(4, false, null), 0.0f);
- assertEquals(40.0f, tl.measure(5, false, null), 0.0f);
- assertEquals(40.0f, tl.measure(6, false, null), 0.0f);
- assertEquals(50.0f, tl.measure(7, false, null), 0.0f);
-
- assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
- assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
- assertEquals(10.0f, tl.measure(2, true, null), 0.0f);
- assertEquals(40.0f, tl.measure(3, true, null), 0.0f);
- assertEquals(20.0f, tl.measure(4, true, null), 0.0f);
- assertEquals(10.0f, tl.measure(5, true, null), 0.0f);
- assertEquals(40.0f, tl.measure(6, true, null), 0.0f);
- assertEquals(50.0f, tl.measure(7, true, null), 0.0f);
+ assertMeasurements(tl, 7, false,
+ new float[]{0.0f, 10.0f, 30.0f, 30.0f, 20.0f, 40.0f, 40.0f, 50.0f});
+ assertMeasurements(tl, 7, true,
+ new float[]{0.0f, 10.0f, 10.0f, 40.0f, 20.0f, 10.0f, 40.0f, 50.0f});
}
@Test
@@ -212,23 +182,10 @@
paint.setTextSize(10.0f); // make 1em = 10px
TextLine tl = getTextLine("\u05D0" + LRI + "\u05D0II" + PDI + "\u05D0", paint);
- assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
- assertEquals(-10.0f, tl.measure(1, false, null), 0.0f);
- assertEquals(-30.0f, tl.measure(2, false, null), 0.0f);
- assertEquals(-30.0f, tl.measure(3, false, null), 0.0f);
- assertEquals(-20.0f, tl.measure(4, false, null), 0.0f);
- assertEquals(-40.0f, tl.measure(5, false, null), 0.0f);
- assertEquals(-40.0f, tl.measure(6, false, null), 0.0f);
- assertEquals(-50.0f, tl.measure(7, false, null), 0.0f);
-
- assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
- assertEquals(-10.0f, tl.measure(1, true, null), 0.0f);
- assertEquals(-10.0f, tl.measure(2, true, null), 0.0f);
- assertEquals(-40.0f, tl.measure(3, true, null), 0.0f);
- assertEquals(-20.0f, tl.measure(4, true, null), 0.0f);
- assertEquals(-10.0f, tl.measure(5, true, null), 0.0f);
- assertEquals(-40.0f, tl.measure(6, true, null), 0.0f);
- assertEquals(-50.0f, tl.measure(7, true, null), 0.0f);
+ assertMeasurements(tl, 7, false,
+ new float[]{0.0f, -10.0f, -30.0f, -30.0f, -20.0f, -40.0f, -40.0f, -50.0f});
+ assertMeasurements(tl, 7, true,
+ new float[]{0.0f, -10.0f, -10.0f, -40.0f, -20.0f, -10.0f, -40.0f, -50.0f});
}
@Test
@@ -240,17 +197,10 @@
paint.setTextSize(10.0f); // make 1em = 10px
TextLine tl = getTextLine("II\tII", paint, stops);
- assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
- assertEquals(10.0f, tl.measure(1, false, null), 0.0f);
- assertEquals(20.0f, tl.measure(2, false, null), 0.0f);
- assertEquals(100.0f, tl.measure(3, false, null), 0.0f);
- assertEquals(110.0f, tl.measure(4, false, null), 0.0f);
-
- assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
- assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
- assertEquals(20.0f, tl.measure(2, true, null), 0.0f);
- assertEquals(100.0f, tl.measure(3, true, null), 0.0f);
- assertEquals(110.0f, tl.measure(4, true, null), 0.0f);
+ assertMeasurements(tl, 5, false,
+ new float[]{0.0f, 10.0f, 20.0f, 100.0f, 110.0f, 120.0f});
+ assertMeasurements(tl, 5, true,
+ new float[]{0.0f, 10.0f, 20.0f, 100.0f, 110.0f, 120.0f});
}
@Test
@@ -262,17 +212,10 @@
paint.setTextSize(10.0f); // make 1em = 10px
TextLine tl = getTextLine("\u05D0\u05D0\t\u05D0\u05D0", paint, stops);
- assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
- assertEquals(-10.0f, tl.measure(1, false, null), 0.0f);
- assertEquals(-20.0f, tl.measure(2, false, null), 0.0f);
- assertEquals(-100.0f, tl.measure(3, false, null), 0.0f);
- assertEquals(-110.0f, tl.measure(4, false, null), 0.0f);
-
- assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
- assertEquals(-10.0f, tl.measure(1, true, null), 0.0f);
- assertEquals(-20.0f, tl.measure(2, true, null), 0.0f);
- assertEquals(-100.0f, tl.measure(3, true, null), 0.0f);
- assertEquals(-110.0f, tl.measure(4, true, null), 0.0f);
+ assertMeasurements(tl, 5, false,
+ new float[]{0.0f, -10.0f, -20.0f, -100.0f, -110.0f, -120.0f});
+ assertMeasurements(tl, 5, true,
+ new float[]{0.0f, -10.0f, -20.0f, -100.0f, -110.0f, -120.0f});
}
@Test
@@ -284,19 +227,10 @@
paint.setTextSize(10.0f); // make 1em = 10px
TextLine tl = getTextLine("I\u05D0\tI\u05D0", paint, stops);
- assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
- assertEquals(20.0f, tl.measure(1, false, null), 0.0f);
- assertEquals(20.0f, tl.measure(2, false, null), 0.0f);
- assertEquals(100.0f, tl.measure(3, false, null), 0.0f);
- assertEquals(120.0f, tl.measure(4, false, null), 0.0f);
- assertEquals(120.0f, tl.measure(5, false, null), 0.0f);
-
- assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
- assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
- assertEquals(10.0f, tl.measure(2, true, null), 0.0f);
- assertEquals(100.0f, tl.measure(3, true, null), 0.0f);
- assertEquals(110.0f, tl.measure(4, true, null), 0.0f);
- assertEquals(110.0f, tl.measure(5, true, null), 0.0f);
+ assertMeasurements(tl, 5, false,
+ new float[]{0.0f, 20.0f, 20.0f, 100.0f, 120.0f, 120.0f});
+ assertMeasurements(tl, 5, true,
+ new float[]{0.0f, 10.0f, 10.0f, 100.0f, 110.0f, 110.0f});
}
@Test
@@ -308,18 +242,9 @@
paint.setTextSize(10.0f); // make 1em = 10px
TextLine tl = getTextLine("\u05D0I\t\u05D0I", paint, stops);
- assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
- assertEquals(-20.0f, tl.measure(1, false, null), 0.0f);
- assertEquals(-20.0f, tl.measure(2, false, null), 0.0f);
- assertEquals(-100.0f, tl.measure(3, false, null), 0.0f);
- assertEquals(-120.0f, tl.measure(4, false, null), 0.0f);
- assertEquals(-120.0f, tl.measure(5, false, null), 0.0f);
-
- assertEquals(-0.0f, tl.measure(0, true, null), 0.0f);
- assertEquals(-10.0f, tl.measure(1, true, null), 0.0f);
- assertEquals(-10.0f, tl.measure(2, true, null), 0.0f);
- assertEquals(-100.0f, tl.measure(3, true, null), 0.0f);
- assertEquals(-110.0f, tl.measure(4, true, null), 0.0f);
- assertEquals(-110.0f, tl.measure(5, true, null), 0.0f);
+ assertMeasurements(tl, 5, false,
+ new float[]{0.0f, -20.0f, -20.0f, -100.0f, -120.0f, -120.0f});
+ assertMeasurements(tl, 5, true,
+ new float[]{0.0f, -10.0f, -10.0f, -100.0f, -110.0f, -110.0f});
}
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 007cddd..b644cc3 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -458,7 +458,7 @@
// The chunk must be at least the size of the string pool header.
if (size < sizeof(ResStringPool_header)) {
- LOG_ALWAYS_FATAL("Bad string block: data size %zu is too small to be a string block", size);
+ ALOGW("Bad string block: data size %zu is too small to be a string block", size);
return (mError=BAD_TYPE);
}
@@ -468,7 +468,7 @@
if (validate_chunk(reinterpret_cast<const ResChunk_header*>(data), sizeof(ResStringPool_header),
reinterpret_cast<const uint8_t*>(data) + size,
"ResStringPool_header") != NO_ERROR) {
- LOG_ALWAYS_FATAL("Bad string block: malformed block dimensions");
+ ALOGW("Bad string block: malformed block dimensions");
return (mError=BAD_TYPE);
}
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 7b69b63..08f8da8 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -77,13 +77,20 @@
// apply a simple clip with a scissor or a complex clip with a stencil
SkRegion clipRegion;
canvas->temporary_internal_getRgnClip(&clipRegion);
+ canvas->flush();
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glViewport(0, 0, info.width, info.height);
if (CC_UNLIKELY(clipRegion.isComplex())) {
+ //TODO: move stencil clear and canvas flush to SkAndroidFrameworkUtils::clipWithStencil
glDisable(GL_SCISSOR_TEST);
glStencilMask(0x1);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
+ // GL ops get inserted here if previous flush is missing, which could dirty the stencil
bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(canvas);
- canvas->flush();
+ canvas->flush(); //need this flush for the single op that draws into the stencil
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glViewport(0, 0, info.width, info.height);
if (stencilWritten) {
glStencilMask(0x1);
glStencilFunc(GL_EQUAL, 0x1, 0x1);
@@ -94,11 +101,9 @@
glDisable(GL_STENCIL_TEST);
}
} else if (clipRegion.isEmpty()) {
- canvas->flush();
glDisable(GL_STENCIL_TEST);
glDisable(GL_SCISSOR_TEST);
} else {
- canvas->flush();
glDisable(GL_STENCIL_TEST);
glEnable(GL_SCISSOR_TEST);
setScissor(info.height, clipRegion.getBounds());
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 703f2dc..684cafa 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -1033,6 +1033,9 @@
/**
* Sets the extra information associated with this fix to the
* given Bundle.
+ *
+ * <p>Note this stores a copy of the given extras, so any changes to extras after calling this
+ * method won't be reflected in the location bundle.
*/
public void setExtras(Bundle extras) {
mExtras = (extras == null) ? null : new Bundle(extras);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f210eea..196b886 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3940,6 +3940,7 @@
* @param device Bluetooth device connected/disconnected
* @param state new connection state (BluetoothProfile.STATE_xxx)
* @param profile profile for the A2DP device
+ * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting.
* (either {@link android.bluetooth.BluetoothProfile.A2DP} or
* {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
* @param suppressNoisyIntent if true the
@@ -3949,12 +3950,13 @@
* {@hide}
*/
public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent) {
+ BluetoothDevice device, int state, int profile,
+ boolean suppressNoisyIntent, int a2dpVolume) {
final IAudioService service = getService();
int delay = 0;
try {
delay = service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
- state, profile, suppressNoisyIntent);
+ state, profile, suppressNoisyIntent, a2dpVolume);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4718,7 +4720,7 @@
NativeEventHandlerDelegate delegate =
new NativeEventHandlerDelegate(callback, handler);
mDeviceCallbacks.put(callback, delegate);
- broadcastDeviceListChange(delegate.getHandler());
+ broadcastDeviceListChange_sync(delegate.getHandler());
}
}
}
@@ -4837,9 +4839,9 @@
/**
* Internal method to compute and generate add/remove messages and then send to any
- * registered callbacks.
+ * registered callbacks. Must be called synchronized on mDeviceCallbacks.
*/
- private void broadcastDeviceListChange(Handler handler) {
+ private void broadcastDeviceListChange_sync(Handler handler) {
int status;
// Get the new current set of ports
@@ -4861,20 +4863,18 @@
AudioDeviceInfo[] removed_devices =
calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
if (added_devices.length != 0 || removed_devices.length != 0) {
- synchronized (mDeviceCallbacks) {
- for (int i = 0; i < mDeviceCallbacks.size(); i++) {
- handler = mDeviceCallbacks.valueAt(i).getHandler();
- if (handler != null) {
- if (removed_devices.length != 0) {
- handler.sendMessage(Message.obtain(handler,
- MSG_DEVICES_DEVICES_REMOVED,
- removed_devices));
- }
- if (added_devices.length != 0) {
- handler.sendMessage(Message.obtain(handler,
- MSG_DEVICES_DEVICES_ADDED,
- added_devices));
- }
+ for (int i = 0; i < mDeviceCallbacks.size(); i++) {
+ handler = mDeviceCallbacks.valueAt(i).getHandler();
+ if (handler != null) {
+ if (removed_devices.length != 0) {
+ handler.sendMessage(Message.obtain(handler,
+ MSG_DEVICES_DEVICES_REMOVED,
+ removed_devices));
+ }
+ if (added_devices.length != 0) {
+ handler.sendMessage(Message.obtain(handler,
+ MSG_DEVICES_DEVICES_ADDED,
+ added_devices));
}
}
}
@@ -4890,7 +4890,9 @@
private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
static final String TAG = "OnAmPortUpdateListener";
public void onAudioPortListUpdate(AudioPort[] portList) {
- broadcastDeviceListChange(null);
+ synchronized (mDeviceCallbacks) {
+ broadcastDeviceListChange_sync(null);
+ }
}
/**
@@ -4904,7 +4906,9 @@
* Callback method called when the mediaserver dies
*/
public void onServiceDied() {
- broadcastDeviceListChange(null);
+ synchronized (mDeviceCallbacks) {
+ broadcastDeviceListChange_sync(null);
+ }
}
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4af8850..569db16 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -211,7 +211,7 @@
oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
- int state, int profile, boolean suppressNoisyIntent);
+ int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
in IAudioPolicyCallback pcb);
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 9828275..a768dd3 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -207,8 +207,9 @@
* after {@link Image#close Image.close()} has been called.
* </p>
* @return the HardwareBuffer associated with this Image or null if this Image doesn't support
- * this feature (e.g. {@link android.media.ImageWriter ImageWriter} or
- * {@link android.media.MediaCodec MediaCodec} don't).
+ * this feature. (Unsupported use cases include Image instances obtained through
+ * {@link android.media.MediaCodec MediaCodec}, and on versions prior to Android P,
+ * {@link android.media.ImageWriter ImageWriter}).
*/
@Nullable
public HardwareBuffer getHardwareBuffer() {
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 397768a..4c0153f 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -20,6 +20,7 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.camera2.utils.SurfaceUtils;
+import android.hardware.HardwareBuffer;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -58,12 +59,17 @@
* </p>
* <p>
* If the application already has an Image from {@link ImageReader}, the
- * application can directly queue this Image into ImageWriter (via
- * {@link #queueInputImage}), potentially with zero buffer copies. For the
- * {@link ImageFormat#PRIVATE PRIVATE} format Images produced by
- * {@link ImageReader}, this is the only way to send Image data to ImageWriter,
- * as the Image data aren't accessible by the application.
+ * application can directly queue this Image into the ImageWriter (via
+ * {@link #queueInputImage}), potentially with zero buffer copies. This
+ * even works if the image format of the ImageWriter is
+ * {@link ImageFormat#PRIVATE PRIVATE}, and prior to Android P is the only
+ * way to enqueue images into such an ImageWriter. Starting in Android P
+ * private images may also be accessed through their hardware buffers
+ * (when available) through the {@link Image#getHardwareBuffer()} method.
+ * Attempting to access the planes of a private image, will return an
+ * empty array.
* </p>
+ * <p>
* Once new input Images are queued into an ImageWriter, it's up to the
* downstream components (e.g. {@link ImageReader} or
* {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the
@@ -257,29 +263,26 @@
* <p>
* If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} (
* {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the
- * image buffer is inaccessible to the application, and calling this method
- * will result in an {@link IllegalStateException}. Instead, the application
- * should acquire images from some other component (e.g. an
+ * image buffer is accessible to the application only through the hardware
+ * buffer obtained through {@link Image#getHardwareBuffer()}. (On Android
+ * versions prior to P, dequeueing private buffers will cause an
+ * {@link IllegalStateException} to be thrown). Alternatively,
+ * the application can acquire images from some other component (e.g. an
* {@link ImageReader}), and queue them directly to this ImageWriter via the
* {@link ImageWriter#queueInputImage queueInputImage()} method.
* </p>
*
* @return The next available input Image from this ImageWriter.
* @throws IllegalStateException if {@code maxImages} Images are currently
- * dequeued, or the ImageWriter format is
- * {@link ImageFormat#PRIVATE PRIVATE}, or the input
- * {@link android.view.Surface Surface} has been abandoned by the
- * consumer component that provided the {@link android.view.Surface Surface}.
+ * dequeued, or the input {@link android.view.Surface Surface}
+ * has been abandoned by the consumer component that provided
+ * the {@link android.view.Surface Surface}. Prior to Android
+ * P, throws if the ImageWriter format is
+ * {@link ImageFormat#PRIVATE PRIVATE}.
* @see #queueInputImage
* @see Image#close
*/
public Image dequeueInputImage() {
- if (mWriterFormat == ImageFormat.PRIVATE) {
- throw new IllegalStateException(
- "PRIVATE format ImageWriter doesn't support this operation since the images are"
- + " inaccessible to the application!");
- }
-
if (mDequeuedImages.size() >= mMaxImages) {
throw new IllegalStateException("Already dequeued max number of Images " + mMaxImages);
}
@@ -743,6 +746,13 @@
}
@Override
+ public HardwareBuffer getHardwareBuffer() {
+ throwISEIfImageIsInvalid();
+
+ return nativeGetHardwareBuffer();
+ }
+
+ @Override
public Plane[] getPlanes() {
throwISEIfImageIsInvalid();
@@ -863,6 +873,8 @@
private synchronized native int nativeGetHeight();
private synchronized native int nativeGetFormat();
+
+ private synchronized native HardwareBuffer nativeGetHardwareBuffer();
}
// Native implemented ImageWriter methods.
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 392a1eb..ada91be 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2848,8 +2848,12 @@
mInbandTrackIndices.set(i);
}
+ if (tracks[i] == null) {
+ Log.w(TAG, "unexpected NULL track at index " + i);
+ }
// newly appeared inband track
- if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+ if (tracks[i] != null
+ && tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
SubtitleTrack track = mSubtitleController.addTrack(
tracks[i].getFormat());
mIndexTrackPairs.add(Pair.create(i, track));
diff --git a/media/java/android/media/audiofx/DynamicsProcessing.java b/media/java/android/media/audiofx/DynamicsProcessing.java
index 4c17ae1..1c3cff9 100644
--- a/media/java/android/media/audiofx/DynamicsProcessing.java
+++ b/media/java/android/media/audiofx/DynamicsProcessing.java
@@ -279,25 +279,24 @@
private static final boolean PREEQ_DEFAULT_ENABLED = true;
private static final boolean POSTEQ_DEFAULT_ENABLED = true;
-
private static final boolean MBC_DEFAULT_ENABLED = true;
- private static final float MBC_DEFAULT_ATTACK_TIME = 50; // ms
- private static final float MBC_DEFAULT_RELEASE_TIME = 120; // ms
- private static final float MBC_DEFAULT_RATIO = 2; // 1:N
- private static final float MBC_DEFAULT_THRESHOLD = -30; // dB
+ private static final float MBC_DEFAULT_ATTACK_TIME = 3; // ms
+ private static final float MBC_DEFAULT_RELEASE_TIME = 80; // ms
+ private static final float MBC_DEFAULT_RATIO = 1; // N:1
+ private static final float MBC_DEFAULT_THRESHOLD = -45; // dB
private static final float MBC_DEFAULT_KNEE_WIDTH = 0; // dB
- private static final float MBC_DEFAULT_NOISE_GATE_THRESHOLD = -80; // dB
- private static final float MBC_DEFAULT_EXPANDER_RATIO = 1.5f; // N:1
+ private static final float MBC_DEFAULT_NOISE_GATE_THRESHOLD = -90; // dB
+ private static final float MBC_DEFAULT_EXPANDER_RATIO = 1; // 1:N
private static final float MBC_DEFAULT_PRE_GAIN = 0; // dB
- private static final float MBC_DEFAULT_POST_GAIN = 10; // dB
+ private static final float MBC_DEFAULT_POST_GAIN = 0; // dB
private static final boolean LIMITER_DEFAULT_ENABLED = true;
private static final int LIMITER_DEFAULT_LINK_GROUP = 0;//;
- private static final float LIMITER_DEFAULT_ATTACK_TIME = 50; // ms
- private static final float LIMITER_DEFAULT_RELEASE_TIME = 120; // ms
- private static final float LIMITER_DEFAULT_RATIO = 2; // 1:N
- private static final float LIMITER_DEFAULT_THRESHOLD = -30; // dB
- private static final float LIMITER_DEFAULT_POST_GAIN = 10; // dB
+ private static final float LIMITER_DEFAULT_ATTACK_TIME = 1; // ms
+ private static final float LIMITER_DEFAULT_RELEASE_TIME = 60; // ms
+ private static final float LIMITER_DEFAULT_RATIO = 10; // N:1
+ private static final float LIMITER_DEFAULT_THRESHOLD = -2; // dB
+ private static final float LIMITER_DEFAULT_POST_GAIN = 0; // dB
private static final float DEFAULT_MIN_FREQUENCY = 220; // Hz
private static final float DEFAULT_MAX_FREQUENCY = 20000; // Hz
@@ -540,13 +539,14 @@
* band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on.
* @param attackTime Attack Time for compressor in milliseconds (ms)
* @param releaseTime Release Time for compressor in milliseconds (ms)
- * @param ratio Compressor ratio (1:N)
+ * @param ratio Compressor ratio (N:1) (input:output)
* @param threshold Compressor threshold measured in decibels (dB) from 0 dB Full Scale
* (dBFS).
* @param kneeWidth Width in decibels (dB) around compressor threshold point.
* @param noiseGateThreshold Noise gate threshold in decibels (dB) from 0 dB Full Scale
* (dBFS).
- * @param expanderRatio Expander ratio (N:1) for signals below the Noise Gate Threshold.
+ * @param expanderRatio Expander ratio (1:N) (input:output) for signals below the Noise Gate
+ * Threshold.
* @param preGain Gain applied to the signal BEFORE the compression.
* @param postGain Gain applied to the signal AFTER compression.
*/
@@ -618,13 +618,13 @@
*/
public void setReleaseTime(float releaseTime) { mReleaseTime = releaseTime; }
/**
- * gets the compressor ratio (1:N)
- * @return compressor ratio (1:N)
+ * gets the compressor ratio (N:1)
+ * @return compressor ratio (N:1)
*/
public float getRatio() { return mRatio; }
/**
- * sets compressor ratio (1:N)
- * @param ratio desired for the compressor (1:N)
+ * sets compressor ratio (N:1)
+ * @param ratio desired for the compressor (N:1)
*/
public void setRatio(float ratio) { mRatio = ratio; }
/**
@@ -670,13 +670,13 @@
public void setNoiseGateThreshold(float noiseGateThreshold) {
mNoiseGateThreshold = noiseGateThreshold; }
/**
- * gets Expander ratio (N:1) for signals below the Noise Gate Threshold.
- * @return Expander ratio (N:1)
+ * gets Expander ratio (1:N) for signals below the Noise Gate Threshold.
+ * @return Expander ratio (1:N)
*/
public float getExpanderRatio() { return mExpanderRatio; }
/**
- * sets Expander ratio (N:1) for signals below the Noise Gate Threshold.
- * @param expanderRatio desired expander ratio (N:1)
+ * sets Expander ratio (1:N) for signals below the Noise Gate Threshold.
+ * @param expanderRatio desired expander ratio (1:N)
*/
public void setExpanderRatio(float expanderRatio) { mExpanderRatio = expanderRatio; }
/**
@@ -909,7 +909,7 @@
* same linkGroup index will react together.
* @param attackTime Attack Time for limiter compressor in milliseconds (ms)
* @param releaseTime Release Time for limiter compressor in milliseconds (ms)
- * @param ratio Limiter Compressor ratio (1:N)
+ * @param ratio Limiter Compressor ratio (N:1) (input:output)
* @param threshold Limiter Compressor threshold measured in decibels (dB) from 0 dB Full
* Scale (dBFS).
* @param postGain Gain applied to the signal AFTER compression.
@@ -985,13 +985,13 @@
*/
public void setReleaseTime(float releaseTime) { mReleaseTime = releaseTime; }
/**
- * gets the limiter compressor ratio (1:N)
- * @return limiter compressor ratio (1:N)
+ * gets the limiter compressor ratio (N:1)
+ * @return limiter compressor ratio (N:1)
*/
public float getRatio() { return mRatio; }
/**
- * sets limiter compressor ratio (1:N)
- * @param ratio desired for the limiter compressor (1:N)
+ * sets limiter compressor ratio (N:1)
+ * @param ratio desired for the limiter compressor (N:1)
*/
public void setRatio(float ratio) { mRatio = ratio; }
/**
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 11659e4..f8f7a90 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -25,11 +25,14 @@
#include <gui/Surface.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <private/android/AHardwareBufferHelpers.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <stdint.h>
#include <inttypes.h>
+#include <android/hardware_buffer_jni.h>
#define IMAGE_BUFFER_JNI_ID "mNativeBuffer"
#define IMAGE_FORMAT_UNKNOWN 0 // This is the same value as ImageFormat#UNKNOWN.
@@ -701,6 +704,20 @@
return static_cast<jint>(publicFmt);
}
+static jobject Image_getHardwareBuffer(JNIEnv* env, jobject thiz) {
+ GraphicBuffer* buffer;
+ Image_getNativeContext(env, thiz, &buffer, NULL);
+ if (buffer == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Image is not initialized");
+ return NULL;
+ }
+ AHardwareBuffer* b = AHardwareBuffer_from_GraphicBuffer(buffer);
+ // don't user the public AHardwareBuffer_toHardwareBuffer() because this would force us
+ // to link against libandroid.so
+ return android_hardware_HardwareBuffer_createFromAHardwareBuffer(env, b);
+}
+
static void Image_setFenceFd(JNIEnv* env, jobject thiz, int fenceFd) {
ALOGV("%s:", __FUNCTION__);
env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, reinterpret_cast<jint>(fenceFd));
@@ -818,10 +835,12 @@
static JNINativeMethod gImageMethods[] = {
{"nativeCreatePlanes", "(II)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;",
- (void*)Image_createSurfacePlanes },
- {"nativeGetWidth", "()I", (void*)Image_getWidth },
- {"nativeGetHeight", "()I", (void*)Image_getHeight },
- {"nativeGetFormat", "()I", (void*)Image_getFormat },
+ (void*)Image_createSurfacePlanes },
+ {"nativeGetWidth", "()I", (void*)Image_getWidth },
+ {"nativeGetHeight", "()I", (void*)Image_getHeight },
+ {"nativeGetFormat", "()I", (void*)Image_getFormat },
+ {"nativeGetHardwareBuffer", "()Landroid/hardware/HardwareBuffer;",
+ (void*)Image_getHardwareBuffer },
};
int register_android_media_ImageWriter(JNIEnv *env) {
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index db776c6..9f89d3c 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -16,6 +16,9 @@
package com.android.captiveportallogin;
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
+import static android.net.captiveportal.CaptivePortalProbeSpec.HTTP_LOCATION_HEADER_NAME;
+
import android.app.Activity;
import android.app.LoadedApk;
import android.content.Context;
@@ -29,6 +32,7 @@
import android.net.NetworkRequest;
import android.net.Proxy;
import android.net.Uri;
+import android.net.captiveportal.CaptivePortalProbeSpec;
import android.net.dns.ResolvUtil;
import android.net.http.SslError;
import android.net.wifi.WifiInfo;
@@ -85,6 +89,7 @@
};
private URL mUrl;
+ private CaptivePortalProbeSpec mProbeSpec;
private String mUserAgent;
private Network mNetwork;
private CaptivePortal mCaptivePortal;
@@ -118,6 +123,14 @@
Log.d(TAG, String.format("onCreate for %s", mUrl.toString()));
}
+ final String spec = getIntent().getStringExtra(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC);
+ try {
+ mProbeSpec = CaptivePortalProbeSpec.parseSpecOrNull(spec);
+ } catch (Exception e) {
+ // Make extra sure that invalid configurations do not cause crashes
+ mProbeSpec = null;
+ }
+
// Also initializes proxy system properties.
mCm.bindProcessToNetwork(mNetwork);
mCm.setProcessDefaultNetworkForHostResolution(
@@ -329,6 +342,7 @@
}
HttpURLConnection urlConnection = null;
int httpResponseCode = 500;
+ String locationHeader = null;
try {
urlConnection = (HttpURLConnection) network.openConnection(mUrl);
urlConnection.setInstanceFollowRedirects(false);
@@ -343,6 +357,7 @@
urlConnection.getInputStream();
httpResponseCode = urlConnection.getResponseCode();
+ locationHeader = urlConnection.getHeaderField(HTTP_LOCATION_HEADER_NAME);
if (DBG) {
Log.d(TAG, "probe at " + mUrl +
" ret=" + httpResponseCode +
@@ -353,13 +368,20 @@
} finally {
if (urlConnection != null) urlConnection.disconnect();
}
- if (httpResponseCode == 204) {
+ if (isDismissed(httpResponseCode, locationHeader, mProbeSpec)) {
done(Result.DISMISSED);
}
}
}).start();
}
+ private static boolean isDismissed(
+ int httpResponseCode, String locationHeader, CaptivePortalProbeSpec probeSpec) {
+ return (probeSpec != null)
+ ? probeSpec.getResult(httpResponseCode, locationHeader).isSuccessful()
+ : (httpResponseCode == 204);
+ }
+
private class MyWebViewClient extends WebViewClient {
private static final String INTERNAL_ASSETS = "file:///android_asset/";
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 13f00a1..e609a40 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -57,7 +57,7 @@
private int mLevel = -1;
private boolean mCharging;
private boolean mPowerSaveEnabled;
- private boolean mPowerSaveAsColorError = true;
+ protected boolean mPowerSaveAsColorError = true;
private boolean mShowPercent;
private static final boolean SINGLE_DIGIT_PERCENT = false;
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index 5713dc6..b738d77 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -12,7 +12,8 @@
LOCAL_AIDL_INCLUDES = frameworks/native/cmds/dumpstate/binder
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_STATIC_ANDROID_LIBRARIES := androidx.legacy_legacy-support-v4
+LOCAL_USE_AAPT2 := true
LOCAL_PACKAGE_NAME := Shell
LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b4f331d..8a5cb4a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -157,7 +157,7 @@
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
<provider
- android:name="android.support.v4.content.FileProvider"
+ android:name="androidx.core.content.FileProvider"
android:authorities="com.android.shell"
android:grantUriPermissions="true"
android:exported="false">
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 600f0dc..4fc190d 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -88,7 +88,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
-import android.support.v4.content.FileProvider;
+import androidx.core.content.FileProvider;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index d628ca8..787f91e 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -53,6 +53,7 @@
<dimen name="widget_big_font_size">64dp</dimen>
<!-- Clock with header -->
<dimen name="widget_small_font_size">24dp</dimen>
+ <dimen name="widget_small_font_stroke">0.6dp</dimen>
<!-- Dash between clock and header -->
<dimen name="widget_separator_width">12dp</dimen>
<dimen name="widget_separator_thickness">1dp</dimen>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
deleted file mode 100644
index aa9f6d4..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 0a6074b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 151caea..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 64bc40a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index d7f9449..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index 7c65703..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index eea819a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 504ceb7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked.png
deleted file mode 100755
index 0622ddc..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index fb44f22a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
deleted file mode 100644
index 613afce..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index a665e23..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 8e7d8cb..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 456a68f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
deleted file mode 100644
index 72b2b21..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 4f65660..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index eb80426..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index c57face..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked.png
deleted file mode 100755
index c03ad20..0000000
--- a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index bbaab44..0000000
--- a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index fb854ec..0000000
--- a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 75d184a..0000000
--- a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked.png
deleted file mode 100755
index bfe2b4a..0000000
--- a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index dba0040..0000000
--- a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 9e0af28..0000000
--- a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 7c00bd5d..0000000
--- a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked.png
deleted file mode 100755
index 5ed0ee8..0000000
--- a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 2b64b80..0000000
--- a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 81b4466..0000000
--- a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 724aa9e..0000000
--- a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked.png
deleted file mode 100755
index d181162..0000000
--- a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 151a3c0..0000000
--- a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 7ba0d1b..0000000
--- a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index a175ccb..0000000
--- a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land/ic_sysbar_docked.png
deleted file mode 100755
index 236b70a..0000000
--- a/packages/SystemUI/res/drawable-land/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land/ic_sysbar_docked_dark.png
deleted file mode 100644
index 3456a97..0000000
--- a/packages/SystemUI/res/drawable-land/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
deleted file mode 100644
index 2fcfdde..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 45ce1d4..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 6da0c9e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
deleted file mode 100644
index 48708a5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 71e8959..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index bb7ae26..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back.png
deleted file mode 100644
index 74f9256..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index c3aea46..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back.png
deleted file mode 100644
index 4de10b6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 470b3e2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png
deleted file mode 100644
index 965d2f5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index e7137c6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back.png
deleted file mode 100644
index a123262..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 03dec15..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back.png
deleted file mode 100644
index 0a95ddd..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index e1ca853..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
deleted file mode 100644
index 3d73184..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 32b9ded..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index ed1949c7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
deleted file mode 100644
index 786935d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 2d62a80..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index a52e5b1..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
deleted file mode 100644
index 34a11df..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 5383215..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 1c1e78c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 3a22912..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index d888869..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index dc3b25c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index d4e5a94..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 0e693f7..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked.png
deleted file mode 100755
index 93d1905..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index c7e4731..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
deleted file mode 100644
index 7c25fc5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index d2949f3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 0757799..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 4f07ec1..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
deleted file mode 100644
index 35e7af4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 06e4c26..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index 1ee9cf5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 1c855c4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back.png
deleted file mode 100644
index 1e2c751..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 0520c49..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index fac2da8..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 3dc2b88..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked.png
deleted file mode 100644
index 63739b9..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 2ba5d5b..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home.png
deleted file mode 100644
index bb24c8b..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 62dc2d9..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu.png
deleted file mode 100644
index 711fd7a5..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index e718b7a..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index bbb00a0..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 469800a..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked.png
deleted file mode 100644
index 43f77c0..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 42863c6..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked.png
deleted file mode 100644
index 872af09..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index d9ec9d5..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked.png
deleted file mode 100644
index ea7ac93..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 8ee4e43..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked.png
deleted file mode 100644
index fe07f81..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index dfa8a97..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked.png
deleted file mode 100644
index 4193b21..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index d23abc7..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back.png
deleted file mode 100644
index 56c2638..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 8e56e9c..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index c3aa434..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 28a1465..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked.png
deleted file mode 100644
index 41a7209..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 0fc9677..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home.png
deleted file mode 100644
index faaef60..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 7b81eee..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu.png
deleted file mode 100644
index c8e40d0..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index a6483452..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index 2612485..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 7f74521..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png
deleted file mode 100644
index 3b831a3..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 8c99455..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 3c37782..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked.png
deleted file mode 100644
index b2baa09..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index b78dc9c..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png
deleted file mode 100644
index 37590a5..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 3a208aa..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu.png
deleted file mode 100644
index 4940d5c..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 625ba45..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 7ad2a29..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 604397e..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 274e5df..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 6fb19ae..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked.png
deleted file mode 100644
index 49d2c3a..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index ac16895..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home.png
deleted file mode 100644
index 216f2c7..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index e69a037..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_ime_dark.png
deleted file mode 100644
index 65a4354..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu.png
deleted file mode 100644
index a8c2786..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 8bddcd9..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index ca35888..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 38c5959..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back.png
deleted file mode 100644
index 4d23956..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index c6d7c98..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 74abc31..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 06c52aa..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked.png
deleted file mode 100644
index 89bed92..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 7660997..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home.png
deleted file mode 100644
index 8d4f5f3..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 0d9ecc2..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu.png
deleted file mode 100644
index 83e96a2..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index d6bb8b1..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 636c0c1..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 298ef3a..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
deleted file mode 100644
index 987aac5..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 371a84d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 433e5a74..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 360ed77..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index ba5b457..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index a55ea1d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 407ef28..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 39cfbf2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked.png
deleted file mode 100755
index 73ddde8..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 96cecc9..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
deleted file mode 100644
index 0e2a14d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 9ff9825..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index a7fd3a6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index f2a1255..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
deleted file mode 100644
index 69a018d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index e505f5e..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index f810704..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 472c55b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
deleted file mode 100644
index be03cbe..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index c04d650..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index b6b1615..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 0f6d206..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index 5a7eec6..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index f7abb54..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index a1f44dc..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 175a9ae..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked.png
deleted file mode 100755
index 1e84732..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 58bf920..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
deleted file mode 100644
index f16aa48..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index f47533ec..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 0fb93ca..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 1052940..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
deleted file mode 100644
index a37ca5d..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index f299d97..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 109aeed..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 84d6dc8..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png
deleted file mode 100644
index a059704..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index d813bc7..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 8f00a64..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 30e8782..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index d13c730..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index 31c602e..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index ddbcb07..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index ce91fcbb..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
deleted file mode 100755
index ee3ffde..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 83fc662..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png
deleted file mode 100644
index 194d39f..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 71101a1..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index c606a58..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index c2a5fef..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 4a477ad..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 046d850..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index bc24c00..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
index fba45d1..9c24c2c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
@@ -18,44 +18,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="48dp"
android:width="48dp"
- android:viewportHeight="48"
- android:viewportWidth="48">
- <group
- android:name="device"
- android:translateX="24"
- android:translateY="24" >
- <group
- android:name="device_pivot"
- android:translateX="-24.15"
- android:translateY="-24.25" >
- <group
- android:name="device_0"
- android:translateX="24.14999"
- android:translateY="24.25" >
- <path
- android:name="device_merged"
- android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
- android:fillColor="#FFFFFFFF" />
- </group>
- </group>
- </group>
- <group
- android:name="arrows"
- android:translateX="24"
- android:translateY="24" >
- <group
- android:name="arrows_pivot"
- android:translateX="-24.0798"
- android:translateY="-24.23" >
- <group
- android:name="arrows_0"
- android:translateX="12.2505"
- android:translateY="37.2145" >
- <path
- android:name="bottom_merged"
- android:pathData="M 20.7395019531,-31.9844970703 c 6.23999023438,2.83999633789 10.6999969482,8.7200012207 11.8399963379,15.7799987793 c 0.119995117188,0.699996948242 0.740005493164,1.2200012207 1.46099853516,1.2200012207 c 0.919998168945,0.0 1.6190032959,-0.84001159668 1.47900390625,-1.74000549316 c -1.75900268555,-10.3800048828 -9.75900268555,-19.1199951172 -22.5800018311,-20.1600036621 c -0.919998168945,-0.0800018310547 -1.43899536133,1.04000854492 -0.800003051758,1.70001220703 c 0.0,0.0 5.12100219727,5.11999511719 5.12100219727,5.11999511719 c 0.378997802734,0.380004882812 0.97900390625,0.380004882812 1.37899780273,0.020004272461 c 0.0,0.0 2.10000610352,-1.94000244141 2.10000610352,-1.94000244141 Z M 2.73950195312,6.01550292969 c -6.26000976562,-2.83999633789 -10.7200012207,-8.76000976562 -11.8399963379,-15.8600006104 c -0.118011474609,-0.667007446289 -0.702011108398,-1.15100097656 -1.38000488281,-1.13999938965 c -0.860000610352,0.0 -1.52000427246,0.759994506836 -1.38000488281,1.61999511719 c 1.54000854492,10.4000091553 9.5,19.2200012207 22.4199981689,20.2799987793 c 0.920013427734,0.0800018310547 1.44100952148,-1.03999328613 0.800003051758,-1.69999694824 c 0.0,0.0 -5.11999511719,-5.11999511719 -5.11999511719,-5.11999511719 c -0.380004882812,-0.376007080078 -0.988998413086,-0.385009765625 -1.38000488281,-0.0200042724609 c 0.0,0.0 -2.11999511719,1.94000244141 -2.11999511719,1.94000244141 Z"
- android:fillColor="#FFFFFFFF" />
- </group>
- </group>
- </group>
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12.72,23H11C5.49,23 1,18.51 1,13h2c0,3.78 2.63,6.95 6.15,7.79L8.13,19L9.87,18L12.72,23zM13,1h-1.72l2.85,5L15.87,5l-1.02,-1.79C18.37,4.05 21,7.22 21,11h2C23,5.49 18.51,1 13,1zM10.23,6L18,13.76L13.77,18L6,10.24L10.23,6C10.23,6 10.23,6 10.23,6M10.23,4C9.72,4 9.21,4.2 8.82,4.59L4.59,8.82c-0.78,0.78 -0.78,2.04 0,2.82l7.77,7.77c0.39,0.39 0.9,0.59 1.41,0.59c0.51,0 1.02,-0.2 1.41,-0.59l4.24,-4.24c0.78,-0.78 0.78,-2.04 0,-2.82l-7.77,-7.77C11.26,4.2 10.75,4 10.23,4L10.23,4z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml
index 1603eba..6fbc404 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml
@@ -14,12 +14,11 @@
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="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
android:pathData="M20.5,6c-2.61,0.7 -5.67,1 -8.5,1S6.11,6.7 3.5,6L3,8c1.86,0.5 4,0.83 6,1v13h2v-6h2v6h2V9c2,-0.17 4.14,-0.5 6,-1L20.5,6zM12,6c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S10.9,6 12,6z"
android:fillColor="?attr/singleToneColor"/>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back.xml b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
new file mode 100644
index 0000000..1448843
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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="28dp"
+ android:height="28dp"
+ android:viewportWidth="28"
+ android:viewportHeight="28">
+
+ <path
+ android:fillColor="?attr/singleToneColor"
+ android:pathData="M6.49,14.86c-0.66-0.39-0.66-1.34,0-1.73l6.02-3.53l5.89-3.46C19.11,5.73,20,6.26,20,7.1V14v6.9 c0,0.84-0.89,1.37-1.6,0.95l-5.89-3.46L6.49,14.86z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
new file mode 100644
index 0000000..b02a252
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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="28dp"
+ android:height="28dp"
+ android:viewportWidth="28"
+ android:viewportHeight="28">
+
+ <path
+ android:fillColor="?attr/singleToneColor"
+ android:pathData="M17.25,10.15V14v3.85L14,15.95L10.69,14L14,12.05L17.25,10.15 M18.16,7.71c-0.14,0-0.28,0.04-0.42,0.12 l-4.63,2.72l-4.73,2.78c-0.52,0.3-0.52,1.05,0,1.36l4.73,2.78l4.63,2.72c0.13,0.08,0.28,0.12,0.42,0.12c0.44,0,0.84-0.36,0.84-0.86 V14V8.58C19,8.08,18.6,7.71,18.16,7.71L18.16,7.71z" />
+ <path
+ android:pathData="M 0 0 H 28 V 28 H 0 V 0 Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_docked.xml b/packages/SystemUI/res/drawable/ic_sysbar_docked.xml
new file mode 100644
index 0000000..693835f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_docked.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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="28dp"
+ android:height="28dp"
+ android:viewportWidth="28"
+ android:viewportHeight="28">
+
+ <path
+ android:fillColor="?attr/singleToneColor"
+ android:pathData="M20.5,13h-13C6.67,13,6,12.33,6,11.5v-4C6,6.67,6.67,6,7.5,6h13C21.33,6,22,6.67,22,7.5v4 C22,12.33,21.33,13,20.5,13z" />
+ <path
+ android:fillColor="?attr/singleToneColor"
+ android:pathData="M20.5,22h-13C6.67,22,6,21.33,6,20.5v-4C6,15.67,6.67,15,7.5,15h13c0.83,0,1.5,0.67,1.5,1.5v4 C22,21.33,21.33,22,20.5,22z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_home.xml b/packages/SystemUI/res/drawable/ic_sysbar_home.xml
new file mode 100644
index 0000000..a960af7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_home.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval"
+ android:useLevel="false">
+
+ <solid android:color="?attr/singleToneColor" />
+
+ <size
+ android:height="14dp"
+ android:width="14dp" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_home_quick_step.xml b/packages/SystemUI/res/drawable/ic_sysbar_home_quick_step.xml
new file mode 100644
index 0000000..ba1236e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_home_quick_step.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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="28dp"
+ android:height="28dp"
+ android:viewportWidth="28"
+ android:viewportHeight="28">
+
+ <path
+ android:fillColor="?attr/singleToneColor"
+ android:pathData="M23,19H5c-2.76,0-5-2.24-5-5l0,0c0-2.76,2.24-5,5-5h18c2.76,0,5,2.24,5,5l0,0C28,16.76,25.76,19,23,19z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_menu.xml b/packages/SystemUI/res/drawable/ic_sysbar_menu.xml
new file mode 100644
index 0000000..5cc1791
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_menu.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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="28dp"
+ android:height="28dp"
+ android:viewportWidth="28"
+ android:viewportHeight="28">
+
+ <path
+ android:fillColor="?attr/singleToneColor"
+ android:pathData="M14,9.5c1.24,0,2.25-1.01,2.25-2.25S15.24,5,14,5s-2.25,1.01-2.25,2.25S12.76,9.5,14,9.5z M14,11.75 c-1.24,0-2.25,1.01-2.25,2.25s1.01,2.25,2.25,2.25s2.25-1.01,2.25-2.25S15.24,11.75,14,11.75z M14,18.5 c-1.24,0-2.25,1.01-2.25,2.25S12.76,23,14,23s2.25-1.01,2.25-2.25S15.24,18.5,14,18.5z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_recent.xml b/packages/SystemUI/res/drawable/ic_sysbar_recent.xml
new file mode 100644
index 0000000..6b038d1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_recent.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 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="28dp"
+ android:height="28dp"
+ android:viewportWidth="28"
+ android:viewportHeight="28">
+
+ <path
+ android:fillColor="?attr/singleToneColor"
+ android:pathData="M19.9,21.5H8.1c-0.88,0-1.6-0.72-1.6-1.6V8.1c0-0.88,0.72-1.6,1.6-1.6h11.8c0.88,0,1.6,0.72,1.6,1.6v11.8 C21.5,20.78,20.78,21.5,19.9,21.5z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/back.xml b/packages/SystemUI/res/layout/back.xml
index 6843db9..4e8726b 100644
--- a/packages/SystemUI/res/layout/back.xml
+++ b/packages/SystemUI/res/layout/back.xml
@@ -22,10 +22,8 @@
android:layout_height="match_parent"
android:layout_weight="0"
systemui:keyCode="4"
- android:scaleType="fitCenter"
+ android:scaleType="center"
android:contentDescription="@string/accessibility_back"
- android:paddingTop="@dimen/home_padding"
- android:paddingBottom="@dimen/home_padding"
android:paddingStart="@dimen/navigation_key_padding"
android:paddingEnd="@dimen/navigation_key_padding"
/>
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
index f34811e..8379dbb 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -23,15 +23,13 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
- android:gravity="center"
- >
+ android:gravity="center">
<ImageView android:id="@+id/user_avatar"
android:layout_width="@dimen/car_user_switcher_image_avatar_size"
android:layout_height="@dimen/car_user_switcher_image_avatar_size"
android:background="@drawable/car_button_ripple_background_inverse"
- android:gravity="center"
- />
+ android:gravity="center"/>
<TextView android:id="@+id/user_name"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
index bf5f188..2e1487c 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -37,6 +37,7 @@
android:id="@+id/user_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/car_user_switcher_margin_top"
app:verticallyCenterListContent="true"
app:dayNightStyle="force_night"
app:showPagedListViewDivider="false"
diff --git a/packages/SystemUI/res/layout/home.xml b/packages/SystemUI/res/layout/home.xml
index 7b67b79..9586327 100644
--- a/packages/SystemUI/res/layout/home.xml
+++ b/packages/SystemUI/res/layout/home.xml
@@ -21,10 +21,8 @@
android:layout_height="match_parent"
android:layout_weight="0"
systemui:keyCode="3"
- android:scaleType="fitCenter"
+ android:scaleType="center"
android:contentDescription="@string/accessibility_home"
- android:paddingTop="@dimen/home_padding"
- android:paddingBottom="@dimen/home_padding"
android:paddingStart="@dimen/navigation_key_padding"
android:paddingEnd="@dimen/navigation_key_padding"
/>
diff --git a/packages/SystemUI/res/layout/recent_apps.xml b/packages/SystemUI/res/layout/recent_apps.xml
index 6b08cea..870bcf7 100644
--- a/packages/SystemUI/res/layout/recent_apps.xml
+++ b/packages/SystemUI/res/layout/recent_apps.xml
@@ -21,10 +21,8 @@
android:layout_width="@dimen/navigation_key_width"
android:layout_height="match_parent"
android:layout_weight="0"
- android:scaleType="fitCenter"
+ android:scaleType="center"
android:contentDescription="@string/accessibility_recent"
- android:paddingTop="@dimen/home_padding"
- android:paddingBottom="@dimen/home_padding"
android:paddingStart="@dimen/navigation_key_padding"
android:paddingEnd="@dimen/navigation_key_padding"
/>
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index e902c92..b5d48b4 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -42,7 +42,7 @@
android:singleLine="true"
android:ellipsize="start"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
- android:imeOptions="actionSend" />
+ android:imeOptions="actionSend|flagNoExtractUi|flagNoFullscreen" />
<FrameLayout
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 923edc8..2dc6525 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -91,7 +91,4 @@
<!-- The offsets the tasks animate from when recents is launched while docking -->
<dimen name="recents_task_stack_animation_launched_while_docking_offset">192dp</dimen>
-
- <!-- Home button padding for sizing -->
- <dimen name="home_padding">0dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 3472477..d8607cc 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -104,6 +104,9 @@
<!-- The color of the navigation bar icons. Need to be in sync with ic_sysbar_* -->
<color name="navigation_bar_icon_color">#E5FFFFFF</color>
+ <!-- The shadow color for light navigation bar icons. -->
+ <color name="nav_key_button_shadow_color">#30000000</color>
+
<!-- Shadow color for the first pixels around the fake shadow for recents. -->
<color name="fake_shadow_start_color">#44000000</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c1458b2..0024fe4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -34,10 +34,10 @@
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
<!-- Height of the battery icon in the status bar. -->
- <dimen name="status_bar_battery_icon_height">14.5dp</dimen>
+ <dimen name="status_bar_battery_icon_height">13.0dp</dimen>
<!-- Width of the battery icon in the status bar. -->
- <dimen name="status_bar_battery_icon_width">9.5dp</dimen>
+ <dimen name="status_bar_battery_icon_width">8.5dp</dimen>
<!-- The font size for the clock in the status bar. -->
<dimen name="status_bar_clock_size">14sp</dimen>
@@ -941,8 +941,10 @@
<dimen name="nav_quick_scrub_track_edge_padding">42dp</dimen>
<dimen name="nav_quick_scrub_track_thickness">2dp</dimen>
- <!-- Home button padding for sizing -->
- <dimen name="home_padding">16dp</dimen>
+ <!-- Navigation bar shadow params. -->
+ <dimen name="nav_key_button_shadow_offset_x">0dp</dimen>
+ <dimen name="nav_key_button_shadow_offset_y">1dp</dimen>
+ <dimen name="nav_key_button_shadow_radius">0.5dp</dimen>
<!-- Smart reply button. Total height 48dp, visible height 32dp. -->
<dimen name="smart_reply_button_spacing">8dp</dimen>
@@ -960,6 +962,10 @@
add about 88dp of height to the notifications. -->
<dimen name="smart_reply_button_max_height">100dp</dimen>
+ <!-- The extra height that we allow a notification with a remote input history to be taller than
+ the regular notification, when we have remote input history texts present. -->
+ <dimen name="remote_input_history_extra_height">60dp</dimen>
+
<!-- Fingerprint Dialog values -->
<dimen name="fingerprint_dialog_fp_icon_size">64dp</dimen>
<dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 8e17b52..afbe176 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -21,6 +21,7 @@
<dimen name="car_user_switcher_image_avatar_size">@dimen/car_large_avatar_size</dimen>
<dimen name="car_user_switcher_vertical_spacing_between_users">@dimen/car_padding_5</dimen>
<dimen name="car_user_switcher_vertical_spacing_between_name_and_avatar">@dimen/car_padding_4</dimen>
+ <dimen name="car_user_switcher_margin_top">@dimen/car_padding_4</dimen>
<dimen name="car_navigation_button_width">64dp</dimen>
<dimen name="car_navigation_bar_width">760dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index b8776f7..2de33f9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -84,10 +84,9 @@
private LiveData<Slice> mLiveData;
private int mIconSize;
/**
- * Listener called whenever the view contents change.
- * Boolean will be true when the change happens animated.
+ * Runnable called whenever the view contents change.
*/
- private Consumer<Boolean> mContentChangeListener;
+ private Runnable mContentChangeListener;
private boolean mHasHeader;
private Slice mSlice;
private boolean mPulsing;
@@ -151,7 +150,9 @@
if (mPulsing || mSlice == null) {
mTitle.setVisibility(GONE);
mRow.setVisibility(GONE);
- mContentChangeListener.accept(getLayoutTransition() != null);
+ if (mContentChangeListener != null) {
+ mContentChangeListener.run();
+ }
return;
}
@@ -224,7 +225,7 @@
}
if (mContentChangeListener != null) {
- mContentChangeListener.accept(getLayoutTransition() != null);
+ mContentChangeListener.run();
}
}
@@ -311,11 +312,10 @@
}
/**
- * Listener that gets invoked every time the title or the row visibility changes.
- * Parameter will be {@code true} whenever the change happens animated.
+ * Runnable that gets invoked every time the title or the row visibility changes.
* @param contentChangeListener The listener.
*/
- public void setContentChangeListener(Consumer<Boolean> contentChangeListener) {
+ public void setContentChangeListener(Runnable contentChangeListener) {
mContentChangeListener = contentChangeListener;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 585797a..c521d59 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Paint;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -75,7 +76,6 @@
private float mDarkAmount = 0;
private int mTextColor;
private float mWidgetPadding;
- private boolean mAnimateLayout;
private int mLastLayoutHeight;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -179,10 +179,12 @@
mVisibleInDoze = Sets.newArraySet(mClockView, mKeyguardSlice);
mTextColor = mClockView.getCurrentTextColor();
+ int clockStroke = getResources().getDimensionPixelSize(R.dimen.widget_small_font_stroke);
+ mClockView.getPaint().setStrokeWidth(clockStroke);
mClockView.addOnLayoutChangeListener(this);
mClockSeparator.addOnLayoutChangeListener(this);
mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged);
- onSliceContentChanged(false /* animated */);
+ onSliceContentChanged();
boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setEnableMarquee(shouldMarquee);
@@ -196,8 +198,7 @@
mClockView.setElegantTextHeight(false);
}
- private void onSliceContentChanged(boolean animated) {
- mAnimateLayout = animated;
+ private void onSliceContentChanged() {
boolean smallClock = mKeyguardSlice.hasHeader() || mPulsing;
float clockScale = smallClock ? mSmallClockScale : 1;
@@ -225,9 +226,12 @@
long duration = KeyguardSliceView.DEFAULT_ANIM_DURATION;
long delay = smallClock ? 0 : duration / 4;
+ boolean shouldAnimate = mKeyguardSlice.getLayoutTransition() != null
+ && mKeyguardSlice.getLayoutTransition().isRunning();
if (view == mClockView) {
float clockScale = smallClock ? mSmallClockScale : 1;
- if (mAnimateLayout) {
+ Paint.Style style = smallClock ? Paint.Style.FILL_AND_STROKE : Paint.Style.FILL;
+ if (shouldAnimate) {
mClockView.setY(oldTop + heightOffset);
mClockView.animate().cancel();
mClockView.animate()
@@ -238,16 +242,22 @@
.y(top)
.scaleX(clockScale)
.scaleY(clockScale)
+ .withEndAction(() -> {
+ mClockView.getPaint().setStyle(style);
+ mClockView.invalidate();
+ })
.start();
} else {
mClockView.setY(top);
mClockView.setScaleX(clockScale);
mClockView.setScaleY(clockScale);
+ mClockView.getPaint().setStyle(style);
+ mClockView.invalidate();
}
} else if (view == mClockSeparator) {
boolean hasSeparator = hasHeader && !mPulsing;
float alpha = hasSeparator ? 1 : 0;
- if (mAnimateLayout) {
+ if (shouldAnimate) {
boolean isAwake = mDarkAmount != 0;
mClockSeparator.setY(oldTop + heightOffset);
mClockSeparator.animate().cancel();
@@ -280,6 +290,8 @@
if (mClockView != null) {
mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.widget_big_font_size));
+ mClockView.getPaint().setStrokeWidth(
+ getResources().getDimensionPixelSize(R.dimen.widget_small_font_stroke));
}
if (mOwnerInfo != null) {
mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index beb3c53..9c9f021 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -151,7 +151,6 @@
@Override
public void start() {
- sDependency = this;
// TODO: Think about ways to push these creation rules out of Dependency to cut down
// on imports.
mProviders.put(TIME_TICK_HANDLER, () -> {
@@ -331,6 +330,8 @@
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
+
+ sDependency = this;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 9b16eec..e91b320 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -22,8 +22,8 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static com.android.systemui.tuner.TunablePadding.FLAG_START;
import static com.android.systemui.tuner.TunablePadding.FLAG_END;
+import static com.android.systemui.tuner.TunablePadding.FLAG_START;
import android.annotation.Dimension;
import android.app.Fragment;
@@ -66,6 +66,7 @@
import com.android.systemui.tuner.TunablePadding;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.leak.RotationUtils;
/**
* An overlay that draws screen decorations in software (e.g for rounded corners or display cutout)
@@ -77,6 +78,9 @@
private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
+ private DisplayManager mDisplayManager;
+ private DisplayManager.DisplayListener mDisplayListener;
+
private int mRoundedDefault;
private int mRoundedDefaultTop;
private int mRoundedDefaultBottom;
@@ -84,7 +88,7 @@
private View mBottomOverlay;
private float mDensity;
private WindowManager mWindowManager;
- private boolean mLandscape;
+ private int mRotation;
@Override
public void start() {
@@ -104,6 +108,28 @@
if (padding != 0) {
setupPadding(padding);
}
+
+ mDisplayListener = new DisplayManager.DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ // do nothing
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ // do nothing
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ updateOrientation();
+ }
+ };
+
+ mRotation = -1;
+ mDisplayManager = (DisplayManager) mContext.getSystemService(
+ Context.DISPLAY_SERVICE);
+ mDisplayManager.registerDisplayListener(mDisplayListener, null);
}
private void setupDecorations() {
@@ -169,17 +195,22 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
- boolean newLanscape = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
- if (newLanscape != mLandscape) {
- mLandscape = newLanscape;
+ updateOrientation();
+ }
+
+ protected void updateOrientation() {
+ int newRotation = RotationUtils.getExactRotation(mContext);
+ if (newRotation != mRotation) {
+ mRotation = newRotation;
if (mOverlay != null) {
updateLayoutParams();
updateViews();
}
- }
- if (shouldDrawCutout() && mOverlay == null) {
- setupDecorations();
+
+ if (shouldDrawCutout() && mOverlay == null) {
+ setupDecorations();
+ }
}
}
@@ -188,16 +219,28 @@
View topRight = mOverlay.findViewById(R.id.right);
View bottomLeft = mBottomOverlay.findViewById(R.id.left);
View bottomRight = mBottomOverlay.findViewById(R.id.right);
- if (mLandscape) {
- // Flip corners
- View tmp = topRight;
- topRight = bottomLeft;
- bottomLeft = tmp;
+
+ if (mRotation == RotationUtils.ROTATION_NONE) {
+ updateView(topLeft, Gravity.TOP | Gravity.LEFT, 0);
+ updateView(topRight, Gravity.TOP | Gravity.RIGHT, 90);
+ updateView(bottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+ updateView(bottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+ } else if (mRotation == RotationUtils.ROTATION_LANDSCAPE) {
+ updateView(topLeft, Gravity.TOP | Gravity.LEFT, 0);
+ updateView(topRight, Gravity.BOTTOM | Gravity.LEFT, 270);
+ updateView(bottomLeft, Gravity.TOP | Gravity.RIGHT, 90);;
+ updateView(bottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+ } else if (mRotation == RotationUtils.ROTATION_UPSIDE_DOWN) {
+ updateView(topLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+ updateView(topRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+ updateView(bottomLeft, Gravity.TOP | Gravity.LEFT, 0);
+ updateView(bottomRight, Gravity.TOP | Gravity.RIGHT, 90);
+ } else if (mRotation == RotationUtils.ROTATION_SEASCAPE) {
+ updateView(topLeft, Gravity.BOTTOM | Gravity.RIGHT, 180);
+ updateView(topRight, Gravity.TOP | Gravity.RIGHT, 90);
+ updateView(bottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+ updateView(bottomRight, Gravity.TOP | Gravity.LEFT, 0);
}
- updateView(topLeft, Gravity.TOP | Gravity.LEFT, 0);
- updateView(topRight, Gravity.TOP | Gravity.RIGHT, 90);
- updateView(bottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
- updateView(bottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
updateWindowVisibilities();
}
@@ -269,9 +312,14 @@
}
lp.setTitle("ScreenDecorOverlay");
- lp.gravity = Gravity.TOP | Gravity.LEFT;
+ if (mRotation == RotationUtils.ROTATION_SEASCAPE
+ || mRotation == RotationUtils.ROTATION_UPSIDE_DOWN) {
+ lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+ } else {
+ lp.gravity = Gravity.TOP | Gravity.LEFT;
+ }
lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- if (mLandscape) {
+ if (isLandscape(mRotation)) {
lp.width = WRAP_CONTENT;
lp.height = MATCH_PARENT;
}
@@ -281,7 +329,12 @@
private WindowManager.LayoutParams getBottomLayoutParams() {
WindowManager.LayoutParams lp = getWindowLayoutParams();
lp.setTitle("ScreenDecorOverlayBottom");
- lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+ if (mRotation == RotationUtils.ROTATION_SEASCAPE
+ || mRotation == RotationUtils.ROTATION_UPSIDE_DOWN) {
+ lp.gravity = Gravity.TOP | Gravity.LEFT;
+ } else {
+ lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+ }
return lp;
}
@@ -568,4 +621,9 @@
return cutoutBounds;
}
}
+
+ private boolean isLandscape(int rotation) {
+ return rotation == RotationUtils.ROTATION_LANDSCAPE || rotation ==
+ RotationUtils.ROTATION_SEASCAPE;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 721890f..03a6398 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -56,6 +56,7 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import java.util.function.Consumer;
@@ -148,5 +149,7 @@
providers.put(NotificationEntryManager.class, () -> new NotificationEntryManager(context));
providers.put(KeyguardDismissUtil.class, KeyguardDismissUtil::new);
providers.put(SmartReplyController.class, () -> new SmartReplyController());
+ providers.put(RemoteInputQuickSettingsDisabler.class,
+ () -> new RemoteInputQuickSettingsDisabler(context));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 90140ff..f14d396 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -42,7 +42,7 @@
* hiding the wallpaper and changing the display mode is necessary to hide
* the black frame that's inherent to hardware specs.
*/
- public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 2000;
+ public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 4500;
private final DozeMachine.Service mDozeService;
private final Handler mHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 67f1138..bd89ad1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -35,6 +35,7 @@
import android.view.ViewTreeObserver;
import android.widget.FrameLayout.LayoutParams;
+import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.R.id;
@@ -43,6 +44,7 @@
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.stack.StackStateAnimator;
public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {
@@ -72,6 +74,9 @@
private float mLastQSExpansion = -1;
private boolean mQsDisabled;
+ private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler =
+ Dependency.get(RemoteInputQuickSettingsDisabler.class);
+
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
Bundle savedInstanceState) {
@@ -191,6 +196,8 @@
@Override
public void disable(int state1, int state2, boolean animate) {
+ state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
+
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 89f86c5..23e3f25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -110,7 +110,8 @@
@Override
public Drawable getDrawable(Context context) {
- BatterySaverDrawable b = new BatterySaverDrawable(context, 0);
+ BatterySaverDrawable b =
+ new BatterySaverDrawable(context, QSTileImpl.getColorForState(context, mState));
b.mState = mState;
final int pad = context.getResources()
.getDimensionPixelSize(R.dimen.qs_tile_divider_height);
@@ -130,11 +131,16 @@
setPowerSave(true);
setCharging(false);
setPowerSaveAsColorError(false);
+ mPowerSaveAsColorError = true;
+ mFramePaint.setColor(0);
+ mPowersavePaint.setColor(frameColor);
+ mFramePaint.setStrokeWidth(mPowersavePaint.getStrokeWidth());
+ mPlusPaint.setColor(frameColor);
}
@Override
protected int batteryColorForLevel(int level) {
- return QSTileImpl.getColorForState(mContext, mState);
+ return 0;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 6fcb1c1..7e4acc2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -123,10 +123,16 @@
*/
class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
+ private OverviewProxyService mOverviewProxyService;
+
+ public TaskStackListenerImpl() {
+ mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+ }
+
@Override
public void onTaskStackChangedBackground() {
// Skip background preloading recents in SystemUI if the overview services is bound
- if (Dependency.get(OverviewProxyService.class).isEnabled()) {
+ if (mOverviewProxyService.isEnabled()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 167df8c..481d54f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -28,6 +28,7 @@
import android.os.Binder;
import android.os.RemoteException;
import android.util.DisplayMetrics;
+import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -40,6 +41,7 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.statusbar.phone.NavigationBarView;
@@ -259,10 +261,16 @@
}
if (navigationBarView != null) {
+ int dualToneDarkTheme = Utils.getThemeAttr(getContext(), R.attr.darkIconTheme);
+ int dualToneLightTheme = Utils.getThemeAttr(getContext(), R.attr.lightIconTheme);
+ Context lightContext = new ContextThemeWrapper(getContext(), dualToneLightTheme);
+ Context darkContext = new ContextThemeWrapper(getContext(), dualToneDarkTheme);
((ImageView) mLayout.findViewById(R.id.screen_pinning_back_icon))
- .setImageDrawable(navigationBarView.getBackDrawable(mContext));
+ .setImageDrawable(navigationBarView.getBackDrawable(lightContext,
+ darkContext));
((ImageView) mLayout.findViewById(R.id.screen_pinning_home_icon))
- .setImageDrawable(navigationBarView.getHomeDrawable(mContext));
+ .setImageDrawable(navigationBarView.getHomeDrawable(lightContext,
+ darkContext));
}
((TextView) mLayout.findViewById(R.id.screen_pinning_description))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 364ed80..6a38797 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -515,6 +515,13 @@
}
}
+ @Override
+ public void setDistanceToTopRoundness(float distanceToTopRoundness) {
+ super.setDistanceToTopRoundness(distanceToTopRoundness);
+ mBackgroundNormal.setDistanceToTopRoundness(distanceToTopRoundness);
+ mBackgroundDimmed.setDistanceToTopRoundness(distanceToTopRoundness);
+ }
+
/**
* Set an override tint color that is used for the background.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index d03da8f..f30fa6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -2795,6 +2795,24 @@
}
@Override
+ public boolean topAmountNeedsClipping() {
+ if (isGroupExpanded()) {
+ return true;
+ }
+ if (isGroupExpansionChanging()) {
+ return true;
+ }
+ if (getShowingLayout().shouldClipToRounding(true /* topRounded */,
+ false /* bottomRounded */)) {
+ return true;
+ }
+ if (mGuts != null && mGuts.getAlpha() != 0.0f) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
protected boolean childNeedsClipping(View child) {
if (child instanceof NotificationContentView) {
NotificationContentView contentView = (NotificationContentView) child;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 67268c0..edfa61b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -76,7 +76,7 @@
* it is moved. Otherwise, the translation is set on the {@code ExpandableOutlineView} itself.
*/
protected boolean mShouldTranslateContents;
- private boolean mClipRoundedToClipTopAmount;
+ private boolean mTopAmountRounded;
private float mDistanceToTopRoundness = -1;
private float mExtraWidthForClipping;
private int mMinimumHeightForClipping = 0;
@@ -85,7 +85,8 @@
@Override
public void getOutline(View view, Outline outline) {
if (!mCustomOutline && mCurrentTopRoundness == 0.0f
- && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners) {
+ && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners
+ && !mTopAmountRounded) {
int translation = mShouldTranslateContents ? (int) getTranslation() : 0;
int left = Math.max(translation, 0);
int top = mClipTopAmount + mBackgroundTop;
@@ -145,9 +146,9 @@
return EMPTY_PATH;
}
float topRoundness = mAlwaysRoundBothCorners
- ? mOutlineRadius : mCurrentTopRoundness * mOutlineRadius;
+ ? mOutlineRadius : getCurrentBackgroundRadiusTop();
float bottomRoundness = mAlwaysRoundBothCorners
- ? mOutlineRadius : mCurrentBottomRoundness * mOutlineRadius;
+ ? mOutlineRadius : getCurrentBackgroundRadiusBottom();
if (topRoundness + bottomRoundness > height) {
float overShoot = topRoundness + bottomRoundness - height;
topRoundness -= overShoot * mCurrentTopRoundness
@@ -203,7 +204,7 @@
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
canvas.save();
Path intersectPath = null;
- if (mClipRoundedToClipTopAmount) {
+ if (mTopAmountRounded && topAmountNeedsClipping()) {
int left = (int) (- mExtraWidthForClipping / 2.0f);
int top = (int) (mClipTopAmount - mDistanceToTopRoundness);
int right = getWidth() + (int) (mExtraWidthForClipping + left);
@@ -248,9 +249,9 @@
public void setDistanceToTopRoundness(float distanceToTopRoundness) {
super.setDistanceToTopRoundness(distanceToTopRoundness);
if (distanceToTopRoundness != mDistanceToTopRoundness) {
- mClipRoundedToClipTopAmount = distanceToTopRoundness >= 0;
+ mTopAmountRounded = distanceToTopRoundness >= 0;
mDistanceToTopRoundness = distanceToTopRoundness;
- invalidate();
+ applyRoundness();
}
}
@@ -258,9 +259,12 @@
return false;
}
+ public boolean topAmountNeedsClipping() {
+ return true;
+ }
+
protected boolean isClippingNeeded() {
return mAlwaysRoundBothCorners || mCustomOutline || getTranslation() != 0 ;
-
}
private void initDimens() {
@@ -296,6 +300,11 @@
}
public float getCurrentBackgroundRadiusTop() {
+ // If this view is top amount notification view, it should always has round corners on top.
+ // It will be applied with applyRoundness()
+ if (mTopAmountRounded) {
+ return mOutlineRadius;
+ }
return mCurrentTopRoundness * mOutlineRadius;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index 32e51b3..9f82bcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -19,8 +19,10 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.DisplayCutout;
import android.view.View;
import android.widget.TextView;
@@ -44,9 +46,10 @@
private boolean mPublicMode;
private int mMaxWidth;
private View mRootView;
- private int mLeftCutOutInset;
- private int mLeftInset;
+ private int mSysWinInset;
+ private int mCutOutInset;
private Rect mIconDrawingRect = new Rect();
+ private Point mPoint;
private Runnable mOnDrawingRectChangedListener;
public HeadsUpStatusBarView(Context context) {
@@ -137,9 +140,20 @@
int bottom = top + mIconPlaceholder.getHeight();
mLayoutedIconRect.set(left, top, right, bottom);
updateDrawingRect();
- int targetPadding = mAbsoluteStartPadding + mLeftInset + mLeftCutOutInset;
+ int targetPadding = mAbsoluteStartPadding + mSysWinInset + mCutOutInset;
if (left != targetPadding) {
- int newPadding = targetPadding - left + getPaddingStart();
+ int start;
+ if (isLayoutRtl()) {
+ if (mPoint == null) {
+ mPoint = new Point();
+ }
+ getDisplay().getRealSize(mPoint);
+ start = (mPoint.x - right);
+ } else {
+ start = left;
+ }
+
+ int newPadding = targetPadding - start + getPaddingStart();
setPaddingRelative(newPadding, 0, mEndMargin, 0);
}
if (mFirstLayout) {
@@ -152,7 +166,11 @@
}
public void setPanelTranslation(float translationX) {
- setTranslationX(translationX - mLeftCutOutInset);
+ if (isLayoutRtl()) {
+ setTranslationX(translationX + mCutOutInset);
+ } else {
+ setTranslationX(translationX - mCutOutInset);
+ }
updateDrawingRect();
}
@@ -167,15 +185,19 @@
@Override
protected boolean fitSystemWindows(Rect insets) {
- mLeftInset = insets.left;
- mLeftCutOutInset = (getRootWindowInsets().getDisplayCutout() != null)
- ? getRootWindowInsets().getDisplayCutout().getSafeInsetLeft() : 0;
-
+ boolean isRtl = isLayoutRtl();
+ mSysWinInset = isRtl ? insets.right : insets.left;
+ DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
+ mCutOutInset = (displayCutout != null)
+ ? (isRtl ? displayCutout.getSafeInsetRight() : displayCutout.getSafeInsetLeft())
+ : 0;
// For Double Cut Out mode, the System window navigation bar is at the right
- // hand side of the left cut out. In this condition, mLeftInset include the left cut
- // out width so we set mLeftCutOutInset to be 0.
- if (mLeftInset != 0) {
- mLeftCutOutInset = 0;
+ // side of the left cut out. In this condition, mSysWinInset include the left cut
+ // out width so we set mCutOutInset to be 0. For RTL, the condition is the same.
+ // The navigation bar is at the left side of the right cut out and include the
+ // right cut out width.
+ if (mSysWinInset != 0) {
+ mCutOutInset = 0;
}
return super.fitSystemWindows(insets);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 0ff4dde..969e9d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -53,6 +53,9 @@
private int mDrawableAlpha = 255;
private boolean mIsPressedAllowed;
+ private boolean mTopAmountRounded;
+ private float mDistanceToTopRoundness;
+
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
mDontModifyCorners = getResources().getBoolean(
@@ -74,6 +77,7 @@
private void draw(Canvas canvas, Drawable drawable) {
if (drawable != null) {
+ int top = mBackgroundTop;
int bottom = mActualHeight;
if (mBottomIsRounded && mBottomAmountClips && !mExpandAnimationRunning) {
bottom -= mClipBottomAmount;
@@ -84,7 +88,14 @@
left = (int) ((getWidth() - mActualWidth) / 2.0f);
right = (int) (left + mActualWidth);
}
- drawable.setBounds(left, mBackgroundTop, right, bottom);
+ if (mTopAmountRounded) {
+ int clipTop = (int) (mClipTopAmount - mDistanceToTopRoundness);
+ top += clipTop;
+ if (clipTop >= 0) {
+ bottom += clipTop;
+ }
+ }
+ drawable.setBounds(left, top, right, bottom);
drawable.draw(canvas);
}
}
@@ -165,6 +176,14 @@
invalidate();
}
+ public void setDistanceToTopRoundness(float distanceToTopRoundness) {
+ if (distanceToTopRoundness != mDistanceToTopRoundness) {
+ mTopAmountRounded = distanceToTopRoundness >= 0;
+ mDistanceToTopRoundness = distanceToTopRoundness;
+ invalidate();
+ }
+ }
+
@Override
public boolean hasOverlappingRendering() {
@@ -198,6 +217,9 @@
}
public void setRoundness(float topRoundness, float bottomRoundNess) {
+ if (topRoundness == mCornerRadii[0] && bottomRoundNess == mCornerRadii[4]) {
+ return;
+ }
mBottomIsRounded = bottomRoundNess != 0.0f;
mCornerRadii[0] = topRoundness;
mCornerRadii[1] = topRoundness;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 952c961..70dad19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -189,6 +189,7 @@
if (mExpandedSmartReplyView != null) {
notificationMaxHeight += mExpandedSmartReplyView.getHeightUpperLimit();
}
+ notificationMaxHeight += mExpandedWrapper.getExtraMeasureHeight();
int size = notificationMaxHeight;
ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
boolean useExactly = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 419e262..e24d65a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -32,10 +32,13 @@
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
+import android.app.Person;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService.Ranking;
@@ -50,6 +53,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
@@ -117,6 +121,11 @@
*/
public Boolean mIsSystemNotification;
+ /**
+ * Has the user sent a reply through this Notification.
+ */
+ private boolean hasSentReply;
+
public Entry(StatusBarNotification n) {
this.key = n.getKey();
this.notification = n;
@@ -298,6 +307,40 @@
lastRemoteInputSent = NOT_LAUNCHED_YET;
remoteInputTextWhenReset = null;
}
+
+ public void setHasSentReply() {
+ hasSentReply = true;
+ }
+
+ public boolean isLastMessageFromReply() {
+ if (!hasSentReply) {
+ return false;
+ }
+ Bundle extras = notification.getNotification().extras;
+ CharSequence[] replyTexts = extras.getCharSequenceArray(
+ Notification.EXTRA_REMOTE_INPUT_HISTORY);
+ if (!ArrayUtils.isEmpty(replyTexts)) {
+ return true;
+ }
+ Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+ if (messages != null && messages.length > 0) {
+ Parcelable message = messages[messages.length - 1];
+ if (message instanceof Bundle) {
+ Notification.MessagingStyle.Message lastMessage =
+ Notification.MessagingStyle.Message.getMessageFromBundle(
+ (Bundle) message);
+ if (lastMessage != null) {
+ Person senderPerson = lastMessage.getSenderPerson();
+ if (senderPerson == null) {
+ return true;
+ }
+ Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
+ return Objects.equals(user, senderPerson);
+ }
+ }
+ }
+ return false;
+ }
}
private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 2b7ab10..e52829a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -300,9 +300,11 @@
private void saveImportance() {
if (!mIsNonblockable) {
- // Only go through the lock screen/bouncer if the user didn't hit 'Keep showing'.
+ // Only go through the lock screen/bouncer if the user hit 'Stop notifications'.
+ // Otherwise, update the importance immediately.
if (mCheckSaveListener != null
- && !NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING.equals(mExitReason)) {
+ && NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS.equals(
+ mExitReason)) {
mCheckSaveListener.checkSave(this::updateImportance, mSbn);
} else {
updateImportance();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index 3cf59cf..257fa75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.car;
+import static android.content.DialogInterface.BUTTON_NEGATIVE;
import static android.content.DialogInterface.BUTTON_POSITIVE;
import android.app.AlertDialog;
@@ -28,7 +29,6 @@
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.UserHandle;
-import androidx.recyclerview.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -37,9 +37,10 @@
import android.widget.TextView;
import androidx.car.widget.PagedListView;
-
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.android.internal.util.UserIcons;
import com.android.settingslib.users.UserManagerHelper;
import com.android.systemui.R;
@@ -166,6 +167,9 @@
private AlertDialog mDialog;
// View that holds the add user button. Used to enable/disable the view
private View mAddUserView;
+ // User record for the add user. Need to call notifyUserSelected only if the user
+ // confirms adding a user
+ private UserRecord mAddUserRecord;
public UserAdapter(Context context, List<UserRecord> users) {
mRes = context.getResources();
@@ -200,18 +204,16 @@
circleIcon.setCircular(true);
holder.mUserAvatarImageView.setImageDrawable(circleIcon);
holder.mUserNameTextView.setText(userRecord.mInfo.name);
+
holder.mView.setOnClickListener(v -> {
if (userRecord == null) {
return;
}
- // Notify the listener which user was selected
- if (mUserSelectionListener != null) {
- mUserSelectionListener.onUserSelected(userRecord);
- }
// If the user selects Guest, start the guest session.
if (userRecord.mIsStartGuestSession) {
+ notifyUserSelected(userRecord);
mUserManagerHelper.startNewGuestSession(mGuestName);
return;
}
@@ -227,6 +229,7 @@
.concat(System.getProperty("line.separator"))
.concat(mRes.getString(R.string.user_add_user_message_update));
+ mAddUserRecord = userRecord;
mDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert)
.setTitle(R.string.user_add_user_title)
.setMessage(message)
@@ -239,11 +242,19 @@
return;
}
// If the user doesn't want to be a guest or add a user, switch to the user selected
+ notifyUserSelected(userRecord);
mUserManagerHelper.switchToUser(userRecord.mInfo);
});
}
+ private void notifyUserSelected(UserRecord userRecord) {
+ // Notify the listener which user was selected
+ if (mUserSelectionListener != null) {
+ mUserSelectionListener.onUserSelected(userRecord);
+ }
+ }
+
private Bitmap getUserRecordIcon(UserRecord userRecord) {
if (userRecord.mIsStartGuestSession) {
return mUserManagerHelper.getGuestDefaultIcon();
@@ -259,12 +270,14 @@
@Override
public void onClick(DialogInterface dialog, int which) {
- // Enable the add button
- if (mAddUserView != null) {
- mAddUserView.setEnabled(true);
- }
if (which == BUTTON_POSITIVE) {
+ notifyUserSelected(mAddUserRecord);
new AddNewUserTask().execute(mNewUserName);
+ } else if (which == BUTTON_NEGATIVE) {
+ // Enable the add button only if cancel
+ if (mAddUserView != null) {
+ mAddUserView.setEnabled(true);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 2d983c4..03791c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -34,6 +34,7 @@
import com.android.internal.util.NotificationColorUtil;
import com.android.internal.widget.NotificationActionListLayout;
import com.android.systemui.Dependency;
+import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -58,6 +59,7 @@
private NotificationActionListLayout mActions;
private ArraySet<PendingIntent> mCancelledPendingIntents = new ArraySet<>();
private UiOffloadThread mUiOffloadThread;
+ private View mRemoteInputHistory;
protected NotificationTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
@@ -146,6 +148,8 @@
mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
mActions = mView.findViewById(com.android.internal.R.id.actions);
mReplyAction = mView.findViewById(com.android.internal.R.id.reply_icon_action);
+ mRemoteInputHistory = mView.findViewById(
+ com.android.internal.R.id.notification_material_reply_container);
updatePendingIntentCancellations();
}
@@ -329,6 +333,10 @@
if (mActions != null) {
extra = mActions.getExtraMeasureHeight();
}
+ if (mRemoteInputHistory != null && mRemoteInputHistory.getVisibility() != View.GONE) {
+ extra += mRow.getContext().getResources().getDimensionPixelSize(
+ R.dimen.remote_input_history_extra_height);
+ }
return extra + super.getExtraMeasureHeight();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 6d78d1d..b52e324 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -16,8 +16,10 @@
package com.android.systemui.statusbar.phone;
+import android.graphics.Point;
import android.graphics.Rect;
import android.view.View;
+import android.view.WindowInsets;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
@@ -59,6 +61,7 @@
private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
-> updatePanelTranslation();
+ Point mPoint;
public HeadsUpAppearanceController(
NotificationIconAreaController notificationIconAreaController,
@@ -121,8 +124,54 @@
updateHeader(headsUp.getEntry());
}
+ /** To count the distance from the window right boundary to scroller right boundary. The
+ * distance formula is the following:
+ * Y = screenSize - (SystemWindow's width + Scroller.getRight())
+ * There are four modes MUST to be considered in Cut Out of RTL.
+ * No Cut Out:
+ * Scroller + NB
+ * NB + Scroller
+ * => SystemWindow = NavigationBar's width
+ * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
+ * Corner Cut Out or Tall Cut Out:
+ * cut out + Scroller + NB
+ * NB + Scroller + cut out
+ * => SystemWindow = NavigationBar's width
+ * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
+ * Double Cut Out:
+ * cut out left + Scroller + (NB + cut out right)
+ * SystemWindow = NavigationBar's width + cut out right width
+ * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
+ * (cut out left + NB) + Scroller + cut out right
+ * SystemWindow = NavigationBar's width + cut out left width
+ * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
+ * @return the translation X value for RTL. In theory, it should be negative. i.e. -Y
+ */
+ private int getRtlTranslation() {
+ // TODO: Corner Cut Out still need to handle.
+ if (mPoint == null) {
+ mPoint = new Point();
+ }
+
+ int realDisplaySize = 0;
+ if (mStackScroller.getDisplay() != null) {
+ mStackScroller.getDisplay().getRealSize(mPoint);
+ realDisplaySize = mPoint.x;
+ }
+
+ WindowInsets windowInset = mStackScroller.getRootWindowInsets();
+ return windowInset.getSystemWindowInsetLeft() + mStackScroller.getRight()
+ + windowInset.getSystemWindowInsetRight() - realDisplaySize;
+ }
+
public void updatePanelTranslation() {
- float newTranslation = mStackScroller.getLeft() + mStackScroller.getTranslationX();
+ float newTranslation;
+ if (mStackScroller.isLayoutRtl()) {
+ newTranslation = getRtlTranslation();
+ } else {
+ newTranslation = mStackScroller.getLeft();
+ }
+ newTranslation += mStackScroller.getTranslationX();
mHeadsUpStatusBarView.setPanelTranslation(newTranslation);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 9261d2e..3c25648 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -39,7 +39,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.os.RemoteException;
import android.os.SystemProperties;
import androidx.annotation.ColorInt;
import android.util.AttributeSet;
@@ -119,7 +118,7 @@
private Rect mRotationButtonBounds = new Rect();
private int[] mTmpPosition = new int[2];
- private KeyButtonDrawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
+ private KeyButtonDrawable mBackIcon;
private KeyButtonDrawable mBackCarModeIcon, mBackLandCarModeIcon;
private KeyButtonDrawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
private KeyButtonDrawable mHomeDefaultIcon, mHomeCarModeIcon;
@@ -453,6 +452,7 @@
&& ((mOverviewProxyService.getInteractionFlags() & FLAG_DISABLE_QUICK_SCRUB) == 0);
}
+ // TODO(b/80003212): change car mode icons to vector icons.
private void updateCarModeIcons(Context ctx) {
mBackCarModeIcon = getDrawable(ctx,
R.drawable.ic_sysbar_back_carmode, R.drawable.ic_sysbar_back_carmode);
@@ -469,33 +469,27 @@
}
private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
+ int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
+ int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
+ Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
+ Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
+
if (oldConfig.orientation != newConfig.orientation
|| oldConfig.densityDpi != newConfig.densityDpi) {
- mDockedIcon = getDrawable(ctx,
- R.drawable.ic_sysbar_docked, R.drawable.ic_sysbar_docked_dark);
- mHomeDefaultIcon = getHomeDrawable(ctx);
+ mDockedIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_docked);
+ mHomeDefaultIcon = getHomeDrawable(lightContext, darkContext);
}
if (oldConfig.densityDpi != newConfig.densityDpi
|| oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) {
- mBackIcon = getBackDrawable(ctx);
- mBackLandIcon = mBackIcon;
- mBackAltIcon = getBackImeDrawable(ctx);
- mBackAltLandIcon = mBackAltIcon;
- mRecentIcon = getDrawable(ctx,
- R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark);
- mMenuIcon = getDrawable(ctx, R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu_dark);
+ mBackIcon = getBackDrawable(lightContext, darkContext);
+ mRecentIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_recent);
+ mMenuIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_menu);
- int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
- int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
- Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
- Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
+ mAccessibilityIcon = getDrawable(lightContext, darkContext,
+ R.drawable.ic_sysbar_accessibility_button, false /* hasShadow */);
- mAccessibilityIcon = getDrawable(darkContext, lightContext,
- R.drawable.ic_sysbar_accessibility_button,
- R.drawable.ic_sysbar_accessibility_button);
-
- mImeIcon = getDrawable(darkContext, lightContext,
- R.drawable.ic_ime_switcher_default, R.drawable.ic_ime_switcher_default);
+ mImeIcon = getDrawable(lightContext, darkContext, R.drawable.ic_ime_switcher_default,
+ false /* hasShadow */);
updateRotateSuggestionButtonStyle(mRotateBtnStyle, false);
@@ -505,42 +499,58 @@
}
}
- public KeyButtonDrawable getBackDrawable(Context ctx) {
- return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_back,
- R.drawable.ic_sysbar_back_dark, R.drawable.ic_sysbar_back_quick_step,
- R.drawable.ic_sysbar_back_quick_step_dark);
+ public KeyButtonDrawable getBackDrawable(Context lightContext, Context darkContext) {
+ KeyButtonDrawable drawable = chooseNavigationIconDrawable(lightContext, darkContext,
+ R.drawable.ic_sysbar_back, R.drawable.ic_sysbar_back_quick_step);
+ orientBackButton(drawable);
+ return drawable;
}
- public KeyButtonDrawable getBackImeDrawable(Context ctx) {
- return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_back_ime,
- R.drawable.ic_sysbar_back_ime_dark, R.drawable.ic_sysbar_back_ime_quick_step,
- R.drawable.ic_sysbar_back_ime_quick_step_dark);
+ public KeyButtonDrawable getHomeDrawable(Context lightContext, Context darkContext) {
+ final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
+ KeyButtonDrawable drawable = quickStepEnabled
+ ? getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_home_quick_step)
+ : getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_home,
+ false /* hasShadow */);
+ orientHomeButton(drawable);
+ return drawable;
}
- public KeyButtonDrawable getHomeDrawable(Context ctx) {
- return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_home,
- R.drawable.ic_sysbar_home_dark, R.drawable.ic_sysbar_home_quick_step,
- R.drawable.ic_sysbar_home_quick_step_dark);
+ private void orientBackButton(KeyButtonDrawable drawable) {
+ final boolean useAltBack =
+ (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+ drawable.setRotation(useAltBack
+ ? -90 : (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) ? 180 : 0);
}
- private KeyButtonDrawable chooseNavigationIconDrawable(Context ctx, @DrawableRes int iconLight,
- @DrawableRes int iconDark, @DrawableRes int quickStepIconLight,
- @DrawableRes int quickStepIconDark) {
+ private void orientHomeButton(KeyButtonDrawable drawable) {
+ drawable.setRotation(mVertical ? 90 : 0);
+ }
+
+ private KeyButtonDrawable chooseNavigationIconDrawable(Context lightContext,
+ Context darkContext, @DrawableRes int icon, @DrawableRes int quickStepIcon) {
final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
return quickStepEnabled
- ? getDrawable(ctx, quickStepIconLight, quickStepIconDark)
- : getDrawable(ctx, iconLight, iconDark);
+ ? getDrawable(lightContext, darkContext, quickStepIcon)
+ : getDrawable(lightContext, darkContext, icon);
+ }
+
+ private KeyButtonDrawable getDrawable(Context lightContext, Context darkContext,
+ @DrawableRes int icon) {
+ return getDrawable(lightContext, darkContext, icon, true /* hasShadow */);
+ }
+
+ private KeyButtonDrawable getDrawable(Context lightContext, Context darkContext,
+ @DrawableRes int icon, boolean hasShadow) {
+ return KeyButtonDrawable.create(lightContext, lightContext.getDrawable(icon),
+ darkContext.getDrawable(icon), hasShadow);
}
private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int lightIcon,
@DrawableRes int darkIcon) {
- return getDrawable(ctx, ctx, lightIcon, darkIcon);
- }
-
- private KeyButtonDrawable getDrawable(Context darkContext, Context lightContext,
- @DrawableRes int lightIcon, @DrawableRes int darkIcon) {
- return KeyButtonDrawable.create(lightContext.getDrawable(lightIcon),
- darkContext.getDrawable(darkIcon));
+ // Legacy image icons using separate light and dark images will not support shadows
+ return KeyButtonDrawable.create(ctx, ctx.getDrawable(lightIcon),
+ ctx.getDrawable(darkIcon), false /* hasShadow */);
}
private TintedKeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon,
@@ -557,13 +567,13 @@
private KeyButtonDrawable getBackIconWithAlt(boolean carMode, boolean landscape) {
return landscape
- ? carMode ? mBackAltLandCarModeIcon : mBackAltLandIcon
- : carMode ? mBackAltCarModeIcon : mBackAltIcon;
+ ? carMode ? mBackAltLandCarModeIcon : mBackIcon
+ : carMode ? mBackAltCarModeIcon : mBackIcon;
}
private KeyButtonDrawable getBackIcon(boolean carMode, boolean landscape) {
return landscape
- ? carMode ? mBackLandCarModeIcon : mBackLandIcon
+ ? carMode ? mBackLandCarModeIcon : mBackIcon
: carMode ? mBackCarModeIcon : mBackIcon;
}
@@ -600,20 +610,21 @@
// We have to replace or restore the back and home button icons when exiting or entering
// carmode, respectively. Recents are not available in CarMode in nav bar so change
// to recent icon is not required.
- KeyButtonDrawable backIcon
- = ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0)
- ? getBackIconWithAlt(mUseCarModeUi, mVertical)
- : getBackIcon(mUseCarModeUi, mVertical);
+ final boolean useAltBack =
+ (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+ KeyButtonDrawable backIcon = useAltBack
+ ? getBackIconWithAlt(mUseCarModeUi, mVertical)
+ : getBackIcon(mUseCarModeUi, mVertical);
+ KeyButtonDrawable homeIcon = mUseCarModeUi ? mHomeCarModeIcon : mHomeDefaultIcon;
+ if (!mUseCarModeUi) {
+ orientBackButton(backIcon);
+ orientHomeButton(homeIcon);
+ }
+ getHomeButton().setImageDrawable(homeIcon);
getBackButton().setImageDrawable(backIcon);
updateRecentsIcon();
- if (mUseCarModeUi) {
- getHomeButton().setImageDrawable(mHomeCarModeIcon);
- } else {
- getHomeButton().setImageDrawable(mHomeDefaultIcon);
- }
-
// Update IME button visibility, a11y and rotate button always overrides the appearance
final boolean showImeButton =
!mShowAccessibilityButton &&
@@ -640,8 +651,7 @@
// Always disable recents when alternate car mode UI is active.
boolean disableRecent = mUseCarModeUi || !isOverviewEnabled();
- boolean disableBack = ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
- && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
+ boolean disableBack = ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0) && !useAltBack;
// When screen pinning, don't hide back and home when connected service or back and
// recents buttons when disconnected from launcher service in screen pinning mode,
@@ -945,6 +955,7 @@
}
private void updateRecentsIcon() {
+ mDockedIcon.setRotation(mDockedStackExists && mVertical ? 90 : 0);
getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
mBarTransitions.reapplyDarkIntensity();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 2be10e8..a78dd25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -141,7 +141,7 @@
}
protected boolean shouldShowNotificationIcon(NotificationData.Entry entry,
- boolean showAmbient, boolean hideDismissed) {
+ boolean showAmbient, boolean hideDismissed, boolean hideRepliedMessages) {
if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
return false;
}
@@ -155,6 +155,10 @@
return false;
}
+ if (hideRepliedMessages && entry.isLastMessageFromReply()) {
+ return false;
+ }
+
// showAmbient == show in shade but not shelf
if (!showAmbient && mEntryManager.getNotificationData().shouldSuppressStatusBar(entry)) {
return false;
@@ -170,14 +174,15 @@
updateStatusBarIcons();
updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
- NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */);
+ NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */,
+ false /* hideRepliedMessages */);
applyNotificationIconsTint();
}
- private void updateStatusBarIcons() {
+ public void updateStatusBarIcons() {
updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
- false /* showAmbient */, true /* hideDismissed */);
+ false /* showAmbient */, true /* hideDismissed */, true /* hideRepliedMessages */);
}
/**
@@ -187,9 +192,11 @@
* @param hostLayout which layout should be updated
* @param showAmbient should ambient notification icons be shown
* @param hideDismissed should dismissed icons be hidden
+ * @param hideRepliedMessages should messages that have been replied to be hidden
*/
private void updateIconsForLayout(Function<NotificationData.Entry, StatusBarIconView> function,
- NotificationIconContainer hostLayout, boolean showAmbient, boolean hideDismissed) {
+ NotificationIconContainer hostLayout, boolean showAmbient, boolean hideDismissed,
+ boolean hideRepliedMessages) {
ArrayList<StatusBarIconView> toShow = new ArrayList<>(
mNotificationScrollLayout.getChildCount());
@@ -198,7 +205,8 @@
View view = mNotificationScrollLayout.getChildAt(i);
if (view instanceof ExpandableNotificationRow) {
NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
- if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed)) {
+ if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed,
+ hideRepliedMessages)) {
toShow.add(function.apply(ent));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 2ec9312..653471d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -129,13 +129,14 @@
public static final int MAX_VISIBLE_ICONS_WHEN_DARK = 5;
public static final int MAX_STATIC_ICONS = 4;
- private static final int MAX_DOTS = 3;
+ private static final int MAX_DOTS = 1;
private boolean mIsStaticLayout = true;
private final HashMap<View, IconState> mIconStates = new HashMap<>();
private int mDotPadding;
private int mStaticDotRadius;
private int mStaticDotDiameter;
+ private int mOverflowWidth;
private int mActualLayoutWidth = NO_VALUE;
private float mActualPaddingEnd = NO_VALUE;
private float mActualPaddingStart = NO_VALUE;
@@ -230,7 +231,7 @@
int top = (int) (centerY - height / 2.0f);
child.layout(0, top, width, top + height);
if (i == 0) {
- mIconSize = child.getWidth();
+ setIconSize(child.getWidth());
}
}
getLocationOnScreen(mAbsolutePosition);
@@ -239,6 +240,11 @@
}
}
+ private void setIconSize(int size) {
+ mIconSize = size;
+ mOverflowWidth = mIconSize + (MAX_DOTS - 1) * (mStaticDotDiameter + mDotPadding);
+ }
+
private void updateState() {
resetViewStates();
calculateIconTranslations();
@@ -391,12 +397,12 @@
iconState.visibleState = StatusBarIconView.STATE_ICON;
boolean isOverflowing =
- (translationX >= (noOverflowAfter ? layoutEnd - mIconSize : overflowStart));
+ (translationX > (noOverflowAfter ? layoutEnd - mIconSize
+ : overflowStart - mIconSize));
if (firstOverflowIndex == -1 && (forceOverflow || isOverflowing)) {
firstOverflowIndex = noOverflowAfter && !forceOverflow ? i - 1 : i;
- mVisualOverflowStart = layoutEnd - mIconSize
- - 2 * (mStaticDotDiameter + mDotPadding);
- if (forceOverflow) {
+ mVisualOverflowStart = layoutEnd - mOverflowWidth;
+ if (forceOverflow || mIsStaticLayout) {
mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
}
}
@@ -408,7 +414,7 @@
for (int i = firstOverflowIndex; i < childCount; i++) {
View view = getChildAt(i);
IconState iconState = mIconStates.get(view);
- int dotWidth = mStaticDotRadius * 2 + mDotPadding;
+ int dotWidth = mStaticDotDiameter + mDotPadding;
iconState.xTranslation = translationX;
if (mNumDots < MAX_DOTS) {
if (mNumDots == 0 && iconState.iconAppearAmount < 0.8f) {
@@ -536,7 +542,7 @@
}
private float getMaxOverflowStart() {
- return getLayoutEnd() - mIconSize * (2 + OVERFLOW_EARLY_AMOUNT);
+ return getLayoutEnd() - mOverflowWidth;
}
public void setChangingViewPositions(boolean changingViewPositions) {
@@ -607,7 +613,7 @@
return 0;
}
- int collapsedPadding = mIconSize + 2 * (mStaticDotDiameter + mDotPadding);
+ int collapsedPadding = mOverflowWidth;
if (collapsedPadding + getFinalTranslationX() > getWidth()) {
collapsedPadding = getWidth() - getFinalTranslationX();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadowKeyDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadowKeyDrawable.java
new file mode 100644
index 0000000..8311dfd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadowKeyDrawable.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+
+import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.BlurMaskFilter.Blur;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+
+import com.android.systemui.R;
+
+/**
+ * A drawable which adds shadow around a child drawable.
+ */
+public class ShadowKeyDrawable extends Drawable {
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+
+ private final ShadowDrawableState mState;
+
+ public ShadowKeyDrawable(Drawable d) {
+ this(d, new ShadowDrawableState());
+ }
+
+ private ShadowKeyDrawable(Drawable d, ShadowDrawableState state) {
+ mState = state;
+ if (d != null) {
+ mState.mBaseHeight = d.getIntrinsicHeight();
+ mState.mBaseWidth = d.getIntrinsicWidth();
+ mState.mChangingConfigurations = d.getChangingConfigurations();
+ mState.mChildState = d.getConstantState();
+ }
+ }
+
+ public void setRotation(float degrees) {
+ if (mState.mRotateDegrees != degrees) {
+ mState.mRotateDegrees = degrees;
+ mState.mLastDrawnBitmap = null;
+ invalidateSelf();
+ }
+ }
+
+ public void setShadowProperties(int x, int y, int size, int color) {
+ if (mState.mShadowOffsetX != x || mState.mShadowOffsetY != y
+ || mState.mShadowSize != size || mState.mShadowColor != color) {
+ mState.mShadowOffsetX = x;
+ mState.mShadowOffsetY = y;
+ mState.mShadowSize = size;
+ mState.mShadowColor = color;
+ mState.mLastDrawnBitmap = null;
+ invalidateSelf();
+ }
+ }
+
+ public float getRotation() {
+ return mState.mRotateDegrees;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ Rect bounds = getBounds();
+ if (bounds.isEmpty()) {
+ return;
+ }
+ if (mState.mLastDrawnBitmap == null) {
+ regenerateBitmapCache();
+ }
+ canvas.drawBitmap(mState.mLastDrawnBitmap, null, bounds, mPaint);
+ }
+
+ @Override
+ public void setTint(int tintColor) {
+ super.setTint(tintColor);
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mPaint.setAlpha(alpha);
+ invalidateSelf();
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mPaint.setColorFilter(colorFilter);
+ invalidateSelf();
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ return mState;
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mState.mBaseHeight;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mState.mBaseWidth;
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return mState.canApplyTheme();
+ }
+
+ private void regenerateBitmapCache() {
+ final int width = getIntrinsicWidth();
+ final int height = getIntrinsicHeight();
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ canvas.save();
+ final float radians = (float) (mState.mRotateDegrees * Math.PI / 180);
+
+ // Rotate canvas before drawing original drawable if no shadow
+ if (mState.mShadowSize == 0) {
+ canvas.rotate(mState.mRotateDegrees, width / 2, height / 2);
+ }
+
+ // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared.
+ final Drawable d = mState.mChildState.newDrawable().mutate();
+ d.setBounds(0, 0, mState.mBaseWidth, mState.mBaseHeight);
+ d.draw(canvas);
+
+ if (mState.mShadowSize > 0) {
+ // Draws the shadow
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ paint.setMaskFilter(new BlurMaskFilter(mState.mShadowSize, Blur.NORMAL));
+ int[] offset = new int[2];
+
+ final Bitmap shadow = bitmap.extractAlpha(paint, offset);
+
+ paint.setMaskFilter(null);
+ paint.setColor(mState.mShadowColor);
+ bitmap.eraseColor(Color.TRANSPARENT);
+
+ canvas.rotate(mState.mRotateDegrees, width / 2, height / 2);
+
+ final float shadowOffsetX = (float) (Math.sin(radians) * mState.mShadowOffsetY
+ + Math.cos(radians) * mState.mShadowOffsetX);
+ final float shadowOffsetY = (float) (Math.cos(radians) * mState.mShadowOffsetY
+ - Math.sin(radians) * mState.mShadowOffsetX);
+
+ canvas.drawBitmap(shadow, offset[0] + shadowOffsetX, offset[1] + shadowOffsetY, paint);
+ d.draw(canvas);
+ }
+
+ bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false);
+ mState.mLastDrawnBitmap = bitmap;
+ canvas.restore();
+ }
+
+ private static class ShadowDrawableState extends ConstantState {
+ int mChangingConfigurations;
+ int mBaseWidth;
+ int mBaseHeight;
+ float mRotateDegrees;
+ int mShadowOffsetX;
+ int mShadowOffsetY;
+ int mShadowSize;
+ int mShadowColor;
+
+ Bitmap mLastDrawnBitmap;
+ ConstantState mChildState;
+
+ @Override
+ public Drawable newDrawable() {
+ return new ShadowKeyDrawable(null, this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return true;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1b658b8..c70f034 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -234,6 +234,7 @@
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.PreviewInflater;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -399,6 +400,9 @@
private View mPendingRemoteInputView;
private View mPendingWorkRemoteInputView;
+ private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler =
+ Dependency.get(RemoteInputQuickSettingsDisabler.class);
+
private View mReportRejectedTouch;
private int mMaxAllowedKeyguardNotifications;
@@ -1759,6 +1763,8 @@
*/
@Override
public void disable(int state1, int state2, boolean animate) {
+ state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
+
animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
final int old1 = mDisabled1;
final int diff1 = state1 ^ old1;
@@ -2090,7 +2096,8 @@
* @param animate should the change of the icons be animated.
*/
private void updateHideIconsForBouncer(boolean animate) {
- boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded && mStatusBarWindowHidden;
+ boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded
+ && (mStatusBarWindowHidden || mBouncerShowing);
boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing;
boolean shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard;
if (mHideIconsForBouncer != shouldHideIconsForBouncer) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index cce9d1c..1a85c47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -17,10 +17,16 @@
package com.android.systemui.statusbar.policy;
import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.view.Gravity;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.ShadowKeyDrawable;
+
/**
* Drawable for {@link KeyButtonView}s which contains an asset for both normal mode and light
* navigation bar mode.
@@ -29,13 +35,24 @@
private final boolean mHasDarkDrawable;
- public static KeyButtonDrawable create(Drawable lightDrawable,
- @Nullable Drawable darkDrawable) {
+ public static KeyButtonDrawable create(Context lightContext, Drawable lightDrawable,
+ @Nullable Drawable darkDrawable, boolean hasShadow) {
if (darkDrawable != null) {
- return new KeyButtonDrawable(
- new Drawable[] { lightDrawable.mutate(), darkDrawable.mutate() });
+ ShadowKeyDrawable light = new ShadowKeyDrawable(lightDrawable.mutate());
+ ShadowKeyDrawable dark = new ShadowKeyDrawable(darkDrawable.mutate());
+ if (hasShadow) {
+ // Only apply the shadow on the light drawable
+ Resources res = lightContext.getResources();
+ int offsetX = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_x);
+ int offsetY = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_y);
+ int radius = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_radius);
+ int color = lightContext.getColor(R.color.nav_key_button_shadow_color);
+ light.setShadowProperties(offsetX, offsetY, radius, color);
+ }
+ return new KeyButtonDrawable(new Drawable[] { light, dark });
} else {
- return new KeyButtonDrawable(new Drawable[] { lightDrawable.mutate() });
+ return new KeyButtonDrawable(new Drawable[] {
+ new ShadowKeyDrawable(lightDrawable.mutate()) });
}
}
@@ -57,4 +74,13 @@
getDrawable(1).setAlpha((int) (intensity * 255f));
invalidateSelf();
}
+
+ public void setRotation(float degrees) {
+ if (getDrawable(0) instanceof ShadowKeyDrawable) {
+ ((ShadowKeyDrawable) getDrawable(0)).setRotation(degrees);
+ }
+ if (mHasDarkDrawable && getDrawable(1) instanceof ShadowKeyDrawable) {
+ ((ShadowKeyDrawable) getDrawable(1)).setRotation(degrees);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
new file mode 100644
index 0000000..c2933e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.app.StatusBarManager;
+import android.content.Context;
+import android.content.res.Configuration;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.qs.QSFragment;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Let {@link RemoteInputView} to control the visibility of QuickSetting.
+ */
+public class RemoteInputQuickSettingsDisabler
+ implements ConfigurationController.ConfigurationListener {
+
+ private Context mContext;
+ @VisibleForTesting boolean mRemoteInputActive;
+ @VisibleForTesting boolean misLandscape;
+ private int mLastOrientation;
+ @VisibleForTesting CommandQueue mCommandQueue;
+
+ public RemoteInputQuickSettingsDisabler(Context context) {
+ mContext = context;
+ mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class);
+ mLastOrientation = mContext.getResources().getConfiguration().orientation;
+ Dependency.get(ConfigurationController.class).addCallback(this);
+ }
+
+ public int adjustDisableFlags(int state) {
+ if (mRemoteInputActive && misLandscape) {
+ state |= StatusBarManager.DISABLE2_QUICK_SETTINGS;
+ }
+
+ return state;
+ }
+
+ public void setRemoteInputActive(boolean active){
+ if(mRemoteInputActive != active){
+ mRemoteInputActive = active;
+ recomputeDisableFlags();
+ }
+ }
+
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ if (newConfig.orientation != mLastOrientation) {
+ misLandscape = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
+ mLastOrientation = newConfig.orientation;
+ recomputeDisableFlags();
+ }
+ }
+
+ /**
+ * Reapplies the disable flags. Then the method adjustDisableFlags in this class will be invoked
+ * in {@link QSFragment#disable(int, int, boolean)} and
+ * {@link StatusBar#disable(int, int, boolean)}
+ * to modify the disable flags according to the status of mRemoteInputActive and misLandscape.
+ */
+ private void recomputeDisableFlags() {
+ mCommandQueue.recomputeDisableFlags(true);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 310f14c..4ec9ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -53,6 +53,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
@@ -81,6 +82,7 @@
private RemoteInput[] mRemoteInputs;
private RemoteInput mRemoteInput;
private RemoteInputController mController;
+ private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private NotificationData.Entry mEntry;
@@ -96,6 +98,7 @@
public RemoteInputView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mRemoteInputQuickSettingsDisabler = Dependency.get(RemoteInputQuickSettingsDisabler.class);
}
@Override
@@ -151,6 +154,7 @@
mController.removeRemoteInput(mEntry, mToken);
mEditText.mShowImeOnInputConnection = false;
mController.remoteInputSent(mEntry);
+ mEntry.setHasSentReply();
// Tell ShortcutManager that this package has been "activated". ShortcutManager
// will reset the throttling for this package.
@@ -232,6 +236,9 @@
}
}
}
+
+ mRemoteInputQuickSettingsDisabler.setRemoteInputActive(false);
+
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_CLOSE,
mEntry.notification.getPackageName());
}
@@ -291,6 +298,9 @@
mEditText.setSelection(mEditText.getText().length());
mEditText.requestFocus();
mController.addRemoteInput(mEntry, mToken);
+
+ mRemoteInputQuickSettingsDisabler.setRemoteInputActive(true);
+
updateSendButton();
}
@@ -554,6 +564,14 @@
}
@Override
+ public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ mRemoteInputView.mRemoteInputQuickSettingsDisabler.setRemoteInputActive(false);
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ @Override
public boolean onCheckIsTextEditor() {
// Stop being editable while we're being removed. During removal, we get reattached,
// and editable views get their spellchecking state re-evaluated which is too costly
@@ -565,11 +583,6 @@
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
- //if pinned, set imeOption to keep the behavior like in portrait.
- if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isPinned()) {
- outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI
- | EditorInfo.IME_FLAG_NO_FULLSCREEN;
- }
if (mShowImeOnInputConnection && inputConnection != null) {
final InputMethodManager imm = InputMethodManager.getInstance();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 585787e..924aa01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -213,6 +213,7 @@
Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
RemoteInput.addResultsToIntent(new RemoteInput[]{remoteInput}, intent, results);
RemoteInput.setResultsSource(intent, RemoteInput.SOURCE_CHOICE);
+ entry.setHasSentReply();
try {
pendingIntent.send(context, 0, intent);
} catch (PendingIntent.CanceledException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
index 4d33dec..30a5cc84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
@@ -21,6 +21,7 @@
import android.graphics.drawable.Drawable;
import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.statusbar.phone.ShadowKeyDrawable;
/**
* Drawable for {@link KeyButtonView}s which contains a single asset and colors for light and dark
@@ -36,7 +37,8 @@
public static TintedKeyButtonDrawable create(Drawable drawable, @ColorInt int lightColor,
@ColorInt int darkColor) {
- return new TintedKeyButtonDrawable(new Drawable[] { drawable }, lightColor, darkColor);
+ return new TintedKeyButtonDrawable(new Drawable[] { drawable },
+ lightColor, darkColor);
}
private TintedKeyButtonDrawable(Drawable[] drawables, int lightColor, int darkColor){
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 91a4b07..db3f0d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -30,7 +30,6 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
-import java.util.Collection;
/**
* A global state to track all input states for the algorithm.
@@ -72,6 +71,7 @@
private ExpandableNotificationRow mExpandingNotification;
private int mDarkTopPadding;
private float mDarkAmount;
+ private boolean mAppearing;
public AmbientState(Context context) {
reload(context);
@@ -436,4 +436,12 @@
public int getDarkTopPadding() {
return mDarkTopPadding;
}
+
+ public void setAppearing(boolean appearing) {
+ mAppearing = appearing;
+ }
+
+ public boolean isAppearing() {
+ return mAppearing;
+ }
}
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 3c3eb6b..794779d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -885,7 +885,9 @@
float appearEndPosition = getAppearEndPosition();
float appearStartPosition = getAppearStartPosition();
float appearFraction = 1.0f;
- if (height >= appearEndPosition) {
+ boolean appearing = height < appearEndPosition;
+ mAmbientState.setAppearing(appearing);
+ if (!appearing) {
translationY = 0;
if (mShouldShowShelfOnly) {
stackHeight = mTopPadding + mShelf.getIntrinsicHeight();
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 85f33d7..0d50f5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -478,22 +478,6 @@
childState.hidden = false;
}
}
- // Let's hide all the views if we are not expanded. the views might otherwise be visible
- // in the headsup area if a view was swiped away
- if (!mIsExpanded) {
- for (int i = 0; i < childCount; i++) {
- boolean visible = false;
- View child = algorithmState.visibleChildren.get(i);
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- visible = row.isHeadsUp() || row.isHeadsUpAnimatingAway();
- }
- if (!visible) {
- ExpandableViewState childState = resultState.getViewStateForView(child);
- childState.hidden = true;
- }
- }
- }
}
private void clampHunToTop(AmbientState ambientState, ExpandableNotificationRow row,
@@ -536,6 +520,10 @@
int shelfStart = ambientState.getInnerHeight()
- ambientState.getShelf().getIntrinsicHeight();
+ if (ambientState.isAppearing() && !child.isAboveShelf()) {
+ // Don't show none heads-up notifications while in appearing phase.
+ childViewState.yTranslation = Math.max(childViewState.yTranslation, shelfStart);
+ }
childViewState.yTranslation = Math.min(childViewState.yTranslation, shelfStart);
if (childViewState.yTranslation >= shelfStart) {
childViewState.hidden = !child.isExpandAnimationRunning() && !child.hasExpandingChild();
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index d527465..2f8dfdc 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -640,7 +640,7 @@
}
private PendingIntent buildBrowsePendingIntent(VolumeInfo vol) {
- final Intent intent = vol.buildBrowseIntent();
+ final Intent intent = vol.buildBrowseIntentForUser(vol.getMountUserId());
final int requestKey = vol.getId().hashCode();
return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
index ad20900..11c72c4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
@@ -23,6 +23,7 @@
public static final int ROTATION_NONE = 0;
public static final int ROTATION_LANDSCAPE = 1;
public static final int ROTATION_SEASCAPE = 2;
+ public static final int ROTATION_UPSIDE_DOWN = 3;
public static int getRotation(Context context) {
Configuration config = context.getResources().getConfiguration();
@@ -36,4 +37,19 @@
}
return ROTATION_NONE;
}
+
+ public static int getExactRotation(Context context) {
+ Configuration config = context.getResources().getConfiguration();
+ int rot = context.getDisplay().getRotation();
+ if (config.smallestScreenWidthDp < 600) {
+ if (rot == Surface.ROTATION_90) {
+ return ROTATION_LANDSCAPE;
+ } else if (rot == Surface.ROTATION_270) {
+ return ROTATION_SEASCAPE;
+ } else if (rot == Surface.ROTATION_180) {
+ return ROTATION_UPSIDE_DOWN;
+ }
+ }
+ return ROTATION_NONE;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 9488f03..4588675 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -727,6 +727,12 @@
}
protected void onStateChangedH(State state) {
+ if (mState != null && state != null
+ && mState.ringerModeInternal != state.ringerModeInternal
+ && state.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) {
+ mController.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK));
+ }
+
mState = state;
mDynamic.clear();
// add any new dynamic rows
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index 3a262c2..d2e8371 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -57,9 +57,7 @@
public void showSlice_notifiesListener() {
ListBuilder builder = new ListBuilder(getContext(), mSliceUri);
AtomicBoolean notified = new AtomicBoolean();
- mKeyguardSliceView.setContentChangeListener((hasHeader)-> {
- notified.set(true);
- });
+ mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
mKeyguardSliceView.onChanged(builder.build());
Assert.assertTrue("Listener should be notified about slice changes.",
notified.get());
@@ -68,9 +66,7 @@
@Test
public void showSlice_emptySliceNotifiesListener() {
AtomicBoolean notified = new AtomicBoolean();
- mKeyguardSliceView.setContentChangeListener((hasHeader)-> {
- notified.set(true);
- });
+ mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
mKeyguardSliceView.onChanged(null);
Assert.assertTrue("Listener should be notified about slice changes.",
notified.get());
@@ -92,9 +88,7 @@
@Test
public void refresh_replacesSliceContentAndNotifiesListener() {
AtomicBoolean notified = new AtomicBoolean();
- mKeyguardSliceView.setContentChangeListener((hasHeader)-> {
- notified.set(true);
- });
+ mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
mKeyguardSliceView.refresh();
Assert.assertTrue("Listener should be notified about slice changes.",
notified.get());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 2f05b06..f1bf31d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -36,6 +36,7 @@
import android.content.res.Configuration;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
@@ -54,6 +55,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+@RunWithLooper
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class ScreenDecorationsTest extends SysuiTestCase {
@@ -98,6 +100,8 @@
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 0);
+ mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius_top, 0);
+ mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius_bottom, 0);
mContext.getOrCreateTestableResources()
.addOverride(dimen.rounded_corner_content_padding, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index bdeb8bc..a72fed4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -508,7 +508,6 @@
anyString(), eq(TEST_UID), eq(true));
}
-
@Test
public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing()
throws Exception {
@@ -537,6 +536,43 @@
anyString(), eq(TEST_UID), eq(true));
}
+ @Test
+ public void testCloseControls_nonNullCheckSaveListenerDoesntDelayDismiss()
+ throws Exception {
+ NotificationInfo.CheckSaveListener listener =
+ mock(NotificationInfo.CheckSaveListener.class);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
+ 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
+ null /* onSettingsClick */, null /* onAppSettingsClick */ ,
+ false /* isNonblockable */, true /* isForBlockingHelper */,
+ true /* isUserSentimentNegative */);
+
+ mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
+
+ mTestableLooper.processAllMessages();
+ verify(listener, times(0)).checkSave(any(Runnable.class), eq(mSbn));
+ }
+
+ @Test
+ public void testCloseControls_checkSaveListenerDelaysStopNotifications()
+ throws Exception {
+ NotificationInfo.CheckSaveListener listener =
+ mock(NotificationInfo.CheckSaveListener.class);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
+ 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
+ null /* onSettingsClick */, null /* onAppSettingsClick */ ,
+ false /* isNonblockable */, true /* isForBlockingHelper */,
+ true /* isUserSentimentNegative */);
+
+ mNotificationInfo.findViewById(R.id.block).performClick();
+ waitForUndoButton();
+ mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
+
+ mTestableLooper.processAllMessages();
+ verify(listener).checkSave(any(Runnable.class), eq(mSbn));
+ }
@Test
public void testCloseControls_blockingHelperDismissedIfShown() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
new file mode 100644
index 0000000..3b47eae
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RemoteInputQuickSettingsDisablerTest extends SysuiTestCase {
+
+ private CommandQueue mCommandQueue;
+ private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mCommandQueue = mock(CommandQueue.class);
+ mContext.putComponent(CommandQueue.class, mCommandQueue);
+
+ mRemoteInputQuickSettingsDisabler = new RemoteInputQuickSettingsDisabler(mContext);
+ }
+
+ @Test
+ public void shouldEnableQuickSetting_afterDeactiviate() {
+ mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE);
+ mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE);
+ assertFalse(mRemoteInputQuickSettingsDisabler.mRemoteInputActive);
+ verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+ }
+
+ @Test
+ public void shouldDisableQuickSetting_afteActiviate() {
+ mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE);
+ mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE);
+ assertTrue(mRemoteInputQuickSettingsDisabler.mRemoteInputActive);
+ verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+ }
+
+ @Test
+ public void testChangeToLandscape() {
+ Configuration c = new Configuration(mContext.getResources().getConfiguration());
+ c.orientation = Configuration.ORIENTATION_PORTRAIT;
+ mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
+ c.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
+ assertTrue(mRemoteInputQuickSettingsDisabler.misLandscape);
+ verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+ }
+
+ @Test
+ public void testChangeToPortrait() {
+ Configuration c = new Configuration(mContext.getResources().getConfiguration());
+ c.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
+ c.orientation = Configuration.ORIENTATION_PORTRAIT;
+ mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
+ assertFalse(mRemoteInputQuickSettingsDisabler.misLandscape);
+ verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 938dfca..a6fa4f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -54,6 +54,7 @@
@Mock private RemoteInputController mController;
@Mock private ShortcutManager mShortcutManager;
+ @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private BlockingQueueIntentReceiver mReceiver;
private RemoteInputView mView;
@@ -61,6 +62,9 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mDependency.injectTestDependency(RemoteInputQuickSettingsDisabler.class,
+ mRemoteInputQuickSettingsDisabler);
+
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION), null,
Handler.createAsync(Dependency.get(Dependency.BG_LOOPER)));
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0ca4d9a..c67a9f8 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -205,6 +205,14 @@
HARDWARE_FAILURE_FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5;
}
+ enum IoOperation {
+ IOOP_UNKNOWN = 0;
+ IOOP_READ = 1;
+ IOOP_WRITE = 2;
+ IOOP_UNMAP = 3;
+ IOOP_SYNC = 4;
+ }
+
// Known visual elements: views or controls.
enum View {
// Unknown view
@@ -5931,8 +5939,7 @@
// ACTION: Battery health snapshot
// CATEGORY: OTHER
// OS: P
- // uses FIELD_END_BATTERY_PERCENT for batt %
- // uses FIELD_END_BATTERY_UA for instantaneous current load
+ // uses FIELD_END_BATTERY_PERCENT for instantaneous batt %
ACTION_BATTERY_HEALTH = 1433;
// FIELD: Battery health snapshot type - min daily voltage, resistance, etc.
@@ -5940,31 +5947,33 @@
// OS: P
FIELD_BATTERY_HEALTH_SNAPSHOT_TYPE = 1434;
- // FIELD: Battery temperature at snapshop.
+ // FIELD: Battery temperature at snapshot, in 1/10 deg C.
// CATEGORY: OTHER
// OS: P
- FIELD_BATTERY_TEMPERATURE = 1435;
+ FIELD_BATTERY_TEMPERATURE_DECI_C = 1435;
- // FIELD: Battery voltage at snapshot.
+ // FIELD: Battery voltage at snapshot, in microVolts.
// CATEGORY: OTHER
// OS: P
- FIELD_BATTERY_VOLTAGE = 1436;
+ FIELD_BATTERY_VOLTAGE_UV = 1436;
- // FIELD: Battery open circuit voltage at snapshot.
+ // FIELD: Battery open circuit voltage at snapshot, in microVolts.
// CATEGORY: OTHER
// OS: P
- FIELD_BATTERY_OPEN_CIRCUIT_VOLTAGE = 1437;
+ FIELD_BATTERY_OPEN_CIRCUIT_VOLTAGE_UV = 1437;
- // ACTION: Battery charge cycles
- // Number of times the battery has charged beyond a
+ // ACTION: Number of times the battery has charged beyond a
// fractional threshold of full capacity.
// CATEGORY: OTHER
// OS: P
ACTION_BATTERY_CHARGE_CYCLES = 1438;
- // FIELD: Battery charge cycles
- // Number of times the battery has charged beyond a
- // fractional threshold of full capacity.
+ // FIELD: BATTERY_CHARGE_CYCLES - Number of times the battery has charged
+ // beyond a fractional threshold of full
+ // capacity. A comma-separated string of
+ // buckets. If there are eight buckets,
+ // each bucket represents charging to n/8
+ // percent full.
// CATEGORY: OTHER
// OS: P
FIELD_BATTERY_CHARGE_CYCLES = 1439;
@@ -5980,6 +5989,62 @@
// OS: P
DIALOG_BLUETOOTH_DISABLE_A2DP_HW_OFFLOAD = 1441;
+ // ACTION: SLOW_IO - I/O operation took longer than threshold,
+ // reported aggregated per day when > 0.
+ // CATEGORY: OTHER
+ // OS: P
+ ACTION_SLOW_IO = 1442;
+
+ // FIELD: IO_OPERATION_TYPE - The IO Operation that caused the high latency.
+ // The value is an integer from the enum IoOperation.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_IO_OPERATION_TYPE = 1443;
+
+ // FIELD: IO_OPERATION_COUNT - Count of how many times this slow IO operation happened
+ // over the past 24hr (reported only if > 0).
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_IO_OPERATION_COUNT = 1444;
+
+ // ACTION: Speaker Imedance - last recorded speaker impedance.
+ // reported max once per 24hr.
+ // CATEGORY: OTHER
+ // OS: P
+ ACTION_SPEAKER_IMPEDANCE = 1445;
+
+ // FIELD: Speaker Impedance in milliohms.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_SPEAKER_IMPEDANCE_MILLIOHMS = 1446;
+
+ // FIELD: Speaker Location - identifies one of several speakers on a device.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_SPEAKER_LOCATION = 1447;
+
+ // FIELD: Instantaneous battery resistance in microohms.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_BATTERY_RESISTANCE_UOHMS = 1448;
+
+ // FIELD: Instantaneous battery current - in microamps.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_BATTERY_CURRENT_UA = 1449;
+
+ // FIELD: HARDWARE_LOCATION - Identifier for instance of a hardware type on a
+ // board.
+ // CATEGORY: OTHER
+ // OS: P
+ FIELD_HARDWARE_LOCATION = 1450;
+
+ // ACTION: BATTERY_CAUSED_SHUTDOWN - shutdown due to low battery, the
+ // action is logged after the subsequent boot.
+ // CATEGORY: OTHER
+ // OS: P
+ ACTION_BATTERY_CAUSED_SHUTDOWN = 1451;
+
// ---- End P Constants, all P constants go above this line ----
// First Q constant in master goes here:
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 9ff8e7d..72f11e0 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -453,6 +453,10 @@
// Number of times the firmware picked a SoftAp channel not satisfying user band preference.
optional int32 num_soft_ap_user_band_preference_unsatisfied = 116;
+
+ // Identifier for experimental scoring parameter settings.
+ optional string score_experiment_id = 117;
+
}
// Information that gets logged for every WiFi connection.
@@ -615,6 +619,9 @@
// Number of RSSI polls with 'rssi'
optional int32 count = 2;
+
+ // Beacon frequency of the channel in MHz
+ optional int32 frequency = 3;
}
// Number of occurrences of a specific alert reason value
diff --git a/services/art-profile b/services/art-profile
index a372a9c..0fdbf6b 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -3272,11 +3272,11 @@
Lcom/android/server/soundtrigger/SoundTriggerService$SoundTriggerServiceStub;
Lcom/android/server/soundtrigger/SoundTriggerService;
Lcom/android/server/stats/StatsCompanionService$1;
-Lcom/android/server/stats/StatsCompanionService$AnomalyAlarmReceiver;
+Lcom/android/server/stats/StatsCompanionService$AnomalyAlarmListener;
Lcom/android/server/stats/StatsCompanionService$AppUpdateReceiver;
Lcom/android/server/stats/StatsCompanionService$Lifecycle;
-Lcom/android/server/stats/StatsCompanionService$PeriodicAlarmReceiver;
-Lcom/android/server/stats/StatsCompanionService$PullingAlarmReceiver;
+Lcom/android/server/stats/StatsCompanionService$PeriodicAlarmListener;
+Lcom/android/server/stats/StatsCompanionService$PullingAlarmListener;
Lcom/android/server/stats/StatsCompanionService$ShutdownEventReceiver;
Lcom/android/server/stats/StatsCompanionService$StatsdDeathRecipient;
Lcom/android/server/stats/StatsCompanionService;
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index fa2a0d9..a5311b2 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -53,7 +53,6 @@
import android.view.autofill.AutofillManager;
import android.widget.ImageView;
import android.widget.RemoteViews;
-import android.widget.ScrollView;
import android.widget.TextView;
import com.android.internal.R;
@@ -208,7 +207,7 @@
mSubTitle = info.getDescription();
if (mSubTitle != null) {
writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_SUBTITLE, type);
- final ScrollView subtitleContainer =
+ final ViewGroup subtitleContainer =
view.findViewById(R.id.autofill_save_custom_subtitle);
final TextView subtitleView = new TextView(context);
subtitleView.setText(mSubTitle);
@@ -361,7 +360,7 @@
}
// Finally, add the custom description to the save UI.
- final ScrollView subtitleContainer =
+ final ViewGroup subtitleContainer =
saveUiView.findViewById(R.id.autofill_save_custom_subtitle);
subtitleContainer.addView(customSubtitleView);
subtitleContainer.setVisibility(View.VISIBLE);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index bd51af2..d7db471 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -2901,6 +2901,25 @@
return currentTransport;
}
+ /**
+ * Returns the {@link ComponentName} of the host service of the selected transport or {@code
+ * null} if no transport selected or if the transport selected is not registered.
+ */
+ @Override
+ @Nullable
+ public ComponentName getCurrentTransportComponent() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BACKUP, "getCurrentTransportComponent");
+ long oldId = Binder.clearCallingIdentity();
+ try {
+ return mTransportManager.getCurrentTransportComponent();
+ } catch (TransportNotRegisteredException e) {
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
+ }
+
// Report all known, available backup transports
@Override
public String[] listAllTransports() {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
index aabe7f6..f2219a0 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
@@ -16,6 +16,7 @@
package com.android.server.backup;
+import android.annotation.Nullable;
import android.app.IBackupAgent;
import android.app.backup.IBackupManager;
import android.app.backup.IBackupManagerMonitor;
@@ -132,6 +133,10 @@
// Report the name of the currently active transport
String getCurrentTransport();
+ // Report the component name of the host service of the currently active transport
+ @Nullable
+ ComponentName getCurrentTransportComponent();
+
// Report all known, available backup transports
String[] listAllTransports();
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 2abeaa6..787d667 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -19,8 +19,8 @@
import android.annotation.Nullable;
import android.app.backup.BackupManager;
import android.app.backup.IBackupManager;
-import android.app.backup.IBackupObserver;
import android.app.backup.IBackupManagerMonitor;
+import android.app.backup.IBackupObserver;
import android.app.backup.IFullBackupRestoreObserver;
import android.app.backup.IRestoreSession;
import android.app.backup.ISelectBackupTransportCallback;
@@ -341,6 +341,17 @@
return (svc != null) ? svc.getCurrentTransport() : null;
}
+ /**
+ * Returns the {@link ComponentName} of the host service of the selected transport or
+ * {@code null} if no transport selected or if the transport selected is not registered.
+ */
+ @Override
+ @Nullable
+ public ComponentName getCurrentTransportComponent() {
+ BackupManagerServiceInterface svc = mService;
+ return (svc != null) ? svc.getCurrentTransportComponent() : null;
+ }
+
@Override
public String[] listAllTransports() throws RemoteException {
BackupManagerServiceInterface svc = mService;
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 64e24d8..ddce6bb 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -176,12 +176,30 @@
return mTransportWhitelist;
}
+ /** Returns the name of the selected transport or {@code null} if no transport selected. */
@Nullable
public String getCurrentTransportName() {
return mCurrentTransportName;
}
/**
+ * Returns the {@link ComponentName} of the host service of the selected transport or
+ * {@code null} if no transport selected.
+ *
+ * @throws TransportNotRegisteredException if the selected transport is not registered.
+ */
+ @Nullable
+ public ComponentName getCurrentTransportComponent()
+ throws TransportNotRegisteredException {
+ synchronized (mTransportLock) {
+ if (mCurrentTransportName == null) {
+ return null;
+ }
+ return getRegisteredTransportComponentOrThrowLocked(mCurrentTransportName);
+ }
+ }
+
+ /**
* Returns the transport name associated with {@code transportComponent}.
*
* @throws TransportNotRegisteredException if the transport is not registered.
@@ -325,6 +343,16 @@
}
@GuardedBy("mTransportLock")
+ private ComponentName getRegisteredTransportComponentOrThrowLocked(String transportName)
+ throws TransportNotRegisteredException {
+ ComponentName transportComponent = getRegisteredTransportComponentLocked(transportName);
+ if (transportComponent == null) {
+ throw new TransportNotRegisteredException(transportName);
+ }
+ return transportComponent;
+ }
+
+ @GuardedBy("mTransportLock")
private TransportDescription getRegisteredTransportDescriptionOrThrowLocked(
ComponentName transportComponent) throws TransportNotRegisteredException {
TransportDescription description =
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 0775abf..a62d973 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1388,7 +1388,19 @@
}
synchronized (mLock) {
- return setKernelTime(mNativeData, millis) == 0;
+ final long currentTimeMillis = System.currentTimeMillis();
+ setKernelTime(mNativeData, millis);
+ final TimeZone timeZone = TimeZone.getDefault();
+ final int currentTzOffset = timeZone.getOffset(currentTimeMillis);
+ final int newTzOffset = timeZone.getOffset(millis);
+ if (currentTzOffset != newTzOffset) {
+ Slog.i(TAG, "Timezone offset has changed, updating kernel timezone");
+ setKernelTimezone(mNativeData, -(newTzOffset / 60000));
+ }
+ // The native implementation of setKernelTime can return -1 even when the kernel
+ // time was set correctly, so assume setting kernel time was successful and always
+ // return true.
+ return true;
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0893c4b..48817d2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4674,7 +4674,7 @@
}
private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
- LinkProperties newLp = networkAgent.linkProperties;
+ LinkProperties newLp = new LinkProperties(networkAgent.linkProperties);
int netId = networkAgent.network.netId;
// The NetworkAgentInfo does not know whether clatd is running on its network or not. Before
@@ -4708,6 +4708,9 @@
}
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
+ synchronized (networkAgent) {
+ networkAgent.linkProperties = newLp;
+ }
notifyIfacesChangedForNetworkStats();
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 2869114..5a25f48 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import android.annotation.Nullable;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -47,10 +49,18 @@
import dalvik.system.VMRuntime;
import java.io.FileDescriptor;
+import java.io.Closeable;
+import java.io.InputStream;
+import java.io.DataInputStream;
import java.io.IOException;
+import java.io.EOFException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipException;
+import java.util.zip.ZipEntry;
+
/**
* <p>PinnerService pins important files for key processes in memory.</p>
* <p>Files to pin are specified in the config_defaultPinnerServiceFiles
@@ -60,16 +70,18 @@
public final class PinnerService extends SystemService {
private static final boolean DEBUG = false;
private static final String TAG = "PinnerService";
+ private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); //80MB max
+ private static final String PIN_META_FILENAME = "pinlist.meta";
+ private static final int PAGE_SIZE = (int) Os.sysconf(OsConstants._SC_PAGESIZE);
private final Context mContext;
- private final ArrayList<PinnedFile> mPinnedFiles = new ArrayList<PinnedFile>();
- private final ArrayList<PinnedFile> mPinnedCameraFiles = new ArrayList<PinnedFile>();
private final boolean mShouldPinCamera;
+ /* These lists protected by PinnerService monitor lock */
+ private final ArrayList<PinnedFile> mPinnedFiles = new ArrayList<PinnedFile>();
+ private final ArrayList<PinnedFile> mPinnedCameraFiles = new ArrayList<PinnedFile>();
+
private BinderService mBinderService;
-
- private final long MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); //80MB max
-
private PinnerHandler mPinnerHandler = null;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -146,18 +158,18 @@
// Files to pin come from the overlay and can be specified per-device config
String[] filesToPin = mContext.getResources().getStringArray(
com.android.internal.R.array.config_defaultPinnerServiceFiles);
- synchronized(this) {
- // Continue trying to pin remaining files even if there is a failure
- for (int i = 0; i < filesToPin.length; i++){
- PinnedFile pf = pinFile(filesToPin[i], 0, 0, 0);
- if (pf != null) {
- mPinnedFiles.add(pf);
- if (DEBUG) {
- Slog.i(TAG, "Pinned file = " + pf.mFilename);
- }
- } else {
- Slog.e(TAG, "Failed to pin file = " + filesToPin[i]);
- }
+ // Continue trying to pin each file even if we fail to pin some of them
+ for (String fileToPin : filesToPin) {
+ PinnedFile pf = pinFile(fileToPin,
+ Integer.MAX_VALUE,
+ /*attemptPinIntrospection=*/false);
+ if (pf == null) {
+ Slog.e(TAG, "Failed to pin file = " + fileToPin);
+ continue;
+ }
+
+ synchronized (this) {
+ mPinnedFiles.add(pf);
}
}
}
@@ -166,44 +178,23 @@
* Handler for camera pinning message
*/
private void handlePinCamera(int userHandle) {
- if (mShouldPinCamera) {
- synchronized(this) {
- boolean success = pinCamera(userHandle);
- if (!success) {
- //this is not necessarily an error
- if (DEBUG) {
- Slog.v(TAG, "Failed to pin camera.");
- }
- }
+ if (!mShouldPinCamera) return;
+ if (!pinCamera(userHandle)) {
+ if (DEBUG) {
+ Slog.v(TAG, "Failed to pin camera.");
}
}
}
- /**
- * determine if the camera app is already pinned by comparing the
- * intent resolution to the pinned files list
- */
- private boolean alreadyPinned(int userHandle) {
- ApplicationInfo cameraInfo = getCameraInfo(userHandle);
- if (cameraInfo == null ) {
- return false;
- }
- for (int i = 0; i < mPinnedCameraFiles.size(); i++) {
- if (mPinnedCameraFiles.get(i).mFilename.equals(cameraInfo.sourceDir)) {
- if (DEBUG) {
- Slog.v(TAG, "Camera is already pinned");
- }
- return true;
- }
- }
- return false;
- }
-
private void unpinCameraApp() {
- for (int i = 0; i < mPinnedCameraFiles.size(); i++) {
- unpinFile(mPinnedCameraFiles.get(i));
+ ArrayList<PinnedFile> pinnedCameraFiles;
+ synchronized (this) {
+ pinnedCameraFiles = new ArrayList<>(mPinnedCameraFiles);
+ mPinnedCameraFiles.clear();
}
- mPinnedCameraFiles.clear();
+ for (PinnedFile pinnedFile : pinnedCameraFiles) {
+ pinnedFile.close();
+ }
}
private boolean isResolverActivity(ActivityInfo info) {
@@ -255,15 +246,19 @@
//pin APK
String camAPK = cameraInfo.sourceDir;
- PinnedFile pf = pinFile(camAPK, 0, 0, MAX_CAMERA_PIN_SIZE);
+ PinnedFile pf = pinFile(camAPK,
+ MAX_CAMERA_PIN_SIZE,
+ /*attemptPinIntrospection=*/true);
if (pf == null) {
Slog.e(TAG, "Failed to pin " + camAPK);
return false;
}
if (DEBUG) {
- Slog.i(TAG, "Pinned " + pf.mFilename);
+ Slog.i(TAG, "Pinned " + pf.fileName);
}
- mPinnedCameraFiles.add(pf);
+ synchronized (this) {
+ mPinnedCameraFiles.add(pf);
+ }
// determine the ABI from either ApplicationInfo or Build
String arch = "arm";
@@ -289,11 +284,13 @@
//not pinning the oat/odex is not a fatal error
for (String file : files) {
- pf = pinFile(file, 0, 0, MAX_CAMERA_PIN_SIZE);
+ pf = pinFile(file, MAX_CAMERA_PIN_SIZE, /*attemptPinIntrospection=*/false);
if (pf != null) {
- mPinnedCameraFiles.add(pf);
+ synchronized (this) {
+ mPinnedCameraFiles.add(pf);
+ }
if (DEBUG) {
- Slog.i(TAG, "Pinned " + pf.mFilename);
+ Slog.i(TAG, "Pinned " + pf.fileName);
}
}
}
@@ -302,70 +299,294 @@
}
- /** mlock length bytes of fileToPin in memory, starting at offset
- * length == 0 means pin from offset to end of file
- * maxSize == 0 means infinite
+ /** mlock length bytes of fileToPin in memory
+ *
+ * If attemptPinIntrospection is true, then treat the file to pin as a zip file and
+ * look for a "pinlist.meta" file in the archive root directory. The structure of this
+ * file is a PINLIST_META as described below:
+ *
+ * <pre>
+ * PINLIST_META: PIN_RANGE*
+ * PIN_RANGE: PIN_START PIN_LENGTH
+ * PIN_START: big endian i32: offset in bytes of pin region from file start
+ * PIN_LENGTH: big endian i32: length of pin region in bytes
+ * </pre>
+ *
+ * (We use big endian because that's what DataInputStream is hardcoded to use.)
+ *
+ * If attemptPinIntrospection is false, then we use a single implicit PIN_RANGE of (0,
+ * maxBytesToPin); that is, we attempt to pin the first maxBytesToPin bytes of the file.
+ *
+ * After we open a file, we march through the list of pin ranges and attempt to pin
+ * each one, stopping after we've pinned maxBytesToPin bytes. (We may truncate the last
+ * pinned range to fit.) In this way, by choosing to emit certain PIN_RANGE pairs
+ * before others, file generators can express pins in priority order, making most
+ * effective use of the pinned-page quota.
+ *
+ * N.B. Each PIN_RANGE is clamped to the actual bounds of the file; all inputs have a
+ * meaningful interpretation. Also, a range locking a single byte of a page locks the
+ * whole page. Any truncated PIN_RANGE at EOF is ignored. Overlapping pinned entries
+ * are legal, but each pin of a byte counts toward the pin quota regardless of whether
+ * that byte has already been pinned, so the generator of PINLIST_META ought to ensure
+ * that ranges are non-overlapping.
+ *
+ * @param fileToPin Path to file to pin
+ * @param maxBytesToPin Maximum number of bytes to pin
+ * @param attemptPinIntrospection If true, try to open file as a
+ * zip in order to extract the
+ * @return Pinned memory resource owner thing or null on error
*/
- private static PinnedFile pinFile(String fileToPin, long offset, long length, long maxSize) {
- FileDescriptor fd = new FileDescriptor();
+ private static PinnedFile pinFile(String fileToPin,
+ int maxBytesToPin,
+ boolean attemptPinIntrospection) {
+ ZipFile fileAsZip = null;
+ InputStream pinRangeStream = null;
try {
- fd = Os.open(fileToPin,
- OsConstants.O_RDONLY | OsConstants.O_CLOEXEC | OsConstants.O_NOFOLLOW,
- OsConstants.O_RDONLY);
-
- StructStat sb = Os.fstat(fd);
-
- if (offset + length > sb.st_size) {
- Os.close(fd);
- Slog.e(TAG, "Failed to pin file " + fileToPin +
- ", request extends beyond end of file. offset + length = "
- + (offset + length) + ", file length = " + sb.st_size);
- return null;
+ if (attemptPinIntrospection) {
+ fileAsZip = maybeOpenZip(fileToPin);
}
- if (length == 0) {
- length = sb.st_size - offset;
+ if (fileAsZip != null) {
+ pinRangeStream = maybeOpenPinMetaInZip(fileAsZip, fileToPin);
}
- if (maxSize > 0 && length > maxSize) {
- Slog.e(TAG, "Could not pin file " + fileToPin +
- ", size = " + length + ", maxSize = " + maxSize);
- Os.close(fd);
- return null;
- }
+ Slog.d(TAG, "pinRangeStream: " + pinRangeStream);
- long address = Os.mmap(0, length, OsConstants.PROT_READ,
- OsConstants.MAP_PRIVATE, fd, offset);
- Os.close(fd);
-
- Os.mlock(address, length);
-
- return new PinnedFile(address, length, fileToPin);
- } catch (ErrnoException e) {
- Slog.e(TAG, "Could not pin file " + fileToPin + " with error " + e.getMessage());
- if(fd.valid()) {
- try {
- Os.close(fd);
- }
- catch (ErrnoException eClose) {
- Slog.e(TAG, "Failed to close fd, error = " + eClose.getMessage());
- }
- }
- return null;
+ PinRangeSource pinRangeSource = (pinRangeStream != null)
+ ? new PinRangeSourceStream(pinRangeStream)
+ : new PinRangeSourceStatic(0, Integer.MAX_VALUE /* will be clipped */);
+ return pinFileRanges(fileToPin, maxBytesToPin, pinRangeSource);
+ } finally {
+ safeClose(pinRangeStream);
+ safeClose(fileAsZip); // Also closes any streams we've opened
}
}
- private static boolean unpinFile(PinnedFile pf) {
+ /**
+ * Attempt to open a file as a zip file. On any sort of corruption, log, swallow the
+ * error, and return null.
+ */
+ private static ZipFile maybeOpenZip(String fileName) {
+ ZipFile zip = null;
try {
- Os.munlock(pf.mAddress, pf.mLength);
- } catch (ErrnoException e) {
- Slog.e(TAG, "Failed to unpin file " + pf.mFilename + " with error " + e.getMessage());
- return false;
+ zip = new ZipFile(fileName);
+ } catch (IOException ex) {
+ Slog.w(TAG,
+ String.format(
+ "could not open \"%s\" as zip: pinning as blob",
+ fileName),
+ ex);
}
- if (DEBUG) {
- Slog.i(TAG, "Unpinned file " + pf.mFilename );
+ return zip;
+ }
+
+ /**
+ * Open a pin metadata file in the zip if one is present.
+ *
+ * @param zipFile Zip file to search
+ * @return Open input stream or null on any error
+ */
+ private static InputStream maybeOpenPinMetaInZip(ZipFile zipFile, String fileName) {
+ ZipEntry pinMetaEntry = zipFile.getEntry(PIN_META_FILENAME);
+ InputStream pinMetaStream = null;
+ if (pinMetaEntry != null) {
+ try {
+ pinMetaStream = zipFile.getInputStream(pinMetaEntry);
+ } catch (IOException ex) {
+ Slog.w(TAG,
+ String.format("error reading pin metadata \"%s\": pinning as blob",
+ fileName),
+ ex);
+ }
}
- return true;
+ return pinMetaStream;
+ }
+
+ private static abstract class PinRangeSource {
+ /** Retrive a range to pin.
+ *
+ * @param outPinRange Receives the pin region
+ * @return True if we filled in outPinRange or false if we're out of pin entries
+ */
+ abstract boolean read(PinRange outPinRange);
+ }
+
+ private static final class PinRangeSourceStatic extends PinRangeSource {
+ private final int mPinStart;
+ private final int mPinLength;
+ private boolean mDone = false;
+
+ PinRangeSourceStatic(int pinStart, int pinLength) {
+ mPinStart = pinStart;
+ mPinLength = pinLength;
+ }
+
+ @Override
+ boolean read(PinRange outPinRange) {
+ outPinRange.start = mPinStart;
+ outPinRange.length = mPinLength;
+ boolean done = mDone;
+ mDone = true;
+ return !done;
+ }
+ }
+
+ private static final class PinRangeSourceStream extends PinRangeSource {
+ private final DataInputStream mStream;
+ private boolean mDone = false;
+
+ PinRangeSourceStream(InputStream stream) {
+ mStream = new DataInputStream(stream);
+ }
+
+ @Override
+ boolean read(PinRange outPinRange) {
+ if (!mDone) {
+ try {
+ outPinRange.start = mStream.readInt();
+ outPinRange.length = mStream.readInt();
+ } catch (IOException ex) {
+ mDone = true;
+ }
+ }
+ return !mDone;
+ }
+ }
+
+ /**
+ * Helper for pinFile.
+ *
+ * @param fileToPin Name of file to pin
+ * @param maxBytesToPin Maximum number of bytes to pin
+ * @param pinRangeSource Read PIN_RANGE entries from this stream to tell us what bytes
+ * to pin.
+ * @return PinnedFile or null on error
+ */
+ private static PinnedFile pinFileRanges(
+ String fileToPin,
+ int maxBytesToPin,
+ PinRangeSource pinRangeSource)
+ {
+ FileDescriptor fd = new FileDescriptor();
+ long address = -1;
+ int mapSize = 0;
+
+ try {
+ int openFlags = (OsConstants.O_RDONLY |
+ OsConstants.O_CLOEXEC |
+ OsConstants.O_NOFOLLOW);
+ fd = Os.open(fileToPin, openFlags, 0);
+ mapSize = (int) Math.min(Os.fstat(fd).st_size, Integer.MAX_VALUE);
+ address = Os.mmap(0, mapSize,
+ OsConstants.PROT_READ,
+ OsConstants.MAP_SHARED,
+ fd, /*offset=*/0);
+
+ PinRange pinRange = new PinRange();
+ int bytesPinned = 0;
+
+ // We pin at page granularity, so make sure the limit is page-aligned
+ if (maxBytesToPin % PAGE_SIZE != 0) {
+ maxBytesToPin -= maxBytesToPin % PAGE_SIZE;
+ }
+
+ while (bytesPinned < maxBytesToPin && pinRangeSource.read(pinRange)) {
+ int pinStart = pinRange.start;
+ int pinLength = pinRange.length;
+ pinStart = clamp(0, pinStart, mapSize);
+ pinLength = clamp(0, pinLength, mapSize - pinStart);
+ pinLength = Math.min(maxBytesToPin - bytesPinned, pinLength);
+
+ // mlock doesn't require the region to be page-aligned, but we snap the
+ // lock region to page boundaries anyway so that we don't under-count
+ // locking a single byte of a page as a charge of one byte even though the
+ // OS will retain the whole page. Thanks to this adjustment, we slightly
+ // over-count the pin charge of back-to-back pins touching the same page,
+ // but better that than undercounting. Besides: nothing stops pin metafile
+ // creators from making the actual regions page-aligned.
+ pinLength += pinStart % PAGE_SIZE;
+ pinStart -= pinStart % PAGE_SIZE;
+ if (pinLength % PAGE_SIZE != 0) {
+ pinLength += PAGE_SIZE - pinLength % PAGE_SIZE;
+ }
+ pinLength = clamp(0, pinLength, maxBytesToPin - bytesPinned);
+
+ if (pinLength > 0) {
+ if (DEBUG) {
+ Slog.d(TAG,
+ String.format(
+ "pinning at %s %s bytes of %s",
+ pinStart, pinLength, fileToPin));
+ }
+ Os.mlock(address + pinStart, pinLength);
+ }
+ bytesPinned += pinLength;
+ }
+
+ PinnedFile pinnedFile = new PinnedFile(address, mapSize, fileToPin, bytesPinned);
+ address = -1; // Ownership transferred
+ return pinnedFile;
+ } catch (ErrnoException ex) {
+ Slog.e(TAG, "Could not pin file " + fileToPin, ex);
+ return null;
+ } finally {
+ safeClose(fd);
+ if (address >= 0) {
+ safeMunmap(address, mapSize);
+ }
+ }
+ }
+
+ private static int clamp(int min, int value, int max) {
+ return Math.max(min, Math.min(value, max));
+ }
+
+ private static void safeMunmap(long address, long mapSize) {
+ try {
+ Os.munmap(address, mapSize);
+ } catch (ErrnoException ex) {
+ Slog.w(TAG, "ignoring error in unmap", ex);
+ }
+ }
+
+ /**
+ * Close FD, swallowing irrelevant errors.
+ */
+ private static void safeClose(@Nullable FileDescriptor fd) {
+ if (fd != null && fd.valid()) {
+ try {
+ Os.close(fd);
+ } catch (ErrnoException ex) {
+ // Swallow the exception: non-EBADF errors in close(2)
+ // indicate deferred paging write errors, which we
+ // don't care about here. The underlying file
+ // descriptor is always closed.
+ if (ex.errno == OsConstants.EBADF) {
+ throw new AssertionError(ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Close closeable thing, swallowing errors.
+ */
+ private static void safeClose(@Nullable Closeable thing) {
+ if (thing != null) {
+ try {
+ thing.close();
+ } catch (IOException ex) {
+ Slog.w(TAG, "ignoring error closing resource: " + thing, ex);
+ }
+ }
+ }
+
+ private synchronized ArrayList<PinnedFile> snapshotPinnedFiles() {
+ int nrPinnedFiles = mPinnedFiles.size() + mPinnedCameraFiles.size();
+ ArrayList<PinnedFile> pinnedFiles = new ArrayList<>(nrPinnedFiles);
+ pinnedFiles.addAll(mPinnedFiles);
+ pinnedFiles.addAll(mPinnedCameraFiles);
+ return pinnedFiles;
}
private final class BinderService extends Binder {
@@ -373,31 +594,44 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
long totalSize = 0;
- pw.println("Pinned Files:");
- synchronized(this) {
- for (int i = 0; i < mPinnedFiles.size(); i++) {
- pw.println(mPinnedFiles.get(i).mFilename);
- totalSize += mPinnedFiles.get(i).mLength;
- }
- for (int i = 0; i < mPinnedCameraFiles.size(); i++) {
- pw.println(mPinnedCameraFiles.get(i).mFilename);
- totalSize += mPinnedCameraFiles.get(i).mLength;
- }
+ for (PinnedFile pinnedFile : snapshotPinnedFiles()) {
+ pw.format("%s %s\n", pinnedFile.fileName, pinnedFile.bytesPinned);
+ totalSize += pinnedFile.bytesPinned;
}
- pw.println("Total size: " + totalSize);
+ pw.format("Total size: %s\n", totalSize);
}
}
- private static class PinnedFile {
- long mAddress;
- long mLength;
- String mFilename;
+ private static final class PinnedFile implements AutoCloseable {
+ private long mAddress;
+ final int mapSize;
+ final String fileName;
+ final int bytesPinned;
- PinnedFile(long address, long length, String filename) {
+ PinnedFile(long address, int mapSize, String fileName, int bytesPinned) {
mAddress = address;
- mLength = length;
- mFilename = filename;
+ this.mapSize = mapSize;
+ this.fileName = fileName;
+ this.bytesPinned = bytesPinned;
}
+
+ @Override
+ public void close() {
+ if (mAddress >= 0) {
+ safeMunmap(mAddress, mapSize);
+ mAddress = -1;
+ }
+ }
+
+ @Override
+ public void finalize() {
+ close();
+ }
+ }
+
+ final static class PinRange {
+ int start;
+ int length;
}
final class PinnerHandler extends Handler {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4b386be..8e87ebd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -37,9 +37,7 @@
import static android.app.ActivityManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static android.app.ActivityManagerInternal.ASSIST_KEY_STRUCTURE;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
-import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
import static android.app.AppOpsManager.OP_NONE;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -5128,6 +5126,7 @@
final ActivityRecord sourceRecord;
final int targetUid;
final String targetPackage;
+ final boolean isResolver;
synchronized (this) {
if (resultTo == null) {
throw new SecurityException("Must be called from an activity");
@@ -5165,6 +5164,7 @@
}
targetUid = sourceRecord.launchedFromUid;
targetPackage = sourceRecord.launchedFromPackage;
+ isResolver = sourceRecord.isResolverOrChildActivity();
}
if (userId == UserHandle.USER_NULL) {
@@ -5184,6 +5184,7 @@
.setActivityOptions(bOptions)
.setMayWait(userId)
.setIgnoreTargetSecurity(ignoreTargetSecurity)
+ .setFilterCallingUid(isResolver ? 0 /* system */ : targetUid)
.execute();
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.
@@ -15821,7 +15822,10 @@
}
@Override
- public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo) {
+ public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outState) {
+ if (outState == null) {
+ throw new IllegalArgumentException("outState is null");
+ }
enforceNotIsolatedCaller("getMyMemoryState");
final int callingUid = Binder.getCallingUid();
@@ -15832,7 +15836,9 @@
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(Binder.getCallingPid());
}
- fillInProcMemInfo(proc, outInfo, clientTargetSdk);
+ if (proc != null) {
+ fillInProcMemInfo(proc, outState, clientTargetSdk);
+ }
}
}
@@ -20411,7 +20417,7 @@
IPackageManager pm = AppGlobals.getPackageManager();
ApplicationInfo app = null;
try {
- app = pm.getApplicationInfo(packageName, 0, userId);
+ app = pm.getApplicationInfo(packageName, STOCK_PM_FLAGS, userId);
} catch (RemoteException e) {
// can't happen; package manager is process-local
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 73710d3..ef5a5a3 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -826,6 +826,18 @@
return ResolverActivity.class.getName().equals(realActivity.getClassName());
}
+ boolean isResolverOrChildActivity() {
+ if (!"android".equals(packageName)) {
+ return false;
+ }
+ try {
+ return ResolverActivity.class.isAssignableFrom(
+ Object.class.getClassLoader().loadClass(realActivity.getClassName()));
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromPid,
int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration,
@@ -1077,6 +1089,11 @@
// System process can launch home activity.
return true;
}
+ // Allow the recents component to launch the home activity.
+ final RecentTasks recentTasks = mStackSupervisor.mService.getRecentTasks();
+ if (recentTasks != null && recentTasks.isCallerRecents(uid)) {
+ return true;
+ }
// Resolver activity can launch home activity.
return sourceRecord != null && sourceRecord.isResolverActivity();
}
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index bbdc924..a7c3200 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -37,6 +37,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
import android.view.RemoteAnimationAdapter;
@@ -340,7 +341,7 @@
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
null, userId, ActivityStarter.computeResolveFilterUid(
- callingUid, realCallingUid));
+ callingUid, realCallingUid, UserHandle.USER_NULL));
// TODO: New, check if this is correct
aInfo = mService.getActivityInfoForUser(aInfo, userId);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index ad434b4..73e3d33 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -312,6 +312,7 @@
Configuration globalConfig;
int userId;
WaitResult waitResult;
+ int filterCallingUid;
/**
* If set to {@code true}, allows this activity start to look into
@@ -367,6 +368,7 @@
mayWait = false;
avoidMoveToFront = false;
allowPendingRemoteAnimationRegistryLookup = true;
+ filterCallingUid = UserHandle.USER_NULL;
}
/**
@@ -404,6 +406,7 @@
avoidMoveToFront = request.avoidMoveToFront;
allowPendingRemoteAnimationRegistryLookup
= request.allowPendingRemoteAnimationRegistryLookup;
+ filterCallingUid = request.filterCallingUid;
}
}
@@ -792,7 +795,8 @@
callingPid = realCallingPid;
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
- computeResolveFilterUid(callingUid, realCallingUid));
+ computeResolveFilterUid(
+ callingUid, realCallingUid, mRequest.filterCallingUid));
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
null /*profilerInfo*/);
@@ -984,7 +988,9 @@
}
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
- 0 /* matchFlags */, computeResolveFilterUid(callingUid, realCallingUid));
+ 0 /* matchFlags */,
+ computeResolveFilterUid(
+ callingUid, realCallingUid, mRequest.filterCallingUid));
if (rInfo == null) {
UserInfo userInfo = mSupervisor.getUserInfo(userId);
if (userInfo != null && userInfo.isManagedProfile()) {
@@ -1006,7 +1012,8 @@
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- computeResolveFilterUid(callingUid, realCallingUid));
+ computeResolveFilterUid(
+ callingUid, realCallingUid, mRequest.filterCallingUid));
}
}
}
@@ -1078,8 +1085,8 @@
callingPid = Binder.getCallingPid();
componentSpecified = true;
rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId,
- 0 /* matchFlags */, computeResolveFilterUid(callingUid,
- realCallingUid));
+ 0 /* matchFlags */, computeResolveFilterUid(
+ callingUid, realCallingUid, mRequest.filterCallingUid));
aInfo = rInfo != null ? rInfo.activityInfo : null;
if (aInfo != null) {
aInfo = mService.getActivityInfoForUser(aInfo, userId);
@@ -1173,10 +1180,14 @@
*
* @param customCallingUid The UID on whose behalf to make the call.
* @param actualCallingUid The UID actually making the call.
+ * @param filterCallingUid The UID to be used to filter for instant apps.
* @return The logical UID making the call.
*/
- static int computeResolveFilterUid(int customCallingUid, int actualCallingUid) {
- return customCallingUid >= 0 ? customCallingUid : actualCallingUid;
+ static int computeResolveFilterUid(int customCallingUid, int actualCallingUid,
+ int filterCallingUid) {
+ return filterCallingUid != UserHandle.USER_NULL
+ ? filterCallingUid
+ : (customCallingUid >= 0 ? customCallingUid : actualCallingUid);
}
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
@@ -2562,6 +2573,11 @@
return this;
}
+ ActivityStarter setFilterCallingUid(int filterCallingUid) {
+ mRequest.filterCallingUid = filterCallingUid;
+ return this;
+ }
+
ActivityStarter setComponentSpecified(boolean componentSpecified) {
mRequest.componentSpecified = componentSpecified;
return this;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 89ea251..cddb05e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3808,7 +3808,7 @@
queueMsgUnderWakeLock(mAudioHandler,
MSG_SET_A2DP_SINK_CONNECTION_STATE,
state,
- 0 /* arg2 unused */,
+ -1,
btDevice,
delay);
}
@@ -4654,22 +4654,22 @@
public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
{
return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
- device, state, profile, false /* suppressNoisyIntent */);
+ device, state, profile, false /* suppressNoisyIntent */, -1 /* a2dpVolume */);
}
public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
- int state, int profile, boolean suppressNoisyIntent)
+ int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
{
if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
return 0;
}
return setBluetoothA2dpDeviceConnectionStateInt(
- device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE);
+ device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
}
public int setBluetoothA2dpDeviceConnectionStateInt(
BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
- int musicDevice)
+ int musicDevice, int a2dpVolume)
{
int delay;
if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
@@ -4687,7 +4687,7 @@
(profile == BluetoothProfile.A2DP ?
MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
state,
- 0 /* arg2 unused */,
+ a2dpVolume,
device,
delay);
}
@@ -5217,41 +5217,41 @@
}
}
- /** Handles internal volume messages in separate volume thread. */
- private class AudioHandler extends Handler {
+ private void setDeviceVolume(VolumeStreamState streamState, int device) {
- private void setDeviceVolume(VolumeStreamState streamState, int device) {
+ synchronized (VolumeStreamState.class) {
+ // Apply volume
+ streamState.applyDeviceVolume_syncVSS(device);
- synchronized (VolumeStreamState.class) {
- // Apply volume
- streamState.applyDeviceVolume_syncVSS(device);
-
- // Apply change to all streams using this one as alias
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- if (streamType != streamState.mStreamType &&
- mStreamVolumeAlias[streamType] == streamState.mStreamType) {
- // Make sure volume is also maxed out on A2DP device for aliased stream
- // that may have a different device selected
- int streamDevice = getDeviceForStream(streamType);
- if ((device != streamDevice) && mAvrcpAbsVolSupported &&
- ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
- mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
- }
- mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
+ // Apply change to all streams using this one as alias
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ if (streamType != streamState.mStreamType &&
+ mStreamVolumeAlias[streamType] == streamState.mStreamType) {
+ // Make sure volume is also maxed out on A2DP device for aliased stream
+ // that may have a different device selected
+ int streamDevice = getDeviceForStream(streamType);
+ if ((device != streamDevice) && mAvrcpAbsVolSupported &&
+ ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
+ mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
}
+ mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
}
}
- // Post a persist volume msg
- sendMsg(mAudioHandler,
- MSG_PERSIST_VOLUME,
- SENDMSG_QUEUE,
- device,
- 0,
- streamState,
- PERSIST_DELAY);
-
}
+ // Post a persist volume msg
+ sendMsg(mAudioHandler,
+ MSG_PERSIST_VOLUME,
+ SENDMSG_QUEUE,
+ device,
+ 0,
+ streamState,
+ PERSIST_DELAY);
+
+ }
+
+ /** Handles internal volume messages in separate volume thread. */
+ private class AudioHandler extends Handler {
private void setAllVolumes(VolumeStreamState streamState) {
@@ -5618,7 +5618,7 @@
break;
case MSG_SET_A2DP_SINK_CONNECTION_STATE:
- onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+ onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1, msg.arg2);
mAudioEventWakeLock.release();
break;
@@ -5912,7 +5912,7 @@
return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
}
- private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
+ private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume)
{
if (DEBUG_DEVICES) {
Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
@@ -5957,6 +5957,14 @@
makeA2dpDeviceUnavailableNow(mDockAddress);
}
}
+ if (a2dpVolume != -1) {
+ VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+ // Convert index to internal representation in VolumeStreamState
+ a2dpVolume = a2dpVolume * 10;
+ streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ "onSetA2dpSinkConnectionState");
+ setDeviceVolume(streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ }
makeA2dpDeviceAvailable(address, btDevice.getName(),
"onSetA2dpSinkConnectionState");
setCurrentAudioRouteName(btDevice.getAliasName());
@@ -6059,7 +6067,7 @@
// consistent with audio policy manager state
setBluetoothA2dpDeviceConnectionStateInt(
btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
- false /* suppressNoisyIntent */, musicDevice);
+ false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
}
}
}
@@ -6069,6 +6077,9 @@
// address is not used for now, but may be used when multiple a2dp devices are supported
synchronized (mA2dpAvrcpLock) {
mAvrcpAbsVolSupported = support;
+ sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
+ mStreamStates[AudioSystem.STREAM_MUSIC], 0);
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 4521d3a..9b9a380 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -19,7 +19,11 @@
import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
import static android.net.CaptivePortal.APP_RETURN_UNWANTED;
import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL;
+import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
+import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -35,6 +39,7 @@
import android.net.TrafficStats;
import android.net.Uri;
import android.net.captiveportal.CaptivePortalProbeResult;
+import android.net.captiveportal.CaptivePortalProbeSpec;
import android.net.dns.ResolvUtil;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
@@ -63,6 +68,7 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
@@ -259,6 +265,8 @@
private final URL mCaptivePortalHttpsUrl;
private final URL mCaptivePortalHttpUrl;
private final URL[] mCaptivePortalFallbackUrls;
+ @Nullable
+ private final CaptivePortalProbeSpec[] mCaptivePortalFallbackSpecs;
@VisibleForTesting
protected boolean mIsCaptivePortalCheckEnabled;
@@ -334,6 +342,7 @@
mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl(settings, context));
mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
+ mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
start();
}
@@ -542,8 +551,12 @@
sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
}
}));
- intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL,
- mLastPortalProbeResult.detectUrl);
+ final CaptivePortalProbeResult probeRes = mLastPortalProbeResult;
+ intent.putExtra(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl);
+ if (probeRes.probeSpec != null) {
+ final String encodedSpec = probeRes.probeSpec.getEncodedSpec();
+ intent.putExtra(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC, encodedSpec);
+ }
intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT,
mCaptivePortalUserAgent);
intent.setFlags(
@@ -782,8 +795,9 @@
private void resolveStrictModeHostname() {
try {
// Do a blocking DNS resolution using the network-assigned nameservers.
+ // Do not set AI_ADDRCONFIG in ai_flags so we get all address families in advance.
final InetAddress[] ips = ResolvUtil.blockingResolveAllLocally(
- mNetwork, mPrivateDnsProviderHostname);
+ mNetwork, mPrivateDnsProviderHostname, 0 /* aiFlags */);
mPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips);
} catch (UnknownHostException uhe) {
mPrivateDnsConfig = null;
@@ -882,23 +896,47 @@
}
private URL[] makeCaptivePortalFallbackUrls() {
- String separator = ",";
- String firstUrl = mSettings.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
- String joinedUrls = firstUrl + separator + mSettings.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, DEFAULT_OTHER_FALLBACK_URLS);
- List<URL> urls = new ArrayList<>();
- for (String s : joinedUrls.split(separator)) {
- URL u = makeURL(s);
- if (u == null) {
- continue;
+ try {
+ String separator = ",";
+ String firstUrl = mSettings.getSetting(mContext,
+ Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
+ String joinedUrls = firstUrl + separator + mSettings.getSetting(mContext,
+ Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
+ DEFAULT_OTHER_FALLBACK_URLS);
+ List<URL> urls = new ArrayList<>();
+ for (String s : joinedUrls.split(separator)) {
+ URL u = makeURL(s);
+ if (u == null) {
+ continue;
+ }
+ urls.add(u);
}
- urls.add(u);
+ if (urls.isEmpty()) {
+ Log.e(TAG, String.format("could not create any url from %s", joinedUrls));
+ }
+ return urls.toArray(new URL[urls.size()]);
+ } catch (Exception e) {
+ // Don't let a misconfiguration bootloop the system.
+ Log.e(TAG, "Error parsing configured fallback URLs", e);
+ return new URL[0];
}
- if (urls.isEmpty()) {
- Log.e(TAG, String.format("could not create any url from %s", joinedUrls));
+ }
+
+ private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs() {
+ try {
+ final String settingsValue = mSettings.getSetting(
+ mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
+ // Probe specs only used if configured in settings
+ if (TextUtils.isEmpty(settingsValue)) {
+ return null;
+ }
+
+ return CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
+ } catch (Exception e) {
+ // Don't let a misconfiguration bootloop the system.
+ Log.e(TAG, "Error parsing configured fallback probe specs", e);
+ return null;
}
- return urls.toArray(new URL[urls.size()]);
}
private String getCaptivePortalUserAgent() {
@@ -915,6 +953,15 @@
return mCaptivePortalFallbackUrls[idx];
}
+ private CaptivePortalProbeSpec nextFallbackSpec() {
+ if (ArrayUtils.isEmpty(mCaptivePortalFallbackSpecs)) {
+ return null;
+ }
+ // Randomly change spec without memory. Also randomize the first attempt.
+ final int idx = Math.abs(new Random().nextInt()) % mCaptivePortalFallbackSpecs.length;
+ return mCaptivePortalFallbackSpecs[idx];
+ }
+
@VisibleForTesting
protected CaptivePortalProbeResult isCaptivePortal() {
if (!mIsCaptivePortalCheckEnabled) {
@@ -985,7 +1032,7 @@
// unnecessary resolution.
final String host = (proxy != null) ? proxy.getHost() : url.getHost();
sendDnsProbe(host);
- return sendHttpProbe(url, probeType);
+ return sendHttpProbe(url, probeType, null);
}
/** Do a DNS resolution of the given server. */
@@ -1021,7 +1068,8 @@
* @return a CaptivePortalProbeResult inferred from the HTTP response.
*/
@VisibleForTesting
- protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType) {
+ protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType,
+ @Nullable CaptivePortalProbeSpec probeSpec) {
HttpURLConnection urlConnection = null;
int httpResponseCode = CaptivePortalProbeResult.FAILED_CODE;
String redirectUrl = null;
@@ -1093,7 +1141,12 @@
TrafficStats.setThreadStatsTag(oldTag);
}
logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
- return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
+
+ if (probeSpec == null) {
+ return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
+ } else {
+ return probeSpec.getResult(httpResponseCode, redirectUrl);
+ }
}
private CaptivePortalProbeResult sendParallelHttpProbes(
@@ -1156,11 +1209,12 @@
if (httpsResult.isPortal() || httpsResult.isSuccessful()) {
return httpsResult;
}
- // If a fallback url exists, use a fallback probe to try again portal detection.
- URL fallbackUrl = nextFallbackUrl();
+ // If a fallback method exists, use it to retry portal detection.
+ // If we have new-style probe specs, use those. Otherwise, use the fallback URLs.
+ final CaptivePortalProbeSpec probeSpec = nextFallbackSpec();
+ final URL fallbackUrl = (probeSpec != null) ? probeSpec.getUrl() : nextFallbackUrl();
if (fallbackUrl != null) {
- CaptivePortalProbeResult result =
- sendHttpProbe(fallbackUrl, ValidationProbeEvent.PROBE_FALLBACK);
+ CaptivePortalProbeResult result = sendHttpProbe(fallbackUrl, PROBE_FALLBACK, probeSpec);
if (result.isPortal()) {
return result;
}
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 213ec36..0b6786c 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -189,6 +189,13 @@
mController = new ColorDisplayController(getContext(), mCurrentUser);
mController.setListener(this);
+ // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
+ // existing activated state. This ensures consistency of tint across the color mode change.
+ onDisplayColorModeChanged(mController.getColorMode());
+
+ // Reset the activated state.
+ mIsActivated = null;
+
setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix());
// Prepare color transformation matrix.
@@ -201,9 +208,6 @@
if (mIsActivated == null) {
onActivated(mController.isActivated());
}
-
- // Transition the screen to the current temperature.
- applyTint(false);
}
private void tearDown() {
@@ -223,8 +227,6 @@
mColorMatrixAnimator.end();
mColorMatrixAnimator = null;
}
-
- mIsActivated = null;
}
@Override
@@ -288,6 +290,10 @@
@Override
public void onDisplayColorModeChanged(int mode) {
+ if (mode == -1) {
+ return;
+ }
+
// Cancel the night display tint animator if it's running.
if (mColorMatrixAnimator != null) {
mColorMatrixAnimator.cancel();
@@ -297,7 +303,8 @@
setMatrix(mController.getColorTemperature(), mMatrixNight);
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
- dtm.setColorMode(mode, mIsActivated ? mMatrixNight : MATRIX_IDENTITY);
+ dtm.setColorMode(mode, (mIsActivated != null && mIsActivated) ? mMatrixNight
+ : MATRIX_IDENTITY);
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3c66526..99412c5 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -489,6 +489,7 @@
mTemporaryScreenBrightness = -1;
mPendingScreenBrightnessSetting = -1;
mTemporaryAutoBrightnessAdjustment = Float.NaN;
+ mPendingAutoBrightnessAdjustment = Float.NaN;
}
/**
@@ -1499,6 +1500,7 @@
return false;
}
if (mAutoBrightnessAdjustment == mPendingAutoBrightnessAdjustment) {
+ mPendingAutoBrightnessAdjustment = Float.NaN;
return false;
}
mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b06dba9..ba6da05 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -88,7 +88,7 @@
* Provides a service for sending and processing HDMI control messages,
* HDMI-CEC and MHL control command, and providing the information on both standard.
*/
-public final class HdmiControlService extends SystemService {
+public class HdmiControlService extends SystemService {
private static final String TAG = "HdmiControlService";
private final Locale HONG_KONG = new Locale("zh", "HK");
private final Locale MACAU = new Locale("zh", "MO");
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 1078f6e..36b04fc 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2537,6 +2537,7 @@
* Returns a fixed pseudorandom byte string derived from the user's synthetic password.
* This is used to salt the password history hash to protect the hash against offline
* bruteforcing, since rederiving this value requires a successful authentication.
+ * If user is a managed profile with unified challenge, currentCredential is ignored.
*/
@Override
public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException {
@@ -2544,6 +2545,14 @@
if (TextUtils.isEmpty(currentCredential)) {
currentCredential = null;
}
+ if (isManagedProfileWithUnifiedLock(userId)) {
+ try {
+ currentCredential = getDecryptedPasswordForTiedProfile(userId);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to get work profile credential", e);
+ return null;
+ }
+ }
synchronized (mSpManager) {
if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
Slog.w(TAG, "Synthetic password not enabled");
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 5bd7c0b..ab482bb 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2706,6 +2706,9 @@
private void normalizePoliciesNL(NetworkPolicy[] policies) {
mNetworkPolicy.clear();
for (NetworkPolicy policy : policies) {
+ if (policy == null) {
+ continue;
+ }
// When two normalized templates conflict, prefer the most
// restrictive policy
policy.template = NetworkTemplate.normalize(policy.template, mMergedSubscriberIds);
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 4bee55e..a16dcf3 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -241,6 +241,20 @@
NetworkStats.Entry entry = null;
for (int i = 0; i < delta.size(); i++) {
entry = delta.getValues(i, entry);
+
+ // As a last-ditch sanity check, report any negative values and
+ // clamp them so recording below doesn't croak.
+ if (entry.isNegative()) {
+ if (mObserver != null) {
+ mObserver.foundNonMonotonic(delta, i, mCookie);
+ }
+ entry.rxBytes = Math.max(entry.rxBytes, 0);
+ entry.rxPackets = Math.max(entry.rxPackets, 0);
+ entry.txBytes = Math.max(entry.txBytes, 0);
+ entry.txPackets = Math.max(entry.txPackets, 0);
+ entry.operations = Math.max(entry.operations, 0);
+ }
+
final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
if (ident == null) {
unknownIfaces.add(entry.iface);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 3107241..aba75dd 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1711,7 +1711,7 @@
@Override
public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
int rightIndex, String cookie) {
- Log.w(TAG, "found non-monotonic values; saving to dropbox");
+ Log.w(TAG, "Found non-monotonic values; saving to dropbox");
// record error for debugging
final StringBuilder builder = new StringBuilder();
@@ -1720,9 +1720,21 @@
builder.append("left=").append(left).append('\n');
builder.append("right=").append(right).append('\n');
- final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService(
- Context.DROPBOX_SERVICE);
- dropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
+ mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
+ builder.toString());
+ }
+
+ @Override
+ public void foundNonMonotonic(
+ NetworkStats stats, int statsIndex, String cookie) {
+ Log.w(TAG, "Found non-monotonic values; saving to dropbox");
+
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Found non-monotonic " + cookie + " values at [" + statsIndex + "]\n");
+ builder.append("stats=").append(stats).append('\n');
+
+ mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
+ builder.toString());
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8db676a..75592fb 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -822,6 +822,7 @@
}
}
r.setVisibility(true, nv.rank, nv.count);
+ maybeRecordInterruptionLocked(r);
nv.recycle();
}
// Note that we might receive this event after notifications
@@ -1929,11 +1930,12 @@
@GuardedBy("mNotificationLock")
protected void maybeRecordInterruptionLocked(NotificationRecord r) {
- if (r.isInterruptive()) {
+ if (r.isInterruptive() && !r.hasRecordedInterruption()) {
mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
r.getChannel().getId(),
getRealUserId(r.sbn.getUserId()));
logRecentLocked(r);
+ r.setRecordedInterruption(true);
}
}
@@ -2670,6 +2672,7 @@
if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
reportSeen(r);
r.setSeen();
+ maybeRecordInterruptionLocked(r);
}
}
}
@@ -4441,7 +4444,7 @@
if (index < 0) {
mNotificationList.add(r);
mUsageStats.registerPostedByApp(r);
- r.setInterruptive(isVisuallyInterruptive(null, r));
+ r.setInterruptive(true);
} else {
old = mNotificationList.get(index);
mNotificationList.set(index, r);
@@ -4450,7 +4453,7 @@
notification.flags |=
old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
r.isUpdate = true;
- r.setInterruptive(isVisuallyInterruptive(old, r));
+ r.setTextChanged(isVisuallyInterruptive(old, r));
}
mNotificationsByKey.put(n.getKey(), r);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 2aec3ea..0f3f44e 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -158,6 +158,8 @@
private final NotificationStats mStats;
private int mUserSentiment;
private boolean mIsInterruptive;
+ private boolean mTextChanged;
+ private boolean mRecordedInterruption;
private int mNumberOfSmartRepliesAdded;
private boolean mHasSeenSmartReplies;
/**
@@ -839,6 +841,9 @@
/** Mark the notification as seen by the user. */
public void setSeen() {
mStats.setSeen();
+ if (mTextChanged) {
+ mIsInterruptive = true;
+ }
}
public void setAuthoritativeRank(int authoritativeRank) {
@@ -935,6 +940,18 @@
mIsInterruptive = interruptive;
}
+ public void setTextChanged(boolean textChanged) {
+ mTextChanged = textChanged;
+ }
+
+ public void setRecordedInterruption(boolean recorded) {
+ mRecordedInterruption = recorded;
+ }
+
+ public boolean hasRecordedInterruption() {
+ return mRecordedInterruption;
+ }
+
public boolean isInterruptive() {
return mIsInterruptive;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b05b900..2a2c877 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2075,6 +2075,16 @@
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds);
}
+ // if the required verifier is defined, but, is not the installer of record
+ // for the package, it gets notified
+ final boolean notifyVerifier = mRequiredVerifierPackage != null
+ && !mRequiredVerifierPackage.equals(installerPackageName);
+ if (notifyVerifier) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ extras, 0 /*flags*/,
+ mRequiredVerifierPackage, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
+ }
// Send replaced for users that don't see the package for the first time
if (update) {
@@ -2088,6 +2098,12 @@
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds);
}
+ if (notifyVerifier) {
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+ extras, 0 /*flags*/,
+ mRequiredVerifierPackage, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds);
+ }
sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
@@ -8799,8 +8815,16 @@
if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
// The version of the application on the /system partition is less than or
- // equal to the version on the /data partition. Throw an exception and use
- // the application already installed on the /data partition.
+ // equal to the version on the /data partition. Even though the disabled system package
+ // is likely to be replaced by a version on the /data partition, we make assumptions
+ // that it's part of the mPackages collection during package manager initialization. So,
+ // add it to mPackages if there isn't already a package in the collection and then throw
+ // an exception to use the application already installed on the /data partition.
+ synchronized (mPackages) {
+ if (!mPackages.containsKey(pkg.packageName)) {
+ mPackages.put(pkg.packageName, pkg);
+ }
+ }
throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
+ pkg.codePath + " ignored: updated version " + pkgSetting.versionCode
+ " better than this " + pkg.getLongVersionCode());
@@ -24418,6 +24442,9 @@
if (info.targetSdkVersion < Build.VERSION_CODES.O) {
return false;
}
+ if (isInstantApp(packageName, userId)) {
+ return false;
+ }
String appOpPermission = Manifest.permission.REQUEST_INSTALL_PACKAGES;
String[] packagesDeclaringPermission = getAppOpPermissionPackages(appOpPermission);
if (!ArrayUtils.contains(packagesDeclaringPermission, packageName)) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6005d61..407cb93 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -873,9 +873,8 @@
throw new SecurityException("MANAGE_USERS permission is required to start intent "
+ "after disabling quiet mode.");
}
- final boolean hasModifyQuietModePermission = ActivityManager.checkComponentPermission(
- Manifest.permission.MODIFY_QUIET_MODE,
- callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+ final boolean hasModifyQuietModePermission = hasPermissionGranted(
+ Manifest.permission.MODIFY_QUIET_MODE, callingUid);
if (hasModifyQuietModePermission) {
return;
}
@@ -1002,6 +1001,30 @@
}
}
+ @Override
+ public void setUserAdmin(int userId) {
+ checkManageUserAndAcrossUsersFullPermission("set user admin");
+
+ synchronized (mPackagesLock) {
+ UserInfo info;
+ synchronized (mUsersLock) {
+ info = getUserInfoLU(userId);
+ }
+ if (info == null || info.isAdmin()) {
+ // Exit if no user found with that id, or the user is already an Admin.
+ return;
+ }
+
+ info.flags ^= UserInfo.FLAG_ADMIN;
+ writeUserLP(getUserDataLU(info.id));
+ }
+
+ // Remove non-admin restrictions.
+ // Keep synchronized with createUserEvenWhenDisallowed.
+ setUserRestriction(UserManager.DISALLOW_SMS, false, userId);
+ setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, userId);
+ }
+
/**
* Evicts a user's CE key by stopping and restarting the user.
*
@@ -1122,8 +1145,8 @@
hasManageUsersPermission()) {
return;
}
- if (ActivityManager.checkComponentPermission(Manifest.permission.INTERACT_ACROSS_USERS,
- Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
+ if (!hasPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS,
+ Binder.getCallingUid())) {
throw new SecurityException("You need INTERACT_ACROSS_USERS or MANAGE_USERS permission "
+ "to: check " + name);
}
@@ -1801,17 +1824,26 @@
*/
private static final void checkManageUserAndAcrossUsersFullPermission(String message) {
final int uid = Binder.getCallingUid();
- if (uid != Process.SYSTEM_UID && uid != 0
- && ActivityManager.checkComponentPermission(
- Manifest.permission.MANAGE_USERS,
- uid, -1, true) != PackageManager.PERMISSION_GRANTED
- && ActivityManager.checkComponentPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "You need MANAGE_USERS and INTERACT_ACROSS_USERS_FULL permission to: "
- + message);
+
+ if (uid == Process.SYSTEM_UID || uid == 0) {
+ // System UID or root's UID are granted privilege.
+ return;
}
+
+ if (hasPermissionGranted(Manifest.permission.MANAGE_USERS, uid)
+ && hasPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid)) {
+ // Apps with both permissions are granted privilege.
+ return;
+ }
+
+ throw new SecurityException(
+ "You need MANAGE_USERS and INTERACT_ACROSS_USERS_FULL permission to: " + message);
+ }
+
+ private static boolean hasPermissionGranted(String permission, int uid) {
+ return ActivityManager.checkComponentPermission(
+ permission, uid, /* owningUid = */-1, /* exported = */ true) ==
+ PackageManager.PERMISSION_GRANTED;
}
/**
@@ -1872,9 +1904,7 @@
final int callingUid = Binder.getCallingUid();
return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
|| callingUid == Process.ROOT_UID
- || ActivityManager.checkComponentPermission(
- android.Manifest.permission.MANAGE_USERS,
- callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+ || hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid);
}
/**
@@ -1886,12 +1916,8 @@
final int callingUid = Binder.getCallingUid();
return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
|| callingUid == Process.ROOT_UID
- || ActivityManager.checkComponentPermission(
- android.Manifest.permission.MANAGE_USERS,
- callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
- || ActivityManager.checkComponentPermission(
- android.Manifest.permission.CREATE_USERS,
- callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+ || hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid)
+ || hasPermissionGranted(android.Manifest.permission.CREATE_USERS, callingUid);
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c73ab75..199098b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -234,7 +234,6 @@
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.DisplayCutout;
-import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IApplicationToken;
@@ -2292,6 +2291,11 @@
public void onTrustedChanged() {
mWindowManagerFuncs.notifyKeyguardTrustedChanged();
}
+
+ @Override
+ public void onShowingChanged() {
+ mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
+ }
});
mScreenshotHelper = new ScreenshotHelper(mContext);
}
@@ -6643,6 +6647,8 @@
}
void launchVoiceAssistWithWakeLock() {
+ sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
+
final Intent voiceIntent;
if (!keyguardOn()) {
voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 89ae468..a1e54b6 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -653,6 +653,11 @@
* abort animations that have no timeout, in case they got stuck.
*/
void triggerAnimationFailsafe();
+
+ /**
+ * The keyguard showing state has changed
+ */
+ void onKeyguardShowingAndNotOccludedChanged();
}
/** Window has been added to the screen. */
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index e56caf8..1cba1c7 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -94,6 +94,7 @@
public void onShowingStateChanged(boolean showing) {
mIsShowing = showing;
+ mCallback.onShowingChanged();
try {
mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
} catch (RemoteException e) {
@@ -132,6 +133,7 @@
public interface StateCallback {
void onTrustedChanged();
+ void onShowingChanged();
}
public void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 2621c50..c3b9841 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -55,6 +55,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml.Encoding;
import com.android.internal.annotations.GuardedBy;
@@ -77,6 +78,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.function.Supplier;
public class SliceManagerService extends ISliceManager.Stub {
@@ -90,6 +92,10 @@
@GuardedBy("mLock")
private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private final SparseArray<PackageMatchingCache> mAssistantLookup = new SparseArray<>();
+ @GuardedBy("mLock")
+ private final SparseArray<PackageMatchingCache> mHomeLookup = new SparseArray<>();
private final Handler mHandler;
private final SlicePermissionManager mPermissions;
@@ -453,17 +459,37 @@
}
private boolean isAssistant(String pkg, int userId) {
- final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
- if (cn == null) {
- return false;
- }
- return cn.getPackageName().equals(pkg);
+ return getAssistantMatcher(userId).matches(pkg);
}
private boolean isDefaultHomeApp(String pkg, int userId) {
- String defaultHome = getDefaultHome(userId);
+ return getHomeMatcher(userId).matches(pkg);
+ }
- return pkg != null && Objects.equals(pkg, defaultHome);
+ private PackageMatchingCache getAssistantMatcher(int userId) {
+ PackageMatchingCache matcher = mAssistantLookup.get(userId);
+ if (matcher == null) {
+ matcher = new PackageMatchingCache(() -> getAssistant(userId));
+ mAssistantLookup.put(userId, matcher);
+ }
+ return matcher;
+ }
+
+ private PackageMatchingCache getHomeMatcher(int userId) {
+ PackageMatchingCache matcher = mHomeLookup.get(userId);
+ if (matcher == null) {
+ matcher = new PackageMatchingCache(() -> getDefaultHome(userId));
+ mHomeLookup.put(userId, matcher);
+ }
+ return matcher;
+ }
+
+ private String getAssistant(int userId) {
+ final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
+ if (cn == null) {
+ return null;
+ }
+ return cn.getPackageName();
}
// Based on getDefaultHome in ShortcutService.
@@ -559,6 +585,30 @@
return mPermissions.getAllPackagesGranted(pkg);
}
+ /**
+ * Holder that caches a package that has access to a slice.
+ */
+ static class PackageMatchingCache {
+
+ private final Supplier<String> mPkgSource;
+ private String mCurrentPkg;
+
+ public PackageMatchingCache(Supplier<String> pkgSource) {
+ mPkgSource = pkgSource;
+ }
+
+ public boolean matches(String pkgCandidate) {
+ if (pkgCandidate == null) return false;
+
+ if (Objects.equals(pkgCandidate, mCurrentPkg)) {
+ return true;
+ }
+ // Failed on cached value, try updating.
+ mCurrentPkg = mPkgSource.get();
+ return Objects.equals(pkgCandidate, mCurrentPkg);
+ }
+ }
+
public static class Lifecycle extends SystemService {
private SliceManagerService mService;
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 3798416..4d65440 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
import android.app.PendingIntent;
import android.app.ProcessMemoryState;
import android.app.StatsManager;
@@ -124,9 +125,9 @@
private static IStatsManager sStatsd;
private static final Object sStatsdLock = new Object();
- private final PendingIntent mAnomalyAlarmIntent;
- private final PendingIntent mPullingAlarmIntent;
- private final PendingIntent mPeriodicAlarmIntent;
+ private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener();
+ private final OnAlarmListener mPullingAlarmListener = new PullingAlarmListener();
+ private final OnAlarmListener mPeriodicAlarmListener = new PeriodicAlarmListener();
private final BroadcastReceiver mAppUpdateReceiver;
private final BroadcastReceiver mUserUpdateReceiver;
private final ShutdownEventReceiver mShutdownEventReceiver;
@@ -158,12 +159,6 @@
mContext = context;
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent(mContext, AnomalyAlarmReceiver.class), 0);
- mPullingAlarmIntent = PendingIntent.getBroadcast(
- mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
- mPeriodicAlarmIntent = PendingIntent.getBroadcast(
- mContext, 0, new Intent(mContext, PeriodicAlarmReceiver.class), 0);
mAppUpdateReceiver = new AppUpdateReceiver();
mUserUpdateReceiver = new BroadcastReceiver() {
@Override
@@ -345,9 +340,9 @@
}
}
- public final static class AnomalyAlarmReceiver extends BroadcastReceiver {
+ public final static class AnomalyAlarmListener implements OnAlarmListener {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onAlarm() {
Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+ System.currentTimeMillis() + "ms.");
synchronized (sStatsdLock) {
@@ -366,9 +361,9 @@
}
}
- public final static class PullingAlarmReceiver extends BroadcastReceiver {
+ public final static class PullingAlarmListener implements OnAlarmListener {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onAlarm() {
if (DEBUG)
Slog.d(TAG, "Time to poll something.");
synchronized (sStatsdLock) {
@@ -386,9 +381,9 @@
}
}
- public final static class PeriodicAlarmReceiver extends BroadcastReceiver {
+ public final static class PeriodicAlarmListener implements OnAlarmListener {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onAlarm() {
if (DEBUG)
Slog.d(TAG, "Time to trigger periodic alarm.");
synchronized (sStatsdLock) {
@@ -442,9 +437,9 @@
try {
// using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
// only fire when it awakens.
- // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
- // AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm.
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, mAnomalyAlarmIntent);
+ // AlarmManager will automatically cancel any previous mAnomalyAlarmListener alarm.
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".anomaly",
+ mAnomalyAlarmListener, null);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -456,7 +451,7 @@
if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm");
final long callingToken = Binder.clearCallingIdentity();
try {
- mAlarmManager.cancel(mAnomalyAlarmIntent);
+ mAlarmManager.cancel(mAnomalyAlarmListener);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -472,7 +467,8 @@
try {
// using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
// only fire when it awakens.
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent);
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".periodic",
+ mPeriodicAlarmListener, null);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -485,7 +481,7 @@
Slog.d(TAG, "Cancelling periodic alarm");
final long callingToken = Binder.clearCallingIdentity();
try {
- mAlarmManager.cancel(mPeriodicAlarmIntent);
+ mAlarmManager.cancel(mPeriodicAlarmListener);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -493,31 +489,33 @@
@Override // Binder call
public void setPullingAlarm(long nextPullTimeMs) {
- enforceCallingPermission();
- if (DEBUG)
- Slog.d(TAG,
- "Setting pulling alarm in about " + (nextPullTimeMs - SystemClock.elapsedRealtime()));
- final long callingToken = Binder.clearCallingIdentity();
- try {
- // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
- // only fire when it awakens.
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, mPullingAlarmIntent);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
+ enforceCallingPermission();
+ if (DEBUG) {
+ Slog.d(TAG, "Setting pulling alarm in about "
+ + (nextPullTimeMs - SystemClock.elapsedRealtime()));
+ }
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
+ // only fire when it awakens.
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, TAG + ".pull",
+ mPullingAlarmListener, null);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
}
@Override // Binder call
public void cancelPullingAlarm() {
- enforceCallingPermission();
- if (DEBUG)
- Slog.d(TAG, "Cancelling pulling alarm");
- final long callingToken = Binder.clearCallingIdentity();
- try {
- mAlarmManager.cancel(mPullingAlarmIntent);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
+ enforceCallingPermission();
+ if (DEBUG)
+ Slog.d(TAG, "Cancelling pulling alarm");
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ mAlarmManager.cancel(mPullingAlarmListener);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
}
private void addNetworkStats(
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index a7c203d..2886126 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -51,6 +51,7 @@
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
@@ -75,6 +76,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
@@ -336,6 +338,102 @@
}
}
+ /**
+ * Observes changes of theme settings. It will check whether to call
+ * notifyWallpaperColorsChanged by the current theme and updated theme.
+ * The light theme and dark theme are controlled by the hint values in Wallpaper colors,
+ * threrfore, if light theme mode is chosen, HINT_SUPPORTS_DARK_THEME in hint will be
+ * removed and then notify listeners.
+ */
+ private class ThemeSettingsObserver extends ContentObserver {
+
+ public ThemeSettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void startObserving(Context context) {
+ context.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.THEME_MODE),
+ false,
+ this);
+ }
+
+ public void stopObserving(Context context) {
+ context.getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ onThemeSettingsChanged();
+ }
+ }
+
+ /**
+ * Check whether to call notifyWallpaperColorsChanged. Assumed that the theme mode
+ * was wallpaper theme mode and dark wallpaper was set, therefoe, the theme was dark.
+ * Then theme mode changing to dark theme mode, however, theme should not update since
+ * theme was dark already.
+ */
+ private boolean needUpdateLocked(WallpaperColors colors, int themeMode) {
+ if (colors == null) {
+ return false;
+ }
+
+ if (themeMode == mThemeMode) {
+ return false;
+ }
+
+ boolean result = true;
+ boolean supportDarkTheme =
+ (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
+ switch (themeMode) {
+ case Settings.Secure.THEME_MODE_WALLPAPER:
+ if (mThemeMode == Settings.Secure.THEME_MODE_LIGHT) {
+ result = supportDarkTheme;
+ } else {
+ result = !supportDarkTheme;
+ }
+ break;
+ case Settings.Secure.THEME_MODE_LIGHT:
+ if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER) {
+ result = supportDarkTheme;
+ }
+ break;
+ case Settings.Secure.THEME_MODE_DARK:
+ if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER) {
+ result = !supportDarkTheme;
+ }
+ break;
+ default:
+ Slog.w(TAG, "unkonwn theme mode " + themeMode);
+ return false;
+ }
+ mThemeMode = themeMode;
+ return result;
+ }
+
+ void onThemeSettingsChanged() {
+ WallpaperData wallpaper;
+ synchronized (mLock) {
+ wallpaper = mWallpaperMap.get(mCurrentUserId);
+ int updatedThemeMode = Settings.Secure.getInt(
+ mContext.getContentResolver(), Settings.Secure.THEME_MODE,
+ Settings.Secure.THEME_MODE_WALLPAPER);
+
+ if (DEBUG) {
+ Slog.v(TAG, "onThemeSettingsChanged, mode = " + updatedThemeMode);
+ }
+
+ if (!needUpdateLocked(wallpaper.primaryColors, updatedThemeMode)) {
+ return;
+ }
+ }
+
+ if (wallpaper != null) {
+ notifyWallpaperColorsChanged(wallpaper, FLAG_SYSTEM);
+ }
+ }
+
void notifyLockWallpaperChanged() {
final IWallpaperManagerCallback cb = mKeyguardListener;
if (cb != null) {
@@ -413,6 +511,7 @@
}
userAllColorListeners.finishBroadcast();
}
+ wallpaperColors = getThemeColorsLocked(wallpaperColors);
}
final int count = colorListeners.size();
@@ -481,6 +580,40 @@
}
/**
+ * We can easily change theme by modified colors hint. This function will check
+ * current theme mode and return the WallpaperColors fit current theme mode.
+ * If color need modified, it will return a copied WallpaperColors which
+ * its ColorsHint is modified to fit current theme mode.
+ *
+ * @param colors a wallpaper primary colors representation
+ */
+ private WallpaperColors getThemeColorsLocked(WallpaperColors colors) {
+ if (colors == null) {
+ Slog.w(TAG, "Cannot get theme colors because WallpaperColors is null.");
+ return null;
+ }
+
+ int colorHints = colors.getColorHints();
+ boolean supportDarkTheme = (colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
+ if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER ||
+ (mThemeMode == Settings.Secure.THEME_MODE_LIGHT && !supportDarkTheme) ||
+ (mThemeMode == Settings.Secure.THEME_MODE_DARK && supportDarkTheme)) {
+ return colors;
+ }
+
+ WallpaperColors themeColors = new WallpaperColors(colors.getPrimaryColor(),
+ colors.getSecondaryColor(), colors.getTertiaryColor());
+
+ if (mThemeMode == Settings.Secure.THEME_MODE_LIGHT) {
+ colorHints &= ~WallpaperColors.HINT_SUPPORTS_DARK_THEME;
+ } else if (mThemeMode == Settings.Secure.THEME_MODE_DARK) {
+ colorHints |= WallpaperColors.HINT_SUPPORTS_DARK_THEME;
+ }
+ themeColors.setColorHints(colorHints);
+ return themeColors;
+ }
+
+ /**
* Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
* for display.
*/
@@ -676,6 +809,7 @@
final SparseArray<Boolean> mUserRestorecon = new SparseArray<Boolean>();
int mCurrentUserId = UserHandle.USER_NULL;
boolean mInAmbientMode;
+ int mThemeMode;
static class WallpaperData {
@@ -734,6 +868,7 @@
long lastDiedTime;
boolean wallpaperUpdating;
WallpaperObserver wallpaperObserver;
+ ThemeSettingsObserver themeSettingsObserver;
/**
* List of callbacks registered they should each be notified when the wallpaper is changed.
@@ -1279,6 +1414,10 @@
wallpaper.wallpaperObserver.stopWatching();
wallpaper.wallpaperObserver = null;
}
+ if (wallpaper.themeSettingsObserver != null) {
+ wallpaper.themeSettingsObserver.stopObserving(mContext);
+ wallpaper.themeSettingsObserver = null;
+ }
}
}
@@ -1362,6 +1501,13 @@
systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
systemWallpaper.wallpaperObserver.startWatching();
}
+ if (systemWallpaper.themeSettingsObserver == null) {
+ systemWallpaper.themeSettingsObserver = new ThemeSettingsObserver(null);
+ systemWallpaper.themeSettingsObserver.startObserving(mContext);
+ }
+ mThemeMode = Settings.Secure.getInt(
+ mContext.getContentResolver(), Settings.Secure.THEME_MODE,
+ Settings.Secure.THEME_MODE_WALLPAPER);
switchWallpaper(systemWallpaper, reply);
}
@@ -1835,7 +1981,7 @@
}
synchronized (mLock) {
- return wallpaperData.primaryColors;
+ return getThemeColorsLocked(wallpaperData.primaryColors);
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 50d0d0a..a709c55 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -157,10 +157,18 @@
}
WindowState computeFocusedWindow() {
+ // While the keyguard is showing, we must focus anything besides the main display.
+ // Otherwise we risk input not going to the keyguard when the user expects it to.
+ final boolean forceDefaultDisplay = mService.isKeyguardShowingAndNotOccluded();
+
for (int i = mChildren.size() - 1; i >= 0; i--) {
final DisplayContent dc = mChildren.get(i);
final WindowState win = dc.findFocusedWindow();
if (win != null) {
+ if (forceDefaultDisplay && !dc.isDefaultDisplay) {
+ EventLog.writeEvent(0x534e4554, "71786287", win.mOwnerUid, "");
+ continue;
+ }
return win;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 05626eb..ab19b82 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2845,6 +2845,11 @@
mH.sendEmptyMessage(H.ANIMATION_FAILSAFE);
}
+ @Override
+ public void onKeyguardShowingAndNotOccludedChanged() {
+ mH.sendEmptyMessage(H.RECOMPUTE_FOCUS);
+ }
+
/**
* Starts deferring layout passes. Useful when doing multiple changes but to optimize
* performance, only one layout pass should be done. This can be called multiple times, and
@@ -4615,6 +4620,7 @@
public static final int SET_HAS_OVERLAY_UI = 58;
public static final int SET_RUNNING_REMOTE_ANIMATION = 59;
public static final int ANIMATION_FAILSAFE = 60;
+ public static final int RECOMPUTE_FOCUS = 61;
/**
* Used to denote that an integer field in a message will not be used.
@@ -5041,6 +5047,13 @@
}
}
break;
+ case RECOMPUTE_FOCUS: {
+ synchronized (mWindowMap) {
+ updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+ true /* updateInputWindows */);
+ }
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7e86f3a..0c9ed21 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2298,8 +2298,8 @@
if (DEBUG_FOCUS_LIGHT) Slog.i(TAG,
"setAnimationLocked: setting mFocusMayChange true");
mService.mFocusMayChange = true;
- setDisplayLayoutNeeded();
}
+ setDisplayLayoutNeeded();
// Window is no longer visible -- make sure if we were waiting
// for it to be displayed before enabling the display, that
// we allow the display to be enabled now.
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 70287db..d247960 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -644,6 +644,11 @@
? null : wallpaperTarget;
final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
+ final AppWindowToken topOpeningApp = getTopApp(mService.mOpeningApps,
+ false /* ignoreHidden */);
+ final AppWindowToken topClosingApp = getTopApp(mService.mClosingApps,
+ true /* ignoreHidden */);
+
boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New wallpaper target=" + wallpaperTarget
@@ -677,13 +682,15 @@
"New transit: " + AppTransition.appTransitionToString(transit));
} else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
&& !openingApps.contains(oldWallpaper.mAppToken)
- && closingApps.contains(oldWallpaper.mAppToken)) {
+ && closingApps.contains(oldWallpaper.mAppToken)
+ && topClosingApp == oldWallpaper.mAppToken) {
// We are transitioning from an activity with a wallpaper to one without.
transit = TRANSIT_WALLPAPER_CLOSE;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
+ AppTransition.appTransitionToString(transit));
} else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
&& openingApps.contains(wallpaperTarget.mAppToken)
+ && topOpeningApp == wallpaperTarget.mAppToken
&& transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
// We are transitioning from an activity without
// a wallpaper to now showing the wallpaper
@@ -748,6 +755,31 @@
return false;
}
+ /**
+ * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
+ * compare z-order.
+ *
+ * @param apps The list of apps to search.
+ * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
+ * @return The top {@link AppWindowToken}.
+ */
+ private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
+ int topPrefixOrderIndex = Integer.MIN_VALUE;
+ AppWindowToken topApp = null;
+ for (int i = apps.size() - 1; i >= 0; i--) {
+ final AppWindowToken app = apps.valueAt(i);
+ if (ignoreHidden && app.isHidden()) {
+ continue;
+ }
+ final int prefixOrderIndex = app.getPrefixOrderIndex();
+ if (prefixOrderIndex > topPrefixOrderIndex) {
+ topPrefixOrderIndex = prefixOrderIndex;
+ topApp = app;
+ }
+ }
+ return topApp;
+ }
+
private void processApplicationsAnimatingInPlace(int transit) {
if (transit == TRANSIT_TASK_IN_PLACE) {
// Find the focused window
diff --git a/services/net/java/android/net/dns/ResolvUtil.java b/services/net/java/android/net/dns/ResolvUtil.java
index a2a6615..d9d4b96 100644
--- a/services/net/java/android/net/dns/ResolvUtil.java
+++ b/services/net/java/android/net/dns/ResolvUtil.java
@@ -16,6 +16,8 @@
package android.net.dns;
+import static android.system.OsConstants.AI_ADDRCONFIG;
+
import android.net.Network;
import android.net.NetworkUtils;
import android.system.GaiException;
@@ -41,12 +43,17 @@
public static InetAddress[] blockingResolveAllLocally(Network network, String name)
throws UnknownHostException {
+ // Use AI_ADDRCONFIG by default
+ return blockingResolveAllLocally(network, name, AI_ADDRCONFIG);
+ }
+
+ public static InetAddress[] blockingResolveAllLocally(
+ Network network, String name, int aiFlags) throws UnknownHostException {
final StructAddrinfo hints = new StructAddrinfo();
- // Unnecessary, but expressly no AI_ADDRCONFIG.
- hints.ai_flags = 0;
- // Fetch all IP addresses at once to minimize re-resolution.
+ hints.ai_flags = aiFlags;
+ // Other hints identical to the default Inet6AddressImpl implementation
hints.ai_family = OsConstants.AF_UNSPEC;
- hints.ai_socktype = OsConstants.SOCK_DGRAM;
+ hints.ai_socktype = OsConstants.SOCK_STREAM;
final Network networkForResolv = getNetworkWithUseLocalNameserversFlag(network);
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
index 340100f..8399aaf 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -76,10 +76,9 @@
@RunWith(FrameworkRobolectricTestRunner.class)
@Config(
- manifest = Config.NONE,
- sdk = 26,
- shadows = {ShadowAppBackupUtils.class, ShadowBackupPolicyEnforcer.class}
-)
+ manifest = Config.NONE,
+ sdk = 26,
+ shadows = {ShadowAppBackupUtils.class, ShadowBackupPolicyEnforcer.class})
@SystemLoaderPackages({"com.android.server.backup"})
@Presubmit
public class BackupManagerServiceTest {
@@ -406,6 +405,51 @@
mContext.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
}
+ /* Tests for transport attributes */
+
+ @Test
+ public void testGetCurrentTransportComponent() throws Exception {
+ mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+ when(mTransportManager.getCurrentTransportComponent())
+ .thenReturn(mTransport.getTransportComponent());
+ BackupManagerService backupManagerService = createInitializedBackupManagerService();
+
+ ComponentName transportComponent = backupManagerService.getCurrentTransportComponent();
+
+ assertThat(transportComponent).isEqualTo(mTransport.getTransportComponent());
+ }
+
+ @Test
+ public void testGetCurrentTransportComponent_whenNoTransportSelected() throws Exception {
+ mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+ when(mTransportManager.getCurrentTransportComponent()).thenReturn(null);
+ BackupManagerService backupManagerService = createInitializedBackupManagerService();
+
+ ComponentName transportComponent = backupManagerService.getCurrentTransportComponent();
+
+ assertThat(transportComponent).isNull();
+ }
+
+ @Test
+ public void testGetCurrentTransportComponent_whenTransportNotRegistered() throws Exception {
+ mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+ when(mTransportManager.getCurrentTransportComponent())
+ .thenThrow(TransportNotRegisteredException.class);
+ BackupManagerService backupManagerService = createInitializedBackupManagerService();
+
+ ComponentName transportComponent = backupManagerService.getCurrentTransportComponent();
+
+ assertThat(transportComponent).isNull();
+ }
+
+ @Test
+ public void testGetCurrentTransportComponent_withoutPermission() throws Exception {
+ mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
+ BackupManagerService backupManagerService = createInitializedBackupManagerService();
+
+ expectThrows(SecurityException.class, backupManagerService::getCurrentTransportComponent);
+ }
+
/* Tests for updating transport attributes */
private static final int PACKAGE_UID = 10;
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index c2e7595..051a4a0 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -77,10 +77,9 @@
@RunWith(FrameworkRobolectricTestRunner.class)
@Config(
- manifest = Config.NONE,
- sdk = 26,
- shadows = {FrameworkShadowContextImpl.class}
-)
+ manifest = Config.NONE,
+ sdk = 26,
+ shadows = {FrameworkShadowContextImpl.class})
@SystemLoaderPackages({"com.android.server.backup"})
@Presubmit
public class TransportManagerTest {
@@ -394,6 +393,36 @@
}
@Test
+ public void testGetCurrentTransportComponent() throws Exception {
+ TransportManager transportManager =
+ createTransportManagerWithRegisteredTransports(mTransportA1);
+
+ ComponentName transportComponent = transportManager.getCurrentTransportComponent();
+
+ assertThat(transportComponent).isEqualTo(mTransportA1.getTransportComponent());
+ }
+
+ @Test
+ public void testGetCurrentTransportComponent_whenNoTransportSelected() throws Exception {
+ TransportManager transportManager =
+ createTransportManagerWithRegisteredTransports(null, mTransportA1);
+
+ ComponentName transportComponent = transportManager.getCurrentTransportComponent();
+
+ assertThat(transportComponent).isNull();
+ }
+
+ @Test
+ public void testGetCurrentTransportComponent_whenTransportNotRegistered() throws Exception {
+ TransportManager transportManager =
+ createTransportManagerWithRegisteredTransports(mTransportA1.unregistered());
+
+ expectThrows(
+ TransportNotRegisteredException.class,
+ transportManager::getCurrentTransportComponent);
+ }
+
+ @Test
public void testGetTransportClient_forRegisteredTransport() throws Exception {
TransportManager transportManager =
createTransportManagerWithRegisteredTransports(mTransportA1, mTransportA2);
diff --git a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
index 1fbadd4..5844131 100644
--- a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
+++ b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
@@ -55,6 +55,9 @@
ShadowPackageManager shadowPackageManager, TransportData... transports)
throws Exception {
for (TransportData transport : transports) {
+ if (transport.transportStatus == TransportStatus.UNREGISTERED) {
+ continue;
+ }
ComponentName transportComponent = transport.getTransportComponent();
String packageName = transportComponent.getPackageName();
ResolveInfo resolveInfo = resolveInfo(transportComponent);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index b4dc941..17babe9 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -1628,6 +1628,20 @@
}
}
+ /**
+ * Test that policy set of {null, NetworkPolicy, null} does not crash and restores the valid
+ * NetworkPolicy.
+ */
+ @Test
+ public void testSetNetworkPolicies_withNullPolicies_doesNotThrow() {
+ NetworkPolicy[] policies = new NetworkPolicy[3];
+ policies[1] = buildDefaultFakeMobilePolicy();
+ setNetworkPolicies(policies);
+
+ assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
+ true);
+ }
+
private SubscriptionPlan buildMonthlyDataPlan(ZonedDateTime start, long limitBytes) {
return SubscriptionPlan.Builder
.createRecurringMonthly(start)
diff --git a/services/tests/servicestests/src/com/android/server/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/ColorDisplayServiceTest.java
rename to services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
index c004074..6bd8011 100644
--- a/services/tests/servicestests/src/com/android/server/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.display;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -32,8 +32,8 @@
import com.android.internal.app.ColorDisplayController;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.display.DisplayTransformManager;
-import com.android.server.display.ColorDisplayService;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
new file mode 100644
index 0000000..1089f69
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2018 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.server.hdmi;
+
+import android.content.Context;
+import android.hardware.hdmi.HdmiPortInfo;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.os.test.TestLooper;
+import android.support.test.filters.SmallTest;
+import android.util.Log;
+import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
+import com.android.server.hdmi.HdmiCecController.NativeWrapper;
+
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM;
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK;
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
+import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_3;
+import static com.android.server.hdmi.Constants.ADDR_SPECIFIC_USE;
+import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
+import static junit.framework.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link com.android.server.hdmi.HdmiCecController} class.
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class HdmiCecControllerTest {
+
+ private static final class NativeWrapperImpl implements NativeWrapper {
+
+ @Override
+ public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
+ return 1L;
+ }
+
+ @Override
+ public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
+ byte[] body) {
+ return mOccupied[srcAddress] ? 0 : 1;
+ }
+
+ @Override
+ public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
+ return 0;
+ }
+
+ @Override
+ public void nativeClearLogicalAddress(long controllerPtr) {
+
+ }
+
+ @Override
+ public int nativeGetPhysicalAddress(long controllerPtr) {
+ return 0;
+ }
+
+ @Override
+ public int nativeGetVersion(long controllerPtr) {
+ return 0;
+ }
+
+ @Override
+ public int nativeGetVendorId(long controllerPtr) {
+ return 0;
+ }
+
+ @Override
+ public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
+ return new HdmiPortInfo[0];
+ }
+
+ @Override
+ public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {
+
+ }
+
+ @Override
+ public void nativeSetLanguage(long controllerPtr, String language) {
+
+ }
+
+ @Override
+ public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {
+
+ }
+
+ @Override
+ public boolean nativeIsConnected(long controllerPtr, int port) {
+ return false;
+ }
+ }
+
+ private class MyHdmiControlService extends HdmiControlService {
+
+ MyHdmiControlService(Context context) {
+ super(context);
+ }
+
+ @Override
+ Looper getIoLooper() {
+ return mMyLooper;
+ }
+
+ @Override
+ Looper getServiceLooper() {
+ return mMyLooper;
+ }
+ }
+
+ private static final String TAG = HdmiCecControllerTest.class.getSimpleName();
+ private HdmiControlService mHdmiControlService;
+ private HdmiCecController mHdmiCecController;
+ private static boolean[] mOccupied = new boolean[15];
+ private int mLogicalAddress = 16;
+ private AllocateAddressCallback mCallback = new AllocateAddressCallback() {
+ @Override
+ public void onAllocated(int deviceType, int logicalAddress) {
+ mLogicalAddress = logicalAddress;
+ }
+ };
+ private Looper mMyLooper;
+ private TestLooper mTestLooper = new TestLooper();
+
+ @Before
+ public void SetUp() {
+ mMyLooper = mTestLooper.getLooper();
+ mMyLooper = mTestLooper.getLooper();
+ mHdmiControlService = new MyHdmiControlService(null);
+ mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+ mHdmiControlService, new NativeWrapperImpl());
+ }
+
+ /**
+ * Tests for {@link HdmiCecController#allocateLogicalAddress}
+ */
+ @Test
+ public void testAllocatLogicalAddress_TvDevicePreferredNotOcupied() {
+ mOccupied[ADDR_TV] = false;
+ mOccupied[ADDR_SPECIFIC_USE] = false;
+ mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_TV, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_TV, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_TvDeviceNonPreferredNotOcupied() {
+ mOccupied[ADDR_TV] = false;
+ mOccupied[ADDR_SPECIFIC_USE] = false;
+ mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_TV, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_TvDeviceNonPreferredFirstOcupied() {
+ mOccupied[ADDR_TV] = true;
+ mOccupied[ADDR_SPECIFIC_USE] = false;
+ mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_SPECIFIC_USE, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_TvDeviceNonPreferredAllOcupied() {
+ mOccupied[ADDR_TV] = true;
+ mOccupied[ADDR_SPECIFIC_USE] = true;
+ mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_AudioSystemNonPreferredNotOcupied() {
+ mOccupied[ADDR_AUDIO_SYSTEM] = false;
+ mHdmiCecController.allocateLogicalAddress(
+ DEVICE_AUDIO_SYSTEM, ADDR_UNREGISTERED, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_AUDIO_SYSTEM, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_AudioSystemNonPreferredAllOcupied() {
+ mOccupied[ADDR_AUDIO_SYSTEM] = true;
+ mHdmiCecController.allocateLogicalAddress(
+ DEVICE_AUDIO_SYSTEM, ADDR_UNREGISTERED, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_PlaybackPreferredNotOccupied() {
+ mOccupied[ADDR_PLAYBACK_1] = false;
+ mOccupied[ADDR_PLAYBACK_2] = false;
+ mOccupied[ADDR_PLAYBACK_3] = false;
+ mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_PLAYBACK_1, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_PlaybackPreferredOcuppied() {
+ mOccupied[ADDR_PLAYBACK_1] = true;
+ mOccupied[ADDR_PLAYBACK_2] = false;
+ mOccupied[ADDR_PLAYBACK_3] = false;
+ mHdmiCecController.allocateLogicalAddress(
+ DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_PLAYBACK_2, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_PlaybackNoPreferredNotOcuppied() {
+ mOccupied[ADDR_PLAYBACK_1] = false;
+ mOccupied[ADDR_PLAYBACK_2] = false;
+ mOccupied[ADDR_PLAYBACK_3] = false;
+ mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_PLAYBACK_1, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_PlaybackNoPreferredFirstOcuppied() {
+ mOccupied[ADDR_PLAYBACK_1] = true;
+ mOccupied[ADDR_PLAYBACK_2] = false;
+ mOccupied[ADDR_PLAYBACK_3] = false;
+ mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_PLAYBACK_2, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_PlaybackNonPreferredFirstTwoOcuppied() {
+ mOccupied[ADDR_PLAYBACK_1] = true;
+ mOccupied[ADDR_PLAYBACK_2] = true;
+ mOccupied[ADDR_PLAYBACK_3] = false;
+ mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_PLAYBACK_3, mLogicalAddress);
+ }
+
+ @Test
+ public void testAllocatLogicalAddress_PlaybackNonPreferredAllOcupied() {
+ mOccupied[ADDR_PLAYBACK_1] = true;
+ mOccupied[ADDR_PLAYBACK_2] = true;
+ mOccupied[ADDR_PLAYBACK_3] = true;
+ mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
+ mTestLooper.dispatchAll();
+ assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 142b950..94e02bc 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -448,6 +448,39 @@
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
}
+ public void testgetHashFactorPrimaryUser() throws RemoteException {
+ final String password = "password";
+ mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
+ assertNotNull(hashFactor);
+
+ mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
+ PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
+ assertNotNull(newHashFactor);
+ // Hash factor should never change after password change/removal
+ assertArrayEquals(hashFactor, newHashFactor);
+ }
+
+ public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
+ final String pattern = "1236";
+ mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null,
+ PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+ assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
+ }
+
+ public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException {
+ final String primaryPassword = "primary";
+ final String profilePassword = "profile";
+ mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID);
+ assertNotNull(mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID));
+ }
+
public void testPasswordData_serializeDeserialize() {
PasswordData data = new PasswordData();
data.scryptN = 11;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index dd9a8ab..7bcb571 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -170,6 +170,31 @@
}
@MediumTest
+ public void testSetUserAdmin() throws Exception {
+ UserInfo userInfo = createUser("SecondaryUser", /*flags=*/ 0);
+
+ // Assert user is not admin and has SMS and calls restrictions.
+ assertFalse(userInfo.isAdmin());
+ assertTrue(mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS,
+ userInfo.getUserHandle()));
+ assertTrue(mUserManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
+ userInfo.getUserHandle()));
+
+ // Assign admin privileges.
+ mUserManager.setUserAdmin(userInfo.id);
+
+ // Refresh.
+ userInfo = mUserManager.getUserInfo(userInfo.id);
+
+ // Verify user became admin and SMS and call restrictions are lifted.
+ assertTrue(userInfo.isAdmin());
+ assertFalse(mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS,
+ userInfo.getUserHandle()));
+ assertFalse(mUserManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
+ userInfo.getUserHandle()));
+ }
+
+ @MediumTest
public void testGetProfileParent() throws Exception {
final int primaryUserId = mUserManager.getPrimaryUser().id;
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 845095a..ac196f9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -329,6 +329,21 @@
assertEquals(window1, sWm.mRoot.computeFocusedWindow());
}
+ @Test
+ public void testKeyguard_preventsSecondaryDisplayFocus() throws Exception {
+ final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR,
+ sWm.getDefaultDisplayContentLocked(), "keyguard");
+ assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
+
+ // Add a window to a second display, and it should be focused
+ final DisplayContent dc = createNewDisplay();
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+ assertEquals(win, sWm.mRoot.computeFocusedWindow());
+
+ mWmRule.getWindowManagerPolicy().keyguardShowingAndNotOccluded = true;
+ assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
+ }
+
/**
* This tests setting the maximum ui width on a display.
*/
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 765b3d5..50f3fbe 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -51,6 +51,7 @@
private final Supplier<WindowManagerService> mWmSupplier;
int rotationToReport = 0;
+ boolean keyguardShowingAndNotOccluded = false;
private Runnable mRunnableWhenAddingSplashScreen;
@@ -338,7 +339,7 @@
@Override
public boolean isKeyguardLocked() {
- return false;
+ return keyguardShowingAndNotOccluded;
}
@Override
@@ -358,7 +359,7 @@
@Override
public boolean isKeyguardShowingAndNotOccluded() {
- return false;
+ return keyguardShowingAndNotOccluded;
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 32bfda32..d91079e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -59,6 +59,7 @@
public class WindowManagerServiceRule implements TestRule {
private WindowManagerService mService;
+ private TestWindowManagerPolicy mPolicy;
@Override
public Statement apply(Statement base, Description description) {
@@ -108,7 +109,7 @@
}
mService = WindowManagerService.main(context, ims, true, false,
- false, new TestWindowManagerPolicy(
+ false, mPolicy = new TestWindowManagerPolicy(
WindowManagerServiceRule.this::getWindowManagerService));
mService.onInitReady();
@@ -132,6 +133,7 @@
waitUntilWindowManagerHandlersIdle();
removeServices();
mService = null;
+ mPolicy = null;
}
};
}
@@ -140,6 +142,10 @@
return mService;
}
+ public TestWindowManagerPolicy getWindowManagerPolicy() {
+ return mPolicy;
+ }
+
public void waitUntilWindowManagerHandlersIdle() {
final WindowManagerService wm = getWindowManagerService();
if (wm != null) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ebc432b..1a38385 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -91,10 +91,12 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
import android.provider.Settings.Secure;
import android.service.notification.Adjustment;
+import android.service.notification.INotificationListener;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
import android.service.notification.NotifyingApp;
@@ -161,6 +163,8 @@
@Mock
private NotificationUsageStats mUsageStats;
@Mock
+ private UsageStatsManagerInternal mAppUsageStats;
+ @Mock
private AudioManager mAudioManager;
@Mock
ActivityManager mActivityManager;
@@ -277,7 +281,7 @@
mPackageManager, mPackageManagerClient, mockLightsManager,
mListeners, mAssistants, mConditionProviders,
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
- mGroupHelper, mAm, mock(UsageStatsManagerInternal.class),
+ mGroupHelper, mAm, mAppUsageStats,
mock(DevicePolicyManagerInternal.class));
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
@@ -3041,4 +3045,46 @@
assertEquals(true, mService.canUseManagedServices("d"));
}
+
+ @Test
+ public void testOnNotificationVisibilityChanged_triggersInterruptionUsageStat() {
+ final NotificationRecord r = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ r.setTextChanged(true);
+ mService.addNotification(r);
+
+ mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
+ {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
+ new NotificationVisibility[]{});
+
+ verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
+ }
+
+ @Test
+ public void testSetNotificationsShownFromListener_triggersInterruptionUsageStat()
+ throws RemoteException {
+ final NotificationRecord r = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ r.setTextChanged(true);
+ mService.addNotification(r);
+
+ mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
+
+ verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
+ }
+
+ @Test
+ public void testMybeRecordInterruptionLocked_doesNotRecordTwice()
+ throws RemoteException {
+ final NotificationRecord r = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ r.setInterruptive(true);
+ mService.addNotification(r);
+
+ mService.maybeRecordInterruptionLocked(r);
+ mService.maybeRecordInterruptionLocked(r);
+
+ verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
+ anyString(), anyString(), anyInt());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index e3289ab..c1868e7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -602,4 +602,45 @@
record.setIsAppImportanceLocked(false);
assertEquals(false, record.getIsAppImportanceLocked());
}
+
+ @Test
+ public void testIsInterruptive_textChanged_notSeen() {
+ StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+ false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /* defaultLights */, null /* group */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+ assertEquals(false, record.isInterruptive());
+
+ record.setTextChanged(true);
+ assertEquals(false, record.isInterruptive());
+ }
+
+ @Test
+ public void testIsInterruptive_textChanged_seen() {
+ StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+ false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /* defaultLights */, null /* group */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+ assertEquals(false, record.isInterruptive());
+
+ record.setTextChanged(true);
+ record.setSeen();
+ assertEquals(true, record.isInterruptive());
+ }
+
+ @Test
+ public void testIsInterruptive_textNotChanged_seen() {
+ StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+ false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+ false /* lights */, false /* defaultLights */, null /* group */);
+ NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+ assertEquals(false, record.isInterruptive());
+
+ record.setTextChanged(false);
+ record.setSeen();
+ assertEquals(false, record.isInterruptive());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java
new file mode 100644
index 0000000..c6aea88
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 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.server.slice;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.server.UiServiceTestCase;
+import com.android.server.slice.SliceManagerService.PackageMatchingCache;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Supplier;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class PackageMatchingCacheTest extends UiServiceTestCase {
+
+ private final Supplier<String> supplier = mock(Supplier.class);
+ private final PackageMatchingCache cache = new PackageMatchingCache(supplier);
+
+ @Test
+ public void testNulls() {
+ // Doesn't get for a null input
+ cache.matches(null);
+ verify(supplier, never()).get();
+
+ // Gets once valid input in sent.
+ cache.matches("");
+ verify(supplier).get();
+ }
+
+ @Test
+ public void testCaching() {
+ when(supplier.get()).thenReturn("ret.pkg");
+
+ assertTrue(cache.matches("ret.pkg"));
+ assertTrue(cache.matches("ret.pkg"));
+ assertTrue(cache.matches("ret.pkg"));
+
+ verify(supplier, times(1)).get();
+ }
+
+ @Test
+ public void testGetOnFailure() {
+ when(supplier.get()).thenReturn("ret.pkg");
+ assertTrue(cache.matches("ret.pkg"));
+
+ when(supplier.get()).thenReturn("other.pkg");
+ assertTrue(cache.matches("other.pkg"));
+ verify(supplier, times(2)).get();
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 271f813..4e99732 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -340,15 +340,27 @@
public void setAppStandbyBucket(String packageName, int userId, long elapsedRealtime,
int bucket, int reason) {
+ setAppStandbyBucket(packageName, userId, elapsedRealtime, bucket, reason, false);
+ }
+
+ public void setAppStandbyBucket(String packageName, int userId, long elapsedRealtime,
+ int bucket, int reason, boolean resetTimeout) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory =
getPackageHistory(userHistory, packageName, elapsedRealtime, true);
appUsageHistory.currentBucket = bucket;
appUsageHistory.bucketingReason = reason;
+
+ final long elapsed = getElapsedTime(elapsedRealtime);
+
if ((reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED) {
- appUsageHistory.lastPredictedTime = getElapsedTime(elapsedRealtime);
+ appUsageHistory.lastPredictedTime = elapsed;
appUsageHistory.lastPredictedBucket = bucket;
}
+ if (resetTimeout) {
+ appUsageHistory.bucketActiveTimeoutTime = elapsed;
+ appUsageHistory.bucketWorkingSetTimeoutTime = elapsed;
+ }
if (DEBUG) {
Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
+ ", reason=0x0" + Integer.toHexString(appUsageHistory.bucketingReason));
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 08b0496..3378897 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -113,6 +113,9 @@
/**
* Manages the standby state of an app, listening to various events.
+ *
+ * Unit test:
+ atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
*/
public class AppStandbyController {
@@ -1106,6 +1109,11 @@
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
int reason, long elapsedRealtime) {
+ setAppStandbyBucket(packageName, userId, newBucket, reason, elapsedRealtime, false);
+ }
+
+ void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
+ int reason, long elapsedRealtime, boolean resetTimeout) {
synchronized (mAppIdleLock) {
AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
userId, elapsedRealtime);
@@ -1155,7 +1163,7 @@
}
mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
- reason);
+ reason, resetTimeout);
}
maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false);
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 71f9bb3..7d42eb3 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -900,6 +900,7 @@
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
+ final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID;
final boolean systemCaller = UserHandle.isCore(callingUid);
final int reason = systemCaller
? UsageStatsManager.REASON_MAIN_FORCED
@@ -918,7 +919,7 @@
+ ")");
}
mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason,
- SystemClock.elapsedRealtime());
+ SystemClock.elapsedRealtime(), shellCaller);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -985,7 +986,7 @@
throw new IllegalArgumentException("Cannot set your own standby bucket");
}
mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason,
- elapsedRealtime);
+ elapsedRealtime, shellCaller);
}
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/tests/net/java/android/net/captiveportal/CaptivePortalProbeSpecTest.java b/tests/net/java/android/net/captiveportal/CaptivePortalProbeSpecTest.java
new file mode 100644
index 0000000..40a8b3e
--- /dev/null
+++ b/tests/net/java/android/net/captiveportal/CaptivePortalProbeSpecTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2018 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.net.captiveportal;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.ParseException;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CaptivePortalProbeSpecTest {
+
+ @Test
+ public void testGetResult_Regex() throws MalformedURLException, ParseException {
+ // 2xx status or 404, with an empty (match everything) location regex
+ CaptivePortalProbeSpec statusRegexSpec = CaptivePortalProbeSpec.parseSpec(
+ "http://www.google.com@@/@@2[0-9]{2}|404@@/@@");
+
+ // 404, or 301/302 redirect to some HTTPS page under google.com
+ CaptivePortalProbeSpec redirectSpec = CaptivePortalProbeSpec.parseSpec(
+ "http://google.com@@/@@404|30[12]@@/@@https://([0-9a-z]+\\.)*google\\.com.*");
+
+ assertSuccess(statusRegexSpec.getResult(200, null));
+ assertSuccess(statusRegexSpec.getResult(299, "qwer"));
+ assertSuccess(statusRegexSpec.getResult(404, null));
+ assertSuccess(statusRegexSpec.getResult(404, ""));
+
+ assertPortal(statusRegexSpec.getResult(300, null));
+ assertPortal(statusRegexSpec.getResult(399, "qwer"));
+ assertPortal(statusRegexSpec.getResult(500, null));
+
+ assertSuccess(redirectSpec.getResult(404, null));
+ assertSuccess(redirectSpec.getResult(404, ""));
+ assertSuccess(redirectSpec.getResult(301, "https://www.google.com"));
+ assertSuccess(redirectSpec.getResult(301, "https://www.google.com/test?q=3"));
+ assertSuccess(redirectSpec.getResult(302, "https://google.com/test?q=3"));
+
+ assertPortal(redirectSpec.getResult(299, "https://google.com/test?q=3"));
+ assertPortal(redirectSpec.getResult(299, ""));
+ assertPortal(redirectSpec.getResult(499, null));
+ assertPortal(redirectSpec.getResult(301, "http://login.portal.example.com/loginpage"));
+ assertPortal(redirectSpec.getResult(302, "http://www.google.com/test?q=3"));
+ }
+
+ @Test(expected = ParseException.class)
+ public void testParseSpec_Empty() throws MalformedURLException, ParseException {
+ CaptivePortalProbeSpec.parseSpec("");
+ }
+
+ @Test(expected = ParseException.class)
+ public void testParseSpec_Null() throws MalformedURLException, ParseException {
+ CaptivePortalProbeSpec.parseSpec(null);
+ }
+
+ @Test(expected = ParseException.class)
+ public void testParseSpec_MissingParts() throws MalformedURLException, ParseException {
+ CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123");
+ }
+
+ @Test(expected = ParseException.class)
+ public void testParseSpec_TooManyParts() throws MalformedURLException, ParseException {
+ CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123@@/@@456@@/@@extra");
+ }
+
+ @Test(expected = ParseException.class)
+ public void testParseSpec_InvalidStatusRegex() throws MalformedURLException, ParseException {
+ CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@unmatched(parenthesis@@/@@456");
+ }
+
+ @Test(expected = ParseException.class)
+ public void testParseSpec_InvalidLocationRegex() throws MalformedURLException, ParseException {
+ CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123@@/@@unmatched[[]bracket");
+ }
+
+ @Test(expected = MalformedURLException.class)
+ public void testParseSpec_EmptyURL() throws MalformedURLException, ParseException {
+ CaptivePortalProbeSpec.parseSpec("@@/@@123@@/@@123");
+ }
+
+ @Test(expected = ParseException.class)
+ public void testParseSpec_NoParts() throws MalformedURLException, ParseException {
+ CaptivePortalProbeSpec.parseSpec("invalid");
+ }
+
+ @Test(expected = MalformedURLException.class)
+ public void testParseSpec_RegexInvalidUrl() throws MalformedURLException, ParseException {
+ CaptivePortalProbeSpec.parseSpec("notaurl@@/@@123@@/@@123");
+ }
+
+ @Test
+ public void testParseSpecOrNull_UsesSpec() {
+ final String specUrl = "http://google.com/probe";
+ final String redirectUrl = "https://google.com/probe";
+ CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull(
+ specUrl + "@@/@@302@@/@@" + redirectUrl);
+ assertEquals(specUrl, spec.getUrl().toString());
+
+ assertPortal(spec.getResult(302, "http://portal.example.com"));
+ assertSuccess(spec.getResult(302, redirectUrl));
+ }
+
+ @Test
+ public void testParseSpecOrNull_UsesFallback() throws MalformedURLException {
+ CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull(null);
+ assertNull(spec);
+
+ spec = CaptivePortalProbeSpec.parseSpecOrNull("");
+ assertNull(spec);
+
+ spec = CaptivePortalProbeSpec.parseSpecOrNull("@@/@@ @@/@@ @@/@@");
+ assertNull(spec);
+
+ spec = CaptivePortalProbeSpec.parseSpecOrNull("invalid@@/@@123@@/@@456");
+ assertNull(spec);
+ }
+
+ @Test
+ public void testParseSpecOrUseStatusCodeFallback_EmptySpec() throws MalformedURLException {
+ CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull("");
+ assertNull(spec);
+ }
+
+ private void assertIsStatusSpec(CaptivePortalProbeSpec spec) {
+ assertSuccess(spec.getResult(204, null));
+ assertSuccess(spec.getResult(204, "1234"));
+
+ assertPortal(spec.getResult(200, null));
+ assertPortal(spec.getResult(301, null));
+ assertPortal(spec.getResult(302, "1234"));
+ assertPortal(spec.getResult(399, ""));
+
+ assertFailed(spec.getResult(404, null));
+ assertFailed(spec.getResult(500, "1234"));
+ }
+
+ private void assertPortal(CaptivePortalProbeResult result) {
+ assertTrue(result.isPortal());
+ }
+
+ private void assertSuccess(CaptivePortalProbeResult result) {
+ assertTrue(result.isSuccessful());
+ }
+
+ private void assertFailed(CaptivePortalProbeResult result) {
+ assertTrue(result.isFailed());
+ }
+}