Merge "Update RestrictedSwitchPreference to have an additional summary." into nyc-dev
diff --git a/Android.mk b/Android.mk
index ae5d67e..2017404 100644
--- a/Android.mk
+++ b/Android.mk
@@ -442,8 +442,6 @@
telephony/java/com/android/internal/telephony/ISms.aidl \
telephony/java/com/android/internal/telephony/ISub.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
- telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
- telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index baef0a4..f924b5b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -891,6 +891,7 @@
field public static final int notificationTimeout = 16843651; // 0x1010383
field public static final int numColumns = 16843032; // 0x1010118
field public static final int numStars = 16843076; // 0x1010144
+ field public static final int numberPickerStyle = 16844071; // 0x1010527
field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
field public static final int numbersSelectorColor = 16843939; // 0x10104a3
@@ -2534,6 +2535,7 @@
field public static final int Widget_Material_Light_ListView = 16974513; // 0x10302b1
field public static final int Widget_Material_Light_ListView_DropDown = 16974514; // 0x10302b2
field public static final int Widget_Material_Light_MediaRouteButton = 16974515; // 0x10302b3
+ field public static final int Widget_Material_Light_NumberPicker = 16974557; // 0x10302dd
field public static final int Widget_Material_Light_PopupMenu = 16974516; // 0x10302b4
field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
field public static final int Widget_Material_Light_PopupWindow = 16974518; // 0x10302b6
@@ -2566,6 +2568,7 @@
field public static final int Widget_Material_ListView = 16974448; // 0x1030270
field public static final int Widget_Material_ListView_DropDown = 16974449; // 0x1030271
field public static final int Widget_Material_MediaRouteButton = 16974450; // 0x1030272
+ field public static final int Widget_Material_NumberPicker = 16974556; // 0x10302dc
field public static final int Widget_Material_PopupMenu = 16974451; // 0x1030273
field public static final int Widget_Material_PopupMenu_Overflow = 16974452; // 0x1030274
field public static final int Widget_Material_PopupWindow = 16974453; // 0x1030275
@@ -4480,6 +4483,7 @@
method public void startActivity(android.content.Intent, android.os.Bundle);
method public void startActivityForResult(android.content.Intent, int);
method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+ method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public void unregisterForContextMenu(android.view.View);
}
@@ -4571,6 +4575,7 @@
method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
method public boolean onShouldSaveFragmentState(android.app.Fragment);
method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+ method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public boolean onUseFragmentManagerInflaterFactory();
}
@@ -22893,6 +22898,7 @@
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+ field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -34955,6 +34961,7 @@
method public void onDestroy();
method public boolean[] onGetSupportedCommands(java.lang.String[]);
method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
+ method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
method public void onHandleScreenshot(android.graphics.Bitmap);
method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
diff --git a/api/system-current.txt b/api/system-current.txt
index d8545f1..915ceb2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -217,6 +217,7 @@
field public static final java.lang.String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
field public static final java.lang.String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
+ field public static final java.lang.String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
field public static final java.lang.String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
@@ -987,6 +988,7 @@
field public static final int notificationTimeout = 16843651; // 0x1010383
field public static final int numColumns = 16843032; // 0x1010118
field public static final int numStars = 16843076; // 0x1010144
+ field public static final int numberPickerStyle = 16844071; // 0x1010527
field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
field public static final int numbersSelectorColor = 16843939; // 0x10104a3
@@ -2637,6 +2639,7 @@
field public static final int Widget_Material_Light_ListView = 16974513; // 0x10302b1
field public static final int Widget_Material_Light_ListView_DropDown = 16974514; // 0x10302b2
field public static final int Widget_Material_Light_MediaRouteButton = 16974515; // 0x10302b3
+ field public static final int Widget_Material_Light_NumberPicker = 16974557; // 0x10302dd
field public static final int Widget_Material_Light_PopupMenu = 16974516; // 0x10302b4
field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
field public static final int Widget_Material_Light_PopupWindow = 16974518; // 0x10302b6
@@ -2669,6 +2672,7 @@
field public static final int Widget_Material_ListView = 16974448; // 0x1030270
field public static final int Widget_Material_ListView_DropDown = 16974449; // 0x1030271
field public static final int Widget_Material_MediaRouteButton = 16974450; // 0x1030272
+ field public static final int Widget_Material_NumberPicker = 16974556; // 0x10302dc
field public static final int Widget_Material_PopupMenu = 16974451; // 0x1030273
field public static final int Widget_Material_PopupMenu_Overflow = 16974452; // 0x1030274
field public static final int Widget_Material_PopupWindow = 16974453; // 0x1030275
@@ -4613,6 +4617,7 @@
method public void startActivity(android.content.Intent, android.os.Bundle);
method public void startActivityForResult(android.content.Intent, int);
method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+ method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public void unregisterForContextMenu(android.view.View);
}
@@ -4704,6 +4709,7 @@
method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
method public boolean onShouldSaveFragmentState(android.app.Fragment);
method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+ method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public boolean onUseFragmentManagerInflaterFactory();
}
@@ -24498,6 +24504,7 @@
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+ field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -37528,6 +37535,7 @@
method public void onDestroy();
method public boolean[] onGetSupportedCommands(java.lang.String[]);
method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
+ method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
method public void onHandleScreenshot(android.graphics.Bitmap);
method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
diff --git a/api/test-current.txt b/api/test-current.txt
index 6a0f071..0c86fd1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -891,6 +891,7 @@
field public static final int notificationTimeout = 16843651; // 0x1010383
field public static final int numColumns = 16843032; // 0x1010118
field public static final int numStars = 16843076; // 0x1010144
+ field public static final int numberPickerStyle = 16844071; // 0x1010527
field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
field public static final int numbersSelectorColor = 16843939; // 0x10104a3
@@ -2534,6 +2535,7 @@
field public static final int Widget_Material_Light_ListView = 16974513; // 0x10302b1
field public static final int Widget_Material_Light_ListView_DropDown = 16974514; // 0x10302b2
field public static final int Widget_Material_Light_MediaRouteButton = 16974515; // 0x10302b3
+ field public static final int Widget_Material_Light_NumberPicker = 16974557; // 0x10302dd
field public static final int Widget_Material_Light_PopupMenu = 16974516; // 0x10302b4
field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
field public static final int Widget_Material_Light_PopupWindow = 16974518; // 0x10302b6
@@ -2566,6 +2568,7 @@
field public static final int Widget_Material_ListView = 16974448; // 0x1030270
field public static final int Widget_Material_ListView_DropDown = 16974449; // 0x1030271
field public static final int Widget_Material_MediaRouteButton = 16974450; // 0x1030272
+ field public static final int Widget_Material_NumberPicker = 16974556; // 0x10302dc
field public static final int Widget_Material_PopupMenu = 16974451; // 0x1030273
field public static final int Widget_Material_PopupMenu_Overflow = 16974452; // 0x1030274
field public static final int Widget_Material_PopupWindow = 16974453; // 0x1030275
@@ -4480,6 +4483,7 @@
method public void startActivity(android.content.Intent, android.os.Bundle);
method public void startActivityForResult(android.content.Intent, int);
method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+ method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public void unregisterForContextMenu(android.view.View);
}
@@ -4571,6 +4575,7 @@
method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
method public boolean onShouldSaveFragmentState(android.app.Fragment);
method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+ method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public boolean onUseFragmentManagerInflaterFactory();
}
@@ -22961,6 +22966,7 @@
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+ field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -35030,6 +35036,7 @@
method public void onDestroy();
method public boolean[] onGetSupportedCommands(java.lang.String[]);
method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
+ method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
method public void onHandleScreenshot(android.graphics.Bitmap);
method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7652766..f7884a7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4405,8 +4405,8 @@
@Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
Bundle options) throws IntentSender.SendIntentException {
if (mParent == null) {
- startIntentSenderForResultInner(intent, requestCode, fillInIntent,
- flagsMask, flagsValues, this, options);
+ startIntentSenderForResultInner(intent, mEmbeddedID, requestCode, fillInIntent,
+ flagsMask, flagsValues, options);
} else if (options != null) {
mParent.startIntentSenderFromChild(this, intent, requestCode,
fillInIntent, flagsMask, flagsValues, extraFlags, options);
@@ -4418,8 +4418,8 @@
}
}
- private void startIntentSenderForResultInner(IntentSender intent, int requestCode,
- Intent fillInIntent, int flagsMask, int flagsValues, Activity activity,
+ private void startIntentSenderForResultInner(IntentSender intent, String who, int requestCode,
+ Intent fillInIntent, int flagsMask, int flagsValues,
Bundle options)
throws IntentSender.SendIntentException {
try {
@@ -4431,7 +4431,7 @@
}
int result = ActivityManagerNative.getDefault()
.startActivityIntentSender(mMainThread.getApplicationThread(), intent,
- fillInIntent, resolvedType, mToken, activity.mEmbeddedID,
+ fillInIntent, resolvedType, mToken, who,
requestCode, flagsMask, flagsValues, options);
if (result == ActivityManager.START_CANCELED) {
throw new IntentSender.SendIntentException();
@@ -4888,8 +4888,23 @@
int requestCode, Intent fillInIntent, int flagsMask, int flagsValues,
int extraFlags, @Nullable Bundle options)
throws IntentSender.SendIntentException {
- startIntentSenderForResultInner(intent, requestCode, fillInIntent,
- flagsMask, flagsValues, child, options);
+ startIntentSenderForResultInner(intent, child.mEmbeddedID, requestCode, fillInIntent,
+ flagsMask, flagsValues, options);
+ }
+
+ /**
+ * Like {@link #startIntentSenderFromChild}, but taking a Fragment; see
+ * {@link #startIntentSenderForResult(IntentSender, int, Intent, int, int, int)}
+ * for more information.
+ *
+ * @hide
+ */
+ public void startIntentSenderFromChildFragment(Fragment child, IntentSender intent,
+ int requestCode, Intent fillInIntent, int flagsMask, int flagsValues,
+ int extraFlags, @Nullable Bundle options)
+ throws IntentSender.SendIntentException {
+ startIntentSenderForResultInner(intent, child.mWho, requestCode, fillInIntent,
+ flagsMask, flagsValues, options);
}
/**
@@ -7035,6 +7050,19 @@
}
@Override
+ public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
+ int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
+ int extraFlags, Bundle options) throws IntentSender.SendIntentException {
+ if (mParent == null) {
+ startIntentSenderForResultInner(intent, fragment.mWho, requestCode, fillInIntent,
+ flagsMask, flagsValues, options);
+ } else if (options != null) {
+ mParent.startIntentSenderFromChildFragment(fragment, intent, requestCode,
+ fillInIntent, flagsMask, flagsValues, extraFlags, options);
+ }
+ }
+
+ @Override
public void onRequestPermissionsFromFragment(Fragment fragment, String[] permissions,
int requestCode) {
String who = REQUEST_PERMISSIONS_WHO_PREFIX + fragment.mWho;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 5116634..374c4f6 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -23,6 +23,8 @@
import com.android.internal.app.IVoiceInteractor;
+import java.util.List;
+
/**
* Activity manager local system service interface.
*
@@ -125,4 +127,10 @@
* Callback for window manager to let activity manager know that the app transition is finished.
*/
public abstract void notifyAppTransitionFinished();
+
+ /**
+ * Returns the top activity from each of the currently visible stacks. The first entry will be
+ * the focused activity.
+ */
+ public abstract List<IBinder> getTopVisibleActivities();
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 65d48e6..7bf03de 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2411,8 +2411,11 @@
data.enforceInterface(IActivityManager.descriptor);
int requestType = data.readInt();
IResultReceiver receiver = IResultReceiver.Stub.asInterface(data.readStrongBinder());
+ Bundle receiverExtras = data.readBundle();
IBinder activityToken = data.readStrongBinder();
- boolean res = requestAssistContextExtras(requestType, receiver, activityToken);
+ boolean focused = data.readInt() == 1;
+ boolean res = requestAssistContextExtras(requestType, receiver, receiverExtras,
+ activityToken, focused);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
return true;
@@ -6080,13 +6083,16 @@
}
public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
- IBinder activityToken) throws RemoteException {
+ Bundle receiverExtras,
+ IBinder activityToken, boolean focused) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(requestType);
data.writeStrongBinder(receiver.asBinder());
+ data.writeBundle(receiverExtras);
data.writeStrongBinder(activityToken);
+ data.writeInt(focused ? 1 : 0);
mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 2a04c39..29f594f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -23,6 +23,7 @@
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -1116,6 +1117,20 @@
}
/**
+ * Call {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int,
+ * Bundle)} from the fragment's containing Activity.
+ */
+ public void startIntentSenderForResult(IntentSender intent, int requestCode,
+ @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
+ Bundle options) throws IntentSender.SendIntentException {
+ if (mHost == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
+ mHost.onStartIntentSenderFromFragment(this, intent, requestCode, fillInIntent, flagsMask,
+ flagsValues, extraFlags, options);
+ }
+
+ /**
* Receive the result from a previous call to
* {@link #startActivityForResult(Intent, int)}. This follows the
* related Activity API as described there in
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index 13517e6..cf6b114 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
import android.os.Bundle;
import android.os.Handler;
import android.util.ArrayMap;
@@ -131,6 +132,21 @@
}
/**
+ * Starts a new {@link IntentSender} from the given fragment.
+ * See {@link Activity#startIntentSender(IntentSender, Intent, int, int, int, Bundle)}.
+ */
+ public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
+ int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
+ int extraFlags, Bundle options) throws IntentSender.SendIntentException {
+ if (requestCode != -1) {
+ throw new IllegalStateException(
+ "Starting intent sender with a requestCode requires a FragmentActivity host");
+ }
+ mContext.startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags,
+ options);
+ }
+
+ /**
* Requests permissions from the given fragment.
* See {@link Activity#requestPermissions(String[], int)}
*/
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 8ee6fd0..6975116 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -523,7 +523,8 @@
public Bundle getAssistContextExtras(int requestType) throws RemoteException;
public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
- IBinder activityToken) throws RemoteException;
+ Bundle receiverExtras,
+ IBinder activityToken, boolean focused) throws RemoteException;
public void reportAssistContextExtras(IBinder token, Bundle extras,
AssistStructure structure, AssistContent content, Uri referrer) throws RemoteException;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 052874f..400a313 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -25,6 +25,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
@@ -779,6 +781,16 @@
/**
* {@link #extras} key: this is the remote input history, as supplied to
* {@link Builder#setRemoteInputHistory(CharSequence[])}.
+ *
+ * Apps can fill this through {@link Builder#setRemoteInputHistory(CharSequence[])}
+ * with the most recent inputs that have been sent through a {@link RemoteInput} of this
+ * Notification and are expected to clear it once the it is no longer relevant (e.g. for chat
+ * notifications once the other party has responded).
+ *
+ * The extra with this key is of type CharSequence[] and contains the most recent entry at
+ * the 0 index, the second most recent at the 1 index, etc.
+ *
+ * @see Builder#setRemoteInputHistory(CharSequence[])
*/
public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
@@ -960,6 +972,12 @@
*/
public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView";
+ /**
+ * @SystemApi
+ * @hide
+ */
+ public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
+
private Icon mSmallIcon;
private Icon mLargeIcon;
@@ -3269,14 +3287,38 @@
}
}
- private void bindHeaderAppName(RemoteViews contentView) {
- CharSequence appName = mContext.getPackageManager()
- .getApplicationLabel(mContext.getApplicationInfo());
-
- if (TextUtils.isEmpty(appName)) {
- return;
+ private String loadHeaderAppName() {
+ CharSequence name = null;
+ final PackageManager pm = mContext.getPackageManager();
+ if (mN.extras.containsKey(EXTRA_SUBSTITUTE_APP_NAME)) {
+ // only system packages which lump together a bunch of unrelated stuff
+ // may substitute a different name to make the purpose of the
+ // notification more clear. the correct package label should always
+ // be accessible via SystemUI.
+ final String pkg = mContext.getPackageName();
+ final String subName = mN.extras.getString(EXTRA_SUBSTITUTE_APP_NAME);
+ if (PackageManager.PERMISSION_GRANTED == pm.checkPermission(
+ android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, pkg)) {
+ name = subName;
+ } else {
+ Log.w(TAG, "warning: pkg "
+ + pkg + " attempting to substitute app name '" + subName
+ + "' without holding perm "
+ + android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME);
+ }
}
- contentView.setTextViewText(R.id.app_name_text, appName);
+ if (TextUtils.isEmpty(name)) {
+ name = pm.getApplicationLabel(mContext.getApplicationInfo());
+ }
+ if (TextUtils.isEmpty(name)) {
+ // still nothing?
+ return null;
+ }
+
+ return String.valueOf(name);
+ }
+ private void bindHeaderAppName(RemoteViews contentView) {
+ contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName());
contentView.setTextColor(R.id.app_name_text, resolveContrastColor());
}
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 8236f55..995d2cc 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -87,6 +87,11 @@
/**
* Test if the given component is considered installed, enabled and a match
* for the given flags.
+ *
+ * <p>
+ * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
+ * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
+ * </p>
*/
public boolean isMatch(ComponentInfo componentInfo, int flags) {
if (!isInstalled(flags)) return false;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index ddf90a8..8c73e6a 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3599,10 +3599,20 @@
/**
* <p>The shading map is a low-resolution floating-point map
- * that lists the coefficients used to correct for vignetting, for each
- * Bayer color channel of RAW image data.</p>
- * <p>The least shaded section of the image should have a gain factor
- * of 1; all other sections should have gains above 1.</p>
+ * that lists the coefficients used to correct for vignetting and color shading,
+ * for each Bayer color channel of RAW image data.</p>
+ * <p>The lens shading correction is defined as a full shading correction that
+ * corrects both color shading for the output non-RAW images. After the
+ * shading map is applied, the output non-RAW images will be flat-field images
+ * for flat scenes under uniform illumination.</p>
+ * <p>When there is no lens shading correction applied to RAW output images
+ * ({@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} <code>==</code> false), this map is a full lens
+ * shading correction map; when there is some lens shading correction applied
+ * to the RAW output image ({@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} <code>==</code> true),
+ * this map reports the remaining lens shading correction map that needs to be
+ * applied to get fully shading corrected images.</p>
+ * <p>For a full shading correction map, the least shaded section of the image
+ * should have a gain factor of 1; all other sections should have gains above 1.</p>
* <p>When {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} = TRANSFORM_MATRIX, the map
* must take into account the colorCorrection settings.</p>
* <p>The shading map is for the entire active pixel array, and is not
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index 87a0b70..e0fa63a 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -17,6 +17,7 @@
package android.net.http;
import android.annotation.SystemApi;
+import android.security.net.config.UserCertificateSource;
import com.android.org.conscrypt.TrustManagerImpl;
@@ -43,7 +44,6 @@
// Methods to use when mDelegate is not a TrustManagerImpl and duck typing is being used.
private final X509TrustManager mTrustManager;
private final Method mCheckServerTrusted;
- private final Method mIsUserAddedCertificate;
private final Method mIsSameTrustConfiguration;
/**
@@ -57,7 +57,6 @@
mDelegate = (TrustManagerImpl) tm;
mTrustManager = null;
mCheckServerTrusted = null;
- mIsUserAddedCertificate = null;
mIsSameTrustConfiguration = null;
return;
}
@@ -74,14 +73,6 @@
throw new IllegalArgumentException("Required method"
+ " checkServerTrusted(X509Certificate[], String, String, String) missing");
}
- // Check that isUserAddedCertificate is present.
- try {
- mIsUserAddedCertificate = tm.getClass().getMethod("isUserAddedCertificate",
- X509Certificate.class);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException(
- "Required method isUserAddedCertificate(X509Certificate) missing");
- }
// Get the option isSameTrustConfiguration method.
Method isSameTrustConfiguration = null;
try {
@@ -128,29 +119,15 @@
/**
* Checks whether a CA certificate is added by an user.
*
- * <p>Since {@link X509TrustManager#checkServerTrusted} allows its parameter {@code chain} to
+ * <p>Since {@link X509TrustManager#checkServerTrusted} may allow its parameter {@code chain} to
* chain up to user-added CA certificates, this method can be used to perform additional
* policies for user-added CA certificates.
*
- * @return {@code true} to indicate that the certificate was added by the user, {@code false}
- * otherwise.
+ * @return {@code true} to indicate that the certificate authority exists in the user added
+ * certificate store, {@code false} otherwise.
*/
public boolean isUserAddedCertificate(X509Certificate cert) {
- if (mDelegate != null) {
- return mDelegate.isUserAddedCertificate(cert);
- } else {
- try {
- return (Boolean) mIsUserAddedCertificate.invoke(mTrustManager, cert);
- } catch (IllegalAccessException e) {
- throw new RuntimeException("Failed to call isUserAddedCertificate", e);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof RuntimeException) {
- throw (RuntimeException) e.getCause();
- } else {
- throw new RuntimeException("isUserAddedCertificate failed", e.getCause());
- }
- }
- }
+ return UserCertificateSource.getInstance().findBySubjectAndPublicKey(cert) != null;
}
/**
diff --git a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
index c6fcb2d..a491ffc 100644
--- a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
+++ b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
@@ -25,18 +25,40 @@
public class ConnectivityServiceChangeEvent extends IpConnectivityEvent implements Parcelable {
public static final String TAG = "ConnectivityServiceChangeEvent";
- private int mNetId;
+ // The ID of the network that has become the new default or NETID_UNSET if none.
+ private final int mNetId;
+ // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
+ // defined in NetworkCapabilities.java.
+ private final int[] mTransportTypes;
+ // The ID of the network that was the default before or NETID_UNSET if none.
+ private final int mPrevNetId;
+ // Whether the previous network had IPv4/IPv6 connectivity.
+ private final boolean mPrevIPv4;
+ private final boolean mPrevIPv6;
- public ConnectivityServiceChangeEvent(int netId) {
+ public ConnectivityServiceChangeEvent(int netId, int[] transportTypes,
+ int prevNetId, boolean prevIPv4, boolean prevIPv6) {
mNetId = netId;
+ mTransportTypes = transportTypes;
+ mPrevNetId = prevNetId;
+ mPrevIPv4 = prevIPv4;
+ mPrevIPv6 = prevIPv6;
}
public ConnectivityServiceChangeEvent(Parcel in) {
mNetId = in.readInt();
+ mTransportTypes = in.createIntArray();
+ mPrevNetId = in.readInt();
+ mPrevIPv4 = (in.readByte() > 0);
+ mPrevIPv6 = (in.readByte() > 0);
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mNetId);
+ out.writeIntArray(mTransportTypes);
+ out.writeInt(mPrevNetId);
+ out.writeByte(mPrevIPv4 ? (byte) 1 : (byte) 0);
+ out.writeByte(mPrevIPv6 ? (byte) 1 : (byte) 0);
}
public static final Parcelable.Creator<ConnectivityServiceChangeEvent> CREATOR
@@ -50,8 +72,10 @@
}
};
- public static void logEvent(int netId) {
+ public static void logEvent(int netId, int[] transportTypes,
+ int prevNetId, boolean prevIPv4, boolean prevIPv6) {
IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_CONSRV_DEFAULT_NET_CHANGE,
- new ConnectivityServiceChangeEvent(netId));
+ new ConnectivityServiceChangeEvent(
+ netId, transportTypes, prevNetId, prevIPv4, prevIPv6));
}
};
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
new file mode 100644
index 0000000..3869823
--- /dev/null
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -0,0 +1,93 @@
+/*
+ * 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 android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide} Event class used to record error events when parsing DHCP response packets.
+ */
+public class DhcpErrorEvent extends IpConnectivityEvent implements Parcelable {
+ public static final String TAG = "DhcpErrorEvent";
+
+ public static final int L2_ERROR = 1;
+ public static final int L3_ERROR = 2;
+ public static final int L4_ERROR = 3;
+ public static final int DHCP_ERROR = 4;
+ public static final int MISC_ERROR = 5;
+
+ public static final int L2_TOO_SHORT = makeErrorCode(L2_ERROR, 1);
+ public static final int L2_WRONG_ETH_TYPE = makeErrorCode(L2_ERROR, 2);
+
+ public static final int L3_TOO_SHORT = makeErrorCode(L3_ERROR, 1);
+ public static final int L3_NOT_IPV4 = makeErrorCode(L3_ERROR, 2);
+ public static final int L3_INVALID_IP = makeErrorCode(L3_ERROR, 3);
+
+ public static final int L4_NOT_UDP = makeErrorCode(L4_ERROR, 1);
+ public static final int L4_WRONG_PORT = makeErrorCode(L4_ERROR, 2);
+
+ public static final int BOOTP_TOO_SHORT = makeErrorCode(DHCP_ERROR, 1);
+ public static final int DHCP_BAD_MAGIC_COOKIE = makeErrorCode(DHCP_ERROR, 2);
+ public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
+ public static final int DHCP_NO_MSG_TYPE = makeErrorCode(DHCP_ERROR, 4);
+ public static final int DHCP_UNKNOWN_MSG_TYPE = makeErrorCode(DHCP_ERROR, 5);
+
+ public static final int BUFFER_UNDERFLOW = makeErrorCode(MISC_ERROR, 1);
+
+ // error code byte format (MSB to LSB):
+ // byte 0: error type
+ // byte 1: error subtype
+ // byte 2: unused
+ // byte 3: optional code
+ public final int errorCode;
+
+ private DhcpErrorEvent(int errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ private DhcpErrorEvent(Parcel in) {
+ this.errorCode = in.readInt();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(errorCode);
+ }
+
+ public static final Parcelable.Creator<DhcpErrorEvent> CREATOR
+ = new Parcelable.Creator<DhcpErrorEvent>() {
+ public DhcpErrorEvent createFromParcel(Parcel in) {
+ return new DhcpErrorEvent(in);
+ }
+
+ public DhcpErrorEvent[] newArray(int size) {
+ return new DhcpErrorEvent[size];
+ }
+ };
+
+ public static void logEvent(int errorCode) {
+ IpConnectivityEvent.logEvent(IPCE_DHCP_PARSE_ERROR, new DhcpErrorEvent(errorCode));
+ }
+
+ public static void logEvent(int errorCode, int option) {
+ logEvent((0xFFFF0000 & errorCode) | (0xFF & option));
+ }
+
+ private static int makeErrorCode(int type, int subtype) {
+ return (type << 24) | ((0xFF & subtype) << 16);
+ }
+}
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
index ec42890..59c1cfe 100644
--- a/core/java/android/net/metrics/IpConnectivityEvent.java
+++ b/core/java/android/net/metrics/IpConnectivityEvent.java
@@ -28,14 +28,17 @@
// DHCP = DhcpClient
// NETMON = NetworkMonitorEvent
// CONSRV = ConnectivityServiceEvent
+ // IPMGR = IpManager
public static final String TAG = "IpConnectivityEvent";
public static final int IPCE_IPRM_BASE = 0*1024;
public static final int IPCE_DHCP_BASE = 1*1024;
public static final int IPCE_NETMON_BASE = 2*1024;
public static final int IPCE_CONSRV_BASE = 3*1024;
+ public static final int IPCE_IPMGR_BASE = 4*1024;
public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0;
public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1;
+ public static final int IPCE_IPRM_REACHABILITY_LOST = IPCE_IPRM_BASE + 2;
public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0;
public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1;
public static final int IPCE_DHCP_TIMEOUT = IPCE_DHCP_BASE + 2;
@@ -43,6 +46,9 @@
public static final int IPCE_NETMON_STATE_CHANGE = IPCE_NETMON_BASE + 0;
public static final int IPCE_NETMON_CHECK_RESULT = IPCE_NETMON_BASE + 1;
public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0;
+ public static final int IPCE_IPMGR_PROVISIONING_OK = IPCE_IPMGR_BASE + 0;
+ public static final int IPCE_IPMGR_PROVISIONING_FAIL = IPCE_IPMGR_BASE + 1;
+ public static final int IPCE_IPMGR_COMPLETE_LIFECYCLE = IPCE_IPMGR_BASE + 2;
private static ConnectivityMetricsLogger mMetricsLogger = new ConnectivityMetricsLogger();
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
new file mode 100644
index 0000000..6328ccb
--- /dev/null
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -0,0 +1,58 @@
+/*
+ * 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 android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class IpManagerEvent extends IpConnectivityEvent implements Parcelable {
+ private String mIfName;
+ private long mDurationMs;
+
+ public IpManagerEvent(String ifName, long duration) {
+ mIfName = ifName;
+ mDurationMs = duration;
+ }
+
+ public IpManagerEvent(Parcel in) {
+ mIfName = in.readString();
+ mDurationMs = in.readLong();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mIfName);
+ out.writeLong(mDurationMs);
+ }
+
+ public static final Parcelable.Creator<IpManagerEvent> CREATOR
+ = new Parcelable.Creator<IpManagerEvent>() {
+ public IpManagerEvent createFromParcel(Parcel in) {
+ return new IpManagerEvent(in);
+ }
+
+ public IpManagerEvent[] newArray(int size) {
+ return new IpManagerEvent[size];
+ }
+ };
+
+ public static void logEvent(int eventType, String ifName, long durationMs) {
+ IpConnectivityEvent.logEvent(eventType, new IpManagerEvent(ifName, durationMs));
+ }
+};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
new file mode 100644
index 0000000..0f14210
--- /dev/null
+++ b/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
@@ -0,0 +1,56 @@
+/*
+ * 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 android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class IpReachabilityMonitorLostEvent extends IpConnectivityEvent
+ implements Parcelable {
+ private String mIfName;
+
+ public IpReachabilityMonitorLostEvent(String ifName) {
+ mIfName = ifName;
+ }
+
+ public IpReachabilityMonitorLostEvent(Parcel in) {
+ mIfName = in.readString();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mIfName);
+ }
+
+ public static final Parcelable.Creator<IpReachabilityMonitorLostEvent> CREATOR
+ = new Parcelable.Creator<IpReachabilityMonitorLostEvent>() {
+ public IpReachabilityMonitorLostEvent createFromParcel(Parcel in) {
+ return new IpReachabilityMonitorLostEvent(in);
+ }
+
+ public IpReachabilityMonitorLostEvent[] newArray(int size) {
+ return new IpReachabilityMonitorLostEvent[size];
+ }
+ };
+
+ public static void logEvent(String ifName) {
+ IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_IPRM_REACHABILITY_LOST,
+ new IpReachabilityMonitorLostEvent(ifName));
+ }
+};
diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
index 3c292ca..d9cc82a 100644
--- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java
+++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
@@ -115,15 +115,6 @@
return trustedChain;
}
- /**
- * Check if the provided certificate is a user added certificate authority.
- * This is required by android.net.http.X509TrustManagerExtensions.
- */
- public boolean isUserAddedCertificate(X509Certificate cert) {
- // TODO: Figure out the right way to handle this, and if it is still even used.
- return false;
- }
-
private void checkPins(List<X509Certificate> chain) throws CertificateException {
PinSet pinSet = mNetworkSecurityConfig.getPins();
if (pinSet.pins.isEmpty()
diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java
index 859e022..2a30f11 100644
--- a/core/java/android/security/net/config/RootTrustManager.java
+++ b/core/java/android/security/net/config/RootTrustManager.java
@@ -131,15 +131,6 @@
return config.getTrustManager().checkServerTrusted(certs, authType, hostname);
}
- /**
- * Check if the provided certificate is a user added certificate authority.
- * This is required by android.net.http.X509TrustManagerExtensions.
- */
- public boolean isUserAddedCertificate(X509Certificate cert) {
- // TODO: Figure out the right way to handle this, and if it is still even used.
- return false;
- }
-
@Override
public X509Certificate[] getAcceptedIssuers() {
// getAcceptedIssuers is meant to be used to determine which trust anchors the server will
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index dbc28f7..78e6bc3 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -30,7 +30,8 @@
oneway interface IVoiceInteractionSession {
void show(in Bundle sessionArgs, int flags, IVoiceInteractionSessionShowCallback showCallback);
void hide();
- void handleAssist(in Bundle assistData, in AssistStructure structure, in AssistContent content);
+ void handleAssist(in Bundle assistData, in AssistStructure structure, in AssistContent content,
+ int index, int count);
void handleScreenshot(in Bitmap screenshot);
void taskStarted(in Intent intent, int taskId);
void taskFinished(in Intent intent, int taskId);
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 6ff9fe7..e354ab3 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -77,7 +77,7 @@
*/
public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCallbacks2 {
static final String TAG = "VoiceInteractionSession";
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
/**
* Flag received in {@link #onShow}: originator requested that the session be started with
@@ -110,6 +110,16 @@
*/
public static final int SHOW_SOURCE_ACTIVITY = 1<<4;
+ // Keys for Bundle values
+ /** @hide */
+ public static final String KEY_DATA = "data";
+ /** @hide */
+ public static final String KEY_STRUCTURE = "structure";
+ /** @hide */
+ public static final String KEY_CONTENT = "content";
+ /** @hide */
+ public static final String KEY_RECEIVER_EXTRAS = "receiverExtras";
+
final Context mContext;
final HandlerCaller mHandlerCaller;
@@ -229,7 +239,7 @@
@Override
public void handleAssist(final Bundle data, final AssistStructure structure,
- final AssistContent content) {
+ final AssistContent content, final int index, final int count) {
// We want to pre-warm the AssistStructure before handing it off to the main
// thread. We also want to do this on a separate thread, so that if the app
// is for some reason slow (due to slow filling in of async children in the
@@ -247,8 +257,9 @@
failure = e;
}
}
- mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_HANDLE_ASSIST,
- data, failure == null ? structure : null, failure, content));
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOOII(MSG_HANDLE_ASSIST,
+ data, failure == null ? structure : null, failure, content,
+ index, count));
}
};
retriever.start();
@@ -831,9 +842,16 @@
case MSG_HANDLE_ASSIST:
args = (SomeArgs)msg.obj;
if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1
- + " structure=" + args.arg2 + " content=" + args.arg3);
- doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
- (Throwable) args.arg3, (AssistContent) args.arg4);
+ + " structure=" + args.arg2 + " content=" + args.arg3
+ + " activityIndex=" + args.argi5 + " activityCount=" + args.argi6);
+ if (args.argi5 == 0) {
+ doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
+ (Throwable) args.arg3, (AssistContent) args.arg4);
+ } else {
+ doOnHandleAssistSecondary((Bundle) args.arg1, (AssistStructure) args.arg2,
+ (Throwable) args.arg3, (AssistContent) args.arg4,
+ args.argi5, args.argi6);
+ }
break;
case MSG_HANDLE_SCREENSHOT:
if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj);
@@ -1320,6 +1338,14 @@
onHandleAssist(data, structure, content);
}
+ void doOnHandleAssistSecondary(Bundle data, AssistStructure structure, Throwable failure,
+ AssistContent content, int index, int count) {
+ if (failure != null) {
+ onAssistStructureFailure(failure);
+ }
+ onHandleAssistSecondary(data, structure, content, index, count);
+ }
+
/**
* Called when there has been a failure transferring the {@link AssistStructure} to
* the assistant. This may happen, for example, if the data is too large and results
@@ -1356,6 +1382,45 @@
}
/**
+ * Called to receive data from other applications that the user was or is interacting with,
+ * that are currently on the screen in a multi-window display environment, not including the
+ * currently focused activity. This could be
+ * a free-form window, a picture-in-picture window, or another window in a split-screen display.
+ * <p>
+ * This method is very similar to
+ * {@link #onHandleAssist} except that it is called
+ * for additional non-focused activities along with an index and count that indicates
+ * which additional activity the data is for. {@code index} will be between 1 and
+ * {@code count}-1 and this method is called once for each additional window, in no particular
+ * order. The {@code count} indicates how many windows to expect assist data for, including the
+ * top focused activity, which continues to be returned via {@link #onHandleAssist}.
+ * <p>
+ * To be responsive to assist requests, process assist data as soon as it is received,
+ * without waiting for all queued activities to return assist data.
+ *
+ * @param data Arbitrary data supplied by the app through
+ * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
+ * May be null if assist data has been disabled by the user or device policy.
+ * @param structure If available, the structure definition of all windows currently
+ * displayed by the app. May be null if assist data has been disabled by the user
+ * or device policy; will be an empty stub if the application has disabled assist
+ * by marking its window as secure.
+ * @param content Additional content data supplied by the app through
+ * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
+ * May be null if assist data has been disabled by the user or device policy; will
+ * not be automatically filled in with data from the app if the app has marked its
+ * window as secure.
+ * @param index the index of the additional activity that this data
+ * is for.
+ * @param count the total number of additional activities for which the assist data is being
+ * returned, including the focused activity that is returned via
+ * {@link #onHandleAssist}.
+ */
+ public void onHandleAssistSecondary(@Nullable Bundle data, @Nullable AssistStructure structure,
+ @Nullable AssistContent content, int index, int count) {
+ }
+
+ /**
* Called to receive a screenshot of what the user was currently viewing when an assist
* session is started. May be null if screenshots are disabled by the user, policy,
* or application. If the original show request did not specify
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 1eaa7cf..9b238ce 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -457,8 +457,17 @@
private class SynthHandler extends Handler {
private SpeechItem mCurrentSpeechItem = null;
- private ArrayList<Object> mFlushedObjects = new ArrayList<Object>();
- private boolean mFlushAll;
+ // When a message with QUEUE_FLUSH arrives we add the caller identity to the List and when a
+ // message with QUEUE_DESTROY arrives we increment mFlushAll. Then a message is added to the
+ // handler queue that removes the caller identify from the list and decrements the mFlushAll
+ // counter. This is so that when a message is processed and the caller identity is in the
+ // list or mFlushAll is not zero, we know that the message should be flushed.
+ // It's important that mFlushedObjects is a List and not a Set, and that mFlushAll is an
+ // int and not a bool. This is because when multiple messages arrive with QUEUE_FLUSH or
+ // QUEUE_DESTROY, we want to keep flushing messages until we arrive at the last QUEUE_FLUSH
+ // or QUEUE_DESTROY message.
+ private List<Object> mFlushedObjects = new ArrayList<>();
+ private int mFlushAll = 0;
public SynthHandler(Looper looper) {
super(looper);
@@ -467,7 +476,7 @@
private void startFlushingSpeechItems(Object callerIdentity) {
synchronized (mFlushedObjects) {
if (callerIdentity == null) {
- mFlushAll = true;
+ mFlushAll += 1;
} else {
mFlushedObjects.add(callerIdentity);
}
@@ -476,7 +485,7 @@
private void endFlushingSpeechItems(Object callerIdentity) {
synchronized (mFlushedObjects) {
if (callerIdentity == null) {
- mFlushAll = false;
+ mFlushAll -= 1;
} else {
mFlushedObjects.remove(callerIdentity);
}
@@ -484,7 +493,7 @@
}
private boolean isFlushed(SpeechItem speechItem) {
synchronized (mFlushedObjects) {
- return mFlushAll || mFlushedObjects.contains(speechItem.getCallerIdentity());
+ return mFlushAll > 0 || mFlushedObjects.contains(speechItem.getCallerIdentity());
}
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index c4ed94f..206ba16 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -485,15 +485,25 @@
}
/**
- * Stops any rendering into the surface. Use this if it is unclear whether
+ * Halts any current rendering into the surface. Use this if it is unclear whether
* or not the surface used by the HardwareRenderer will be changing. It
- * Suspends any rendering into the surface, but will not do any destruction
+ * Suspends any rendering into the surface, but will not do any destruction.
+ *
+ * Any subsequent draws will override the pause, resuming normal operation.
*/
boolean pauseSurface(Surface surface) {
return nPauseSurface(mNativeProxy, surface);
}
/**
+ * Hard stops or resumes rendering into the surface. This flag is used to
+ * determine whether or not it is safe to use the given surface *at all*
+ */
+ void setStopped(boolean stopped) {
+ nSetStopped(mNativeProxy, stopped);
+ }
+
+ /**
* Destroys all hardware rendering resources associated with the specified
* view hierarchy.
*
@@ -992,6 +1002,7 @@
private static native void nInitialize(long nativeProxy, Surface window);
private static native void nUpdateSurface(long nativeProxy, Surface window);
private static native boolean nPauseSurface(long nativeProxy, Surface window);
+ private static native void nSetStopped(long nativeProxy, boolean stopped);
private static native void nSetup(long nativeProxy, int width, int height,
float lightRadius, int ambientShadowAlpha, int spotShadowAlpha);
private static native void nSetLightCenter(long nativeProxy,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 307e700..8a6b5da 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15742,8 +15742,10 @@
return;
}
- // Destroy any previous software drawing cache if needed
- if (mLayerType == LAYER_TYPE_SOFTWARE) {
+ if (layerType != LAYER_TYPE_SOFTWARE) {
+ // Destroy any previous software drawing cache if present
+ // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up
+ // drawing cache created in View#draw when drawing to a SW canvas.
destroyDrawingCache();
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2ce43c8..e9ca623 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1080,13 +1080,16 @@
void setWindowStopped(boolean stopped) {
if (mStopped != stopped) {
mStopped = stopped;
+ final ThreadedRenderer renderer = mAttachInfo.mHardwareRenderer;
+ if (renderer != null) {
+ if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
+ renderer.setStopped(mStopped);
+ }
if (!mStopped) {
scheduleTraversals();
} else {
- if (mAttachInfo.mHardwareRenderer != null) {
- if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle());
- mAttachInfo.mHardwareRenderer.updateSurface(null);
- mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
+ if (renderer != null) {
+ renderer.destroyHardwareResources(mView);
}
}
}
@@ -2556,6 +2559,7 @@
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.fence();
+ mAttachInfo.mHardwareRenderer.setStopped(mStopped);
}
if (LOCAL_LOGV) {
@@ -2705,6 +2709,13 @@
// shortly before the draw commands get send to the renderer.
final boolean updated = updateContentDrawBounds();
+ if (mReportNextDraw) {
+ // report next draw overrides setStopped()
+ // This value is re-sync'd to the value of mStopped
+ // in the handling of mReportNextDraw post-draw.
+ mAttachInfo.mHardwareRenderer.setStopped(false);
+ }
+
mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
if (updated) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e3de810..89e146b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1726,6 +1726,16 @@
*/
public CharSequence accessibilityTitle;
+ /**
+ * Sets a timeout in milliseconds before which the window will be removed
+ * by the window manager. Useful for transient notifications like toasts
+ * so we don't have to rely on client cooperation to ensure the window
+ * is removed. Must be specified at window creation time.
+ *
+ * @hide
+ */
+ public long removeTimeoutMilliseconds = -1;
+
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
@@ -1774,7 +1784,6 @@
title = "";
mTitle = TextUtils.stringOrSpannedString(title);
- accessibilityTitle = mTitle;
}
public final CharSequence getTitle() {
@@ -1847,6 +1856,7 @@
out.writeInt(needsMenuKey);
out.writeInt(accessibilityIdOfAnchor);
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
+ out.writeLong(removeTimeoutMilliseconds);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1900,6 +1910,7 @@
needsMenuKey = in.readInt();
accessibilityIdOfAnchor = in.readInt();
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ removeTimeoutMilliseconds = in.readLong();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -2120,6 +2131,9 @@
changes |= ACCESSIBILITY_TITLE_CHANGED;
}
+ // This can't change, it's only set at window creation time.
+ removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
+
return changes;
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 02d2a8b..c1076e7 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3842,7 +3842,15 @@
*/
public static RangeInfo obtain(int type, float min, float max, float current) {
RangeInfo info = sPool.acquire();
- return (info != null) ? info : new RangeInfo(type, min, max, current);
+ if (info == null) {
+ return new RangeInfo(type, min, max, current);
+ }
+
+ info.mType = type;
+ info.mMin = min;
+ info.mMax = max;
+ info.mCurrent = current;
+ return info;
}
/**
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 0ac5731..f13cbae 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -18,13 +18,14 @@
import android.annotation.SystemApi;
import android.app.ActivityManagerInternal;
+import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.res.XmlResourceParser;
+import android.content.pm.Signature;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
@@ -32,27 +33,21 @@
import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.Trace;
-import android.provider.Settings;
-import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
+import android.util.ArraySet;
import android.util.Log;
-import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
import dalvik.system.VMRuntime;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-import org.xmlpull.v1.XmlPullParserException;
-
/**
* Top level factory, used creating all the main WebView implementation classes.
*
@@ -192,52 +187,126 @@
}
}
+ /**
+ * Returns true if the signatures match, false otherwise
+ */
+ private static boolean signaturesEquals(Signature[] s1, Signature[] s2) {
+ if (s1 == null) {
+ return s2 == null;
+ }
+ if (s2 == null) return false;
+
+ ArraySet<Signature> set1 = new ArraySet<>();
+ for(Signature signature : s1) {
+ set1.add(signature);
+ }
+ ArraySet<Signature> set2 = new ArraySet<>();
+ for(Signature signature : s2) {
+ set2.add(signature);
+ }
+ return set1.equals(set2);
+ }
+
+ // Throws MissingWebViewPackageException on failure
+ private static void verifyPackageInfo(PackageInfo chosen, PackageInfo toUse) {
+ if (!chosen.packageName.equals(toUse.packageName)) {
+ throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+ + "packageName mismatch, expected: "
+ + chosen.packageName + " actual: " + toUse.packageName);
+ }
+ if (chosen.versionCode > toUse.versionCode) {
+ throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+ + "version code mismatch, expected: " + chosen.versionCode
+ + " actual: " + toUse.versionCode);
+ }
+ if (getWebViewLibrary(toUse.applicationInfo) == null) {
+ throw new MissingWebViewPackageException("Tried to load an invalid WebView provider: "
+ + toUse.packageName);
+ }
+ if (!signaturesEquals(chosen.signatures, toUse.signatures)) {
+ throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+ + "signature mismatch");
+ }
+ }
+
+ private static Context getWebViewContextAndSetProvider() {
+ Application initialApplication = AppGlobals.getInitialApplication();
+ try {
+ WebViewProviderResponse response = null;
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
+ "WebViewUpdateService.waitForAndGetProvider()");
+ try {
+ response = getUpdateService().waitForAndGetProvider();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
+ if (response.status != LIBLOAD_SUCCESS) {
+ throw new MissingWebViewPackageException("Failed to load WebView provider: "
+ + getWebViewPreparationErrorReason(response.status));
+ }
+ // Register to be killed before fetching package info - so that we will be
+ // killed if the package info goes out-of-date.
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "ActivityManager.addPackageDependency()");
+ try {
+ ActivityManagerNative.getDefault().addPackageDependency(
+ response.packageInfo.packageName);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
+ // Fetch package info and verify it against the chosen package
+ PackageInfo newPackageInfo = null;
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getPackageInfo()");
+ try {
+ newPackageInfo = initialApplication.getPackageManager().getPackageInfo(
+ response.packageInfo.packageName,
+ PackageManager.GET_SHARED_LIBRARY_FILES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
+ // Make sure that we fetch the current provider even if its not
+ // installed for the current user
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES
+ // Fetch signatures for verification
+ | PackageManager.GET_SIGNATURES
+ // Get meta-data for meta data flag verification
+ | PackageManager.GET_META_DATA);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
+
+ // Validate the newly fetched package info, throws MissingWebViewPackageException on
+ // failure
+ verifyPackageInfo(response.packageInfo, newPackageInfo);
+
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
+ "initialApplication.createApplicationContext");
+ try {
+ // Construct an app context to load the Java code into the current app.
+ Context webViewContext = initialApplication.createApplicationContext(
+ newPackageInfo.applicationInfo,
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ sPackageInfo = response.packageInfo;
+ return webViewContext;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
+ } catch (RemoteException | PackageManager.NameNotFoundException e) {
+ throw new MissingWebViewPackageException("Failed to load WebView provider: " + e);
+ }
+ }
+
private static Class<WebViewFactoryProvider> getProviderClass() {
+ Context webViewContext = null;
+ Application initialApplication = AppGlobals.getInitialApplication();
+
try {
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
- "WebViewFactory.waitForProviderAndSetPackageInfo()");
+ "WebViewFactory.getWebViewContextAndSetProvider()");
try {
- // First fetch the package info so we can log the webview package version.
- int res = waitForProviderAndSetPackageInfo();
- if (res != LIBLOAD_SUCCESS) {
- throw new MissingWebViewPackageException(
- "Failed to load WebView provider, error: "
- + getWebViewPreparationErrorReason(res));
- }
+ webViewContext = getWebViewContextAndSetProvider();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
- sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
-
- Application initialApplication = AppGlobals.getInitialApplication();
- Context webViewContext = null;
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getApplicationInfo()");
- try {
- // Construct a package context to load the Java code into the current app.
- // This is done as early as possible since by constructing a package context we
- // register the WebView package as a dependency for the current application so that
- // when the WebView package is updated this application will be killed.
- ApplicationInfo applicationInfo =
- initialApplication.getPackageManager().getApplicationInfo(
- sPackageInfo.packageName, PackageManager.GET_SHARED_LIBRARY_FILES
- | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
- // make sure that we fetch the current provider even if its not installed
- // for the current user
- | PackageManager.MATCH_UNINSTALLED_PACKAGES);
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
- "initialApplication.createApplicationContext");
- try {
- webViewContext = initialApplication.createApplicationContext(applicationInfo,
- Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
- }
- } catch (PackageManager.NameNotFoundException e) {
- throw new MissingWebViewPackageException(e);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
- }
+ sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index af46756..bb883ea 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1512,6 +1512,24 @@
outParams.x = drawingLocation[0] + xOffset;
outParams.y = drawingLocation[1] + anchorHeight + yOffset;
+ // Let the window manager know to align the top to y.
+ outParams.gravity = Gravity.LEFT | Gravity.TOP;
+ outParams.width = width;
+ outParams.height = height;
+
+ // If width or height is unspecified. We can leave it to the window manager to match
+ // to the parent size, but for our local purposes of calculating positioning, we need
+ // to fill in real width and height values.
+ final Rect displayFrame = new Rect();
+ anchor.getWindowVisibleDisplayFrame(displayFrame);
+ if (width < 0) {
+ width = displayFrame.right - displayFrame.left;
+ }
+ if (height < 0) {
+ height = displayFrame.bottom - displayFrame.top;
+ }
+
+
// If we need to adjust for gravity RIGHT, align to the bottom-right
// corner of the anchor (still accounting for offsets).
final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection())
@@ -1520,17 +1538,9 @@
outParams.x -= width - anchorWidth;
}
- // Let the window manager know to align the top to y.
- outParams.gravity = Gravity.LEFT | Gravity.TOP;
- outParams.width = width;
- outParams.height = height;
-
final int[] screenLocation = mTmpScreenLocation;
anchor.getLocationOnScreen(screenLocation);
- final Rect displayFrame = new Rect();
- anchor.getWindowVisibleDisplayFrame(displayFrame);
-
// First, attempt to fit the popup vertically without resizing.
final boolean fitsVertical = tryFitVertical(outParams, yOffset, height,
anchorHeight, drawingLocation[1], screenLocation[1], displayFrame.top,
@@ -2114,10 +2124,10 @@
// If an explicit width/height has not specified, use the most recent
// explicitly specified value (either from setWidth/Height or update).
- if (width == -1) {
+ if (width < 0) {
width = mWidth;
}
- if (height == -1) {
+ if (height < 0) {
height = mHeight;
}
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index ee716df..1a81d20 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -849,10 +849,12 @@
mEnabledDayStart = MathUtils.constrain(enabledDayStart, 1, mDaysInMonth);
mEnabledDayEnd = MathUtils.constrain(enabledDayEnd, mEnabledDayStart, mDaysInMonth);
+ updateMonthYearLabel();
+ updateDayOfWeekLabels();
+
// Invalidate cached accessibility information.
mTouchHelper.invalidateRoot();
-
- updateMonthYearLabel();
+ invalidate();
if (DEBUG_WRONG_DATE) {
Log.d(LOG_TAG, "mMonth = " + mMonth);
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 207f675..7762675 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -163,6 +163,7 @@
*/
public void setDuration(@Duration int duration) {
mDuration = duration;
+ mTN.mDuration = duration;
}
/**
@@ -342,7 +343,7 @@
};
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
- final Handler mHandler = new Handler();
+ final Handler mHandler = new Handler();
int mGravity;
int mX, mY;
@@ -352,9 +353,13 @@
View mView;
View mNextView;
+ int mDuration;
WindowManager mWM;
+ static final long SHORT_DURATION_TIMEOUT = 5000;
+ static final long LONG_DURATION_TIMEOUT = 1000;
+
TN() {
// XXX This should be changed to use a Dialog, with a Theme.Toast
// defined that sets up the layout params appropriately.
@@ -417,6 +422,8 @@
mParams.verticalMargin = mVerticalMargin;
mParams.horizontalMargin = mHorizontalMargin;
mParams.packageName = packageName;
+ mParams.removeTimeoutMilliseconds = mDuration ==
+ Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
if (mView.getParent() != null) {
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 113768e..c26fc3a 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -209,6 +209,18 @@
return mH.obtainMessage(what, 0, 0, args);
}
+ public Message obtainMessageOOOOII(int what, Object arg1, Object arg2,
+ Object arg3, Object arg4, int arg5, int arg6) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = arg1;
+ args.arg2 = arg2;
+ args.arg3 = arg3;
+ args.arg4 = arg4;
+ args.argi5 = arg5;
+ args.argi6 = arg6;
+ return mH.obtainMessage(what, 0, 0, args);
+ }
+
public Message obtainMessageIIII(int what, int arg1, int arg2,
int arg3, int arg4) {
SomeArgs args = SomeArgs.obtain();
@@ -218,7 +230,7 @@
args.argi4 = arg4;
return mH.obtainMessage(what, 0, 0, args);
}
-
+
public Message obtainMessageIIIIII(int what, int arg1, int arg2,
int arg3, int arg4, int arg5, int arg6) {
SomeArgs args = SomeArgs.obtain();
@@ -230,7 +242,7 @@
args.argi6 = arg6;
return mH.obtainMessage(what, 0, 0, args);
}
-
+
public Message obtainMessageIIIIO(int what, int arg1, int arg2,
int arg3, int arg4, Object arg5) {
SomeArgs args = SomeArgs.obtain();
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index ddca51f..5cb307f 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -347,14 +347,21 @@
final LayoutInflater inflater = LayoutInflater.from(mContext);
final MenuAdapter adapter = new MenuAdapter(menu, inflater, mOverflowOnly);
- // Apply "force show icon" setting; if the menu being shown is the top level menu, apply the
- // setting set on this CascadingMenuPopup by its creating code. If it's a submenu, or if no
- // "force" setting was explicitly set, determine the setting by examining the items.
+ // Apply "force show icon" setting. There are 4 cases:
+ // (1) This is the top level menu. Only add spacing for icons if forced.
+ // (2) This is a submenu. Add spacing if any of the visible menu items has an icon.
+ // (3) This is a top level menu that is not an overflow menu. Add spacing if any of the
+ // visible menu items has an icon.
+ // (4) This is an overflow menu or a top level menu that doesn't have "force" set.
+ // Don't allow spacing.
if (!isShowing() && mForceShowIcon) {
- adapter.setForceShowIcon(mForceShowIcon);
- } else {
- adapter.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(menu));
+ // Case 1
+ adapter.setForceShowIcon(true);
+ } else if (isShowing() || !isShowing() && !mForceShowIcon && !mOverflowOnly) {
+ // Case 2 or 3
+ adapter.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(menu));
}
+ // Case 4: Else, don't allow spacing for icons.
final int menuWidth = measureIndividualMenuWidth(adapter, null, mContext, mMenuMaxWidth);
final MenuPopupWindow popupWindow = createPopupWindow();
@@ -734,4 +741,4 @@
return window.getListView();
}
}
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
index 16e4156..10bd66f 100644
--- a/core/java/com/android/internal/view/menu/MenuPopup.java
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -187,6 +187,11 @@
/**
* Returns whether icon spacing needs to be preserved for the given menu, based on whether any
* of its items contains an icon.
+ *
+ * NOTE: This should only be used for non-overflow-only menus, because this method does not
+ * take into account whether the menu items are being shown as part of the popup or or being
+ * shown as actions in the action bar.
+ *
* @param menu
* @return Whether to preserve icon spacing.
*/
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index c4347f8..8b9d503 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -17,9 +17,15 @@
package com.android.internal.widget;
+import com.android.internal.R;
+
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,7 +44,6 @@
import android.view.animation.AnimationUtils;
import android.widget.AbsListView;
import android.widget.OverScroller;
-import com.android.internal.R;
public class ResolverDrawerLayout extends ViewGroup {
private static final String TAG = "ResolverDrawerLayout";
@@ -86,6 +91,8 @@
private final OverScroller mScroller;
private final VelocityTracker mVelocityTracker;
+ private Drawable mScrollIndicatorDrawable;
+
private OnDismissedListener mOnDismissedListener;
private RunOnDismissedListener mRunOnDismissedListener;
@@ -127,6 +134,8 @@
mMaxCollapsedHeight);
a.recycle();
+ mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material);
+
mScroller = new OverScroller(context, AnimationUtils.loadInterpolator(context,
android.R.interpolator.decelerate_quint));
mVelocityTracker = VelocityTracker.obtain();
@@ -202,8 +211,7 @@
}
final boolean isCollapsedNew = mCollapseOffset != 0;
if (isCollapsedOld != isCollapsedNew) {
- notifyViewAccessibilityStateChangedIfNeeded(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ onCollapsedChanged(isCollapsedNew);
}
} else {
// Start out collapsed at first unless we restored state for otherwise
@@ -442,8 +450,7 @@
mTopOffset += dy;
final boolean isCollapsedNew = newPos != 0;
if (isCollapsedOld != isCollapsedNew) {
- notifyViewAccessibilityStateChangedIfNeeded(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ onCollapsedChanged(isCollapsedNew);
}
postInvalidateOnAnimation();
return dy;
@@ -451,6 +458,15 @@
return 0;
}
+ private void onCollapsedChanged(boolean isCollapsed) {
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+
+ if (mScrollIndicatorDrawable != null) {
+ setWillNotDraw(!isCollapsed);
+ }
+ }
+
void dispatchOnDismissed() {
if (mOnDismissedListener != null) {
mOnDismissedListener.onDismissed();
@@ -709,6 +725,15 @@
}
@Override
+ public void onDrawForeground(Canvas canvas) {
+ if (mScrollIndicatorDrawable != null) {
+ mScrollIndicatorDrawable.draw(canvas);
+ }
+
+ super.onDrawForeground(canvas);
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int sourceWidth = MeasureSpec.getSize(widthMeasureSpec);
int widthSize = sourceWidth;
@@ -794,6 +819,8 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = getWidth();
+ View indicatorHost = null;
+
int ypos = mTopOffset;
int leftEdge = getPaddingLeft();
int rightEdge = width - getPaddingRight();
@@ -802,6 +829,9 @@
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.hasNestedScrollIndicator) {
+ indicatorHost = child;
+ }
if (child.getVisibility() == GONE) {
continue;
@@ -822,6 +852,20 @@
ypos = bottom + lp.bottomMargin;
}
+
+ if (mScrollIndicatorDrawable != null) {
+ if (indicatorHost != null) {
+ final int left = indicatorHost.getLeft();
+ final int right = indicatorHost.getRight();
+ final int bottom = indicatorHost.getTop();
+ final int top = bottom - mScrollIndicatorDrawable.getIntrinsicHeight();
+ mScrollIndicatorDrawable.setBounds(left, top, right, bottom);
+ setWillNotDraw(!isCollapsed());
+ } else {
+ mScrollIndicatorDrawable = null;
+ setWillNotDraw(true);
+ }
+ }
}
@Override
@@ -861,6 +905,7 @@
public static class LayoutParams extends MarginLayoutParams {
public boolean alwaysShow;
public boolean ignoreOffset;
+ public boolean hasNestedScrollIndicator;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
@@ -873,6 +918,9 @@
ignoreOffset = a.getBoolean(
R.styleable.ResolverDrawerLayout_LayoutParams_layout_ignoreOffset,
false);
+ hasNestedScrollIndicator = a.getBoolean(
+ R.styleable.ResolverDrawerLayout_LayoutParams_layout_hasNestedScrollIndicator,
+ false);
a.recycle();
}
@@ -884,6 +932,7 @@
super(source);
this.alwaysShow = source.alwaysShow;
this.ignoreOffset = source.ignoreOffset;
+ this.hasNestedScrollIndicator = source.hasNestedScrollIndicator;
}
public LayoutParams(MarginLayoutParams source) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7ff38fd5..d3dca5d9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -592,6 +592,7 @@
char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
+ char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -701,6 +702,9 @@
if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
addOption("-Xjitsaveprofilinginfo");
}
+ parseRuntimeOption("dalvik.vm.jitprithreadweight",
+ jitprithreadweightOptBuf,
+ "-Xjitprithreadweight:");
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index faa4192..68c818e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -479,6 +479,12 @@
return proxy->pauseSurface(surface);
}
+static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jboolean stopped) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setStopped(stopped);
+}
+
static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
jint width, jint height, jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -740,6 +746,7 @@
{ "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize },
{ "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
{ "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
+ { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped },
{ "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
{ "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 778f797..1ed93cc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3008,6 +3008,12 @@
<permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
android:protectionLevel="signature|setup" />
+ <!-- @SystemApi Allows an application to replace the app name displayed alongside notifications
+ in the N-release and later.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"
+ android:protectionLevel="signature|privileged" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 5850e50..ae94503 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -30,33 +30,37 @@
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
android:elevation="8dp"
- android:background="@color/white" >
- <TextView android:id="@+id/profile_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginEnd="8dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:visibility="gone"
- style="?attr/borderlessButtonStyle"
- android:textAppearance="?attr/textAppearanceButton"
- android:textColor="@color/material_deep_teal_500"
- android:gravity="center_vertical"
- android:layout_alignParentTop="true"
- android:layout_alignParentRight="true"
- android:singleLine="true"/>
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minHeight="56dp"
- android:textAppearance="?attr/textAppearanceMedium"
- android:gravity="start|center_vertical"
- android:paddingStart="?attr/dialogPreferredPadding"
- android:paddingEnd="?attr/dialogPreferredPadding"
- android:paddingTop="8dp"
- android:layout_below="@id/profile_button"
- android:layout_alignParentLeft="true"
- android:paddingBottom="8dp" />
+ android:background="@color/white">
+
+ <TextView
+ android:id="@+id/profile_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginEnd="8dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:visibility="gone"
+ style="?attr/borderlessButtonStyle"
+ android:textAppearance="?attr/textAppearanceButton"
+ android:textColor="@color/material_deep_teal_500"
+ android:gravity="center_vertical"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="56dp"
+ android:textAppearance="?attr/textAppearanceMedium"
+ android:gravity="start|center_vertical"
+ android:paddingStart="?attr/dialogPreferredPadding"
+ android:paddingEnd="?attr/dialogPreferredPadding"
+ android:paddingTop="8dp"
+ android:layout_below="@id/profile_button"
+ android:layout_alignParentLeft="true"
+ android:paddingBottom="8dp" />
</RelativeLayout>
<ListView
@@ -68,6 +72,7 @@
android:background="@color/white"
android:elevation="8dp"
android:nestedScrollingEnabled="true"
+ android:scrollIndicators="top|bottom"
android:divider="@null" />
<TextView android:id="@+id/empty"
@@ -84,11 +89,12 @@
<LinearLayout
android:id="@+id/button_bar"
android:visibility="gone"
- style="?android:attr/buttonBarStyle"
+ style="?attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_ignoreOffset="true"
android:layout_alwaysShow="true"
+ android:layout_hasNestedScrollIndicator="true"
android:gravity="end|center_vertical"
android:orientation="horizontal"
android:layoutDirection="locale"
@@ -99,26 +105,30 @@
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:elevation="8dp">
- <Button android:id="@+id/button_once"
- android:layout_width="wrap_content"
- android:layout_gravity="start"
- android:maxLines="2"
- style="?android:attr/buttonBarNegativeButtonStyle"
- android:minHeight="@dimen/alert_dialog_button_bar_height"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:text="@string/activity_resolver_use_once"
- android:onClick="onButtonClick" />
- <Button android:id="@+id/button_always"
- android:layout_width="wrap_content"
- android:layout_gravity="end"
- android:maxLines="2"
- android:minHeight="@dimen/alert_dialog_button_bar_height"
- style="?android:attr/buttonBarPositiveButtonStyle"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:text="@string/activity_resolver_use_always"
- android:onClick="onButtonClick" />
+
+ <Button
+ android:id="@+id/button_once"
+ android:layout_width="wrap_content"
+ android:layout_gravity="start"
+ android:maxLines="2"
+ style="?attr/buttonBarNegativeButtonStyle"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/activity_resolver_use_once"
+ android:onClick="onButtonClick" />
+
+ <Button
+ android:id="@+id/button_always"
+ android:layout_width="wrap_content"
+ android:layout_gravity="end"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?attr/buttonBarPositiveButtonStyle"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/activity_resolver_use_always"
+ android:onClick="onButtonClick" />
</LinearLayout>
</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 31361e5..02dc2ed 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -22,8 +22,7 @@
android:layout_height="match_parent"
android:maxWidth="@dimen/resolver_max_width"
android:maxCollapsedHeight="144dp"
- android:id="@id/contentPanel"
- >
+ android:id="@id/contentPanel">
<LinearLayout
android:layout_width="match_parent"
@@ -31,66 +30,75 @@
android:layout_alwaysShow="true"
android:orientation="vertical"
android:background="@color/white"
- android:elevation="8dp" >
+ android:elevation="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dp"
- android:orientation="horizontal" >
+ android:orientation="horizontal">
- <ImageView android:id="@+id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="start|top"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginTop="20dp"
- android:scaleType="fitCenter" />
- <TextView android:id="@+id/title"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:layout_marginStart="16dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:gravity="start|center_vertical"
- android:paddingEnd="16dp" />
- <LinearLayout android:id="@+id/profile_button"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginTop="4dp"
- android:layout_marginEnd="4dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
- android:focusable="true"
- android:visibility="gone"
- style="?attr/borderlessButtonStyle">
- <ImageView android:id="@+id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="start|center_vertical"
- android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
- android:scaleType="fitCenter" />
- <TextView android:id="@id/text1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start|center_vertical"
- android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
- android:textAppearance="?attr/textAppearanceButton"
- android:textColor="?attr/textColorPrimary"
- android:minLines="1"
- android:maxLines="1"
- android:ellipsize="marquee" />
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="start|top"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginTop="20dp"
+ android:scaleType="fitCenter" />
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="?attr/listPreferredItemHeight"
+ android:layout_marginStart="16dp"
+ android:textAppearance="?attr/textAppearanceMedium"
+ android:gravity="start|center_vertical"
+ android:paddingEnd="16dp" />
+
+ <LinearLayout
+ android:id="@+id/profile_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginEnd="4dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:focusable="true"
+ android:visibility="gone"
+ style="?attr/borderlessButtonStyle">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="start|center_vertical"
+ android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
+ android:scaleType="fitCenter" />
+
+ <TextView
+ android:id="@id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|center_vertical"
+ android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
+ android:textAppearance="?attr/textAppearanceButton"
+ android:textColor="?attr/textColorPrimary"
+ android:minLines="1"
+ android:maxLines="1"
+ android:ellipsize="marquee" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/button_bar"
android:visibility="gone"
- style="?android:attr/buttonBarStyle"
+ style="?attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
@@ -104,30 +112,36 @@
android:paddingEnd="12dp"
android:background="@color/white"
android:elevation="8dp">
- <Button android:id="@+id/button_once"
- android:layout_width="wrap_content"
- android:layout_gravity="start"
- android:maxLines="2"
- style="?android:attr/buttonBarNegativeButtonStyle"
- android:minHeight="@dimen/alert_dialog_button_bar_height"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:text="@string/activity_resolver_use_once"
- android:onClick="onButtonClick" />
- <Button android:id="@+id/button_always"
- android:layout_width="wrap_content"
- android:layout_gravity="end"
- android:maxLines="2"
- android:minHeight="@dimen/alert_dialog_button_bar_height"
- style="?android:attr/buttonBarPositiveButtonStyle"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:text="@string/activity_resolver_use_always"
- android:onClick="onButtonClick" />
+
+ <Button
+ android:id="@+id/button_once"
+ android:layout_width="wrap_content"
+ android:layout_gravity="start"
+ android:maxLines="2"
+ style="?attr/buttonBarNegativeButtonStyle"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/activity_resolver_use_once"
+ android:onClick="onButtonClick" />
+
+ <Button
+ android:id="@+id/button_always"
+ android:layout_width="wrap_content"
+ android:layout_gravity="end"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?attr/buttonBarPositiveButtonStyle"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/activity_resolver_use_always"
+ android:onClick="onButtonClick" />
</LinearLayout>
- <View android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/dividerVertical" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/dividerVertical" />
</LinearLayout>
<ListView
@@ -139,7 +153,6 @@
android:background="@color/white"
android:elevation="8dp"
android:nestedScrollingEnabled="true"
- android:divider="@null"
- />
+ android:divider="@null" />
</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/values-mcc310-mnc160/strings.xml b/core/res/res/values-mcc310-mnc160/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc160/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc200/strings.xml b/core/res/res/values-mcc310-mnc200/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc200/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc210/strings.xml b/core/res/res/values-mcc310-mnc210/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc210/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc220/strings.xml b/core/res/res/values-mcc310-mnc220/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc220/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc230/strings.xml b/core/res/res/values-mcc310-mnc230/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc230/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc240/strings.xml b/core/res/res/values-mcc310-mnc240/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc240/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc250/strings.xml b/core/res/res/values-mcc310-mnc250/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc250/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc260/strings.xml b/core/res/res/values-mcc310-mnc260/strings.xml
deleted file mode 100644
index dc79877..0000000
--- a/core/res/res/values-mcc310-mnc260/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc270/strings.xml b/core/res/res/values-mcc310-mnc270/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc270/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc310/strings.xml b/core/res/res/values-mcc310-mnc310/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc310/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc490/strings.xml b/core/res/res/values-mcc310-mnc490/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc490/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc660/strings.xml b/core/res/res/values-mcc310-mnc660/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc660/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc800/strings.xml b/core/res/res/values-mcc310-mnc800/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc800/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false">
- <item>REG09</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages">
- <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
- </string-array>
- <!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages">
- <item>Register with your carrier</item>
- </string-array>
- <!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a320ef6..85e0b88 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8138,6 +8138,7 @@
<attr name="layout_alwaysShow" format="boolean" />
<attr name="layout_ignoreOffset" format="boolean" />
<attr name="layout_gravity" />
+ <attr name="layout_hasNestedScrollIndicator" format="boolean" />
</declare-styleable>
<!-- @hide -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6ff7139..80b3a64 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2713,11 +2713,14 @@
<public type="attr" name="forceHasOverlappingRendering" />
<public type="attr" name="contentInsetStartWithNavigation" />
<public type="attr" name="contentInsetEndWithActions" />
+ <public type="attr" name="numberPickerStyle" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
<public type="style" name="Widget.Material.CompoundButton.Switch" />
<public type="style" name="Widget.Material.Light.CompoundButton.Switch" />
+ <public type="style" name="Widget.Material.NumberPicker" />
+ <public type="style" name="Widget.Material.Light.NumberPicker" />
<public type="id" name="accessibilityActionSetProgress" />
<public type="id" name="icon_frame" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0a99239..836efde 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -245,16 +245,19 @@
<!-- Displayed when WFC registration fails -->
<string name="wfcRegErrorTitle">Wi-Fi Calling</string>
- <!-- WFC Operator Error Codes -->
- <string-array name="wfcOperatorErrorCodes" translatable="false" />
<!-- WFC Operator Error Messages showed as alerts -->
- <string-array name="wfcOperatorErrorAlertMessages" />
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+ </string-array>
<!-- WFC Operator Error Messages showed as notifications -->
- <string-array name="wfcOperatorErrorNotificationMessages" />
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item>Register with your carrier</item>
+ </string-array>
<!-- Template for showing cellular network operator name while WFC is active -->
- <string name="wfcSpnFormat">%s</string>
- <!-- Template for showing operator name for data connection while WFC is active -->
- <string name="wfcDataSpnFormat">%s</string>
+ <string-array name="wfcSpnFormats">
+ <item>%s</item>
+ <item>%s Wi-Fi Calling</item>
+ </string-array>
<!-- WFC, summary for Disabled -->
<string name="wifi_calling_off_summary">Off</string>
<!-- WFC, summary for Wi-Fi Preferred -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 541ee75..a35b409 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -771,11 +771,9 @@
<java-symbol type="string" name="phoneTypeWorkMobile" />
<java-symbol type="string" name="phoneTypeWorkPager" />
<java-symbol type="string" name="wfcRegErrorTitle" />
- <java-symbol type="array" name="wfcOperatorErrorCodes" />
<java-symbol type="array" name="wfcOperatorErrorAlertMessages" />
<java-symbol type="array" name="wfcOperatorErrorNotificationMessages" />
- <java-symbol type="string" name="wfcSpnFormat" />
- <java-symbol type="string" name="wfcDataSpnFormat" />
+ <java-symbol type="array" name="wfcSpnFormats" />
<java-symbol type="string" name="wifi_calling_off_summary" />
<java-symbol type="string" name="wfc_mode_wifi_preferred_summary" />
<java-symbol type="string" name="wfc_mode_cellular_preferred_summary" />
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index bcac6a1..117e17b 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -320,6 +320,7 @@
</family>
<family lang="und-Tibt">
<font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
+ <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font>
</family>
<family lang="und-Tfng">
<font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
@@ -350,6 +351,9 @@
<font weight="400" style="normal">NotoColorEmoji.ttf</font>
</family>
<family>
+ <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
+ </family>
+ <family>
<font weight="400" style="normal">DroidSansFallback.ttf</font>
</family>
<!--
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index aa1ed0a..026f7a0 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -152,8 +152,10 @@
<p>Generating a new {@link java.security.PrivateKey} requires that
you also specify the initial X.509 attributes that the self-signed
- certificate will have. You can replace the certificate at a later
- time with a certificate signed by a Certificate Authority.</p>
+ certificate will have. You can use
+ {@link java.security.KeyStore#setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[]) KeyStore.setKeyEntry}
+ to replace the certificate at a later time with a certificate signed
+ by a Certificate Authority (CA).</p>
<p>To generate the key, use a {@link java.security.KeyPairGenerator}
with {@link android.security.KeyPairGeneratorSpec}:</p>
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index cf5c563..7f3a437 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -121,6 +121,47 @@
* whose overall size is modified based on the current level.
* </ul>
*
+ * <a name="Custom"></a>
+ * <h3>Custom drawables</h3>
+ *
+ * <p>
+ * All versions of Android allow the Drawable class to be extended and used at
+ * run time in place of framework-provided drawable classes. Starting in
+ * {@link android.os.Build.VERSION_CODES#N API 24}, custom drawables classes
+ * may also be used in XML.
+ * <p>
+ * <strong>Note:</strong> Custom drawable classes are only accessible from
+ * within your application package. Other applications will not be able to load
+ * them.
+ * <p>
+ * At a minimum, custom drawable classes must implement the abstract methods on
+ * Drawable and should override the {@link Drawable#draw(Canvas)} method to
+ * draw content.
+ * <p>
+ * Custom drawables classes may be used in XML in multiple ways:
+ * <ul>
+ * <li>
+ * Using the fully-qualified class name as the XML element name. For
+ * this method, the custom drawable class must be a public top-level
+ * class.
+ * <pre>
+ * <com.myapp.MyCustomDrawable xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:color="#ffff0000" />
+ * </pre>
+ * </li>
+ * <li>
+ * Using <em>drawable</em> as the XML element name and specifying the
+ * fully-qualified class name from the <em>class</em> attribute. This
+ * method may be used for both public top-level classes and public
+ * static inner classes.
+ * <pre>
+ * <drawable xmlns:android="http://schemas.android.com/apk/res/android"
+ * class="com.myapp.MyTopLevelClass$InnerCustomDrawable"
+ * android:color="#ffff0000" />
+ * </pre>
+ * </li>
+ * </ul>
+ *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about how to use drawables, read the
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 35fe06d..fe68239 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -253,7 +253,9 @@
path.transform(skTransform, &transformed);
SkRegion region;
regionFromPath(transformed, region);
- clipRegion(region, op);
+ enterRegionMode();
+ mClipRegion.op(region, op);
+ onClipRegionUpdated();
}
/*
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ab66b2a..890d4a1 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -113,18 +113,11 @@
mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
mHaveNewSurface = true;
mSwapHistory.clear();
- makeCurrent();
} else {
mRenderThread.removeFrameCallback(this);
}
}
-void CanvasContext::requireSurface() {
- LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
- "requireSurface() called but no surface set!");
- makeCurrent();
-}
-
void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
mSwapBehavior = swapBehavior;
}
@@ -146,6 +139,18 @@
return mRenderThread.removeFrameCallback(this);
}
+void CanvasContext::setStopped(bool stopped) {
+ if (mStopped != stopped) {
+ mStopped = stopped;
+ if (mStopped) {
+ mRenderThread.removeFrameCallback(this);
+ if (mEglManager.isCurrent(mEglSurface)) {
+ mEglManager.makeCurrent(EGL_NO_SURFACE);
+ }
+ }
+ }
+}
+
// TODO: don't pass viewport size, it's automatic via EGL
void CanvasContext::setup(int width, int height, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
@@ -172,7 +177,9 @@
mOpaque = opaque;
}
-void CanvasContext::makeCurrent() {
+bool CanvasContext::makeCurrent() {
+ if (mStopped) return false;
+
// TODO: Figure out why this workaround is needed, see b/13913604
// In the meantime this matches the behavior of GLRenderer, so it is not a regression
EGLint error = 0;
@@ -180,6 +187,7 @@
if (error) {
setSurface(nullptr);
}
+ return !error;
}
static bool wasSkipped(FrameInfo* info) {
@@ -671,7 +679,7 @@
}
Layer* CanvasContext::createTextureLayer() {
- requireSurface();
+ mEglManager.initialize();
return LayerRenderer::createTextureLayer(mRenderThread.renderState());
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 9350114..52df3abe 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -82,13 +82,14 @@
void initialize(Surface* surface);
void updateSurface(Surface* surface);
bool pauseSurface(Surface* surface);
+ void setStopped(bool stopped);
bool hasSurface() { return mNativeSurface.get(); }
void setup(int width, int height, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightCenter(const Vector3& lightCenter);
void setOpaque(bool opaque);
- void makeCurrent();
+ bool makeCurrent();
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
int64_t syncQueued, RenderNode* target);
void draw();
@@ -172,7 +173,6 @@
friend class android::uirenderer::RenderState;
void setSurface(Surface* window);
- void requireSurface();
void freePrefetchedLayers(TreeObserver* observer);
@@ -185,6 +185,7 @@
EglManager& mEglManager;
sp<Surface> mNativeSurface;
EGLSurface mEglSurface = EGL_NO_SURFACE;
+ bool mStopped = false;
bool mBufferPreserved = false;
SwapBehavior mSwapBehavior = kSwap_default;
struct SwapHistory {
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 651aaa2..ed472ac 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -115,7 +115,7 @@
ATRACE_CALL();
int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
mRenderThread->timeLord().vsyncReceived(vsync);
- mContext->makeCurrent();
+ bool canDraw = mContext->makeCurrent();
Caches::getInstance().textureCache.resetMarkInUse(mContext);
for (size_t i = 0; i < mLayers.size(); i++) {
@@ -126,8 +126,9 @@
// This is after the prepareTree so that any pending operations
// (RenderNode tree state, prefetched layers, etc...) will be flushed.
- if (CC_UNLIKELY(!mContext->hasSurface())) {
+ if (CC_UNLIKELY(!mContext->hasSurface() || !canDraw)) {
mSyncResult |= kSync_LostSurfaceRewardIfFound;
+ info.out.canDrawThisFrame = false;
}
if (info.out.hasAnimations) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 8def7ad..ac6a28f 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -270,12 +270,6 @@
// Ensure we always have a valid surface & context
surface = mPBufferSurface;
}
- // TODO: Temporary to help diagnose b/27286867
- if (mCurrentSurface == mPBufferSurface || surface == mPBufferSurface) {
- ALOGD("Switching from surface %p%s to %p%s", mCurrentSurface,
- mCurrentSurface == mPBufferSurface ? " (pbuffer)" : "",
- surface, surface == mPBufferSurface ? " (pbuffer)" : "");
- }
if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
if (errOut) {
*errOut = eglGetError();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 096093c..5e37856 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -168,6 +168,18 @@
return (bool) postAndWait(task);
}
+CREATE_BRIDGE2(setStopped, CanvasContext* context, bool stopped) {
+ args->context->setStopped(args->stopped);
+ return nullptr;
+}
+
+void RenderProxy::setStopped(bool stopped) {
+ SETUP_TASK(setStopped);
+ args->context = mContext;
+ args->stopped = stopped;
+ postAndWait(task);
+}
+
CREATE_BRIDGE6(setup, CanvasContext* context, int width, int height,
float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
args->context->setup(args->width, args->height, args->lightRadius,
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 98aace0..c39319d 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -79,6 +79,7 @@
ANDROID_API void initialize(const sp<Surface>& surface);
ANDROID_API void updateSurface(const sp<Surface>& surface);
ANDROID_API bool pauseSurface(const sp<Surface>& surface);
+ ANDROID_API void setStopped(bool stopped);
ANDROID_API void setup(int width, int height, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
ANDROID_API void setLightCenter(const Vector3& lightCenter);
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index b864703..54ca68d 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -132,6 +132,7 @@
auto serializedClip = area.serializeClip(allocator);
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode);
+ ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
EXPECT_EQ(Rect(200, 200), serializedClip->rect);
EXPECT_EQ(serializedClip, area.serializeClip(allocator))
<< "Requery of clip on unmodified ClipArea must return same pointer.";
@@ -145,6 +146,7 @@
auto serializedClip = area.serializeClip(allocator);
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
+ ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
EXPECT_EQ(Rect(37, 54, 145, 163), clipRectList->rect);
@@ -160,6 +162,7 @@
auto serializedClip = area.serializeClip(allocator);
ASSERT_NE(nullptr, serializedClip);
ASSERT_EQ(ClipMode::Region, serializedClip->mode);
+ ASSERT_TRUE(serializedClip->intersectWithRoot) << "Replace op, so expect intersectWithRoot";
auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip);
EXPECT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
<< "Clip region should be 200x200";
@@ -169,6 +172,18 @@
}
}
+TEST(ClipArea, serializeClip_pathIntersectWithRoot) {
+ ClipArea area(createClipArea());
+ LinearAllocator allocator;
+ SkPath circlePath;
+ circlePath.addCircle(100, 100, 100);
+ area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kIntersect_Op);
+
+ auto serializedClip = area.serializeClip(allocator);
+ ASSERT_NE(nullptr, serializedClip);
+ EXPECT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
+}
+
TEST(ClipArea, serializeIntersectedClip) {
ClipArea area(createClipArea());
LinearAllocator allocator;
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index e8c50e3..db7b43a 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1217,6 +1217,18 @@
public static final String COLUMN_SEARCHABLE = "searchable";
/**
+ * The flag indicating whether recording of this program is prohibited.
+ *
+ * <p>A value of 1 indicates that recording of this program is prohibited and application
+ * will not schedule any recording for this program. A value of 0 indicates that the
+ * recording is not prohibited. If not specified, this value is set to 0 (not prohibited) by
+ * default.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+
+ /**
* Internal data used by individual TV input services.
*
* <p>This is internal to the provider that inserted it, and should not be decoded by other
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d74dda6..bfd938e 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -483,26 +483,19 @@
}
/**
- * This is called when the start playback position is changed.
- *
- * <p>The start playback position of the time shifted program should be adjusted when the TV
- * input cannot retain the whole recorded program due to some reason (e.g. limitation on
- * storage space). This is necessary to prevent the application from allowing the user to
- * seek to a time position that is not reachable.
+ * This is called when the start position for time shifting has changed.
*
* @param session A {@link TvInputManager.Session} associated with this callback.
- * @param timeMs The start playback position of the time shifted program, in milliseconds
- * since the epoch.
+ * @param timeMs The start position for time shifting, in milliseconds since the epoch.
*/
public void onTimeShiftStartPositionChanged(Session session, long timeMs) {
}
/**
- * This is called when the current playback position is changed.
+ * This is called when the current position for time shifting is changed.
*
* @param session A {@link TvInputManager.Session} associated with this callback.
- * @param timeMs The current playback position of the time shifted program, in milliseconds
- * since the epoch.
+ * @param timeMs The current position for time shifting, in milliseconds since the epoch.
*/
public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
}
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 3780f6f..e134635 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -996,15 +996,18 @@
}
/**
- * Returns the start playback position for time shifting, in milliseconds since the epoch.
+ * Returns the start position for time shifting, in milliseconds since the epoch.
* Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the
* moment.
*
- * <p>The start playback position of the time shifted program should be adjusted when the
- * implementation cannot retain the whole recorded program due to some reason (e.g.
- * limitation on storage space). It is the earliest possible time position that the user can
- * seek to, thus failure to notifying its change immediately might result in bad experience
- * where the application allows the user to seek to an invalid time position.
+ * <p>The start position for time shifting indicates the earliest possible time the user can
+ * seek to. Initially this is equivalent to the time when the implementation starts
+ * recording. Later it may be adjusted because there is insufficient space or the duration
+ * of recording is limited by the implementation. The application does not allow the user to
+ * seek to a position earlier than the start position.
+ *
+ * <p>For playback of a recorded program initiated by {@link #onTimeShiftPlay(Uri)}, the
+ * start position is the time when playback starts. It does not change.
*
* @see #onTimeShiftPlay(Uri)
* @see #onTimeShiftResume()
@@ -1018,13 +1021,13 @@
}
/**
- * Returns the current playback position for time shifting, in milliseconds since the epoch.
+ * Returns the current position for time shifting, in milliseconds since the epoch.
* Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the
* moment.
*
- * <p>Note that the current playback position should be equal to or greater than the start
- * playback position reported by {@link #onTimeShiftGetStartPosition}. Failure to notifying
- * the correct current position might lead to bad user experience.
+ * <p>The current position for time shifting is the same as the current position of
+ * playback. It should be equal to or greater than the start position reported by
+ * {@link #onTimeShiftGetStartPosition()}.
*
* @see #onTimeShiftPlay(Uri)
* @see #onTimeShiftResume()
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 71b0193..10cec1f 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -848,32 +848,34 @@
public abstract static class TimeShiftPositionCallback {
/**
- * This is called when the start playback position is changed.
+ * This is called when the start position for time shifting has changed.
*
- * <p>The start playback position of the time shifted program can be adjusted by the TV
- * input when it cannot retain the whole recorded program due to some reason (e.g.
- * limitation on storage space). The application should not allow the user to seek to a
- * position earlier than the start position.
+ * <p>The start position for time shifting indicates the earliest possible time the user can
+ * seek to. Initially this is equivalent to the time when the underlying TV input starts
+ * recording. Later it may be adjusted because there is insufficient space or the duration
+ * of recording is limited. The application must not allow the user to seek to a position
+ * earlier than the start position.
*
- * <p>Note that {@code timeMs} is not relative time in the program but wall-clock time,
- * which is intended to avoid calling this method unnecessarily around program boundaries.
+ * <p>For playback of a recorded program initiated by {@link #timeShiftPlay(String, Uri)},
+ * the start position is the time when playback starts. It does not change.
*
* @param inputId The ID of the TV input bound to this view.
- * @param timeMs The start playback position of the time shifted program, in milliseconds
- * since the epoch.
+ * @param timeMs The start position for time shifting, in milliseconds since the epoch.
*/
public void onTimeShiftStartPositionChanged(String inputId, long timeMs) {
}
/**
- * This is called when the current playback position is changed.
+ * This is called when the current position for time shifting has changed.
*
- * <p>Note that {@code timeMs} is not relative time in the program but wall-clock time,
- * which is intended to avoid calling this method unnecessarily around program boundaries.
+ * <p>The current position for time shifting is the same as the current position of
+ * playback. During playback, the current position changes continuously. When paused, it
+ * does not change.
+ *
+ * <p>Note that {@code timeMs} is wall-clock time.
*
* @param inputId The ID of the TV input bound to this view.
- * @param timeMs The current playback position of the time shifted program, in milliseconds
- * since the epoch.
+ * @param timeMs The current position for time shifting, in milliseconds since the epoch.
*/
public void onTimeShiftCurrentPositionChanged(String inputId, long timeMs) {
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
index 15bfc3b..059b5e0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
@@ -32,6 +32,7 @@
import libcore.io.IoUtils;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -76,7 +77,8 @@
* This should be run from inside an AsyncTask.
*/
public List<DocumentInfo> getClippedDocuments() {
- return getDocumentsFromClipData(mClipboard.getPrimaryClip());
+ ClipData data = mClipboard.getPrimaryClip();
+ return data == null ? Collections.EMPTY_LIST : getDocumentsFromClipData(data);
}
/**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index f3b750a..d830c61 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -84,6 +84,13 @@
new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // Only handle key-down events. This is simpler, consistent with most other
+ // UIs, and enables the handling of repeated key events from holding down a
+ // key.
+ if (event.getAction() != KeyEvent.ACTION_DOWN) {
+ return false;
+ }
+
if (keyCode == KeyEvent.KEYCODE_ENTER && mSave.isEnabled()) {
performSave();
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index fba25ab..ccb2886 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -524,6 +524,7 @@
}
if (mActionMode != null) {
+ assert(!mSelected.isEmpty());
final String title = Shared.getQuantityString(getActivity(),
R.plurals.elements_selected, mSelected.size());
mActionMode.setTitle(title);
@@ -809,6 +810,8 @@
// the user cancels the delete.
if (mActionMode != null) {
mActionMode.finish();
+ } else {
+ Log.w(TAG, "Action mode is null before deleting documents.");
}
// Hide the files in the UI...since the operation
// might be queued up on FileOperationService.
@@ -1176,14 +1179,23 @@
case DragEvent.ACTION_DROP:
// After a drop event, always stop highlighting the target.
setDropTargetHighlight(v, false);
+
+ ClipData clipData = event.getClipData();
+ if (clipData == null) {
+ Log.w(TAG, "Received invalid drop event with null clipdata. Ignoring.");
+ return false;
+ }
+
// Don't copy from the cwd into the cwd. Note: this currently doesn't work for
// multi-window drag, because localState isn't carried over from one process to
// another.
Object src = event.getLocalState();
DocumentInfo dst = getDestination(v);
if (Objects.equals(src, dst)) {
+ if (DEBUG) Log.d(TAG, "Drop target same as source. Ignoring.");
return false;
}
+
// Recognize multi-window drag and drop based on the fact that localState is not
// carried between processes. It will stop working when the localsState behavior
// is changed. The info about window should be passed in the localState then.
@@ -1192,7 +1204,8 @@
Metrics.logUserAction(getContext(),
src == null ? Metrics.USER_ACTION_DRAG_N_DROP_MULTI_WINDOW
: Metrics.USER_ACTION_DRAG_N_DROP);
- copyFromClipData(event.getClipData(), dst);
+
+ copyFromClipData(clipData, dst);
return true;
}
return false;
@@ -1436,7 +1449,8 @@
// This has to be handled here instead of in a keyboard shortcut, because
// keyboard shortcuts all have to be modified with the 'Ctrl' key.
if (mSelectionManager.hasSelection()) {
- deleteDocuments(mSelectionManager.getSelection());
+ Selection selection = mSelectionManager.getSelection(new Selection());
+ deleteDocuments(selection);
}
// Always handle the key, even if there was nothing to delete. This is a
// precaution to prevent other handlers from potentially picking up the event
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
index 580fa38..871e135 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
@@ -229,31 +229,32 @@
@OpType int operationType, String id, List<DocumentInfo> srcs, DocumentInfo srcParent,
DocumentStack stack) {
+ if (srcs.isEmpty()) {
+ Log.w(TAG, "Ignoring job request with empty srcs list. Id: " + id);
+ return null;
+ }
+
if (mRunning.containsKey(id)) {
Log.w(TAG, "Duplicate job id: " + id
+ ". Ignoring job request for srcs: " + srcs + ", stack: " + stack + ".");
return null;
}
- Job job = null;
switch (operationType) {
case OPERATION_COPY:
- job = jobFactory.createCopy(this, getApplicationContext(), this, id, stack, srcs);
- break;
+ return jobFactory.createCopy(
+ this, getApplicationContext(), this, id, stack, srcs);
case OPERATION_MOVE:
- job = jobFactory.createMove(this, getApplicationContext(), this, id, stack, srcs,
+ return jobFactory.createMove(
+ this, getApplicationContext(), this, id, stack, srcs,
srcParent);
- break;
case OPERATION_DELETE:
- job = jobFactory.createDelete(this, getApplicationContext(), this, id, stack, srcs,
+ return jobFactory.createDelete(
+ this, getApplicationContext(), this, id, stack, srcs,
srcParent);
- break;
default:
throw new UnsupportedOperationException();
}
-
- assert(job != null);
- return job;
}
@GuardedBy("mRunning")
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index c723ac6..b4f1299 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -291,18 +291,24 @@
Job createCopy(Context service, Context appContext, Listener listener,
String id, DocumentStack stack, List<DocumentInfo> srcs) {
+ assert(!srcs.isEmpty());
+ assert(stack.peek().isCreateSupported());
return new CopyJob(service, appContext, listener, id, stack, srcs);
}
Job createMove(Context service, Context appContext, Listener listener,
String id, DocumentStack stack, List<DocumentInfo> srcs,
DocumentInfo srcParent) {
+ assert(!srcs.isEmpty());
+ assert(stack.peek().isCreateSupported());
return new MoveJob(service, appContext, listener, id, stack, srcs, srcParent);
}
Job createDelete(Context service, Context appContext, Listener listener,
String id, DocumentStack stack, List<DocumentInfo> srcs,
DocumentInfo srcParent) {
+ assert(!srcs.isEmpty());
+ assert(stack.peek().isDirectory()); // we can't currently delete from archives.
return new DeleteJob(service, appContext, listener, id, stack, srcs, srcParent);
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
index 4d5392e..96d963f 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
@@ -79,6 +79,16 @@
mJobFactory.assertAllJobsStarted();
}
+ public void testRunsJobs_AfterExceptionInJobCreation() throws Exception {
+ startService(createCopyIntent(new ArrayList<DocumentInfo>(), BETA_DOC));
+ startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
+
+ mJobFactory.assertJobsCreated(1);
+
+ mExecutor.runAll();
+ mJobFactory.assertAllJobsStarted();
+ }
+
public void testRunsJobs_AfterFailure() throws Exception {
startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
@@ -182,9 +192,18 @@
}
}
+ void assertJobsCreated(int expected) {
+ assertEquals(expected, jobs.size());
+ }
+
@Override
Job createCopy(Context service, Context appContext, Listener listener, String id,
DocumentStack stack, List<DocumentInfo> srcs) {
+
+ if (srcs.isEmpty()) {
+ throw new RuntimeException("Empty srcs not supported!");
+ }
+
TestJob job = new TestJob(service, appContext, listener, OPERATION_COPY, id, stack);
jobs.add(job);
return job;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 8881034..8c2af45 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -839,8 +839,18 @@
for (int i = 0; i < mEntriesMap.size(); i++) {
int userId = mEntriesMap.keyAt(i);
- List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(launchIntent,
- PackageManager.GET_DISABLED_COMPONENTS, userId);
+ // If we do not specify MATCH_DIRECT_BOOT_AWARE or
+ // MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags
+ // according to the user's lock state. When the user is locked, components
+ // with ComponentInfo#directBootAware == false will be filtered. We should
+ // explicitly include both direct boot aware and unaware components here.
+ List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
+ launchIntent,
+ PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ userId
+ );
synchronized (mEntriesMap) {
if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_LAUNCHER acquired lock");
HashMap<String, AppEntry> userEntries = mEntriesMap.valueAt(i);
@@ -1116,6 +1126,10 @@
public boolean mounted;
+ /**
+ * Setting this to {@code true} prevents the entry to be filtered by
+ * {@link #FILTER_DOWNLOADED_AND_LAUNCHER}.
+ */
public boolean hasLauncherEntry;
public String getNormalizedLabel() {
@@ -1286,6 +1300,9 @@
}
};
+ /**
+ * Displays a combined list with "downloaded" and "visible in launcher" apps only.
+ */
public static final AppFilter FILTER_DOWNLOADED_AND_LAUNCHER = new AppFilter() {
public void init() {
}
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_gain_animation.xml
similarity index 92%
rename from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_text_focus_gain_animation.xml
index 681ff91..257bf35 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_gain_animation.xml
@@ -18,4 +18,4 @@
android:propertyName="alpha"
android:valueTo="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_lose_animation.xml
similarity index 92%
rename from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_text_focus_lose_animation.xml
index e6deb0f..e032008 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_lose_animation.xml
@@ -18,4 +18,4 @@
android:propertyName="alpha"
android:valueTo="0"
android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
similarity index 92%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
copy to packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
index 681ff91..257bf35 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
@@ -18,4 +18,4 @@
android:propertyName="alpha"
android:valueTo="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
similarity index 92%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
copy to packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
index e6deb0f..e032008 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
@@ -18,4 +18,4 @@
android:propertyName="alpha"
android:valueTo="0"
android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_button_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_button_enter_animation.xml
new file mode 100644
index 0000000..01c263b
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_onboarding_button_enter_animation.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <objectAnimator
+ android:propertyName="translationY"
+ android:valueFrom="114dp"
+ android:valueTo="0dp"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/tv_pip_onboarding_anim_duration" />
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear"
+ android:duration="@integer/tv_pip_onboarding_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_description_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_description_enter_animation.xml
new file mode 100644
index 0000000..a12b3b6
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_onboarding_description_enter_animation.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <objectAnimator
+ android:propertyName="translationY"
+ android:valueFrom="84dp"
+ android:valueTo="0dp"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/tv_pip_onboarding_anim_duration" />
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear"
+ android:duration="@integer/tv_pip_onboarding_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_image_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_image_enter_animation.xml
new file mode 100644
index 0000000..ae9677e
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_onboarding_image_enter_animation.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <objectAnimator
+ android:propertyName="translationY"
+ android:valueFrom="114dp"
+ android:valueTo="0dp"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/tv_pip_onboarding_anim_duration" />
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/tv_pip_onboarding_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_title_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_title_enter_animation.xml
new file mode 100644
index 0000000..4bde070
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_onboarding_title_enter_animation.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <objectAnimator
+ android:propertyName="translationY"
+ android:valueFrom="84dp"
+ android:valueTo="0dp"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/tv_pip_onboarding_anim_duration" />
+ <objectAnimator
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="@integer/tv_pip_onboarding_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote.png b/packages/SystemUI/res/drawable-xhdpi/remote.png
new file mode 100644
index 0000000..c0ccfe6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_0.png b/packages/SystemUI/res/drawable-xhdpi/remote_0.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_1.png b/packages/SystemUI/res/drawable-xhdpi/remote_1.png
new file mode 100644
index 0000000..252ff5e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_10.png b/packages/SystemUI/res/drawable-xhdpi/remote_10.png
new file mode 100644
index 0000000..5e52b37
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_10.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_100.png b/packages/SystemUI/res/drawable-xhdpi/remote_100.png
new file mode 100644
index 0000000..f604808
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_101.png b/packages/SystemUI/res/drawable-xhdpi/remote_101.png
new file mode 100644
index 0000000..0272e45
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_101.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_102.png b/packages/SystemUI/res/drawable-xhdpi/remote_102.png
new file mode 100644
index 0000000..aaa35c0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_102.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_103.png b/packages/SystemUI/res/drawable-xhdpi/remote_103.png
new file mode 100644
index 0000000..20f95a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_103.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_104.png b/packages/SystemUI/res/drawable-xhdpi/remote_104.png
new file mode 100644
index 0000000..052f23e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_104.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_105.png b/packages/SystemUI/res/drawable-xhdpi/remote_105.png
new file mode 100644
index 0000000..c5c8256
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_105.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_106.png b/packages/SystemUI/res/drawable-xhdpi/remote_106.png
new file mode 100644
index 0000000..4e804fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_106.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_107.png b/packages/SystemUI/res/drawable-xhdpi/remote_107.png
new file mode 100644
index 0000000..76669cc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_107.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_108.png b/packages/SystemUI/res/drawable-xhdpi/remote_108.png
new file mode 100644
index 0000000..c1b2f3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_108.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_109.png b/packages/SystemUI/res/drawable-xhdpi/remote_109.png
new file mode 100644
index 0000000..79e1d7b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_109.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_11.png b/packages/SystemUI/res/drawable-xhdpi/remote_11.png
new file mode 100644
index 0000000..cfec6cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_11.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_110.png b/packages/SystemUI/res/drawable-xhdpi/remote_110.png
new file mode 100644
index 0000000..d902297
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_110.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_111.png b/packages/SystemUI/res/drawable-xhdpi/remote_111.png
new file mode 100644
index 0000000..e48ed0b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_111.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_112.png b/packages/SystemUI/res/drawable-xhdpi/remote_112.png
new file mode 100644
index 0000000..90dd1a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_112.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_113.png b/packages/SystemUI/res/drawable-xhdpi/remote_113.png
new file mode 100644
index 0000000..8fb4ad2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_113.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_114.png b/packages/SystemUI/res/drawable-xhdpi/remote_114.png
new file mode 100644
index 0000000..76873fb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_114.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_115.png b/packages/SystemUI/res/drawable-xhdpi/remote_115.png
new file mode 100644
index 0000000..e923d4c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_115.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_116.png b/packages/SystemUI/res/drawable-xhdpi/remote_116.png
new file mode 100644
index 0000000..41d5124
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_116.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_117.png b/packages/SystemUI/res/drawable-xhdpi/remote_117.png
new file mode 100644
index 0000000..eacde64
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_117.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_118.png b/packages/SystemUI/res/drawable-xhdpi/remote_118.png
new file mode 100644
index 0000000..5dc1fb0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_118.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_119.png b/packages/SystemUI/res/drawable-xhdpi/remote_119.png
new file mode 100644
index 0000000..a16f037
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_119.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_12.png b/packages/SystemUI/res/drawable-xhdpi/remote_12.png
new file mode 100644
index 0000000..28bb387
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_12.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_120.png b/packages/SystemUI/res/drawable-xhdpi/remote_120.png
new file mode 100644
index 0000000..fe3ef41
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_120.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_121.png b/packages/SystemUI/res/drawable-xhdpi/remote_121.png
new file mode 100644
index 0000000..ef2b892
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_121.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_122.png b/packages/SystemUI/res/drawable-xhdpi/remote_122.png
new file mode 100644
index 0000000..5342976
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_122.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_123.png b/packages/SystemUI/res/drawable-xhdpi/remote_123.png
new file mode 100644
index 0000000..bb8a53a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_123.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_124.png b/packages/SystemUI/res/drawable-xhdpi/remote_124.png
new file mode 100644
index 0000000..b68337e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_124.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_125.png b/packages/SystemUI/res/drawable-xhdpi/remote_125.png
new file mode 100644
index 0000000..81fa3a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_125.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_126.png b/packages/SystemUI/res/drawable-xhdpi/remote_126.png
new file mode 100644
index 0000000..2339d74
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_126.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_127.png b/packages/SystemUI/res/drawable-xhdpi/remote_127.png
new file mode 100644
index 0000000..90d1e0b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_127.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_128.png b/packages/SystemUI/res/drawable-xhdpi/remote_128.png
new file mode 100644
index 0000000..6de4eb8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_128.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_129.png b/packages/SystemUI/res/drawable-xhdpi/remote_129.png
new file mode 100644
index 0000000..9086074
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_129.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_13.png b/packages/SystemUI/res/drawable-xhdpi/remote_13.png
new file mode 100644
index 0000000..a1e212d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_13.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_130.png b/packages/SystemUI/res/drawable-xhdpi/remote_130.png
new file mode 100644
index 0000000..2bc9698
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_130.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_131.png b/packages/SystemUI/res/drawable-xhdpi/remote_131.png
new file mode 100644
index 0000000..d18d2c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_131.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_132.png b/packages/SystemUI/res/drawable-xhdpi/remote_132.png
new file mode 100644
index 0000000..10a00cd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_132.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_133.png b/packages/SystemUI/res/drawable-xhdpi/remote_133.png
new file mode 100644
index 0000000..6f495b4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_133.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_134.png b/packages/SystemUI/res/drawable-xhdpi/remote_134.png
new file mode 100644
index 0000000..703f2c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_134.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_135.png b/packages/SystemUI/res/drawable-xhdpi/remote_135.png
new file mode 100644
index 0000000..f4105b0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_135.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_136.png b/packages/SystemUI/res/drawable-xhdpi/remote_136.png
new file mode 100644
index 0000000..0c3a5bc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_136.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_137.png b/packages/SystemUI/res/drawable-xhdpi/remote_137.png
new file mode 100644
index 0000000..cbebc05
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_137.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_138.png b/packages/SystemUI/res/drawable-xhdpi/remote_138.png
new file mode 100644
index 0000000..6dfefb0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_138.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_139.png b/packages/SystemUI/res/drawable-xhdpi/remote_139.png
new file mode 100644
index 0000000..1acfdd6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_139.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_14.png b/packages/SystemUI/res/drawable-xhdpi/remote_14.png
new file mode 100644
index 0000000..a503cdf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_14.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_140.png b/packages/SystemUI/res/drawable-xhdpi/remote_140.png
new file mode 100644
index 0000000..70d27c1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_140.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_141.png b/packages/SystemUI/res/drawable-xhdpi/remote_141.png
new file mode 100644
index 0000000..d523a0c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_141.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_142.png b/packages/SystemUI/res/drawable-xhdpi/remote_142.png
new file mode 100644
index 0000000..ed6a65d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_142.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_143.png b/packages/SystemUI/res/drawable-xhdpi/remote_143.png
new file mode 100644
index 0000000..9b048e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_143.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_144.png b/packages/SystemUI/res/drawable-xhdpi/remote_144.png
new file mode 100644
index 0000000..9e2337d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_144.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_145.png b/packages/SystemUI/res/drawable-xhdpi/remote_145.png
new file mode 100644
index 0000000..3f30629
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_145.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_146.png b/packages/SystemUI/res/drawable-xhdpi/remote_146.png
new file mode 100644
index 0000000..1288039
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_146.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_147.png b/packages/SystemUI/res/drawable-xhdpi/remote_147.png
new file mode 100644
index 0000000..d060539
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_147.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_148.png b/packages/SystemUI/res/drawable-xhdpi/remote_148.png
new file mode 100644
index 0000000..5be839d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_148.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_149.png b/packages/SystemUI/res/drawable-xhdpi/remote_149.png
new file mode 100644
index 0000000..39d31ba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_149.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_15.png b/packages/SystemUI/res/drawable-xhdpi/remote_15.png
new file mode 100644
index 0000000..5695595
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_150.png b/packages/SystemUI/res/drawable-xhdpi/remote_150.png
new file mode 100644
index 0000000..ec2667c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_150.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_151.png b/packages/SystemUI/res/drawable-xhdpi/remote_151.png
new file mode 100644
index 0000000..ec2667c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_151.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_152.png b/packages/SystemUI/res/drawable-xhdpi/remote_152.png
new file mode 100644
index 0000000..a5d58c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_152.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_153.png b/packages/SystemUI/res/drawable-xhdpi/remote_153.png
new file mode 100644
index 0000000..a5d58c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_153.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_154.png b/packages/SystemUI/res/drawable-xhdpi/remote_154.png
new file mode 100644
index 0000000..a5d58c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_154.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_155.png b/packages/SystemUI/res/drawable-xhdpi/remote_155.png
new file mode 100644
index 0000000..793d411
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_155.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_156.png b/packages/SystemUI/res/drawable-xhdpi/remote_156.png
new file mode 100644
index 0000000..793d411
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_156.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_157.png b/packages/SystemUI/res/drawable-xhdpi/remote_157.png
new file mode 100644
index 0000000..f9d6cdc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_157.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_158.png b/packages/SystemUI/res/drawable-xhdpi/remote_158.png
new file mode 100644
index 0000000..da8d5d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_158.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_159.png b/packages/SystemUI/res/drawable-xhdpi/remote_159.png
new file mode 100644
index 0000000..1e0b097
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_159.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_16.png b/packages/SystemUI/res/drawable-xhdpi/remote_16.png
new file mode 100644
index 0000000..4ae106c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_16.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_160.png b/packages/SystemUI/res/drawable-xhdpi/remote_160.png
new file mode 100644
index 0000000..8aa68ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_160.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_161.png b/packages/SystemUI/res/drawable-xhdpi/remote_161.png
new file mode 100644
index 0000000..e49fdd9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_161.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_162.png b/packages/SystemUI/res/drawable-xhdpi/remote_162.png
new file mode 100644
index 0000000..69257a0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_162.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_163.png b/packages/SystemUI/res/drawable-xhdpi/remote_163.png
new file mode 100644
index 0000000..8f0c3d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_163.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_164.png b/packages/SystemUI/res/drawable-xhdpi/remote_164.png
new file mode 100644
index 0000000..a4c3229
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_164.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_165.png b/packages/SystemUI/res/drawable-xhdpi/remote_165.png
new file mode 100644
index 0000000..46fae23
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_165.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_166.png b/packages/SystemUI/res/drawable-xhdpi/remote_166.png
new file mode 100644
index 0000000..40d5a9b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_166.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_167.png b/packages/SystemUI/res/drawable-xhdpi/remote_167.png
new file mode 100644
index 0000000..6bd0380
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_167.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_168.png b/packages/SystemUI/res/drawable-xhdpi/remote_168.png
new file mode 100644
index 0000000..03904bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_168.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_169.png b/packages/SystemUI/res/drawable-xhdpi/remote_169.png
new file mode 100644
index 0000000..564a161
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_169.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_17.png b/packages/SystemUI/res/drawable-xhdpi/remote_17.png
new file mode 100644
index 0000000..0703e1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_17.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_170.png b/packages/SystemUI/res/drawable-xhdpi/remote_170.png
new file mode 100644
index 0000000..0411f94
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_170.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_171.png b/packages/SystemUI/res/drawable-xhdpi/remote_171.png
new file mode 100644
index 0000000..ec141e9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_171.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_172.png b/packages/SystemUI/res/drawable-xhdpi/remote_172.png
new file mode 100644
index 0000000..cb9ecaf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_172.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_173.png b/packages/SystemUI/res/drawable-xhdpi/remote_173.png
new file mode 100644
index 0000000..484ee51
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_173.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_174.png b/packages/SystemUI/res/drawable-xhdpi/remote_174.png
new file mode 100644
index 0000000..85a3135
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_174.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_175.png b/packages/SystemUI/res/drawable-xhdpi/remote_175.png
new file mode 100644
index 0000000..edd6507
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_175.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_176.png b/packages/SystemUI/res/drawable-xhdpi/remote_176.png
new file mode 100644
index 0000000..d95a68b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_176.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_177.png b/packages/SystemUI/res/drawable-xhdpi/remote_177.png
new file mode 100644
index 0000000..305641f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_177.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_178.png b/packages/SystemUI/res/drawable-xhdpi/remote_178.png
new file mode 100644
index 0000000..59de0e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_178.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_179.png b/packages/SystemUI/res/drawable-xhdpi/remote_179.png
new file mode 100644
index 0000000..414e548
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_179.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_18.png b/packages/SystemUI/res/drawable-xhdpi/remote_18.png
new file mode 100644
index 0000000..74df1e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_18.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_180.png b/packages/SystemUI/res/drawable-xhdpi/remote_180.png
new file mode 100644
index 0000000..b5d925c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_180.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_181.png b/packages/SystemUI/res/drawable-xhdpi/remote_181.png
new file mode 100644
index 0000000..e8a7127
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_181.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_182.png b/packages/SystemUI/res/drawable-xhdpi/remote_182.png
new file mode 100644
index 0000000..29c7037
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_182.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_183.png b/packages/SystemUI/res/drawable-xhdpi/remote_183.png
new file mode 100644
index 0000000..9491d94
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_183.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_184.png b/packages/SystemUI/res/drawable-xhdpi/remote_184.png
new file mode 100644
index 0000000..4aa0e32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_184.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_185.png b/packages/SystemUI/res/drawable-xhdpi/remote_185.png
new file mode 100644
index 0000000..2a0dde8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_185.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_186.png b/packages/SystemUI/res/drawable-xhdpi/remote_186.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_186.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_187.png b/packages/SystemUI/res/drawable-xhdpi/remote_187.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_187.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_188.png b/packages/SystemUI/res/drawable-xhdpi/remote_188.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_188.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_189.png b/packages/SystemUI/res/drawable-xhdpi/remote_189.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_189.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_19.png b/packages/SystemUI/res/drawable-xhdpi/remote_19.png
new file mode 100644
index 0000000..222ea31
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_19.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_190.png b/packages/SystemUI/res/drawable-xhdpi/remote_190.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_190.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_191.png b/packages/SystemUI/res/drawable-xhdpi/remote_191.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_191.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_192.png b/packages/SystemUI/res/drawable-xhdpi/remote_192.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_192.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_193.png b/packages/SystemUI/res/drawable-xhdpi/remote_193.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_193.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_194.png b/packages/SystemUI/res/drawable-xhdpi/remote_194.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_194.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_195.png b/packages/SystemUI/res/drawable-xhdpi/remote_195.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_195.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_196.png b/packages/SystemUI/res/drawable-xhdpi/remote_196.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_196.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_197.png b/packages/SystemUI/res/drawable-xhdpi/remote_197.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_197.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_198.png b/packages/SystemUI/res/drawable-xhdpi/remote_198.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_198.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_199.png b/packages/SystemUI/res/drawable-xhdpi/remote_199.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_199.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_2.png b/packages/SystemUI/res/drawable-xhdpi/remote_2.png
new file mode 100644
index 0000000..fb3f7ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_20.png b/packages/SystemUI/res/drawable-xhdpi/remote_20.png
new file mode 100644
index 0000000..646587c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_20.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_200.png b/packages/SystemUI/res/drawable-xhdpi/remote_200.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_200.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_201.png b/packages/SystemUI/res/drawable-xhdpi/remote_201.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_201.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_202.png b/packages/SystemUI/res/drawable-xhdpi/remote_202.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_202.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_203.png b/packages/SystemUI/res/drawable-xhdpi/remote_203.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_203.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_204.png b/packages/SystemUI/res/drawable-xhdpi/remote_204.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_204.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_205.png b/packages/SystemUI/res/drawable-xhdpi/remote_205.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_205.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_206.png b/packages/SystemUI/res/drawable-xhdpi/remote_206.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_206.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_207.png b/packages/SystemUI/res/drawable-xhdpi/remote_207.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_207.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_208.png b/packages/SystemUI/res/drawable-xhdpi/remote_208.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_208.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_209.png b/packages/SystemUI/res/drawable-xhdpi/remote_209.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_209.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_21.png b/packages/SystemUI/res/drawable-xhdpi/remote_21.png
new file mode 100644
index 0000000..5858ba92
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_21.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_210.png b/packages/SystemUI/res/drawable-xhdpi/remote_210.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_210.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_211.png b/packages/SystemUI/res/drawable-xhdpi/remote_211.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_211.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_212.png b/packages/SystemUI/res/drawable-xhdpi/remote_212.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_212.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_213.png b/packages/SystemUI/res/drawable-xhdpi/remote_213.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_213.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_214.png b/packages/SystemUI/res/drawable-xhdpi/remote_214.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_214.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_215.png b/packages/SystemUI/res/drawable-xhdpi/remote_215.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_215.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_216.png b/packages/SystemUI/res/drawable-xhdpi/remote_216.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_216.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_217.png b/packages/SystemUI/res/drawable-xhdpi/remote_217.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_217.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_218.png b/packages/SystemUI/res/drawable-xhdpi/remote_218.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_218.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_219.png b/packages/SystemUI/res/drawable-xhdpi/remote_219.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_219.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_22.png b/packages/SystemUI/res/drawable-xhdpi/remote_22.png
new file mode 100644
index 0000000..1974802
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_22.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_220.png b/packages/SystemUI/res/drawable-xhdpi/remote_220.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_220.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_221.png b/packages/SystemUI/res/drawable-xhdpi/remote_221.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_221.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_222.png b/packages/SystemUI/res/drawable-xhdpi/remote_222.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_222.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_223.png b/packages/SystemUI/res/drawable-xhdpi/remote_223.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_223.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_224.png b/packages/SystemUI/res/drawable-xhdpi/remote_224.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_224.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_225.png b/packages/SystemUI/res/drawable-xhdpi/remote_225.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_225.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_226.png b/packages/SystemUI/res/drawable-xhdpi/remote_226.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_226.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_227.png b/packages/SystemUI/res/drawable-xhdpi/remote_227.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_227.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_228.png b/packages/SystemUI/res/drawable-xhdpi/remote_228.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_228.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_229.png b/packages/SystemUI/res/drawable-xhdpi/remote_229.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_229.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_23.png b/packages/SystemUI/res/drawable-xhdpi/remote_23.png
new file mode 100644
index 0000000..96b7c35
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_23.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_230.png b/packages/SystemUI/res/drawable-xhdpi/remote_230.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_230.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_231.png b/packages/SystemUI/res/drawable-xhdpi/remote_231.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_231.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_232.png b/packages/SystemUI/res/drawable-xhdpi/remote_232.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_232.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_233.png b/packages/SystemUI/res/drawable-xhdpi/remote_233.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_233.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_234.png b/packages/SystemUI/res/drawable-xhdpi/remote_234.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_234.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_235.png b/packages/SystemUI/res/drawable-xhdpi/remote_235.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_235.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_236.png b/packages/SystemUI/res/drawable-xhdpi/remote_236.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_236.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_237.png b/packages/SystemUI/res/drawable-xhdpi/remote_237.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_237.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_238.png b/packages/SystemUI/res/drawable-xhdpi/remote_238.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_238.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_239.png b/packages/SystemUI/res/drawable-xhdpi/remote_239.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_239.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_24.png b/packages/SystemUI/res/drawable-xhdpi/remote_24.png
new file mode 100644
index 0000000..0437200
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_24.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_25.png b/packages/SystemUI/res/drawable-xhdpi/remote_25.png
new file mode 100644
index 0000000..60b0f15
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_25.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_26.png b/packages/SystemUI/res/drawable-xhdpi/remote_26.png
new file mode 100644
index 0000000..c34ed97
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_26.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_27.png b/packages/SystemUI/res/drawable-xhdpi/remote_27.png
new file mode 100644
index 0000000..1a83664
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_27.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_28.png b/packages/SystemUI/res/drawable-xhdpi/remote_28.png
new file mode 100644
index 0000000..a3685ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_29.png b/packages/SystemUI/res/drawable-xhdpi/remote_29.png
new file mode 100644
index 0000000..f7135eb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_29.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_3.png b/packages/SystemUI/res/drawable-xhdpi/remote_3.png
new file mode 100644
index 0000000..937da65
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_30.png b/packages/SystemUI/res/drawable-xhdpi/remote_30.png
new file mode 100644
index 0000000..718cf52
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_30.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_31.png b/packages/SystemUI/res/drawable-xhdpi/remote_31.png
new file mode 100644
index 0000000..c0b55df
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_31.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_32.png b/packages/SystemUI/res/drawable-xhdpi/remote_32.png
new file mode 100644
index 0000000..7a1ce9f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_32.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_33.png b/packages/SystemUI/res/drawable-xhdpi/remote_33.png
new file mode 100644
index 0000000..5428bcf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_33.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_34.png b/packages/SystemUI/res/drawable-xhdpi/remote_34.png
new file mode 100644
index 0000000..264efe8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_34.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_35.png b/packages/SystemUI/res/drawable-xhdpi/remote_35.png
new file mode 100644
index 0000000..a5c450f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_35.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_36.png b/packages/SystemUI/res/drawable-xhdpi/remote_36.png
new file mode 100644
index 0000000..3e469e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_36.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_37.png b/packages/SystemUI/res/drawable-xhdpi/remote_37.png
new file mode 100644
index 0000000..124ebe4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_37.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_38.png b/packages/SystemUI/res/drawable-xhdpi/remote_38.png
new file mode 100644
index 0000000..b2b4844
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_38.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_39.png b/packages/SystemUI/res/drawable-xhdpi/remote_39.png
new file mode 100644
index 0000000..a6d1733
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_39.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_4.png b/packages/SystemUI/res/drawable-xhdpi/remote_4.png
new file mode 100644
index 0000000..c282f40
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_40.png b/packages/SystemUI/res/drawable-xhdpi/remote_40.png
new file mode 100644
index 0000000..4cd615c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_40.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_41.png b/packages/SystemUI/res/drawable-xhdpi/remote_41.png
new file mode 100644
index 0000000..c746ae0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_41.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_42.png b/packages/SystemUI/res/drawable-xhdpi/remote_42.png
new file mode 100644
index 0000000..a93f198
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_42.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_43.png b/packages/SystemUI/res/drawable-xhdpi/remote_43.png
new file mode 100644
index 0000000..966e563
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_44.png b/packages/SystemUI/res/drawable-xhdpi/remote_44.png
new file mode 100644
index 0000000..beb7031
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_44.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_45.png b/packages/SystemUI/res/drawable-xhdpi/remote_45.png
new file mode 100644
index 0000000..718e167
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_45.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_46.png b/packages/SystemUI/res/drawable-xhdpi/remote_46.png
new file mode 100644
index 0000000..aa54ddb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_46.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_47.png b/packages/SystemUI/res/drawable-xhdpi/remote_47.png
new file mode 100644
index 0000000..1d11270
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_47.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_48.png b/packages/SystemUI/res/drawable-xhdpi/remote_48.png
new file mode 100644
index 0000000..ab31163
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_48.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_49.png b/packages/SystemUI/res/drawable-xhdpi/remote_49.png
new file mode 100644
index 0000000..219b7f6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_49.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_5.png b/packages/SystemUI/res/drawable-xhdpi/remote_5.png
new file mode 100644
index 0000000..15f69e1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_5.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_50.png b/packages/SystemUI/res/drawable-xhdpi/remote_50.png
new file mode 100644
index 0000000..8a9725f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_50.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_51.png b/packages/SystemUI/res/drawable-xhdpi/remote_51.png
new file mode 100644
index 0000000..bc839cf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_51.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_52.png b/packages/SystemUI/res/drawable-xhdpi/remote_52.png
new file mode 100644
index 0000000..7bab6e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_52.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_53.png b/packages/SystemUI/res/drawable-xhdpi/remote_53.png
new file mode 100644
index 0000000..34ab855
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_53.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_54.png b/packages/SystemUI/res/drawable-xhdpi/remote_54.png
new file mode 100644
index 0000000..5bd9f59
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_54.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_55.png b/packages/SystemUI/res/drawable-xhdpi/remote_55.png
new file mode 100644
index 0000000..1ff17f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_55.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_56.png b/packages/SystemUI/res/drawable-xhdpi/remote_56.png
new file mode 100644
index 0000000..d57e067
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_56.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_57.png b/packages/SystemUI/res/drawable-xhdpi/remote_57.png
new file mode 100644
index 0000000..a1bdae1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_58.png b/packages/SystemUI/res/drawable-xhdpi/remote_58.png
new file mode 100644
index 0000000..c8bc6a4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_58.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_59.png b/packages/SystemUI/res/drawable-xhdpi/remote_59.png
new file mode 100644
index 0000000..526a24e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_59.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_6.png b/packages/SystemUI/res/drawable-xhdpi/remote_6.png
new file mode 100644
index 0000000..2b6732f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_6.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_60.png b/packages/SystemUI/res/drawable-xhdpi/remote_60.png
new file mode 100644
index 0000000..080619e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_60.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_61.png b/packages/SystemUI/res/drawable-xhdpi/remote_61.png
new file mode 100644
index 0000000..5932a8c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_61.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_62.png b/packages/SystemUI/res/drawable-xhdpi/remote_62.png
new file mode 100644
index 0000000..d1233dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_62.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_63.png b/packages/SystemUI/res/drawable-xhdpi/remote_63.png
new file mode 100644
index 0000000..4f230c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_63.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_64.png b/packages/SystemUI/res/drawable-xhdpi/remote_64.png
new file mode 100644
index 0000000..6b89fcb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_64.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_65.png b/packages/SystemUI/res/drawable-xhdpi/remote_65.png
new file mode 100644
index 0000000..87597b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_65.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_66.png b/packages/SystemUI/res/drawable-xhdpi/remote_66.png
new file mode 100644
index 0000000..0ee8c1e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_66.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_67.png b/packages/SystemUI/res/drawable-xhdpi/remote_67.png
new file mode 100644
index 0000000..9aca8fd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_67.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_68.png b/packages/SystemUI/res/drawable-xhdpi/remote_68.png
new file mode 100644
index 0000000..5f263ae
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_68.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_69.png b/packages/SystemUI/res/drawable-xhdpi/remote_69.png
new file mode 100644
index 0000000..1a22b61
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_69.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_7.png b/packages/SystemUI/res/drawable-xhdpi/remote_7.png
new file mode 100644
index 0000000..9d9d699
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_7.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_70.png b/packages/SystemUI/res/drawable-xhdpi/remote_70.png
new file mode 100644
index 0000000..0372c50
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_70.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_71.png b/packages/SystemUI/res/drawable-xhdpi/remote_71.png
new file mode 100644
index 0000000..854e3e2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_72.png b/packages/SystemUI/res/drawable-xhdpi/remote_72.png
new file mode 100644
index 0000000..6919624
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_72.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_73.png b/packages/SystemUI/res/drawable-xhdpi/remote_73.png
new file mode 100644
index 0000000..d8e9ae1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_73.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_74.png b/packages/SystemUI/res/drawable-xhdpi/remote_74.png
new file mode 100644
index 0000000..24e5b6a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_74.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_75.png b/packages/SystemUI/res/drawable-xhdpi/remote_75.png
new file mode 100644
index 0000000..369a3a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_75.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_76.png b/packages/SystemUI/res/drawable-xhdpi/remote_76.png
new file mode 100644
index 0000000..96824c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_76.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_77.png b/packages/SystemUI/res/drawable-xhdpi/remote_77.png
new file mode 100644
index 0000000..dd60cca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_77.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_78.png b/packages/SystemUI/res/drawable-xhdpi/remote_78.png
new file mode 100644
index 0000000..aa3460b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_78.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_79.png b/packages/SystemUI/res/drawable-xhdpi/remote_79.png
new file mode 100644
index 0000000..9a60e3c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_79.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_8.png b/packages/SystemUI/res/drawable-xhdpi/remote_8.png
new file mode 100644
index 0000000..b73c7ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_8.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_80.png b/packages/SystemUI/res/drawable-xhdpi/remote_80.png
new file mode 100644
index 0000000..cbf883c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_80.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_81.png b/packages/SystemUI/res/drawable-xhdpi/remote_81.png
new file mode 100644
index 0000000..11a6add
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_81.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_82.png b/packages/SystemUI/res/drawable-xhdpi/remote_82.png
new file mode 100644
index 0000000..e05105d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_82.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_83.png b/packages/SystemUI/res/drawable-xhdpi/remote_83.png
new file mode 100644
index 0000000..57813aa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_83.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_84.png b/packages/SystemUI/res/drawable-xhdpi/remote_84.png
new file mode 100644
index 0000000..0f6f0fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_84.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_85.png b/packages/SystemUI/res/drawable-xhdpi/remote_85.png
new file mode 100644
index 0000000..ada83ec
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_86.png b/packages/SystemUI/res/drawable-xhdpi/remote_86.png
new file mode 100644
index 0000000..442dd51
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_86.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_87.png b/packages/SystemUI/res/drawable-xhdpi/remote_87.png
new file mode 100644
index 0000000..bdb4962
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_87.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_88.png b/packages/SystemUI/res/drawable-xhdpi/remote_88.png
new file mode 100644
index 0000000..b318002
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_88.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_89.png b/packages/SystemUI/res/drawable-xhdpi/remote_89.png
new file mode 100644
index 0000000..c4ed874
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_89.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_9.png b/packages/SystemUI/res/drawable-xhdpi/remote_9.png
new file mode 100644
index 0000000..ce5041f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_90.png b/packages/SystemUI/res/drawable-xhdpi/remote_90.png
new file mode 100644
index 0000000..6a662f9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_90.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_91.png b/packages/SystemUI/res/drawable-xhdpi/remote_91.png
new file mode 100644
index 0000000..21be887
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_91.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_92.png b/packages/SystemUI/res/drawable-xhdpi/remote_92.png
new file mode 100644
index 0000000..1bc5361
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_92.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_93.png b/packages/SystemUI/res/drawable-xhdpi/remote_93.png
new file mode 100644
index 0000000..76495ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_93.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_94.png b/packages/SystemUI/res/drawable-xhdpi/remote_94.png
new file mode 100644
index 0000000..081c84b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_94.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_95.png b/packages/SystemUI/res/drawable-xhdpi/remote_95.png
new file mode 100644
index 0000000..e9c27a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_95.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_96.png b/packages/SystemUI/res/drawable-xhdpi/remote_96.png
new file mode 100644
index 0000000..1369603
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_96.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_97.png b/packages/SystemUI/res/drawable-xhdpi/remote_97.png
new file mode 100644
index 0000000..fbd1458
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_97.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_98.png b/packages/SystemUI/res/drawable-xhdpi/remote_98.png
new file mode 100644
index 0000000..ccdd7a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_98.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_99.png b/packages/SystemUI/res/drawable-xhdpi/remote_99.png
new file mode 100644
index 0000000..f3cb4db
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_99.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
index e98d43f..1e52a91 100644
--- a/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
+++ b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
@@ -16,7 +16,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
- android:startColor="#99000000"
- android:endColor="#E6000000"
+ android:startColor="#4C000000"
+ android:endColor="#72000000"
android:angle="90"/>
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
index 405ea0c..0db1a57 100644
--- a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
@@ -14,11 +14,5 @@
limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <size
- android:width="34dp"
- android:height="34dp" />
- <solid
- android:color="#4DFFFFFF" />
-</shape>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="#9AFFFFFF" android:radius="17dp" />
diff --git a/packages/SystemUI/res/drawable/tv_pip_close_button.xml b/packages/SystemUI/res/drawable/tv_pip_close_button.xml
deleted file mode 100644
index 186a4ba..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_close_button.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:constantSize="true">
- <item android:state_focused="true">
- <layer-list>
- <item android:drawable="@drawable/tv_pip_button_focused" />
- <item android:drawable="@drawable/ic_close_white"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
- <item>
- <layer-list>
- <item android:drawable="@drawable/ic_close_white"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_full_button.xml b/packages/SystemUI/res/drawable/tv_pip_full_button.xml
deleted file mode 100644
index c48dc828..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_full_button.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:constantSize="true">
- <item android:state_focused="true">
- <layer-list>
- <item android:drawable="@drawable/tv_pip_button_focused" />
- <item android:drawable="@drawable/ic_fullscreen_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
- <item>
- <layer-list>
- <item android:drawable="@drawable/ic_fullscreen_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_onboarding_remote.xml b/packages/SystemUI/res/drawable/tv_pip_onboarding_remote.xml
new file mode 100644
index 0000000..d46108a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_onboarding_remote.xml
@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="false">
+
+ <item android:drawable="@drawable/remote_0" android:duration="13" />
+ <item android:drawable="@drawable/remote_1" android:duration="13" />
+ <item android:drawable="@drawable/remote_2" android:duration="13" />
+ <item android:drawable="@drawable/remote_3" android:duration="13" />
+ <item android:drawable="@drawable/remote_4" android:duration="13" />
+ <item android:drawable="@drawable/remote_5" android:duration="13" />
+ <item android:drawable="@drawable/remote_6" android:duration="13" />
+ <item android:drawable="@drawable/remote_7" android:duration="13" />
+ <item android:drawable="@drawable/remote_8" android:duration="13" />
+ <item android:drawable="@drawable/remote_9" android:duration="13" />
+ <item android:drawable="@drawable/remote_10" android:duration="13" />
+ <item android:drawable="@drawable/remote_11" android:duration="13" />
+ <item android:drawable="@drawable/remote_12" android:duration="13" />
+ <item android:drawable="@drawable/remote_13" android:duration="13" />
+ <item android:drawable="@drawable/remote_14" android:duration="13" />
+ <item android:drawable="@drawable/remote_15" android:duration="13" />
+ <item android:drawable="@drawable/remote_16" android:duration="13" />
+ <item android:drawable="@drawable/remote_17" android:duration="13" />
+ <item android:drawable="@drawable/remote_18" android:duration="13" />
+ <item android:drawable="@drawable/remote_19" android:duration="13" />
+ <item android:drawable="@drawable/remote_20" android:duration="13" />
+ <item android:drawable="@drawable/remote_21" android:duration="13" />
+ <item android:drawable="@drawable/remote_22" android:duration="13" />
+ <item android:drawable="@drawable/remote_23" android:duration="13" />
+ <item android:drawable="@drawable/remote_24" android:duration="13" />
+ <item android:drawable="@drawable/remote_25" android:duration="13" />
+ <item android:drawable="@drawable/remote_26" android:duration="13" />
+ <item android:drawable="@drawable/remote_27" android:duration="13" />
+ <item android:drawable="@drawable/remote_28" android:duration="13" />
+ <item android:drawable="@drawable/remote_29" android:duration="13" />
+ <item android:drawable="@drawable/remote_30" android:duration="13" />
+ <item android:drawable="@drawable/remote_31" android:duration="13" />
+ <item android:drawable="@drawable/remote_32" android:duration="13" />
+ <item android:drawable="@drawable/remote_33" android:duration="13" />
+ <item android:drawable="@drawable/remote_34" android:duration="13" />
+ <item android:drawable="@drawable/remote_35" android:duration="13" />
+ <item android:drawable="@drawable/remote_36" android:duration="13" />
+ <item android:drawable="@drawable/remote_37" android:duration="13" />
+ <item android:drawable="@drawable/remote_38" android:duration="13" />
+ <item android:drawable="@drawable/remote_39" android:duration="13" />
+ <item android:drawable="@drawable/remote_40" android:duration="13" />
+ <item android:drawable="@drawable/remote_41" android:duration="13" />
+ <item android:drawable="@drawable/remote_42" android:duration="13" />
+ <item android:drawable="@drawable/remote_43" android:duration="13" />
+ <item android:drawable="@drawable/remote_44" android:duration="13" />
+ <item android:drawable="@drawable/remote_45" android:duration="13" />
+ <item android:drawable="@drawable/remote_46" android:duration="13" />
+ <item android:drawable="@drawable/remote_47" android:duration="13" />
+ <item android:drawable="@drawable/remote_48" android:duration="13" />
+ <item android:drawable="@drawable/remote_49" android:duration="13" />
+ <item android:drawable="@drawable/remote_50" android:duration="13" />
+ <item android:drawable="@drawable/remote_51" android:duration="13" />
+ <item android:drawable="@drawable/remote_52" android:duration="13" />
+ <item android:drawable="@drawable/remote_53" android:duration="13" />
+ <item android:drawable="@drawable/remote_54" android:duration="13" />
+ <item android:drawable="@drawable/remote_55" android:duration="13" />
+ <item android:drawable="@drawable/remote_56" android:duration="13" />
+ <item android:drawable="@drawable/remote_57" android:duration="13" />
+ <item android:drawable="@drawable/remote_58" android:duration="13" />
+ <item android:drawable="@drawable/remote_59" android:duration="13" />
+ <item android:drawable="@drawable/remote_60" android:duration="13" />
+ <item android:drawable="@drawable/remote_61" android:duration="13" />
+ <item android:drawable="@drawable/remote_62" android:duration="13" />
+ <item android:drawable="@drawable/remote_63" android:duration="13" />
+ <item android:drawable="@drawable/remote_64" android:duration="13" />
+ <item android:drawable="@drawable/remote_65" android:duration="13" />
+ <item android:drawable="@drawable/remote_66" android:duration="13" />
+ <item android:drawable="@drawable/remote_67" android:duration="13" />
+ <item android:drawable="@drawable/remote_68" android:duration="13" />
+ <item android:drawable="@drawable/remote_69" android:duration="13" />
+ <item android:drawable="@drawable/remote_70" android:duration="13" />
+ <item android:drawable="@drawable/remote_71" android:duration="13" />
+ <item android:drawable="@drawable/remote_72" android:duration="13" />
+ <item android:drawable="@drawable/remote_73" android:duration="13" />
+ <item android:drawable="@drawable/remote_74" android:duration="13" />
+ <item android:drawable="@drawable/remote_75" android:duration="13" />
+ <item android:drawable="@drawable/remote_76" android:duration="13" />
+ <item android:drawable="@drawable/remote_77" android:duration="13" />
+ <item android:drawable="@drawable/remote_78" android:duration="13" />
+ <item android:drawable="@drawable/remote_79" android:duration="13" />
+ <item android:drawable="@drawable/remote_80" android:duration="13" />
+ <item android:drawable="@drawable/remote_81" android:duration="13" />
+ <item android:drawable="@drawable/remote_82" android:duration="13" />
+ <item android:drawable="@drawable/remote_83" android:duration="13" />
+ <item android:drawable="@drawable/remote_84" android:duration="13" />
+ <item android:drawable="@drawable/remote_85" android:duration="13" />
+ <item android:drawable="@drawable/remote_86" android:duration="13" />
+ <item android:drawable="@drawable/remote_87" android:duration="13" />
+ <item android:drawable="@drawable/remote_88" android:duration="13" />
+ <item android:drawable="@drawable/remote_89" android:duration="13" />
+ <item android:drawable="@drawable/remote_90" android:duration="13" />
+ <item android:drawable="@drawable/remote_91" android:duration="13" />
+ <item android:drawable="@drawable/remote_92" android:duration="13" />
+ <item android:drawable="@drawable/remote_93" android:duration="13" />
+ <item android:drawable="@drawable/remote_94" android:duration="13" />
+ <item android:drawable="@drawable/remote_95" android:duration="13" />
+ <item android:drawable="@drawable/remote_96" android:duration="13" />
+ <item android:drawable="@drawable/remote_97" android:duration="13" />
+ <item android:drawable="@drawable/remote_98" android:duration="13" />
+ <item android:drawable="@drawable/remote_99" android:duration="13" />
+ <item android:drawable="@drawable/remote_100" android:duration="13" />
+ <item android:drawable="@drawable/remote_101" android:duration="13" />
+ <item android:drawable="@drawable/remote_102" android:duration="13" />
+ <item android:drawable="@drawable/remote_103" android:duration="13" />
+ <item android:drawable="@drawable/remote_104" android:duration="13" />
+ <item android:drawable="@drawable/remote_105" android:duration="13" />
+ <item android:drawable="@drawable/remote_106" android:duration="13" />
+ <item android:drawable="@drawable/remote_107" android:duration="13" />
+ <item android:drawable="@drawable/remote_108" android:duration="13" />
+ <item android:drawable="@drawable/remote_109" android:duration="13" />
+ <item android:drawable="@drawable/remote_110" android:duration="13" />
+ <item android:drawable="@drawable/remote_111" android:duration="13" />
+ <item android:drawable="@drawable/remote_112" android:duration="13" />
+ <item android:drawable="@drawable/remote_113" android:duration="13" />
+ <item android:drawable="@drawable/remote_114" android:duration="13" />
+ <item android:drawable="@drawable/remote_115" android:duration="13" />
+ <item android:drawable="@drawable/remote_116" android:duration="13" />
+ <item android:drawable="@drawable/remote_117" android:duration="13" />
+ <item android:drawable="@drawable/remote_118" android:duration="13" />
+ <item android:drawable="@drawable/remote_119" android:duration="13" />
+ <item android:drawable="@drawable/remote_120" android:duration="13" />
+ <item android:drawable="@drawable/remote_121" android:duration="13" />
+ <item android:drawable="@drawable/remote_122" android:duration="13" />
+ <item android:drawable="@drawable/remote_123" android:duration="13" />
+ <item android:drawable="@drawable/remote_124" android:duration="13" />
+ <item android:drawable="@drawable/remote_125" android:duration="13" />
+ <item android:drawable="@drawable/remote_126" android:duration="13" />
+ <item android:drawable="@drawable/remote_127" android:duration="13" />
+ <item android:drawable="@drawable/remote_128" android:duration="13" />
+ <item android:drawable="@drawable/remote_129" android:duration="13" />
+ <item android:drawable="@drawable/remote_130" android:duration="13" />
+ <item android:drawable="@drawable/remote_131" android:duration="13" />
+ <item android:drawable="@drawable/remote_132" android:duration="13" />
+ <item android:drawable="@drawable/remote_133" android:duration="13" />
+ <item android:drawable="@drawable/remote_134" android:duration="13" />
+ <item android:drawable="@drawable/remote_135" android:duration="13" />
+ <item android:drawable="@drawable/remote_136" android:duration="13" />
+ <item android:drawable="@drawable/remote_137" android:duration="13" />
+ <item android:drawable="@drawable/remote_138" android:duration="13" />
+ <item android:drawable="@drawable/remote_139" android:duration="13" />
+ <item android:drawable="@drawable/remote_140" android:duration="13" />
+ <item android:drawable="@drawable/remote_141" android:duration="13" />
+ <item android:drawable="@drawable/remote_142" android:duration="13" />
+ <item android:drawable="@drawable/remote_143" android:duration="13" />
+ <item android:drawable="@drawable/remote_144" android:duration="13" />
+ <item android:drawable="@drawable/remote_145" android:duration="13" />
+ <item android:drawable="@drawable/remote_146" android:duration="13" />
+ <item android:drawable="@drawable/remote_147" android:duration="13" />
+ <item android:drawable="@drawable/remote_148" android:duration="13" />
+ <item android:drawable="@drawable/remote_149" android:duration="13" />
+ <item android:drawable="@drawable/remote_150" android:duration="13" />
+ <item android:drawable="@drawable/remote_151" android:duration="13" />
+ <item android:drawable="@drawable/remote_152" android:duration="13" />
+ <item android:drawable="@drawable/remote_153" android:duration="13" />
+ <item android:drawable="@drawable/remote_154" android:duration="13" />
+ <item android:drawable="@drawable/remote_155" android:duration="13" />
+ <item android:drawable="@drawable/remote_156" android:duration="13" />
+ <item android:drawable="@drawable/remote_157" android:duration="13" />
+ <item android:drawable="@drawable/remote_158" android:duration="13" />
+ <item android:drawable="@drawable/remote_159" android:duration="13" />
+ <item android:drawable="@drawable/remote_160" android:duration="13" />
+ <item android:drawable="@drawable/remote_161" android:duration="13" />
+ <item android:drawable="@drawable/remote_162" android:duration="13" />
+ <item android:drawable="@drawable/remote_163" android:duration="13" />
+ <item android:drawable="@drawable/remote_164" android:duration="13" />
+ <item android:drawable="@drawable/remote_165" android:duration="13" />
+ <item android:drawable="@drawable/remote_166" android:duration="13" />
+ <item android:drawable="@drawable/remote_167" android:duration="13" />
+ <item android:drawable="@drawable/remote_168" android:duration="13" />
+ <item android:drawable="@drawable/remote_169" android:duration="13" />
+ <item android:drawable="@drawable/remote_170" android:duration="13" />
+ <item android:drawable="@drawable/remote_171" android:duration="13" />
+ <item android:drawable="@drawable/remote_172" android:duration="13" />
+ <item android:drawable="@drawable/remote_173" android:duration="13" />
+ <item android:drawable="@drawable/remote_174" android:duration="13" />
+ <item android:drawable="@drawable/remote_175" android:duration="13" />
+ <item android:drawable="@drawable/remote_176" android:duration="13" />
+ <item android:drawable="@drawable/remote_177" android:duration="13" />
+ <item android:drawable="@drawable/remote_178" android:duration="13" />
+ <item android:drawable="@drawable/remote_179" android:duration="13" />
+ <item android:drawable="@drawable/remote_180" android:duration="13" />
+ <item android:drawable="@drawable/remote_181" android:duration="13" />
+ <item android:drawable="@drawable/remote_182" android:duration="13" />
+ <item android:drawable="@drawable/remote_183" android:duration="13" />
+ <item android:drawable="@drawable/remote_184" android:duration="13" />
+ <item android:drawable="@drawable/remote_185" android:duration="13" />
+ <item android:drawable="@drawable/remote_186" android:duration="13" />
+ <item android:drawable="@drawable/remote_187" android:duration="13" />
+ <item android:drawable="@drawable/remote_188" android:duration="13" />
+ <item android:drawable="@drawable/remote_189" android:duration="13" />
+ <item android:drawable="@drawable/remote_190" android:duration="13" />
+ <item android:drawable="@drawable/remote_191" android:duration="13" />
+ <item android:drawable="@drawable/remote_192" android:duration="13" />
+ <item android:drawable="@drawable/remote_193" android:duration="13" />
+ <item android:drawable="@drawable/remote_194" android:duration="13" />
+ <item android:drawable="@drawable/remote_195" android:duration="13" />
+ <item android:drawable="@drawable/remote_196" android:duration="13" />
+ <item android:drawable="@drawable/remote_197" android:duration="13" />
+ <item android:drawable="@drawable/remote_198" android:duration="13" />
+ <item android:drawable="@drawable/remote_199" android:duration="13" />
+ <item android:drawable="@drawable/remote_200" android:duration="13" />
+ <item android:drawable="@drawable/remote_201" android:duration="13" />
+ <item android:drawable="@drawable/remote_202" android:duration="13" />
+ <item android:drawable="@drawable/remote_203" android:duration="13" />
+ <item android:drawable="@drawable/remote_204" android:duration="13" />
+ <item android:drawable="@drawable/remote_205" android:duration="13" />
+ <item android:drawable="@drawable/remote_206" android:duration="13" />
+ <item android:drawable="@drawable/remote_207" android:duration="13" />
+ <item android:drawable="@drawable/remote_208" android:duration="13" />
+ <item android:drawable="@drawable/remote_209" android:duration="13" />
+ <item android:drawable="@drawable/remote_210" android:duration="13" />
+ <item android:drawable="@drawable/remote_211" android:duration="13" />
+ <item android:drawable="@drawable/remote_212" android:duration="13" />
+ <item android:drawable="@drawable/remote_213" android:duration="13" />
+ <item android:drawable="@drawable/remote_214" android:duration="13" />
+ <item android:drawable="@drawable/remote_215" android:duration="13" />
+ <item android:drawable="@drawable/remote_216" android:duration="13" />
+ <item android:drawable="@drawable/remote_217" android:duration="13" />
+ <item android:drawable="@drawable/remote_218" android:duration="13" />
+ <item android:drawable="@drawable/remote_219" android:duration="13" />
+ <item android:drawable="@drawable/remote_220" android:duration="13" />
+ <item android:drawable="@drawable/remote_221" android:duration="13" />
+ <item android:drawable="@drawable/remote_222" android:duration="13" />
+ <item android:drawable="@drawable/remote_223" android:duration="13" />
+ <item android:drawable="@drawable/remote_224" android:duration="13" />
+ <item android:drawable="@drawable/remote_225" android:duration="13" />
+ <item android:drawable="@drawable/remote_226" android:duration="13" />
+ <item android:drawable="@drawable/remote_227" android:duration="13" />
+ <item android:drawable="@drawable/remote_228" android:duration="13" />
+ <item android:drawable="@drawable/remote_229" android:duration="13" />
+ <item android:drawable="@drawable/remote_230" android:duration="13" />
+ <item android:drawable="@drawable/remote_231" android:duration="13" />
+ <item android:drawable="@drawable/remote_232" android:duration="13" />
+ <item android:drawable="@drawable/remote_233" android:duration="13" />
+ <item android:drawable="@drawable/remote_234" android:duration="13" />
+ <item android:drawable="@drawable/remote_235" android:duration="13" />
+ <item android:drawable="@drawable/remote_236" android:duration="13" />
+ <item android:drawable="@drawable/remote_237" android:duration="13" />
+ <item android:drawable="@drawable/remote_238" android:duration="13" />
+ <item android:drawable="@drawable/remote_239" android:duration="13" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
index e247dec..2b58fc5 100644
--- a/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
@@ -16,8 +16,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <gradient
- android:startColor="#B2000000"
- android:endColor="#00000000"
- android:angle="90"/>
+ <stroke android:width="1dp" android:color="#33FFFFFF" />
</shape>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml
similarity index 61%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
copy to packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml
index 681ff91..e247dec 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+ 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.
@@ -13,9 +13,11 @@
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="rectangle">
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:propertyName="alpha"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+ <gradient
+ android:startColor="#B2000000"
+ android:endColor="#00000000"
+ android:angle="90"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
deleted file mode 100644
index bcc8973..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:constantSize="true">
- <item android:state_focused="true">
- <layer-list>
- <item android:drawable="@drawable/tv_pip_button_focused" />
- <item android:drawable="@drawable/ic_pause_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
- <item>
- <layer-list>
- <item android:drawable="@drawable/ic_pause_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_play_button.xml b/packages/SystemUI/res/drawable/tv_pip_play_button.xml
deleted file mode 100644
index f77ea1d..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_play_button.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:constantSize="true">
- <item android:state_focused="true">
- <layer-list>
- <item android:drawable="@drawable/tv_pip_button_focused" />
- <item android:drawable="@drawable/ic_play_arrow_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
- <item>
- <layer-list>
- <item android:drawable="@drawable/ic_play_arrow_white_24dp"
- android:top="@dimen/tv_pip_button_icon_padding"
- android:bottom="@dimen/tv_pip_button_icon_padding"
- android:left="@dimen/tv_pip_button_icon_padding"
- android:right="@dimen/tv_pip_button_icon_padding" />
- </layer-list>
- </item>
-</selector>
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout-television/recents_on_tv.xml
similarity index 88%
rename from packages/SystemUI/res/layout/recents_on_tv.xml
rename to packages/SystemUI/res/layout-television/recents_on_tv.xml
index 28ea66d..1dbd1b3 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout-television/recents_on_tv.xml
@@ -19,7 +19,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
- android:clipToPadding="false">
+ android:clipToPadding="false"
+ android:background="@drawable/recents_tv_background_gradient">
<com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
android:id="@+id/task_list"
android:layout_width="wrap_content"
@@ -34,9 +35,9 @@
<!-- Placeholder view to give focus to the PIP menus. -->
<View
android:id="@+id/pip"
- android:layout_width="0dp"
- android:layout_height="0dp"
+ android:layout_width="1dp"
+ android:layout_height="1dp"
android:focusable="true"
- android:visibility="gone" />
+ android:visibility="visible" />
</com.android.systemui.recents.tv.views.RecentsTvView>
diff --git a/packages/SystemUI/res/layout-television/recents_tv_card_dismiss.xml b/packages/SystemUI/res/layout-television/recents_tv_card_dismiss.xml
new file mode 100644
index 0000000..186a058
--- /dev/null
+++ b/packages/SystemUI/res/layout-television/recents_tv_card_dismiss.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/card_dismiss"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_gravity="center_horizontal"
+ android:alpha="0.0"
+ tools:showIn="@layout/recents_tv_task_card_view">
+ <ImageView
+ android:id="@+id/card_dismiss_icon"
+ android:layout_width="@dimen/recents_tv_dismiss_icon_size"
+ android:layout_height="@dimen/recents_tv_dismiss_icon_size"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/recents_tv_dismiss_icon_top_margin"
+ android:layout_marginBottom="@dimen/recents_tv_dismiss_icon_bottom_margin"
+ android:src="@drawable/ic_cancel_white_24dp"/>
+ <TextView
+ android:id="@+id/card_dismiss_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/recents_tv_dismiss_text_size"
+ android:fontFamily="@string/font_roboto_light"
+ android:textColor="@color/recents_tv_dismiss_text_color"
+ android:text="@string/recents_tv_dismiss"
+ android:layout_gravity="center_horizontal"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-television/recents_tv_card_info_field.xml b/packages/SystemUI/res/layout-television/recents_tv_card_info_field.xml
new file mode 100644
index 0000000..20397c3
--- /dev/null
+++ b/packages/SystemUI/res/layout-television/recents_tv_card_info_field.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/card_info_field"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:showIn="@layout/recents_tv_task_card_view_fallback_banner">
+ <ImageView
+ android:id="@+id/card_extra_badge"
+ android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+ android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+ android:layout_marginBottom="@dimen/recents_tv_icon_padding_bottom"
+ android:scaleType="fitCenter"
+ android:layout_centerVertical="true"
+ android:layout_alignParentEnd="true"/>
+ <TextView
+ android:id="@+id/card_title_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:includeFontPadding="true"
+ android:singleLine="true"
+ android:shadowColor="@color/recents_tv_text_shadow_color"
+ android:shadowRadius="5"
+ android:shadowDx="0"
+ android:shadowDy="0"
+ android:textColor="@color/recents_tv_card_title_text_color"
+ android:fontFamily="@string/font_roboto_regular"
+ android:textSize="@dimen/recents_tv_title_text_size"
+ android:paddingStart="@dimen/recents_tv_text_padding_start"
+ android:layout_marginBottom="@dimen/recents_tv_text_padding_bottom"
+ android:ellipsize="end"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml b/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml
new file mode 100644
index 0000000..9b89aa0
--- /dev/null
+++ b/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.systemui.recents.tv.views.TaskCardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:layout_gravity="center"
+ android:layout_centerInParent="true"
+ android:clipToPadding="false"
+ android:orientation="vertical" >
+ <include layout="@layout/recents_tv_card_info_field"/>
+ <LinearLayout
+ android:id="@+id/card_view_thumbnail"
+ android:layout_width="@dimen/recents_tv_card_width"
+ android:layout_height="@dimen/recents_tv_screenshot_height"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:background="@color/recents_tv_card_background_color"
+ android:layout_centerHorizontal="true" >
+
+ <ImageView
+ android:id="@+id/card_view_banner_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerHorizontal="true"
+ android:scaleType="centerCrop"
+ android:gravity="center" />
+
+ </LinearLayout>
+ <include layout="@layout/recents_tv_card_dismiss"/>
+</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index b1b2f1e..1978a93 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -18,47 +18,43 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true">
- <FrameLayout
- android:id="@+id/task_view_content"
+ <com.android.systemui.recents.views.TaskViewThumbnail
+ android:id="@+id/task_view_thumbnail"
android:layout_width="match_parent"
- android:layout_height="match_parent">
- <com.android.systemui.recents.views.TaskViewThumbnail
- android:id="@+id/task_view_thumbnail"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent" />
- <include layout="@layout/recents_task_view_header" />
+ <include layout="@layout/recents_task_view_header" />
- <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
- android:id="@+id/lock_to_app_fab"
- android:layout_width="@dimen/recents_lock_to_app_size"
- android:layout_height="@dimen/recents_lock_to_app_size"
- android:layout_gravity="bottom|right"
- android:layout_marginRight="15dp"
- android:layout_marginBottom="15dp"
- android:translationZ="4dp"
- android:contentDescription="@string/recents_lock_to_app_button_label"
- android:background="@drawable/recents_lock_to_task_button_bg"
- android:visibility="invisible"
- android:alpha="0">
- <ImageView
- android:layout_width="@dimen/recents_lock_to_app_icon_size"
- android:layout_height="@dimen/recents_lock_to_app_icon_size"
- android:layout_gravity="center"
- android:src="@drawable/recents_lock_to_app_pin" />
- </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+ <!-- TODO: Move this into a view stub -->
+ <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+ android:id="@+id/lock_to_app_fab"
+ android:layout_width="@dimen/recents_lock_to_app_size"
+ android:layout_height="@dimen/recents_lock_to_app_size"
+ android:layout_gravity="bottom|right"
+ android:layout_marginRight="15dp"
+ android:layout_marginBottom="15dp"
+ android:translationZ="4dp"
+ android:contentDescription="@string/recents_lock_to_app_button_label"
+ android:background="@drawable/recents_lock_to_task_button_bg"
+ android:visibility="invisible"
+ android:alpha="0">
+ <ImageView
+ android:layout_width="@dimen/recents_lock_to_app_icon_size"
+ android:layout_height="@dimen/recents_lock_to_app_icon_size"
+ android:layout_gravity="center"
+ android:src="@drawable/recents_lock_to_app_pin" />
+ </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
- <!-- The incompatible app toast -->
- <ViewStub android:id="@+id/incompatible_app_toast_stub"
- android:inflatedId="@+id/incompatible_app_toast"
- android:layout="@*android:layout/transient_notification"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:layout_marginTop="48dp"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp" />
- </FrameLayout>
+ <!-- The incompatible app toast -->
+ <ViewStub android:id="@+id/incompatible_app_toast_stub"
+ android:inflatedId="@+id/incompatible_app_toast"
+ android:layout="@*android:layout/transient_notification"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_marginTop="48dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp" />
</com.android.systemui.recents.views.TaskView>
diff --git a/packages/SystemUI/res/layout/recents_tv_task_card_view.xml b/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
deleted file mode 100644
index 766ef60..0000000
--- a/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<com.android.systemui.recents.tv.views.TaskCardView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:layout_gravity="center"
- android:layout_centerInParent="true"
- android:orientation="vertical"
- android:layoutDirection="ltr">
-
- <LinearLayout
- android:id="@+id/recents_tv_card"
- android:layout_width="@dimen/recents_tv_card_width"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:layout_gravity="center"
- android:orientation="vertical" >
- <LinearLayout
- android:id="@+id/card_info_field"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <ImageView
- android:id="@+id/card_extra_badge"
- android:layout_width="@dimen/recents_tv_card_extra_badge_size"
- android:layout_height="@dimen/recents_tv_card_extra_badge_size"
- android:layout_marginBottom="@dimen/recents_tv_icon_padding_bottom"
- android:layout_marginEnd="@dimen/recents_tv_icon_padding_end"
- android:scaleType="fitCenter"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true" />
- <TextView
- android:id="@+id/card_title_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="false"
- android:includeFontPadding="true"
- android:minLines="1"
- android:maxLines="1"
- android:textColor="@color/recents_tv_card_title_text_color"
- android:fontFamily="@string/font_roboto_regular"
- android:textSize="@dimen/recents_tv_title_text_size"
- android:layout_marginBottom="@dimen/recents_tv_text_padding_bottom"
- android:ellipsize="end"/>
- </LinearLayout>
- <ImageView
- android:id="@+id/card_view_thumbnail"
- android:layout_width="match_parent"
- android:layout_height="@dimen/recents_tv_screenshot_height"
- android:scaleType="centerCrop"
- android:gravity="center"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
- android:layout_below="@id/card_title_text" />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/card_dismiss"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="center_horizontal"
- android:layout_below="@id/recents_tv_card"
- android:alpha="0.0">
- <ImageView
- android:id="@+id/card_dismiss_icon"
- android:layout_width="@dimen/recents_tv_dismiss_icon_size"
- android:layout_height="@dimen/recents_tv_dismiss_icon_size"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="@dimen/recents_tv_dismiss_icon_top_margin"
- android:layout_marginBottom="@dimen/recents_tv_dismiss_icon_bottom_margin"
- android:src="@drawable/ic_cancel_white_24dp" />
- <TextView
- android:id="@+id/card_dismiss_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="@dimen/recents_tv_dismiss_text_size"
- android:fontFamily="@string/font_roboto_light"
- android:textColor="@color/recents_tv_dismiss_text_color"
- android:text="@string/recents_tv_dismiss"
- android:layout_gravity="center_horizontal" />
- </LinearLayout>
-</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/tv_pip_control_button.xml b/packages/SystemUI/res/layout/tv_pip_control_button.xml
new file mode 100644
index 0000000..0beeda1
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_control_button.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<!-- Layout for {@link com.android.systemui.tv.pip.PipControlButtonView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <ImageView android:id="@+id/button"
+ android:layout_width="34dp"
+ android:layout_height="34dp"
+ android:padding="5dp"
+ android:focusable="true"
+ android:src="@drawable/ic_fullscreen_white_24dp"
+ android:background="@drawable/tv_pip_button_focused"
+ android:layerType="software" />
+
+ <TextView android:id="@+id/desc"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="3dp"
+ android:gravity="center"
+ android:text="@string/pip_fullscreen"
+ android:alpha="0"
+ android:fontFamily="sans-serif"
+ android:textSize="12sp"
+ android:textColor="#EEEEEE" />
+</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml
index 563441f..0a2f320 100644
--- a/packages/SystemUI/res/layout/tv_pip_controls.xml
+++ b/packages/SystemUI/res/layout/tv_pip_controls.xml
@@ -20,77 +20,26 @@
<!-- Layout for {@link com.android.systemui.tv.pip.PipControlsView}. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <LinearLayout
+ <com.android.systemui.tv.pip.PipControlButtonView
+ android:id="@+id/full_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="center">
+ android:src="@drawable/ic_fullscreen_white_24dp"
+ android:text="@string/pip_fullscreen" />
- <ImageView android:id="@+id/full_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:src="@drawable/tv_pip_full_button" />
-
- <TextView android:id="@+id/full_desc"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:gravity="center"
- android:visibility="invisible"
- android:text="@string/pip_fullscreen"
- android:fontFamily="sans-serif"
- android:textSize="12sp"
- android:textColor="#EEEEEE" />
- </LinearLayout>
-
- <LinearLayout
+ <com.android.systemui.tv.pip.PipControlButtonView
+ android:id="@+id/close_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginStart="-50dp"
- android:orientation="vertical"
- android:gravity="center">
+ android:src="@drawable/ic_close_white"
+ android:text="@string/pip_close" />
- <ImageView android:id="@+id/close_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:src="@drawable/tv_pip_close_button" />
-
- <TextView android:id="@+id/close_desc"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:gravity="center"
- android:visibility="invisible"
- android:text="@string/pip_close"
- android:fontFamily="sans-serif"
- android:textSize="12sp"
- android:textColor="#EEEEEE" />
- </LinearLayout>
-
- <LinearLayout android:id="@+id/play_pause"
+ <com.android.systemui.tv.pip.PipControlButtonView
+ android:id="@+id/play_pause_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_marginStart="-50dp"
- android:orientation="vertical"
- android:gravity="center" >
-
- <ImageView android:id="@+id/play_pause_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:src="@drawable/tv_pip_pause_button" />
-
- <TextView android:id="@+id/play_pause_desc"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dp"
- android:gravity="center"
- android:visibility="invisible"
- android:text="@string/pip_pause"
- android:fontFamily="sans-serif"
- android:textSize="12sp"
- android:textColor="#EEEEEE" />
- </LinearLayout>
+ android:src="@drawable/ic_pause_white_24dp"
+ android:text="@string/pip_pause" />
</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index 2647a99..72a4929 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -29,5 +29,6 @@
<com.android.systemui.tv.pip.PipControlsView
android:id="@+id/pip_controls"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:alpha="0" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_onboarding.xml b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
index b0814cf..288ad1e 100644
--- a/packages/SystemUI/res/layout/tv_pip_onboarding.xml
+++ b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
@@ -17,47 +17,81 @@
*/
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pip_onboarding"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="#C00288D1"
- android:gravity="top|center_horizontal"
+ android:background="#B3000000"
android:orientation="vertical">
- <!-- A rectangle arounds the PIP.
- Size and positions will be programatically set up
- to comply with config_defaultPictureInPictureBounds. -->
<ImageView
- android:id="@+id/pip_outline"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:src="@drawable/tv_pip_outline" />
+ android:id="@+id/remote"
+ android:layout_width="72dp"
+ android:layout_height="273dp"
+ android:layout_marginTop="136dp"
+ android:layout_marginStart="304dp"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true"
+ android:adjustViewBounds="true"
+ android:src="@drawable/remote"
+ android:alpha="0" />
+ <ImageView
+ android:id="@+id/remote_button"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:layout_marginTop="256dp"
+ android:layout_marginStart="315dp"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true"
+ android:scaleType="fitXY"
+ android:src="@drawable/tv_pip_onboarding_remote"
+ android:alpha="0" />
<TextView
+ android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="24dp"
- android:paddingStart="24dp"
- android:paddingEnd="24dp"
+ android:layout_marginTop="188dp"
+ android:layout_marginStart="406dp"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true"
android:fontFamily="sans-serif"
- android:textSize="16sp"
+ android:textSize="24sp"
android:textColor="#EEEEEE"
- android:lineSpacingMultiplier="1.28"
- android:gravity="top|center_horizontal"
- android:text="@string/pip_onboarding_description" />
+ android:text="@string/pip_onboarding_title"
+ android:alpha="0" />
+ <TextView
+ android:id="@+id/description"
+ android:layout_width="200dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ android:layout_marginStart="408dp"
+ android:layout_below="@id/title"
+ android:layout_alignParentStart="true"
+ android:fontFamily="sans-serif"
+ android:textSize="14sp"
+ android:textColor="#EEEEEE"
+ android:lineSpacingMultiplier="1.46286"
+ android:text="@string/pip_onboarding_description"
+ android:alpha="0" />
<Button
- android:id="@+id/close"
+ android:id="@+id/button"
android:layout_width="wrap_content"
- android:layout_height="36dp"
- android:layout_marginTop="24dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginStart="408dp"
+ android:layout_below="@id/description"
+ android:layout_alignParentStart="true"
android:gravity="center"
+ android:paddingTop="10dp"
+ android:paddingBottom="10dp"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:fontFamily="sans-serif-condensed"
android:textSize="16sp"
- android:textColor="#026089"
+ android:textColor="#FFFFFF"
android:textAllCaps="true"
android:text="@string/pip_onboarding_button"
- android:background="#EEEEEE"
+ android:alpha="0"
+ android:background="#009688"
android:elevation="4dp" />
-</LinearLayout>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index 64bf3b5..608680c 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -19,7 +19,8 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:background="@drawable/tv_pip_overlay_background">
<TextView
android:id="@+id/guide_overlay"
@@ -33,7 +34,7 @@
android:textSize="14sp"
android:textColor="#EEEEEE"
android:fontFamily="sans-serif"
- android:background="@drawable/tv_pip_overlay_background"
+ android:background="@drawable/tv_pip_overlay_text_background"
android:lineSpacingMultiplier="1.465"
android:gravity="center"
android:maxLines="2"
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 4126d3c..3817da0 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -17,7 +17,8 @@
*/
-->
<resources>
- <color name="recents_tv_card_background_color">#FF37474F</color>
+ <color name="recents_tv_card_background_color">#FF263238</color>
<color name="recents_tv_card_title_text_color">#CCEEEEEE</color>
<color name="recents_tv_dismiss_text_color">#7FEEEEEE</color>
+ <color name="recents_tv_text_shadow_color">#7F000000</color>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index cf2e338..03b9837 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -606,8 +606,8 @@
<dimen name="recents_layout_z_min">3dp</dimen>
<dimen name="recents_layout_z_max">24dp</dimen>
- <!-- The margin between the freeform and stack. We also don't want this to change across
- configurations that Recents can be opened in, so we define them statically for all
+ <!-- The margin between the freeform and stack. We also don't want this to change across
+ configurations that Recents can be opened in, so we define them statically for all
display sizes. -->
<dimen name="recents_freeform_layout_bottom_margin">16dp</dimen>
@@ -651,4 +651,7 @@
<!-- The amount to translate when animating the removal of a task. -->
<dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
+
+ <!-- The alpha to apply to the recents row when it doesn't have focus -->
+ <item name="recents_recents_row_dim_alpha" format="float" type="dimen">0.5</item>
</resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index f536f86..367dd1d 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -21,11 +21,13 @@
<dimen name="recents_tv_card_width">240dip</dimen>
<dimen name="recents_tv_screenshot_height">135dip</dimen>
<dimen name="recents_tv_card_extra_badge_size">20dip</dimen>
- <dimen name="recents_tv_banner_width">114dip</dimen>
- <dimen name="recents_tv_banner_height">64dip</dimen>
+ <dimen name="recents_tv_banner_width">130dip</dimen>
+ <dimen name="recents_tv_banner_height">72dip</dimen>
+ <dimen name="recents_tv_fallback_icon_width">40dip</dimen>
+ <dimen name="recents_tv_fallback_icon_height">40dip</dimen>
<dimen name="recents_tv_banner_margin_top">16dip</dimen>
<dimen name="recents_tv_icon_padding_bottom">8dip</dimen>
- <dimen name="recents_tv_icon_padding_end">12dip</dimen>
+ <dimen name="recents_tv_text_padding_start">12dip</dimen>
<dimen name="recents_tv_text_padding_bottom">12dip</dimen>
<!-- Padding for grid view in recents view on tv -->
@@ -54,8 +56,6 @@
<!-- Extra space around the PIP and its outline in PIP onboarding activity -->
<dimen name="tv_pip_bounds_space">3dp</dimen>
- <!-- Extra space around the PIP control button icon to match with the focused circle -->
- <dimen name="tv_pip_button_icon_padding">5dp</dimen>
<!-- Values for entering Recents and exiting Recents -->
<dimen name="recents_tv_home_recents_shift">125dip</dimen>
diff --git a/packages/SystemUI/res/values/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml
index 6984d5a..ebfd8ab 100644
--- a/packages/SystemUI/res/values/integers_tv.xml
+++ b/packages/SystemUI/res/values/integers_tv.xml
@@ -24,4 +24,7 @@
<integer name="recents_home_duration">400</integer>
<!-- Delay between the start of slide in animation for each card. -->
<integer name="recents_home_delay">40</integer>
+
+ <!-- Duration of the onboarding animation duration -->
+ <integer name="tv_pip_onboarding_anim_duration">1000</integer>
</resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 52aba0d..dcd1654 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -31,8 +31,10 @@
<string name="pip_hold_home">Hold <b>HOME</b> to control PIP</string>
<!-- Picture-in-Picture (PIP) onboarding screen -->
<eat-comment />
+ <!-- Title for picture-in-picture (PIP) onboarding screen to indicate that an user is in PIP mode. [CHAR LIMIT=NONE] -->
+ <string name="pip_onboarding_title">PIP mode</string>
<!-- Description for picture-in-picture (PIP) onboarding screen to indicate that longpress HOME key to control PIP. [CHAR LIMIT=NONE] -->
- <string name="pip_onboarding_description">Press and hold the HOME button to control PIP</string>
+ <string name="pip_onboarding_description">To control PIP press and hold the <b>HOME</b> button on the remote</string>
<!-- Button to close picture-in-picture (PIP) onboarding screen. -->
<string name="pip_onboarding_button">Got it</string>
<!-- Dismiss icon description -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index e8e17b1..8925d45 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -387,7 +387,7 @@
}
}
}
- if (mTiles.get(mTiles.size() - 1) == null) {
+ if (mTiles.size() - 1 == mTileDividerIndex) {
mTiles.remove(mTiles.size() - 1);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 6b476ee..4d69280 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -66,6 +66,7 @@
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
import com.android.systemui.recents.events.ui.UserInteractionEvent;
+import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
@@ -97,7 +98,7 @@
private RecentsPackageMonitor mPackageMonitor;
private long mLastTabKeyEventTime;
- private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
+ private int mLastDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
private boolean mFinishedOnStartup;
private boolean mIgnoreAltTabRelease;
private boolean mIsVisible;
@@ -275,7 +276,7 @@
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
- mLastOrientation = getResources().getConfiguration().orientation;
+ mLastDeviceOrientation = Utilities.getAppConfiguration(this).orientation;
mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
@Override
@@ -425,13 +426,12 @@
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
-
// Notify of the config change
- int newOrientation = getResources().getConfiguration().orientation;
+ int newDeviceOrientation = Utilities.getAppConfiguration(this).orientation;
int numStackTasks = mRecentsView.getStack().getStackTaskCount();
EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
- (mLastOrientation != newOrientation), numStackTasks > 0));
- mLastOrientation = newOrientation;
+ (mLastDeviceOrientation != newDeviceOrientation), numStackTasks > 0));
+ mLastDeviceOrientation = newDeviceOrientation;
}
@Override
@@ -454,7 +454,7 @@
int numStackTasks = stack.getStackTaskCount();
EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
- false /* fromOrientationChange */, numStackTasks > 0));
+ false /* fromDeviceOrientationChange */, numStackTasks > 0));
if (mRecentsView != null) {
mRecentsView.updateStack(stack);
@@ -752,6 +752,13 @@
mIgnoreAltTabRelease = true;
}
+ public final void onBusEvent(final DragEndEvent event) {
+ // Handle the case where we drop onto a dock region
+ if (event.dropTarget instanceof TaskStack.DockState) {
+ mScrimViews.animateScrimToCurrentNavBarState(false /* hasStackTasks */);
+ }
+ }
+
@Override
public boolean onPreDraw() {
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
@@ -769,6 +776,8 @@
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
+ EventBus.getDefault().dump(prefix, writer);
+
String id = Integer.toHexString(System.identityHashCode(this));
writer.print(prefix); writer.print(TAG);
@@ -779,6 +788,5 @@
if (mRecentsView != null) {
mRecentsView.dump(prefix, writer);
}
- EventBus.getDefault().dump(prefix, writer);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index fda340d..c230cd8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -175,7 +175,11 @@
ssp.registerTaskStackListener(mTaskStackListener);
// Initialize the static configuration resources
- reloadHeaderBarLayout();
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ mDummyStackView = new TaskStackView(mContext);
+ mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
+ null, false);
+ reloadResources();
// When we start, preload the data associated with the previous recent tasks.
// We can use a new plan since the caches will be the same.
@@ -194,7 +198,9 @@
}
public void onConfigurationChanged() {
- reloadHeaderBarLayout();
+ reloadResources();
+ mDummyStackView.reloadOnConfigurationChange();
+ mHeaderBar.onConfigurationChanged();
}
/**
@@ -542,11 +548,10 @@
}
/**
- * Reloads all the layouts for the header bar transition.
+ * Reloads all the resources for the current configuration.
*/
- private void reloadHeaderBarLayout() {
+ private void reloadResources() {
Resources res = mContext.getResources();
- LayoutInflater inflater = LayoutInflater.from(mContext);
mStatusBarHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
@@ -561,9 +566,6 @@
R.dimen.recents_task_view_header_height_tablet_land,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height_tablet_land);
- mDummyStackView = new TaskStackView(mContext);
- mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
- null, false);
}
/**
@@ -687,7 +689,7 @@
TaskStackViewScroller stackScroller = stackView.getScroller();
stackView.updateLayoutAlgorithm(true /* boundScroll */);
- stackView.updateToInitialState(true /* scrollToInitialState */);
+ stackView.updateToInitialState();
for (int i = tasks.size() - 1; i >= 0; i--) {
Task task = tasks.get(i);
@@ -740,7 +742,7 @@
// Get the transform for the running task
stackView.updateLayoutAlgorithm(true /* boundScroll */);
- stackView.updateToInitialState(true /* scrollToInitialState */);
+ stackView.updateToInitialState();
stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
stackView.getScroller().getStackScroll(), mTmpTransform, null);
return mTmpTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
index e3bc2a7..53b67cf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
@@ -24,13 +24,13 @@
public class ConfigurationChangedEvent extends EventBus.AnimatedEvent {
public final boolean fromMultiWindow;
- public final boolean fromOrientationChange;
+ public final boolean fromDeviceOrientationChange;
public final boolean hasStackTasks;
- public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange,
+ public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromDeviceOrientationChange,
boolean hasStackTasks) {
this.fromMultiWindow = fromMultiWindow;
- this.fromOrientationChange = fromOrientationChange;
+ this.fromDeviceOrientationChange = fromDeviceOrientationChange;
this.hasStackTasks = hasStackTasks;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 4ecda54..f6cc12b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -18,8 +18,11 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
+import android.animation.RectEvaluator;
import android.annotation.FloatRange;
import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
@@ -71,7 +74,7 @@
};
public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
-
+ public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
public static final Rect EMPTY_RECT = new Rect();
/**
@@ -270,6 +273,14 @@
}
/**
+ * Returns the application configuration, which is independent of the activity's current
+ * configuration in multiwindow.
+ */
+ public static Configuration getAppConfiguration(Context context) {
+ return context.getApplicationContext().getResources().getConfiguration();
+ }
+
+ /**
* Returns a lightweight dump of a rect.
*/
public static String dumpRect(Rect r) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 9f9c48f..68c46a9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -315,6 +315,15 @@
return key.id != affiliationTaskId;
}
+ /**
+ * Returns the top activity component.
+ */
+ public ComponentName getTopComponent() {
+ return topActivity != null
+ ? topActivity
+ : key.baseIntent.getComponent();
+ }
+
@Override
public boolean equals(Object o) {
// Check that the id matches
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index fbb5987..95e276f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -299,7 +299,7 @@
if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
if (animateBounds) {
PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
- Utilities.DRAWABLE_RECT, new RectEvaluator(new Rect()),
+ Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR,
dockAreaOverlay.getBounds(), bounds);
animators.add(ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop));
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 60a85df..7378102 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -107,7 +107,9 @@
public void onMoveToFullscreen() {
// Recents should be dismissed when PIP moves to fullscreen. If not, Recents will
// be unnecessarily shown in the scenario: PIP->Fullscreen->PIP.
- dismissRecentsToLaunchTargetTaskOrHome();
+ // Do not show Recents close animation because PIP->Fullscreen animation will be shown
+ // instead.
+ dismissRecentsToLaunchTargetTaskOrHome(false);
}
@Override
@@ -118,7 +120,7 @@
new PipRecentsOverlayManager.Callback() {
@Override
public void onClosed() {
- dismissRecentsToLaunchTargetTaskOrHome();
+ dismissRecentsToLaunchTargetTaskOrHome(true);
}
@Override
@@ -211,13 +213,15 @@
}
}
- boolean dismissRecentsToLaunchTargetTaskOrHome() {
+ boolean dismissRecentsToLaunchTargetTaskOrHome(boolean animate) {
SystemServicesProxy ssp = Recents.getSystemServices();
if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
// If we have a focused Task, launch that Task now
- if (mRecentsView.launchPreviousTask()) return true;
+ if (mRecentsView.launchPreviousTask(animate)) {
+ return true;
+ }
// If none of the other cases apply, then just go Home
- dismissRecentsToHome(true /* animateTaskViews */);
+ dismissRecentsToHome(animate /* animateTaskViews */);
}
return false;
}
@@ -247,7 +251,7 @@
dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
dismissEvent.addPostAnimationCallback(closeSystemWindows);
- if(mTaskStackHorizontalGridView.getChildCount() > 0 && animateTaskViews) {
+ if (mTaskStackHorizontalGridView.getChildCount() > 0 && animateTaskViews) {
mHomeRecentsEnterExitAnimationHolder.startExitAnimation(dismissEvent);
} else {
closeSystemWindows.run();
@@ -374,7 +378,7 @@
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
if(mLaunchedFromHome) {
- mHomeRecentsEnterExitAnimationHolder.startEnterAnimation();
+ mHomeRecentsEnterExitAnimationHolder.startEnterAnimation(mPipManager.isPipShown());
}
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
}
@@ -463,7 +467,7 @@
if (launchState.launchedFromHome) {
dismissRecentsToHome(true /* animateTaskViews */);
} else {
- dismissRecentsToLaunchTargetTaskOrHome();
+ dismissRecentsToLaunchTargetTaskOrHome(true);
}
}
@@ -561,6 +565,8 @@
// as if it's the part of the Recents UI.
mPipRecentsOverlayManager.requestFocus(
mTaskStackViewAdapter.getItemCount() > 0);
+ } else {
+ mPipRecentsOverlayManager.clearFocus();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
index 3e668af..66d8576 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
@@ -18,6 +18,7 @@
import android.animation.Animator;
import android.content.res.Resources;
+import android.view.View;
import android.widget.LinearLayout;
import com.android.systemui.Interpolators;
import com.android.systemui.recents.tv.views.TaskCardView;
@@ -26,17 +27,20 @@
public class DismissAnimationsHolder {
private LinearLayout mDismissArea;
- private LinearLayout mRecentsTvCard;
- private int mCardYDelta;
+ private LinearLayout mInfoField;
+ private View mThumbnailView;
+ private int mDismissEnterYDelta;
+ private int mDismissStartYDelta;
private long mShortDuration;
private long mLongDuration;
public DismissAnimationsHolder(TaskCardView taskCardView) {
- mRecentsTvCard = (LinearLayout) taskCardView.findViewById(R.id.recents_tv_card);
+ mInfoField = (LinearLayout) taskCardView.findViewById(R.id.card_info_field);
mDismissArea = (LinearLayout) taskCardView.findViewById(R.id.card_dismiss);
-
+ mThumbnailView = taskCardView.findViewById(R.id.card_view_thumbnail);
Resources res = taskCardView.getResources();
- mCardYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+ mDismissEnterYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+ mDismissStartYDelta = mDismissEnterYDelta * 2;
mShortDuration = res.getInteger(R.integer.dismiss_short_duration);
mLongDuration = res.getInteger(R.integer.dismiss_long_duration);
}
@@ -47,10 +51,16 @@
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(1.0f);
- mRecentsTvCard.animate()
+ mInfoField.animate()
.setDuration(mShortDuration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .translationYBy(mCardYDelta)
+ .translationY(mDismissEnterYDelta)
+ .alpha(0.5f);
+
+ mThumbnailView.animate()
+ .setDuration(mShortDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .translationY(mDismissEnterYDelta)
.alpha(0.5f);
}
@@ -60,10 +70,16 @@
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(0.0f);
- mRecentsTvCard.animate()
+ mInfoField.animate()
.setDuration(mShortDuration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .translationYBy(-mCardYDelta)
+ .translationY(0)
+ .alpha(1.0f);
+
+ mThumbnailView.animate()
+ .setDuration(mShortDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .translationY(0)
.alpha(1.0f);
}
@@ -73,17 +89,25 @@
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.alpha(0.0f);
- mRecentsTvCard.animate()
+ mInfoField.animate()
.setDuration(mLongDuration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .translationYBy(mCardYDelta)
+ .translationY(mDismissStartYDelta)
.alpha(0.0f)
.setListener(listener);
+
+ mThumbnailView.animate()
+ .setDuration(mLongDuration)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .translationY(mDismissStartYDelta)
+ .alpha(0.0f);
}
public void reset() {
- mRecentsTvCard.setAlpha(1.0f);
- mRecentsTvCard.setTranslationY(0);
- mRecentsTvCard.animate().setListener(null);
+ mInfoField.setAlpha(1.0f);
+ mInfoField.setTranslationY(0);
+ mInfoField.animate().setListener(null);
+ mThumbnailView.setAlpha(1.0f);
+ mThumbnailView.setTranslationY(0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
index 278de87..92718a3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
@@ -28,6 +28,7 @@
private Context mContext;
private TaskStackHorizontalGridView mGridView;
+ private float mDimAlpha;
private long mDelay;
private int mDuration;
private int mTranslationX;
@@ -36,19 +37,19 @@
TaskStackHorizontalGridView gridView) {
mContext = context;
mGridView = gridView;
+ mDimAlpha = mContext.getResources().getFloat(R.dimen.recents_recents_row_dim_alpha);
mTranslationX = mContext.getResources()
.getDimensionPixelSize(R.dimen.recents_tv_home_recents_shift);
mDelay = mContext.getResources().getInteger(R.integer.recents_home_delay);
mDuration = mContext.getResources().getInteger(R.integer.recents_home_duration);
}
- public void startEnterAnimation() {
+ public void startEnterAnimation(boolean isPipShown) {
for(int i = 0; i < mGridView.getChildCount(); i++) {
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
view.setTranslationX(-mTranslationX);
- view.setAlpha(0.0f);
view.animate()
- .alpha(1.0f)
+ .alpha(isPipShown ? mDimAlpha : 1.0f)
.translationX(0)
.setDuration(mDuration)
.setStartDelay(mDelay * i)
@@ -76,7 +77,7 @@
public void setEnterFromHomeStartingAnimationValues() {
for(int i = 0; i < mGridView.getChildCount(); i++) {
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
- view.setTranslationX(-mTranslationX);
+ view.setTranslationX(0);
view.setAlpha(0.0f);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
index 28abc34..160835f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
@@ -29,8 +29,6 @@
* Recents row's focus animation with PIP controls.
*/
public class RecentsRowFocusAnimationHolder {
- private static final float DIM_ALPHA = 0.5f;
-
private View mView;
private View mTitleView;
@@ -43,6 +41,7 @@
Resources res = view.getResources();
int duration = res.getInteger(R.integer.recents_tv_pip_focus_anim_duration);
+ float dimAlpha = res.getFloat(R.dimen.recents_recents_row_dim_alpha);
mFocusGainAnimatorSet = new AnimatorSet();
mFocusGainAnimatorSet.playTogether(
@@ -53,7 +52,7 @@
mFocusLoseAnimatorSet = new AnimatorSet();
mFocusLoseAnimatorSet.playTogether(
- ObjectAnimator.ofFloat(mView, "alpha", DIM_ALPHA),
+ ObjectAnimator.ofFloat(mView, "alpha", dimAlpha),
ObjectAnimator.ofFloat(mTitleView, "alpha", 0f));
mFocusLoseAnimatorSet.setDuration(duration);
mFocusLoseAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
index 888561c..9edd5af 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -26,6 +26,7 @@
import android.view.animation.Interpolator;
import com.android.systemui.R;
+import com.android.systemui.recents.tv.views.TaskCardView;
public class ViewFocusAnimator implements View.OnFocusChangeListener {
private final float mUnselectedScale;
@@ -94,10 +95,13 @@
mTargetView.setScaleX(scale);
mTargetView.setScaleY(scale);
- mTargetView.setZ(z);
mTargetView.setPadding((int) spacing, mTargetView.getPaddingTop(),
(int) spacing, mTargetView.getPaddingBottom());
+
+ if (mTargetView instanceof TaskCardView) {
+ ((TaskCardView) mTargetView).getThumbnailView().setZ(z);
+ }
}
public float getFocusProgress() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
index fb1127e..812bff1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
@@ -16,7 +16,6 @@
package com.android.systemui.recents.tv.views;
import android.annotation.Nullable;
-import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Context;
import android.graphics.Bitmap;
@@ -122,11 +121,13 @@
}
try {
Rect taskRect = taskView.getFocusedThumbnailRect();
- Bitmap thumbnail = Bitmap.createScaledBitmap(task.thumbnail, taskRect.width(),
- taskRect.height(), false);
- WindowManagerGlobal.getWindowManagerService()
- .overridePendingAppTransitionAspectScaledThumb(thumbnail, taskRect.left,
- taskRect.top, taskRect.width(), taskRect.height(), callback, true);
+ if (taskRect != null) {
+ Bitmap thumbnail = Bitmap.createScaledBitmap(task.thumbnail, taskRect.width(),
+ taskRect.height(), false);
+ WindowManagerGlobal.getWindowManagerService()
+ .overridePendingAppTransitionAspectScaledThumb(thumbnail, taskRect.left,
+ taskRect.top, taskRect.width(), taskRect.height(), callback, true);
+ }
} catch (RemoteException e) {
Log.w(TAG, "Failed to override transition: " + e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
index b876fc70..4058c62 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
-import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
@@ -35,7 +34,6 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
-import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -114,7 +112,7 @@
if (mTaskStackHorizontalView != null) {
Task task = mTaskStackHorizontalView.getFocusedTask();
if (task != null) {
- launchTaskFomRecents(task);
+ launchTaskFomRecents(task, true);
return true;
}
}
@@ -122,12 +120,12 @@
}
/** Launches the task that recents was launched from if possible */
- public boolean launchPreviousTask() {
+ public boolean launchPreviousTask(boolean animate) {
if (mTaskStackHorizontalView != null) {
TaskStack stack = mTaskStackHorizontalView.getStack();
Task task = stack.getLaunchTarget();
if (task != null) {
- launchTaskFomRecents(task);
+ launchTaskFomRecents(task, animate);
return true;
}
}
@@ -139,18 +137,25 @@
* attempt to scroll to focus the task before launching.
* @param task
*/
- private void launchTaskFomRecents(final Task task) {
- if(task != mTaskStackHorizontalView.getFocusedTask()) {
- if(mScrollListener != null) {
+ private void launchTaskFomRecents(final Task task, boolean animate) {
+ if (!animate) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
+ return;
+ }
+ mTaskStackHorizontalView.requestFocus();
+ Task focusedTask = mTaskStackHorizontalView.getFocusedTask();
+ if (focusedTask != null && task != focusedTask) {
+ if (mScrollListener != null) {
mTaskStackHorizontalView.removeOnScrollListener(mScrollListener);
}
mScrollListener = new OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
- if(newState == RecyclerView.SCROLL_STATE_IDLE) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
TaskCardView cardView = mTaskStackHorizontalView.getChildViewForTask(task);
- if(cardView != null) {
+ if (cardView != null) {
mTransitionHelper.launchTaskFromRecents(mStack, task,
mTaskStackHorizontalView, cardView, null, INVALID_STACK_ID);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
index d3bc4b6..a72a7e6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -17,10 +17,15 @@
import android.animation.Animator;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.KeyEvent;
@@ -38,7 +43,8 @@
public class TaskCardView extends LinearLayout {
- private ImageView mThumbnailView;
+ private static final String TAG = "TaskCardView";
+ private View mThumbnailView;
private TextView mTitleTextView;
private ImageView mBadgeView;
private Task mTask;
@@ -58,26 +64,28 @@
public TaskCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mViewFocusAnimator = new ViewFocusAnimator(this);
mDismissState = false;
+ Configuration config = getResources().getConfiguration();
+ setLayoutDirection(config.getLayoutDirection());
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
+ mThumbnailView = findViewById(R.id.card_view_thumbnail);
mTitleTextView = (TextView) findViewById(R.id.card_title_text);
mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
mDismissAnimationsHolder = new DismissAnimationsHolder(this);
View title = findViewById(R.id.card_info_field);
mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, title);
+ mViewFocusAnimator = new ViewFocusAnimator(this);
}
public void init(Task task) {
mTask = task;
- mThumbnailView.setImageBitmap(task.thumbnail);
mTitleTextView.setText(task.title);
mBadgeView.setImageDrawable(task.icon);
+ setThumbnailView();
}
public Task getTask() {
@@ -238,4 +246,64 @@
mRecentsRowFocusAnimationHolder.reset();
mDismissAnimationsHolder.reset();
}
+
+ private void setThumbnailView() {
+ ImageView screenshotView = (ImageView) findViewById(R.id.card_view_banner_icon);
+ PackageManager pm = getContext().getPackageManager();
+ if (mTask.thumbnail != null) {
+ setAsScreenShotView(mTask.thumbnail, screenshotView);
+ } else {
+ try {
+ Drawable banner = null;
+ if (mTask.key != null) {
+ banner = pm.getActivityBanner(mTask.key.baseIntent);
+ }
+ if (banner != null) {
+ setAsBannerView(banner, screenshotView);
+ } else {
+ setAsIconView(mTask.icon, screenshotView);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Package not found : " + e);
+ setAsIconView(mTask.icon, screenshotView);
+ }
+ }
+ }
+
+ private void setAsScreenShotView(Bitmap screenshot, ImageView screenshotView) {
+ LayoutParams lp = (LayoutParams) screenshotView.getLayoutParams();
+ lp.width = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_card_width);
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_screenshot_height);
+
+ screenshotView.setLayoutParams(lp);
+ screenshotView.setImageBitmap(screenshot);
+ }
+
+ private void setAsBannerView(Drawable banner, ImageView bannerView) {
+ LayoutParams lp = (LayoutParams) bannerView.getLayoutParams();
+ lp.width = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_banner_width);
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_banner_height);
+
+ bannerView.setLayoutParams(lp);
+ bannerView.setImageDrawable(banner);
+ }
+
+ private void setAsIconView(Drawable icon, ImageView iconView) {
+ LayoutParams lp = (LayoutParams) iconView.getLayoutParams();
+ lp.width = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_fallback_icon_width);
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.recents_tv_fallback_icon_height);
+
+ iconView.setLayoutParams(lp);
+ iconView.setImageDrawable(icon);
+ }
+
+ public View getThumbnailView() {
+ return mThumbnailView;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
index 77ab8c1..9f52abd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -33,9 +33,6 @@
import com.android.systemui.recents.model.TaskStack.TaskStackCallbacks;
import com.android.systemui.recents.views.AnimationProps;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Horizontal Grid View Implementation to show the Task Stack for TV.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
index eff1845..eb3b02d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -27,7 +27,6 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
-import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.AnimationProps;
@@ -47,6 +46,7 @@
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private TaskCardView mTaskCardView;
private Task mTask;
+ private boolean mShouldReset;
public ViewHolder(View v) {
super(v);
if(v instanceof TaskCardView) {
@@ -69,7 +69,6 @@
} else {
EventBus.getDefault().send(new LaunchTvTaskEvent(mTaskCardView, mTask,
null, INVALID_STACK_ID));
- ((Activity) (v.getContext())).finish();
}
} catch (Exception e) {
Log.e(TAG, v.getContext()
@@ -89,6 +88,7 @@
public void onAnimationEnd(Animator animation) {
removeAt(position);
EventBus.getDefault().send(new DeleteTaskDataEvent(task));
+ mShouldReset = true;
}
@Override
@@ -114,9 +114,9 @@
@Override
public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
- View view = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.recents_tv_task_card_view, parent, false);
- ViewHolder viewHolder = new ViewHolder(view);
+ LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ ViewHolder viewHolder = new ViewHolder(
+ inflater.inflate(R.layout.recents_tv_task_card_view, parent, false));
return viewHolder;
}
@@ -127,7 +127,12 @@
@Override
public void onViewDetachedFromWindow(ViewHolder holder) {
- holder.mTaskCardView.reset();
+ // We only want to reset on view detach if this is the last task being dismissed.
+ // This is so that we do not reset when shifting to apps etc, as it is not needed.
+ if (holder.mShouldReset) {
+ holder.mTaskCardView.reset();
+ holder.mShouldReset = false;
+ }
}
@Override
@@ -157,6 +162,7 @@
return (position >= 0) ? position : 0;
}
+
public void setTaskStackHorizontalGridView(TaskStackHorizontalGridView gridView) {
mGridView = gridView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
index 9f2b00a..471df6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
@@ -88,6 +88,10 @@
*/
protected void layoutContents(Rect bounds, boolean changed) {
super.onLayout(changed, bounds.left, bounds.top, bounds.right, bounds.bottom);
+
+ int width = getMeasuredWidth();
+ int height = getMeasuredHeight();
+ onSizeChanged(width, height, width, height);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 59b7560..d55c7d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -519,7 +519,9 @@
@Override
public void onAnimationStarted() {
EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
- mTaskStackView.getStack().removeTask(event.task, AnimationProps.IMMEDIATE,
+ // Remove the task and don't bother relaying out, as all the tasks will be
+ // relaid out when the stack changes on the multiwindow change event
+ mTaskStackView.getStack().removeTask(event.task, null,
true /* fromDockGesture */);
}
};
@@ -541,7 +543,7 @@
true /* scaleUp */);
MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
- event.task.topActivity.flattenToShortString());
+ event.task.getTopComponent().flattenToShortString());
} else {
// Animate the overlay alpha back to 0
updateVisibleDockRegions(null, true /* isDefaultDockState */, -1,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 5fbc037..70c4dbd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -162,7 +162,8 @@
mVisibleDockStates.clear();
if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask()
&& mDividerSnapAlgorithm.isSplitScreenFeasible()) {
- Recents.logDockAttempt(mRv.getContext(), event.task.topActivity, event.task.resizeMode);
+ Recents.logDockAttempt(mRv.getContext(), event.task.getTopComponent(),
+ event.task.resizeMode);
if (!event.task.isDockable) {
EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent());
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 07a1d4e..dce2353 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -152,7 +152,7 @@
/**
* Animates the scrim to match the state of the current nav bar.
*/
- private void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
+ public void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks);
if (mHasNavBarScrim != hasNavBarScrim) {
AnimationProps animation = hasNavBarScrim
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index e4da8b3..34d6bce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -297,9 +297,6 @@
private FreePathInterpolator mUnfocusedDimCurveInterpolator;
private FreePathInterpolator mFocusedDimCurveInterpolator;
- // Indexed from the front of the stack, the normalized x in the unfocused range for each task
- private float[] mInitialNormX;
-
// The state of the stack focus (0..1), which controls the transition of the stack from the
// focused to non-focused state
@ViewDebug.ExportedProperty(category="recents")
@@ -406,8 +403,10 @@
/**
* Sets the system insets.
*/
- public void setSystemInsets(Rect systemInsets) {
+ public boolean setSystemInsets(Rect systemInsets) {
+ boolean changed = mSystemInsets.equals(systemInsets);
mSystemInsets.set(systemInsets);
+ return changed;
}
/**
@@ -545,13 +544,11 @@
} else {
mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
}
- mInitialNormX = null;
} else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
// If there is one stack task, ignore the min/max/initial scroll positions
mMinScrollP = 0;
mMaxScrollP = 0;
mInitialScrollP = 0;
- mInitialNormX = null;
} else {
// Set the max scroll to be the point where the front most task is visible with the
// stack bottom offset
@@ -565,42 +562,50 @@
launchState.launchedViaDockGesture;
if (launchState.launchedWithAltTab) {
mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
- mInitialNormX = null;
} else if (scrollToFront) {
mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
- mInitialNormX = null;
} else {
// We are overriding the initial two task positions, so set the initial scroll
// position to match the second task (aka focused task) position
float initialTopNormX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2))
- Math.max(0, mUnfocusedRange.getAbsoluteX(initialTopNormX)));
-
- // Set the initial scroll to the predefined state (which differs from the stack)
- mInitialNormX = new float[] {
- getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset,
- FROM_BOTTOM),
- initialTopNormX
- };
}
}
}
- public void updateToInitialState(List<Task> tasks) {
- if (mInitialNormX == null) {
- return;
- }
+ /**
+ * Creates task overrides to ensure the initial stack layout if necessary.
+ */
+ public void setTaskOverridesForInitialState(TaskStack stack) {
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- mUnfocusedRange.offset(0f);
- int taskCount = tasks.size();
- for (int i = taskCount - 1; i >= 0; i--) {
- int indexFromFront = taskCount - i - 1;
- if (indexFromFront >= mInitialNormX.length) {
- break;
+ mTaskIndexOverrideMap.clear();
+
+ boolean scrollToFront = launchState.launchedFromHome ||
+ launchState.launchedViaDockGesture;
+ if (getInitialFocusState() == STATE_UNFOCUSED && mNumStackTasks > 1) {
+ if (!launchState.launchedWithAltTab && !scrollToFront) {
+ // Set the initial scroll to the predefined state (which differs from the stack)
+ float [] initialNormX = new float[] {
+ getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset,
+ FROM_BOTTOM),
+ getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP)
+ };
+
+ mUnfocusedRange.offset(0f);
+ List<Task> tasks = stack.getStackTasks();
+ int taskCount = tasks.size();
+ for (int i = taskCount - 1; i >= 0; i--) {
+ int indexFromFront = taskCount - i - 1;
+ if (indexFromFront >= initialNormX.length) {
+ break;
+ }
+ float newTaskProgress = mInitialScrollP +
+ mUnfocusedRange.getAbsoluteX(initialNormX[indexFromFront]);
+ mTaskIndexOverrideMap.put(tasks.get(i).key.id, newTaskProgress);
+ }
}
- float newTaskProgress = mInitialScrollP +
- mUnfocusedRange.getAbsoluteX(mInitialNormX[indexFromFront]);
- mTaskIndexOverrideMap.put(tasks.get(i).key.id, newTaskProgress);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 0fc45ed..a75d1e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -28,11 +28,9 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
-import android.os.Parcelable;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -105,12 +103,6 @@
private static final String TAG = "TaskStackView";
- private final static String KEY_SAVED_STATE_SUPER = "saved_instance_state_super";
- private final static String KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE =
- "saved_instance_state_layout_focused_state";
- private final static String KEY_SAVED_STATE_LAYOUT_STACK_SCROLL =
- "saved_instance_state_layout_stack_scroll";
-
// The thresholds at which to show/hide the stack action button.
private static final float SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
private static final float HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
@@ -350,11 +342,9 @@
/**
* Updates this TaskStackView to the initial state.
*/
- public void updateToInitialState(boolean scrollToInitialState) {
- if (scrollToInitialState) {
- mStackScroller.setStackScrollToInitialState();
- }
- mLayoutAlgorithm.updateToInitialState(mStack.getStackTasks());
+ public void updateToInitialState() {
+ mStackScroller.setStackScrollToInitialState();
+ mLayoutAlgorithm.setTaskOverridesForInitialState(mStack);
}
/** Updates the list of task views */
@@ -638,18 +628,11 @@
/**
* @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean)
*/
- void relayoutTaskViews(AnimationProps animation) {
+ public void relayoutTaskViews(AnimationProps animation) {
relayoutTaskViews(animation, mIgnoreTasks, false /* ignoreTaskOverrides */);
}
/**
- * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean)
- */
- void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet) {
- relayoutTaskViews(animation, ignoreTasksSet, false /* ignoreTaskOverrides */);
- }
-
- /**
* Relayout the the visible {@link TaskView}s to their current transforms as specified by the
* {@link TaskStackLayoutAlgorithm} with the given {@param animation}. This call cancels any
* animations that are current running on those task views, and will ensure that the children
@@ -657,7 +640,7 @@
*
* @param ignoreTasksSet the set of tasks to ignore in the relayout
*/
- void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet,
+ private void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet,
boolean ignoreTaskOverrides) {
// If we had a deferred animation, cancel that
mDeferredTaskViewLayoutAnimation = null;
@@ -841,7 +824,7 @@
*
* @param ignoreTasksSet the set of tasks to ignore in the relayout
*/
- public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
+ private void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
ArraySet<Task.TaskKey> ignoreTasksSet) {
// Compute the min and max scroll values
mLayoutAlgorithm.update(mStack, ignoreTasksSet);
@@ -1098,24 +1081,6 @@
}
@Override
- protected Parcelable onSaveInstanceState() {
- Bundle savedState = new Bundle();
- savedState.putParcelable(KEY_SAVED_STATE_SUPER, super.onSaveInstanceState());
- savedState.putInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState());
- savedState.putFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL, mStackScroller.getStackScroll());
- return super.onSaveInstanceState();
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- Bundle savedState = (Bundle) state;
- super.onRestoreInstanceState(savedState.getParcelable(KEY_SAVED_STATE_SUPER));
-
- mLayoutAlgorithm.setFocusState(savedState.getInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE));
- mStackScroller.setStackScroll(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL));
- }
-
- @Override
public CharSequence getAccessibilityClassName() {
return TaskStackView.class.getName();
}
@@ -1181,9 +1146,10 @@
* Updates the system insets.
*/
public void setSystemInsets(Rect systemInsets) {
- if (!systemInsets.equals(mLayoutAlgorithm.mSystemInsets)) {
- mStableLayoutAlgorithm.setSystemInsets(systemInsets);
- mLayoutAlgorithm.setSystemInsets(systemInsets);
+ boolean changed = false;
+ changed |= mStableLayoutAlgorithm.setSystemInsets(systemInsets);
+ changed |= mLayoutAlgorithm.setSystemInsets(systemInsets);
+ if (changed) {
requestLayout();
}
}
@@ -1215,13 +1181,17 @@
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
- updateLayoutAlgorithm(false /* boundScroll */, mIgnoreTasks);
+ updateLayoutAlgorithm(false /* boundScroll */);
// If this is the first layout, then scroll to the front of the stack, then update the
// TaskViews with the stack so that we can lay them out
if (mAwaitingFirstLayout || mInitialState != INITIAL_STATE_UPDATE_NONE) {
- updateToInitialState(mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY);
- mInitialState = INITIAL_STATE_UPDATE_NONE;
+ if (mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY) {
+ updateToInitialState();
+ }
+ if (!mAwaitingFirstLayout) {
+ mInitialState = INITIAL_STATE_UPDATE_NONE;
+ }
}
// Rebind all the views, including the ignore ones
@@ -1245,16 +1215,16 @@
* Measures a TaskView.
*/
private void measureTaskView(TaskView tv) {
+ Rect padding = new Rect();
if (tv.getBackground() != null) {
- tv.getBackground().getPadding(mTmpRect);
- } else {
- mTmpRect.setEmpty();
+ tv.getBackground().getPadding(padding);
}
- Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
+ mTmpRect.set(mStableLayoutAlgorithm.mTaskRect);
+ mTmpRect.union(mLayoutAlgorithm.mTaskRect);
tv.measure(
- MeasureSpec.makeMeasureSpec(taskRect.width() + mTmpRect.left + mTmpRect.right,
+ MeasureSpec.makeMeasureSpec(mTmpRect.width() + padding.left + padding.right,
MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(taskRect.height() + mTmpRect.top + mTmpRect.bottom,
+ MeasureSpec.makeMeasureSpec(mTmpRect.height() + padding.top + padding.bottom,
MeasureSpec.EXACTLY));
}
@@ -1276,11 +1246,12 @@
}
// Relayout all of the task views including the ignored ones
- relayoutTaskViews(AnimationProps.IMMEDIATE, mIgnoreTasks);
+ relayoutTaskViews(AnimationProps.IMMEDIATE);
clipTaskViews();
if (mAwaitingFirstLayout || !mEnterAnimationComplete) {
mAwaitingFirstLayout = false;
+ mInitialState = INITIAL_STATE_UPDATE_NONE;
onFirstLayout();
}
}
@@ -1290,15 +1261,15 @@
*/
private void layoutTaskView(boolean changed, TaskView tv) {
if (changed) {
+ Rect padding = new Rect();
if (tv.getBackground() != null) {
- tv.getBackground().getPadding(mTmpRect);
- } else {
- mTmpRect.setEmpty();
+ tv.getBackground().getPadding(padding);
}
- Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
+ mTmpRect.set(mStableLayoutAlgorithm.mTaskRect);
+ mTmpRect.union(mLayoutAlgorithm.mTaskRect);
tv.cancelTransformAnimation();
- tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
- taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
+ tv.layout(mTmpRect.left - padding.left, mTmpRect.top - padding.top,
+ mTmpRect.right + padding.right, mTmpRect.bottom + padding.bottom);
} else {
// If the layout has not changed, then just lay it out again in-place
tv.layout(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
@@ -1836,9 +1807,17 @@
// Calculate the new task stack bounds that matches the window size that Recents will
// have after the drop
final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
+ Rect systemInsets = new Rect(mStableLayoutAlgorithm.mSystemInsets);
+ // When docked, the nav bar insets are consumed and the activity is measured without
+ // insets. However, the window bounds include the insets, so we need to subtract them
+ // here to make them identical.
+ int height = getMeasuredHeight();
+ height -= systemInsets.bottom;
+ systemInsets.bottom = 0;
mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(),
- getMeasuredHeight(), mDividerSize, mLayoutAlgorithm.mSystemInsets,
+ height, mDividerSize, systemInsets,
mLayoutAlgorithm, getResources(), mWindowRect));
+ mLayoutAlgorithm.setSystemInsets(systemInsets);
mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
updateLayoutAlgorithm(true /* boundScroll */);
@@ -1849,6 +1828,7 @@
mWindowRect.set(mStableWindowRect);
mStackBounds.set(mStableStackBounds);
removeIgnoreTask(event.task);
+ mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets);
mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
updateLayoutAlgorithm(true /* boundScroll */);
@@ -1970,25 +1950,31 @@
public final void onBusEvent(MultiWindowStateChangedEvent event) {
if (!event.inMultiWindow) {
- // Scroll the stack to the front to see the undocked task
- mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, new Runnable() {
+ // Defer until the next frame to ensure that we have received all the system insets, and
+ // initial layout updates
+ post(new Runnable() {
@Override
public void run() {
- List<TaskView> taskViews = getTaskViews();
- int taskViewCount = taskViews.size();
- for (int i = 0; i < taskViewCount; i++) {
- TaskView tv = taskViews.get(i);
- tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
- tv.mIsDisabledInSafeMode);
- }
+ // Scroll the stack to the front to see the undocked task
+ mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, new Runnable() {
+ @Override
+ public void run() {
+ List<TaskView> taskViews = getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int i = 0; i < taskViewCount; i++) {
+ TaskView tv = taskViews.get(i);
+ tv.getHeaderView().rebindToTask(tv.getTask(),
+ tv.mTouchExplorationEnabled, tv.mIsDisabledInSafeMode);
+ }
+ }
+ });
}
});
}
}
public final void onBusEvent(ConfigurationChangedEvent event) {
- mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
- mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+ reloadOnConfigurationChange();
// Notify the task views of the configuration change so they can reload their resources
if (!event.fromMultiWindow) {
@@ -2003,11 +1989,17 @@
// Trigger a new layout and update to the initial state if necessary
if (event.fromMultiWindow) {
- mInitialState = INITIAL_STATE_UPDATE_ALL;
- } else if (event.fromOrientationChange) {
mInitialState = INITIAL_STATE_UPDATE_LAYOUT_ONLY;
+ requestLayout();
+ } else if (event.fromDeviceOrientationChange) {
+ mInitialState = INITIAL_STATE_UPDATE_ALL;
+ requestLayout();
}
- requestLayout();
+ }
+
+ public void reloadOnConfigurationChange() {
+ mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+ mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
}
/**
@@ -2096,7 +2088,7 @@
if (mFocusedTask != null) {
writer.print(innerPrefix);
writer.print("Focused task: ");
- mFocusedTask.dump(innerPrefix, writer);
+ mFocusedTask.dump("", writer);
}
mLayoutAlgorithm.dump(innerPrefix, writer);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 6be8a4a..37f5a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -152,7 +152,6 @@
private final TaskViewTransform mTargetAnimationTransform = new TaskViewTransform();
private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
- View mContent;
@ViewDebug.ExportedProperty(deepExport=true, prefix="thumbnail_")
TaskViewThumbnail mThumbnailView;
@ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
@@ -226,9 +225,9 @@
@Override
protected void onFinishInflate() {
// Bind the views
- mContent = findViewById(R.id.task_view_content);
mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar);
mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail);
+ mThumbnailView.updateClipToTaskBar(mHeaderView);
mActionButtonView = findViewById(R.id.lock_to_app_fab);
mActionButtonView.setOutlineProvider(new ViewOutlineProvider() {
@Override
@@ -255,6 +254,9 @@
if (w > 0 && h > 0) {
mHeaderView.onTaskViewSizeChanged(w, h);
mThumbnailView.onTaskViewSizeChanged(w, h);
+
+ mActionButtonView.setTranslationX(w - getMeasuredWidth());
+ mActionButtonView.setTranslationY(h - getMeasuredHeight());
}
}
@@ -276,13 +278,11 @@
protected void measureContents(int width, int height) {
int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;
+ int widthSpec = MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY);
+ int heightSpec = MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY);
// Measure the content
- mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY));
-
- // Optimization: Prevent overdraw of the thumbnail under the header view
- mThumbnailView.updateClipToTaskBar(mHeaderView);
+ measureChildren(widthSpec, heightSpec);
setMeasuredDimension(width, height);
}
@@ -346,6 +346,8 @@
mActionButtonView.setScaleX(1f);
mActionButtonView.setScaleY(1f);
mActionButtonView.setAlpha(0f);
+ mActionButtonView.setTranslationX(0f);
+ mActionButtonView.setTranslationY(0f);
mActionButtonView.setTranslationZ(mActionButtonTranslationZ);
if (mIncompatibleAppToastView != null) {
mIncompatibleAppToastView.setVisibility(View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 16d8e53..fb0fc30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -280,27 +280,31 @@
/**
* Update the header view when the configuration changes.
*/
- void onConfigurationChanged() {
+ public void onConfigurationChanged() {
// Update the dimensions of everything in the header. We do this because we need to use
// resources for the display, and not the current configuration.
Resources res = getResources();
- mHeaderBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+ int headerBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height_tablet_land,
R.dimen.recents_task_view_header_height,
R.dimen.recents_task_view_header_height_tablet_land);
- mHeaderButtonPadding = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+ int headerButtonPadding = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
R.dimen.recents_task_view_header_button_padding,
R.dimen.recents_task_view_header_button_padding,
R.dimen.recents_task_view_header_button_padding,
R.dimen.recents_task_view_header_button_padding_tablet_land,
R.dimen.recents_task_view_header_button_padding,
R.dimen.recents_task_view_header_button_padding_tablet_land);
- updateLayoutParams(mIconView, mTitleView, mMoveTaskButton, mDismissButton);
- if (mAppOverlayView != null) {
- updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
+ if (headerBarHeight != mHeaderBarHeight || headerButtonPadding != mHeaderButtonPadding) {
+ mHeaderBarHeight = headerBarHeight;
+ mHeaderButtonPadding = headerButtonPadding;
+ updateLayoutParams(mIconView, mTitleView, mMoveTaskButton, mDismissButton);
+ if (mAppOverlayView != null) {
+ updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
+ }
}
}
@@ -346,6 +350,8 @@
}
mDismissButton.setVisibility(showDismissIcon ? View.VISIBLE : View.INVISIBLE);
mDismissButton.setTranslationX(rightInset);
+
+ setLeftTopRightBottom(0, 0, width, getMeasuredHeight());
}
@Override
@@ -434,7 +440,6 @@
/** Binds the bar view to the task */
public void rebindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
- SystemServicesProxy ssp = Recents.getSystemServices();
mTask = t;
// If an activity icon is defined, then we use that as the primary icon to show in the bar,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 62fd585..4de7713 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -123,6 +123,7 @@
}
mTaskViewRect.set(0, 0, width, height);
+ setLeftTopRightBottom(0, 0, width, height);
updateThumbnailScale();
}
@@ -148,22 +149,26 @@
int thumbnailHeight = Math.min(viewHeight,
(int) (mThumbnailRect.height() * mThumbnailScale));
if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
+ int topOffset = mTaskBar != null
+ ? mTaskBar.getHeight() - mCornerRadius
+ : 0;
+
// Draw the background, there will be some small overdraw with the thumbnail
if (thumbnailWidth < viewWidth) {
// Portrait thumbnail on a landscape task view
- canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), 0,
+ canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), topOffset,
viewWidth, viewHeight,
mCornerRadius, mCornerRadius, mBgFillPaint);
}
if (thumbnailHeight < viewHeight) {
// Landscape thumbnail on a portrait task view
- canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
+ canvas.drawRoundRect(0, Math.max(topOffset, thumbnailHeight - mCornerRadius),
viewWidth, viewHeight,
mCornerRadius, mCornerRadius, mBgFillPaint);
}
// Draw the thumbnail
- canvas.drawRoundRect(0, 0, thumbnailWidth, thumbnailHeight,
+ canvas.drawRoundRect(0, topOffset, thumbnailWidth, thumbnailHeight,
mCornerRadius, mCornerRadius, mDrawPaint);
} else {
canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
@@ -274,10 +279,7 @@
/** Updates the clip rect based on the given task bar. */
void updateClipToTaskBar(View taskBar) {
mTaskBar = taskBar;
- int top = (int) Math.max(0, taskBar.getTranslationY() +
- taskBar.getMeasuredHeight() - 1);
- mClipRect.set(0, top, getMeasuredWidth(), getMeasuredHeight());
- setClipBounds(mClipRect);
+ invalidate();
}
/** Updates the visibility of the the thumbnail. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index b512393..397f24e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -19,11 +19,14 @@
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.graphics.Rect;
import android.graphics.RectF;
import android.util.IntProperty;
import android.util.Property;
import android.view.View;
+import com.android.systemui.recents.misc.Utilities;
+
import java.util.ArrayList;
/**
@@ -31,55 +34,20 @@
*/
public class TaskViewTransform {
- public static final Property<View, Integer> LEFT =
- new IntProperty<View>("left") {
+ public static final Property<View, Rect> LTRB =
+ new Property<View, Rect>(Rect.class, "leftTopRightBottom") {
+
+ private Rect mTmpRect = new Rect();
+
@Override
- public void setValue(View object, int v) {
- object.setLeft(v);
+ public void set(View v, Rect ltrb) {
+ v.setLeftTopRightBottom(ltrb.left, ltrb.top, ltrb.right, ltrb.bottom);
}
@Override
- public Integer get(View object) {
- return object.getLeft();
- }
- };
-
- public static final Property<View, Integer> TOP =
- new IntProperty<View>("top") {
- @Override
- public void setValue(View object, int v) {
- object.setTop(v);
- }
-
- @Override
- public Integer get(View object) {
- return object.getTop();
- }
- };
-
- public static final Property<View, Integer> RIGHT =
- new IntProperty<View>("right") {
- @Override
- public void setValue(View object, int v) {
- object.setRight(v);
- }
-
- @Override
- public Integer get(View object) {
- return object.getRight();
- }
- };
-
- public static final Property<View, Integer> BOTTOM =
- new IntProperty<View>("bottom") {
- @Override
- public void setValue(View object, int v) {
- object.setBottom(v);
- }
-
- @Override
- public Integer get(View object) {
- return object.getBottom();
+ public Rect get(View v) {
+ mTmpRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+ return mTmpRect;
}
};
@@ -205,11 +173,12 @@
animators.add(animation.apply(AnimationProps.ALPHA, anim));
}
if (hasRectChangedFrom(v)) {
+ Rect fromViewRect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+ Rect toViewRect = new Rect();
+ rect.round(toViewRect);
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(v,
- PropertyValuesHolder.ofInt(LEFT, v.getLeft(), (int) rect.left),
- PropertyValuesHolder.ofInt(TOP, v.getTop(), (int) rect.top),
- PropertyValuesHolder.ofInt(RIGHT, v.getRight(), (int) rect.right),
- PropertyValuesHolder.ofInt(BOTTOM, v.getBottom(), (int) rect.bottom));
+ PropertyValuesHolder.ofObject(LTRB, Utilities.RECT_EVALUATOR,
+ fromViewRect, toViewRect));
animators.add(animation.apply(AnimationProps.BOUNDS, anim));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 11a7048..237ca5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1341,7 +1341,7 @@
}
protected void toggleKeyboardShortcuts(int deviceId) {
- getKeyboardShortcuts().toggleKeyboardShortcuts(deviceId);
+ KeyboardShortcuts.toggle(mContext, deviceId);
}
protected void cancelPreloadingRecents() {
@@ -1575,7 +1575,11 @@
row.setRemoteInputController(mRemoteInputController);
row.setOnExpandClickListener(this);
- // Get the app name
+ // Get the app name.
+ // Note that Notification.Builder#bindHeaderAppName has similar logic
+ // but since this field is used in the guts, it must be accurate.
+ // Therefore we will only show the application label, or, failing that, the
+ // package name. No substitutions.
final String pkg = sbn.getPackageName();
String appname = pkg;
try {
@@ -1738,14 +1742,6 @@
}
}
- protected KeyboardShortcuts getKeyboardShortcuts() {
- if (mKeyboardShortcuts == null) {
- mKeyboardShortcuts = new KeyboardShortcuts(mContext);
- }
-
- return mKeyboardShortcuts;
- }
-
public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
if (!isDeviceProvisioned()) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index c2521b3..79e06c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -70,6 +70,10 @@
*/
public final class KeyboardShortcuts {
private static final String TAG = KeyboardShortcuts.class.getSimpleName();
+ private static final Object sLock = new Object();
+ private static KeyboardShortcuts sInstance;
+ private static boolean sIsShowing;
+
private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
private final SparseArray<String> mModifierNames = new SparseArray<>();
private final SparseArray<Drawable> mSpecialCharacterDrawables = new SparseArray<>();
@@ -80,7 +84,7 @@
private final IPackageManager mPackageManager;
private final OnClickListener mDialogCloseListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- dismissKeyboardShortcutsDialog();
+ dismissKeyboardShortcuts();
}
};
private final Comparator<KeyboardShortcutInfo> mApplicationItemsComparator =
@@ -108,12 +112,49 @@
private Dialog mKeyboardShortcutsDialog;
private KeyCharacterMap mKeyCharacterMap;
- public KeyboardShortcuts(Context context) {
+ private KeyboardShortcuts(Context context) {
this.mContext = new ContextThemeWrapper(context, android.R.style.Theme_Material_Light);
this.mPackageManager = AppGlobals.getPackageManager();
loadResources(context);
}
+ private static KeyboardShortcuts getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new KeyboardShortcuts(context);
+ }
+ return sInstance;
+ }
+
+ public static void show(Context context, int deviceId) {
+ synchronized (sLock) {
+ if (sInstance != null && !sInstance.mContext.equals(context)) {
+ dismiss();
+ }
+ getInstance(context).showKeyboardShortcuts(deviceId);
+ sIsShowing = true;
+ }
+ }
+
+ public static void toggle(Context context, int deviceId) {
+ synchronized (sLock) {
+ if (sIsShowing) {
+ dismiss();
+ } else {
+ show(context, deviceId);
+ }
+ }
+ }
+
+ public static void dismiss() {
+ synchronized (sLock) {
+ if (sInstance != null) {
+ sInstance.dismissKeyboardShortcuts();
+ sInstance = null;
+ }
+ sIsShowing = false;
+ }
+ }
+
private void loadResources(Context context) {
mSpecialCharacterNames.put(
KeyEvent.KEYCODE_HOME, context.getString(R.string.keyboard_key_home));
@@ -277,27 +318,6 @@
KeyEvent.META_META_ON, context.getDrawable(R.drawable.ic_ksh_key_meta));
}
- public void toggleKeyboardShortcuts(int deviceId) {
- retrieveKeyCharacterMap(deviceId);
- if (mKeyboardShortcutsDialog == null) {
- Recents.getSystemServices().requestKeyboardShortcuts(mContext,
- new KeyboardShortcutsReceiver() {
- @Override
- public void onKeyboardShortcutsReceived(
- final List<KeyboardShortcutGroup> result) {
- result.add(getSystemShortcuts());
- final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts();
- if (appShortcuts != null) {
- result.add(appShortcuts);
- }
- showKeyboardShortcutsDialog(result);
- }
- }, deviceId);
- } else {
- dismissKeyboardShortcutsDialog();
- }
- }
-
/**
* Retrieves a {@link KeyCharacterMap} and assigns it to mKeyCharacterMap. If the given id is an
* existing device, that device's map is used. Otherwise, it checks first all available devices
@@ -327,7 +347,24 @@
mKeyCharacterMap = inputDevice.getKeyCharacterMap();
}
- public void dismissKeyboardShortcutsDialog() {
+ private void showKeyboardShortcuts(int deviceId) {
+ retrieveKeyCharacterMap(deviceId);
+ Recents.getSystemServices().requestKeyboardShortcuts(mContext,
+ new KeyboardShortcutsReceiver() {
+ @Override
+ public void onKeyboardShortcutsReceived(
+ final List<KeyboardShortcutGroup> result) {
+ result.add(getSystemShortcuts());
+ final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts();
+ if (appShortcuts != null) {
+ result.add(appShortcuts);
+ }
+ showKeyboardShortcutsDialog(result);
+ }
+ }, deviceId);
+ }
+
+ private void dismissKeyboardShortcuts() {
if (mKeyboardShortcutsDialog != null) {
mKeyboardShortcutsDialog.dismiss();
mKeyboardShortcutsDialog = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
index 5d22faf..5f4ebd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
@@ -26,8 +26,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
- final KeyboardShortcuts keyboardShortcuts = new KeyboardShortcuts(context);
- keyboardShortcuts.toggleKeyboardShortcuts(-1 /* deviceId unknown */);
+ KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 4f3a6a1..3ca0a6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -133,6 +133,7 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
@@ -3161,7 +3162,7 @@
if (DEBUG) Log.v(TAG, "onReceive: " + intent);
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- getKeyboardShortcuts().dismissKeyboardShortcutsDialog();
+ KeyboardShortcuts.dismiss();
if (isCurrentProfile(getSendingUserId())) {
int flags = CommandQueue.FLAG_EXCLUDE_NONE;
String reason = intent.getStringExtra("reason");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index ebefdde..52fb470 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -674,6 +674,13 @@
} else if (!selfFullscreen && otherFullscreen) {
return 1;
}
+
+ if (remoteInputActive && !o.remoteInputActive) {
+ return -1;
+ } else if (!remoteInputActive && o.remoteInputActive) {
+ return 1;
+ }
+
return postTime < o.postTime ? 1
: postTime == o.postTime ? entry.key.compareTo(o.entry.key)
: -1;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
new file mode 100644
index 0000000..c65415e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
@@ -0,0 +1,142 @@
+/*
+ * 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.tv.pip;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View.OnFocusChangeListener;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+/**
+ * A view containing PIP controls including fullscreen, close, and media controls.
+ */
+public class PipControlButtonView extends LinearLayout {
+ private OnFocusChangeListener mFocusChangeListener;
+ private ImageView mButtonImageView;
+ private TextView mDescriptionTextView;
+ private Animator mFocusGainAnimator;
+ private Animator mFocusLoseAnimator;
+
+ private final OnFocusChangeListener mInternalFocusChangeListener =
+ new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ if (mFocusLoseAnimator.isStarted()) {
+ mFocusLoseAnimator.cancel();
+ }
+ mFocusGainAnimator.start();
+ } else {
+ if (mFocusGainAnimator.isStarted()) {
+ mFocusGainAnimator.cancel();
+ }
+ mFocusLoseAnimator.start();
+ }
+
+ if (mFocusChangeListener != null) {
+ mFocusChangeListener.onFocusChange(v, hasFocus);
+ }
+ }
+ };
+
+ public PipControlButtonView(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ public PipControlButtonView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public PipControlButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public PipControlButtonView(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.tv_pip_control_button, this);
+
+ setOrientation(LinearLayout.VERTICAL);
+ setGravity(Gravity.CENTER);
+
+ mButtonImageView = (ImageView) findViewById(R.id.button);
+ mDescriptionTextView = (TextView) findViewById(R.id.desc);
+
+ int[] values = new int[] {android.R.attr.src, android.R.attr.text};
+ TypedArray typedArray =
+ context.obtainStyledAttributes(attrs, values, defStyleAttr, defStyleRes);
+
+ mButtonImageView.setImageDrawable(typedArray.getDrawable(0));
+ mDescriptionTextView.setText(typedArray.getText(1));
+
+ typedArray.recycle();
+ }
+
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+ mButtonImageView.setOnFocusChangeListener(mInternalFocusChangeListener);
+
+ mFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
+ R.anim.tv_pip_controls_text_focus_gain_animation);
+ mFocusGainAnimator.setTarget(mDescriptionTextView);
+ mFocusLoseAnimator = AnimatorInflater.loadAnimator(getContext(),
+ R.anim.tv_pip_controls_text_focus_lose_animation);
+ mFocusLoseAnimator.setTarget(mDescriptionTextView);
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener listener) {
+ mButtonImageView.setOnClickListener(listener);
+ }
+
+ @Override
+ public void setOnFocusChangeListener(OnFocusChangeListener listener) {
+ mFocusChangeListener = listener;
+ }
+
+ /**
+ * Sets the drawable for the button with the given resource id.
+ */
+ public void setImageResource(int resId) {
+ mButtonImageView.setImageResource(resId);
+ }
+
+ /**
+ * Sets the text for description the with the given resource id.
+ */
+ public void setText(int resId) {
+ mDescriptionTextView.setText(resId);
+ }
+
+ @Override
+ public boolean isFocused() {
+ return mButtonImageView.isFocused();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
index 3f87611..d15799c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
@@ -57,13 +57,9 @@
final PipManager mPipManager = PipManager.getInstance();
Listener mListener;
- View mFullButtonView;
- View mFullDescriptionView;
- View mPlayPauseView;
- ImageView mPlayPauseButtonImageView;
- TextView mPlayPauseDescriptionTextView;
- View mCloseButtonView;
- View mCloseDescriptionView;
+ PipControlButtonView mFullButtonView;
+ PipControlButtonView mCloseButtonView;
+ PipControlButtonView mPlayPauseButtonView;
private boolean mHasFocus;
private OnFocusChangeListener mOnChildFocusChangeListener;
@@ -75,13 +71,20 @@
}
};
- private PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
+ private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
@Override
public void onMediaControllerChanged() {
updateMediaController();
}
};
+ private final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ onChildViewFocusChanged();
+ }
+ };
+
public PipControlsView(Context context) {
this(context, null, 0, 0);
}
@@ -108,26 +111,30 @@
public void onFinishInflate() {
super.onFinishInflate();
- mFullButtonView = findViewById(R.id.full_button);
- mFullDescriptionView = findViewById(R.id.full_desc);
+ mFullButtonView = (PipControlButtonView) findViewById(R.id.full_button);
+ mFullButtonView.setOnFocusChangeListener(mFocusChangeListener);
mFullButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPipManager.movePipToFullscreen();
}
});
- mFullButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+ mCloseButtonView = (PipControlButtonView) findViewById(R.id.close_button);
+ mCloseButtonView.setOnFocusChangeListener(mFocusChangeListener);
+ mCloseButtonView.setOnClickListener(new View.OnClickListener() {
@Override
- public void onFocusChange(View v, boolean hasFocus) {
- mFullDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
- onChildViewFocusChanged();
+ public void onClick(View v) {
+ mPipManager.closePip();
+ if (mListener != null) {
+ mListener.onClosed();
+ }
}
});
- mPlayPauseView = findViewById(R.id.play_pause);
- mPlayPauseButtonImageView = (ImageView) findViewById(R.id.play_pause_button);
- mPlayPauseDescriptionTextView = (TextView) findViewById(R.id.play_pause_desc);
- mPlayPauseButtonImageView.setOnClickListener(new View.OnClickListener() {
+ mPlayPauseButtonView = (PipControlButtonView) findViewById(R.id.play_pause_button);
+ mPlayPauseButtonView.setOnFocusChangeListener(mFocusChangeListener);
+ mPlayPauseButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mMediaController == null || mMediaController.getPlaybackState() == null) {
@@ -143,33 +150,6 @@
// View will be updated later in {@link mMediaControllerCallback}
}
});
- mPlayPauseButtonImageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mPlayPauseDescriptionTextView.setVisibility(
- hasFocus ? View.VISIBLE : View.INVISIBLE);
- onChildViewFocusChanged();
- }
- });
-
- mCloseButtonView = findViewById(R.id.close_button);
- mCloseDescriptionView = findViewById(R.id.close_desc);
- mCloseButtonView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mPipManager.closePip();
- if (mListener != null) {
- mListener.onClosed();
- }
- }
- });
- mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
- onChildViewFocusChanged();
- }
- });
}
@Override
@@ -206,15 +186,15 @@
private void updatePlayPauseView() {
int state = mPipManager.getPlaybackState();
if (state == PLAYBACK_STATE_UNAVAILABLE) {
- mPlayPauseView.setVisibility(View.GONE);
+ mPlayPauseButtonView.setVisibility(View.GONE);
} else {
- mPlayPauseView.setVisibility(View.VISIBLE);
+ mPlayPauseButtonView.setVisibility(View.VISIBLE);
if (state == PLAYBACK_STATE_PLAYING) {
- mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_pause_button);
- mPlayPauseDescriptionTextView.setText(R.string.pip_pause);
+ mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white_24dp);
+ mPlayPauseButtonView.setText(R.string.pip_pause);
} else {
- mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_play_button);
- mPlayPauseDescriptionTextView.setText(R.string.pip_play);
+ mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white_24dp);
+ mPlayPauseButtonView.setText(R.string.pip_play);
}
}
}
@@ -229,7 +209,7 @@
private void onChildViewFocusChanged() {
// At this moment, hasFocus() returns true although there's no focused child.
boolean hasFocus = (mFullButtonView != null && mFullButtonView.isFocused())
- || (mPlayPauseButtonImageView != null && mPlayPauseButtonImageView.isFocused())
+ || (mPlayPauseButtonView != null && mPlayPauseButtonView.isFocused())
|| (mCloseButtonView != null && mCloseButtonView.isFocused());
if (mHasFocus != hasFocus) {
mHasFocus = hasFocus;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 854e09d..542a935 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -16,10 +16,14 @@
package com.android.systemui.tv.pip;
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
import android.app.Activity;
import android.os.Bundle;
+import android.view.View;
import com.android.systemui.R;
+import com.android.systemui.Interpolators;
/**
* Activity to show the PIP menu to control PIP.
@@ -29,7 +33,9 @@
private final PipManager mPipManager = PipManager.getInstance();
- private PipControlsView mPipControlsView;
+ private Animator mFadeInAnimation;
+ private Animator mFadeOutAnimation;
+ private View mPipControlsView;
private boolean mRestorePipSizeWhenClose;
@Override
@@ -38,8 +44,14 @@
setContentView(R.layout.tv_pip_menu);
mPipManager.addListener(this);
- mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
mRestorePipSizeWhenClose = true;
+ mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
+ mFadeInAnimation = AnimatorInflater.loadAnimator(
+ this, R.anim.tv_pip_menu_fade_in_animation);
+ mFadeInAnimation.setTarget(mPipControlsView);
+ mFadeOutAnimation = AnimatorInflater.loadAnimator(
+ this, R.anim.tv_pip_menu_fade_out_animation);
+ mFadeOutAnimation.setTarget(mPipControlsView);
}
private void restorePipAndFinish() {
@@ -51,8 +63,15 @@
}
@Override
+ public void onResume() {
+ super.onResume();
+ mFadeInAnimation.start();
+ }
+
+ @Override
public void onPause() {
super.onPause();
+ mFadeOutAnimation.start();
restorePipAndFinish();
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index 86ceff4..398572a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -16,12 +16,15 @@
package com.android.systemui.tv.pip;
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.app.Activity;
-import android.graphics.Rect;
+import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
-import android.util.Log;
import android.view.View;
-import android.view.ViewGroup.LayoutParams;
+import android.widget.ImageView;
import com.android.systemui.R;
@@ -35,29 +38,47 @@
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.tv_pip_onboarding);
- View pipOnboardingView = findViewById(R.id.pip_onboarding);
- View pipOutlineView = findViewById(R.id.pip_outline);
- mPipManager.addListener(this);
- findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
+ findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
- int pipOutlineSpace = getResources().getDimensionPixelSize(R.dimen.tv_pip_bounds_space);
- int screenWidth = getResources().getDisplayMetrics().widthPixels;
- Rect pipBounds = mPipManager.getPipBounds();
- pipOnboardingView.setPadding(
- pipBounds.left - pipOutlineSpace,
- pipBounds.top - pipOutlineSpace,
- screenWidth - pipBounds.right - pipOutlineSpace, 0);
+ mPipManager.addListener(this);
+ }
- // Set width and height for outline view to enclose the PIP.
- LayoutParams lp = pipOutlineView.getLayoutParams();
- lp.width = pipBounds.width() + pipOutlineSpace * 2;
- lp.height = pipBounds.height() + pipOutlineSpace * 2;
- pipOutlineView.setLayoutParams(lp);
+ @Override
+ public void onResume() {
+ super.onResume();
+ AnimatorSet enterAnimator = new AnimatorSet();
+ enterAnimator.playTogether(
+ loadAnimator(R.id.remote, R.anim.tv_pip_onboarding_image_enter_animation),
+ loadAnimator(R.id.remote_button, R.anim.tv_pip_onboarding_image_enter_animation),
+ loadAnimator(R.id.title, R.anim.tv_pip_onboarding_title_enter_animation),
+ loadAnimator(R.id.description,
+ R.anim.tv_pip_onboarding_description_enter_animation),
+ loadAnimator(R.id.button, R.anim.tv_pip_onboarding_button_enter_animation));
+ enterAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ ImageView button = (ImageView) findViewById(R.id.remote_button);
+ ((AnimationDrawable) button.getDrawable()).start();
+ }
+ });
+ enterAnimator.start();
+ }
+
+ private Animator loadAnimator(int viewResId, int animResId) {
+ Animator animator = AnimatorInflater.loadAnimator(this, animResId);
+ animator.setTarget(findViewById(viewResId));
+ return animator;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ finish();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
index 8b8c105..9c806f7 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
@@ -72,28 +72,20 @@
super.onFinishInflate();
int buttonsFocusGainAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_gain_animation;
- int textFocusGainAnim = R.anim.tv_pip_controls_text_in_recents_focus_gain_animation;
mFocusGainAnimatorSet = new AnimatorSet();
mFocusGainAnimatorSet.playTogether(
loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_gain_animation),
loadAnimator(mFullButtonView,buttonsFocusGainAnim),
- loadAnimator(mPlayPauseButtonImageView, buttonsFocusGainAnim),
- loadAnimator(mCloseButtonView, buttonsFocusGainAnim),
- loadAnimator(mFullDescriptionView, textFocusGainAnim),
- loadAnimator(mPlayPauseDescriptionTextView, textFocusGainAnim),
- loadAnimator(mCloseDescriptionView, textFocusGainAnim));
+ loadAnimator(mPlayPauseButtonView, buttonsFocusGainAnim),
+ loadAnimator(mCloseButtonView, buttonsFocusGainAnim));
int buttonsFocusLoseAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_lose_animation;
- int textFocusLoseAnim = R.anim.tv_pip_controls_text_in_recents_focus_lose_animation;
mFocusLoseAnimatorSet = new AnimatorSet();
mFocusLoseAnimatorSet.playTogether(
loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_lose_animation),
loadAnimator(mFullButtonView, buttonsFocusLoseAnim),
- loadAnimator(mPlayPauseButtonImageView, buttonsFocusLoseAnim),
- loadAnimator(mCloseButtonView, buttonsFocusLoseAnim),
- loadAnimator(mFullDescriptionView, textFocusLoseAnim),
- loadAnimator(mPlayPauseDescriptionTextView, textFocusLoseAnim),
- loadAnimator(mCloseDescriptionView, textFocusLoseAnim));
+ loadAnimator(mPlayPauseButtonView, buttonsFocusLoseAnim),
+ loadAnimator(mCloseButtonView, buttonsFocusLoseAnim));
Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
int pipControlsMarginTop = getContext().getResources().getDimensionPixelSize(
@@ -142,11 +134,8 @@
requestFocus();
setTranslationY(0);
setScaleXY(mFullButtonView, 1);
- setScaleXY(mPlayPauseButtonImageView, 1);
+ setScaleXY(mPlayPauseButtonView, 1);
setScaleXY(mCloseButtonView, 1);
- mFullDescriptionView.setAlpha(1);
- mPlayPauseDescriptionTextView.setAlpha(1);
- mCloseDescriptionView.setAlpha(1);
}
private void setScaleXY(View view, float scale) {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
index 47cd8e5..d75561b 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -16,8 +16,6 @@
package com.android.systemui.tv.pip;
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
import android.content.Context;
import android.graphics.PixelFormat;
import android.util.Log;
@@ -134,6 +132,7 @@
* @param allowRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
*/
public void requestFocus(boolean allowRecentsFocusable) {
+ mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
if (!mIsRecentsShown || mIsPipFocusedInRecent) {
return;
}
@@ -143,7 +142,6 @@
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
mPipControlsView.requestFocus();
mPipControlsView.startFocusGainAnimation();
- mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
}
/**
@@ -152,10 +150,14 @@
* is focused.
* This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
*/
- private void clearFocus() {
+ public void clearFocus() {
if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
return;
}
+ if (!mRecentsView.hasFocus()) {
+ // Let mRecentsView's focus listener handle clearFocus().
+ mRecentsView.requestFocus();
+ }
mIsPipFocusedInRecent = false;
mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2ccc3fe..e5fe03a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2206,6 +2206,10 @@
}
mLegacyTypeTracker.remove(nai, wasDefault);
rematchAllNetworksAndRequests(null, 0);
+ if (wasDefault && getDefaultNetwork() == null) {
+ // Log that we lost the default network and there is no replacement.
+ logConnectivityServiceChangeEvent(null, nai);
+ }
if (nai.created) {
// Tell netd to clean up the configuration for this network
// (routing rules, DNS, etc).
@@ -4427,9 +4431,8 @@
teardownUnneededNetwork(oldNetwork);
}
- private void makeDefault(NetworkAgentInfo newNetwork) {
+ private void makeDefault(NetworkAgentInfo newNetwork, NetworkAgentInfo prevNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
- ConnectivityServiceChangeEvent.logEvent(newNetwork.network.netId);
setupDataActivityTracking(newNetwork);
try {
mNetd.setDefaultNetId(newNetwork.network.netId);
@@ -4440,6 +4443,8 @@
handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
updateTcpBufferSizes(newNetwork);
setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
+
+ logConnectivityServiceChangeEvent(newNetwork, prevNetwork);
}
// Handles a network appearing or improving its score.
@@ -4590,7 +4595,7 @@
}
if (isNewDefault) {
// Notify system services that this network is up.
- makeDefault(newNetwork);
+ makeDefault(newNetwork, oldDefaultNetwork);
synchronized (ConnectivityService.this) {
// have a new default network, release the transition wakelock in
// a second if it's held. The second pause is to allow apps
@@ -5060,4 +5065,22 @@
NetworkAgentInfo nai, NetworkRequest defaultRequest) {
return new NetworkMonitor(context, handler, nai, defaultRequest);
}
+
+ private static void logConnectivityServiceChangeEvent(
+ NetworkAgentInfo next, NetworkAgentInfo prev) {
+ final int newNetId = (next == null) ? NETID_UNSET : next.network.netId;
+ final int[] newTransportTypes = (next == null)
+ ? new int[0]
+ : next.networkCapabilities.getTransportTypes();
+
+ final int oldNetId = (prev == null) ? NETID_UNSET : prev.network.netId;
+ final boolean hadIPv4 = (prev != null) &&
+ prev.linkProperties.hasIPv4Address() &&
+ prev.linkProperties.hasIPv4DefaultRoute();
+ final boolean hadIPv6 = (prev != null) &&
+ prev.linkProperties.hasGlobalIPv6Address() &&
+ prev.linkProperties.hasIPv6DefaultRoute();
+ ConnectivityServiceChangeEvent.logEvent(newNetId, newTransportTypes,
+ oldNetId, hadIPv4, hadIPv6);
+ }
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 2924cef..5ba07cf 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -454,6 +454,12 @@
return;
}
+ if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE
+ && Settings.System.getInt(
+ mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) == 0) {
+ return;
+ }
+
int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
vib.mUsageHint, vib.mUid, vib.mOpPkg);
if (mode == AppOpsManager.MODE_ALLOWED) {
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 4198af9..be53cfc 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -65,10 +65,14 @@
// Which native processes to dump into dropbox's stack traces
public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
"/system/bin/audioserver",
+ "/system/bin/cameraserver",
+ "/system/bin/drmserver",
+ "/system/bin/mediadrmserver",
"/system/bin/mediaserver",
"/system/bin/sdcard",
"/system/bin/surfaceflinger",
- "media.log"
+ "media.codec", // system/bin/mediacodec
+ "media.extractor", // system/bin/mediaextractor
};
static Watchdog sWatchdog;
diff --git a/services/core/java/com/android/server/accounts/CryptoHelper.java b/services/core/java/com/android/server/accounts/CryptoHelper.java
index 2b59b74..2ade673 100644
--- a/services/core/java/com/android/server/accounts/CryptoHelper.java
+++ b/services/core/java/com/android/server/accounts/CryptoHelper.java
@@ -10,15 +10,12 @@
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
/**
* A crypto helper for encrypting and decrypting bundle with in-memory symmetric
@@ -30,15 +27,15 @@
private static final String KEY_CIPHER = "cipher";
private static final String KEY_MAC = "mac";
private static final String KEY_ALGORITHM = "AES";
+ private static final String KEY_IV = "iv";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String MAC_ALGORITHM = "HMACSHA256";
private static final int IV_LENGTH = 16;
private static CryptoHelper sInstance;
// Keys used for encrypting and decrypting data returned in a Bundle.
- private final SecretKeySpec mCipherKeySpec;
- private final SecretKeySpec mMacKeySpec;
- private final IvParameterSpec mIv;
+ private final SecretKey mEncryptionKey;
+ private final SecretKey mMacKey;
/* default */ synchronized static CryptoHelper getInstance() throws NoSuchAlgorithmException {
if (sInstance == null) {
@@ -49,18 +46,10 @@
private CryptoHelper() throws NoSuchAlgorithmException {
KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
- SecretKey skey = kgen.generateKey();
- mCipherKeySpec = new SecretKeySpec(skey.getEncoded(), KEY_ALGORITHM);
-
+ mEncryptionKey = kgen.generateKey();
+ // Use a different key for mac-ing than encryption/decryption.
kgen = KeyGenerator.getInstance(MAC_ALGORITHM);
- skey = kgen.generateKey();
- mMacKeySpec = new SecretKeySpec(skey.getEncoded(), MAC_ALGORITHM);
-
- // Create random iv
- byte[] iv = new byte[IV_LENGTH];
- SecureRandom secureRandom = new SecureRandom();
- secureRandom.nextBytes(iv);
- mIv = new IvParameterSpec(iv);
+ mMacKey = kgen.generateKey();
}
@NonNull
@@ -68,16 +57,19 @@
Preconditions.checkNotNull(bundle, "Cannot encrypt null bundle.");
Parcel parcel = Parcel.obtain();
bundle.writeToParcel(parcel, 0);
- byte[] bytes = parcel.marshall();
+ byte[] clearBytes = parcel.marshall();
parcel.recycle();
+ Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, mEncryptionKey);
+ byte[] encryptedBytes = cipher.doFinal(clearBytes);
+ byte[] iv = cipher.getIV();
+ byte[] mac = createMac(encryptedBytes, iv);
+
Bundle encryptedBundle = new Bundle();
-
- byte[] cipher = encrypt(bytes);
- byte[] mac = createMac(cipher);
-
- encryptedBundle.putByteArray(KEY_CIPHER, cipher);
+ encryptedBundle.putByteArray(KEY_CIPHER, encryptedBytes);
encryptedBundle.putByteArray(KEY_MAC, mac);
+ encryptedBundle.putByteArray(KEY_IV, iv);
return encryptedBundle;
}
@@ -85,19 +77,18 @@
@Nullable
/* default */ Bundle decryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException {
Preconditions.checkNotNull(bundle, "Cannot decrypt null bundle.");
- byte[] cipherArray = bundle.getByteArray(KEY_CIPHER);
- byte[] macArray = bundle.getByteArray(KEY_MAC);
-
- if (!verifyMac(cipherArray, macArray)) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Escrow mac mismatched!");
- }
+ byte[] iv = bundle.getByteArray(KEY_IV);
+ byte[] encryptedBytes = bundle.getByteArray(KEY_CIPHER);
+ byte[] mac = bundle.getByteArray(KEY_MAC);
+ if (!verifyMac(encryptedBytes, iv, mac)) {
+ Log.w(TAG, "Escrow mac mismatched!");
return null;
}
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
- cipher.init(Cipher.DECRYPT_MODE, mCipherKeySpec, mIv);
- byte[] decryptedBytes = cipher.doFinal(cipherArray);
+ cipher.init(Cipher.DECRYPT_MODE, mEncryptionKey, ivSpec);
+ byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
Parcel decryptedParcel = Parcel.obtain();
decryptedParcel.unmarshall(decryptedBytes, 0, decryptedBytes.length);
@@ -108,9 +99,8 @@
return decryptedBundle;
}
- private boolean verifyMac(@Nullable byte[] cipherArray, @Nullable byte[] macArray)
+ private boolean verifyMac(@Nullable byte[] cipherArray, @Nullable byte[] iv, @Nullable byte[] macArray)
throws GeneralSecurityException {
-
if (cipherArray == null || cipherArray.length == 0 || macArray == null
|| macArray.length == 0) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -118,23 +108,29 @@
}
return false;
}
- Mac mac = Mac.getInstance(MAC_ALGORITHM);
- mac.init(mMacKeySpec);
- mac.update(cipherArray);
- return Arrays.equals(macArray, mac.doFinal());
+ return constantTimeArrayEquals(macArray, createMac(cipherArray, iv));
}
@NonNull
- private byte[] encrypt(@NonNull byte[] data) throws GeneralSecurityException {
- Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
- cipher.init(Cipher.ENCRYPT_MODE, mCipherKeySpec, mIv);
- return cipher.doFinal(data);
+ private byte[] createMac(@NonNull byte[] cipher, @NonNull byte[] iv) throws GeneralSecurityException {
+ Mac mac = Mac.getInstance(MAC_ALGORITHM);
+ mac.init(mMacKey);
+ mac.update(cipher);
+ mac.update(iv);
+ return mac.doFinal();
}
- @NonNull
- private byte[] createMac(@NonNull byte[] cipher) throws GeneralSecurityException {
- Mac mac = Mac.getInstance(MAC_ALGORITHM);
- mac.init(mMacKeySpec);
- return mac.doFinal(cipher);
+ private static boolean constantTimeArrayEquals(byte[] a, byte[] b) {
+ if (a == null || b == null) {
+ return a == b;
+ }
+ if (a.length != b.length) {
+ return false;
+ }
+ boolean isEqual = true;
+ for (int i = 0; i < b.length; i++) {
+ isEqual &= (a[i] == b[i]);
+ }
+ return isEqual;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4c75f50..9703d13 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -628,13 +628,16 @@
public Bundle result = null;
public AssistStructure structure = null;
public AssistContent content = null;
+ public Bundle receiverExtras;
+
public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
- String _hint, IResultReceiver _receiver, int _userHandle) {
+ String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _userHandle) {
activity = _activity;
extras = _extras;
intent = _intent;
hint = _hint;
receiver = _receiver;
+ receiverExtras = _receiverExtras;
userHandle = _userHandle;
}
@Override
@@ -11806,7 +11809,7 @@
@Override
public Bundle getAssistContextExtras(int requestType) {
PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
- null, UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
+ null, null, true, UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
if (pae == null) {
return null;
}
@@ -11870,14 +11873,17 @@
@Override
public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
- IBinder activityToken) {
- return enqueueAssistContext(requestType, null, null, receiver, activityToken,
- UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT) != null;
+ Bundle receiverExtras,
+ IBinder activityToken, boolean focused) {
+ return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
+ activityToken, focused,
+ UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
+ != null;
}
private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
- IResultReceiver receiver, IBinder activityToken, int userHandle, Bundle args,
- long timeout) {
+ IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken, boolean focused,
+ int userHandle, Bundle args, long timeout) {
enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
"enqueueAssistContext()");
synchronized (this) {
@@ -11890,14 +11896,24 @@
Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity);
return null;
}
- if (activityToken != null) {
- ActivityRecord caller = ActivityRecord.forTokenLocked(activityToken);
- if (activity != caller) {
- Slog.w(TAG, "enqueueAssistContext failed: caller " + caller
- + " is not current top " + activity);
+ if (focused) {
+ if (activityToken != null) {
+ ActivityRecord caller = ActivityRecord.forTokenLocked(activityToken);
+ if (activity != caller) {
+ Slog.w(TAG, "enqueueAssistContext failed: caller " + caller
+ + " is not current top " + activity);
+ return null;
+ }
+ }
+ } else {
+ activity = ActivityRecord.forTokenLocked(activityToken);
+ if (activity == null) {
+ Slog.w(TAG, "enqueueAssistContext failed: activity for token=" + activityToken
+ + " couldn't be found");
return null;
}
}
+
PendingAssistExtras pae;
Bundle extras = new Bundle();
if (args != null) {
@@ -11905,7 +11921,8 @@
}
extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
- pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, userHandle);
+ pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
+ userHandle);
try {
activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
requestType);
@@ -11975,9 +11992,11 @@
if ((sendReceiver=pae.receiver) != null) {
// Caller wants result sent back to them.
sendBundle = new Bundle();
- sendBundle.putBundle("data", pae.extras);
- sendBundle.putParcelable("structure", pae.structure);
- sendBundle.putParcelable("content", pae.content);
+ sendBundle.putBundle(VoiceInteractionSession.KEY_DATA, pae.extras);
+ sendBundle.putParcelable(VoiceInteractionSession.KEY_STRUCTURE, pae.structure);
+ sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content);
+ sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
+ pae.receiverExtras);
}
}
if (sendReceiver != null) {
@@ -12007,8 +12026,8 @@
public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
Bundle args) {
- return enqueueAssistContext(requestType, intent, hint, null, null, userHandle, args,
- PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
+ return enqueueAssistContext(requestType, intent, hint, null, null, null, true,
+ userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
}
public void registerProcessObserver(IProcessObserver observer) {
@@ -17622,7 +17641,7 @@
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermissions, appOp, null, serialized, sticky,
+ requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
@@ -20962,6 +20981,13 @@
mStackSupervisor.notifyAppTransitionDone();
}
}
+
+ @Override
+ public List<IBinder> getTopVisibleActivities() {
+ synchronized (ActivityManagerService.this) {
+ return mStackSupervisor.getTopVisibleActivities();
+ }
+ }
}
private final class SleepTokenImpl extends SleepToken {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 598d9ff..ab3a0b3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -98,6 +98,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -4282,4 +4283,31 @@
}
return result;
}
+
+ /**
+ * @return a list of activities which are the top ones in each visible stack. The first
+ * entry will be the focused activity.
+ */
+ public List<IBinder> getTopVisibleActivities() {
+ final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
+ if (display == null) {
+ return Collections.EMPTY_LIST;
+ }
+ ArrayList<IBinder> topActivityTokens = new ArrayList<>();
+ final ArrayList<ActivityStack> stacks = display.mStacks;
+ for (int i = stacks.size() - 1; i >= 0; i--) {
+ ActivityStack stack = stacks.get(i);
+ if (stack.getStackVisibilityLocked(null) == ActivityStack.STACK_VISIBLE) {
+ ActivityRecord top = stack.topActivity();
+ if (top != null) {
+ if (stack == mFocusedStack) {
+ topActivityTokens.add(0, top.appToken);
+ } else {
+ topActivityTokens.add(top.appToken);
+ }
+ }
+ }
+ }
+ return topActivityTokens;
+ }
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index d339f69..5e68f8e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -329,6 +329,7 @@
final String ssid = removeDoubleQuotes(config.SSID);
if (id.equals(ssid)) {
final NetworkPolicy policy = newPolicy(ssid);
+ policy.metered = true;
Log.i(TAG, "Creating new policy for " + ssid + ": " + policy);
final NetworkPolicy[] newPolicies = new NetworkPolicy[policies.length + 1];
System.arraycopy(policies, 0, newPolicies, 0, policies.length);
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index c19b51f..62fe70c 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -16,7 +16,7 @@
package com.android.server.notification;
-import android.app.AutomaticZenRule;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -29,7 +29,6 @@
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
-import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -82,6 +81,7 @@
c.caption = "condition provider";
c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE;
c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
+ c.secondarySettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
c.settingsAction = Settings.ACTION_CONDITION_PROVIDER_SETTINGS;
c.clientLabel = R.string.condition_provider_service_binding_label;
@@ -257,7 +257,7 @@
}
@Override
- protected ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+ protected @NonNull ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
int userId) {
final ContentResolver cr = mContext.getContentResolver();
String settingValue = Settings.Secure.getStringForUser(
@@ -265,12 +265,17 @@
settingName,
userId);
if (TextUtils.isEmpty(settingValue))
- return null;
+ return new ArraySet<>();
String[] packages = settingValue.split(ENABLED_SERVICES_SEPARATOR);
ArraySet<ComponentName> result = new ArraySet<>(packages.length);
for (int i = 0; i < packages.length; i++) {
if (!TextUtils.isEmpty(packages[i])) {
- result.addAll(queryPackageForServices(packages[i], userId));
+ final ComponentName component = ComponentName.unflattenFromString(packages[i]);
+ if (component != null) {
+ result.addAll(queryPackageForServices(component.getPackageName(), userId));
+ } else {
+ result.addAll(queryPackageForServices(packages[i], userId));
+ }
}
}
return result;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index c31d93e..29e2e44 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -126,7 +126,8 @@
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
- if (Objects.equals(element, mConfig.secureSettingName)) {
+ if (Objects.equals(element, mConfig.secureSettingName)
+ || Objects.equals(element, mConfig.secondarySettingName)) {
String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
settingRestored(element, prevValue, newValue, getSendingUserId());
@@ -186,8 +187,8 @@
// By convention, restored settings are replicated to another settings
// entry, named similarly but with a disambiguation suffix.
- public static String restoredSettingName(Config config) {
- return config.secureSettingName + ":restored";
+ public static String restoredSettingName(String setting) {
+ return setting + ":restored";
}
// The OS has done a restore of this service's saved state. We clone it to the
@@ -197,14 +198,14 @@
public void settingRestored(String element, String oldValue, String newValue, int userid) {
if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element
+ " ovalue=" + oldValue + " nvalue=" + newValue);
- if (mConfig.secureSettingName.equals(element)) {
+ if (mConfig.secureSettingName.equals(element) ||
+ mConfig.secondarySettingName.equals(element)) {
if (element != null) {
- mRestored = null;
Settings.Secure.putStringForUser(mContext.getContentResolver(),
- restoredSettingName(mConfig),
+ restoredSettingName(element),
newValue,
userid);
- updateSettingsAccordingToInstalledServices(userid);
+ updateSettingsAccordingToInstalledServices(element, userid);
rebuildRestoredPackages();
}
}
@@ -343,21 +344,25 @@
private void rebuildRestoredPackages() {
mRestoredPackages.clear();
mSnoozingForCurrentProfiles.clear();
- String settingName = restoredSettingName(mConfig);
+ String secureSettingName = restoredSettingName(mConfig.secureSettingName);
+ String secondarySettingName = mConfig.secondarySettingName == null
+ ? null : restoredSettingName(mConfig.secondarySettingName);
int[] userIds = mUserProfiles.getCurrentProfileIds();
final int N = userIds.length;
for (int i = 0; i < N; ++i) {
- ArraySet<ComponentName> names = loadComponentNamesFromSetting(settingName, userIds[i]);
- if (names == null)
- continue;
- for (ComponentName name: names) {
+ ArraySet<ComponentName> names =
+ loadComponentNamesFromSetting(secureSettingName, userIds[i]);
+ if (secondarySettingName != null) {
+ names.addAll(loadComponentNamesFromSetting(secondarySettingName, userIds[i]));
+ }
+ for (ComponentName name : names) {
mRestoredPackages.add(name.getPackageName());
}
}
}
- protected ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+ protected @NonNull ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
int userId) {
final ContentResolver cr = mContext.getContentResolver();
String settingValue = Settings.Secure.getStringForUser(
@@ -365,7 +370,7 @@
settingName,
userId);
if (TextUtils.isEmpty(settingValue))
- return null;
+ return new ArraySet<>();
String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
ArraySet<ComponentName> result = new ArraySet<>(restored.length);
for (int i = 0; i < restored.length; i++) {
@@ -405,7 +410,11 @@
int[] userIds = mUserProfiles.getCurrentProfileIds();
final int N = userIds.length;
for (int i = 0; i < N; ++i) {
- updateSettingsAccordingToInstalledServices(userIds[i]);
+ updateSettingsAccordingToInstalledServices(mConfig.secureSettingName, userIds[i]);
+ if (mConfig.secondarySettingName != null) {
+ updateSettingsAccordingToInstalledServices(
+ mConfig.secondarySettingName, userIds[i]);
+ }
}
rebuildRestoredPackages();
}
@@ -442,13 +451,13 @@
return installed;
}
- private void updateSettingsAccordingToInstalledServices(int userId) {
+ private void updateSettingsAccordingToInstalledServices(String setting, int userId) {
boolean restoredChanged = false;
boolean currentChanged = false;
Set<ComponentName> restored =
- loadComponentNamesFromSetting(restoredSettingName(mConfig), userId);
+ loadComponentNamesFromSetting(restoredSettingName(setting), userId);
Set<ComponentName> current =
- loadComponentNamesFromSetting(mConfig.secureSettingName, userId);
+ loadComponentNamesFromSetting(setting, userId);
// Load all services for all packages.
Set<ComponentName> installed = queryPackageForServices(null, userId);
@@ -478,13 +487,13 @@
if (currentChanged) {
if (DEBUG) Slog.v(TAG, "List of " + getCaption() + " services was updated " + current);
- storeComponentsToSetting(retained, mConfig.secureSettingName, userId);
+ storeComponentsToSetting(retained, setting, userId);
}
if (restoredChanged) {
if (DEBUG) Slog.v(TAG,
"List of " + getCaption() + " restored services was updated " + restored);
- storeComponentsToSetting(restored, restoredSettingName(mConfig), userId);
+ storeComponentsToSetting(restored, restoredSettingName(setting), userId);
}
}
@@ -502,6 +511,10 @@
for (int i = 0; i < nUserIds; ++i) {
componentsByUser.put(userIds[i],
loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
+ if (mConfig.secondarySettingName != null) {
+ componentsByUser.get(userIds[i]).addAll(
+ loadComponentNamesFromSetting(mConfig.secondarySettingName, userIds[i]));
+ }
}
final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
@@ -522,7 +535,7 @@
// decode the list of components
final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
if (null == userComponents) {
- toAdd.put(userIds[i], new HashSet<ComponentName>());
+ toAdd.put(userIds[i], new ArraySet<ComponentName>());
continue;
}
@@ -775,15 +788,25 @@
private class SettingsObserver extends ContentObserver {
private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
+ private final Uri mSecondarySettingsUri;
private SettingsObserver(Handler handler) {
super(handler);
+ if (mConfig.secondarySettingName != null) {
+ mSecondarySettingsUri = Settings.Secure.getUriFor(mConfig.secondarySettingName);
+ } else {
+ mSecondarySettingsUri = null;
+ }
}
private void observe() {
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(mSecureSettingsUri,
false, this, UserHandle.USER_ALL);
+ if (mSecondarySettingsUri != null) {
+ resolver.registerContentObserver(mSecondarySettingsUri,
+ false, this, UserHandle.USER_ALL);
+ }
update(null);
}
@@ -793,9 +816,9 @@
}
private void update(Uri uri) {
- if (uri == null || mSecureSettingsUri.equals(uri)) {
- if (DEBUG) Slog.d(TAG, "Setting changed: mSecureSettingsUri=" + mSecureSettingsUri +
- " / uri=" + uri);
+ if (uri == null || mSecureSettingsUri.equals(uri)
+ || uri.equals(mSecondarySettingsUri)) {
+ if (DEBUG) Slog.d(TAG, "Setting changed: uri=" + uri);
rebindServices(false);
rebuildRestoredPackages();
}
@@ -917,6 +940,7 @@
public String caption;
public String serviceInterface;
public String secureSettingName;
+ public String secondarySettingName;
public String bindPermission;
public String settingsAction;
public int clientLabel;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2d3ca1f..cabdced 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2186,16 +2186,18 @@
// Clears the 'fake' auto-bunding summary.
private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
- if (adjustment.getSignals() != null
- && adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
+ if (adjustment.getSignals() != null) {
+ Bundle.setDefusable(adjustment.getSignals(), true);
+ if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
&& !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
- if (mAutobundledSummaries.containsKey(adjustment.getPackage())) {
- // Clear summary.
- final NotificationRecord removed = mNotificationsByKey.get(
- mAutobundledSummaries.remove(adjustment.getPackage()));
- if (removed != null) {
- mNotificationList.remove(removed);
- cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
+ if (mAutobundledSummaries.containsKey(adjustment.getPackage())) {
+ // Clear summary.
+ final NotificationRecord removed = mNotificationsByKey.get(
+ mAutobundledSummaries.remove(adjustment.getPackage()));
+ if (removed != null) {
+ mNotificationList.remove(removed);
+ cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
+ }
}
}
}
@@ -2203,47 +2205,50 @@
// Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
private void maybeAddAutobundleSummary(Adjustment adjustment) {
- if (adjustment.getSignals() != null
- && adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
- final String newAutoBundleKey =
- adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
- int userId = -1;
- NotificationRecord summaryRecord = null;
- synchronized (mNotificationList) {
- if (!mAutobundledSummaries.containsKey(adjustment.getPackage())
- && newAutoBundleKey != null) {
- // Add summary
- final StatusBarNotification adjustedSbn
- = mNotificationsByKey.get(adjustment.getKey()).sbn;
+ if (adjustment.getSignals() != null) {
+ Bundle.setDefusable(adjustment.getSignals(), true);
+ if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
+ final String newAutoBundleKey =
+ adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
+ int userId = -1;
+ NotificationRecord summaryRecord = null;
+ synchronized (mNotificationList) {
+ if (!mAutobundledSummaries.containsKey(adjustment.getPackage())
+ && newAutoBundleKey != null) {
+ // Add summary
+ final StatusBarNotification adjustedSbn
+ = mNotificationsByKey.get(adjustment.getKey()).sbn;
- final ApplicationInfo appInfo =
- adjustedSbn.getNotification().extras.getParcelable(
- Notification.EXTRA_BUILDER_APPLICATION_INFO);
- final Bundle extras = new Bundle();
- extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
- final Notification summaryNotification =
- new Notification.Builder(getContext()).setSmallIcon(
- adjustedSbn.getNotification().getSmallIcon())
- .setGroupSummary(true)
- .setGroup(newAutoBundleKey)
- .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
- .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
- .build();
- summaryNotification.extras.putAll(extras);
- final StatusBarNotification summarySbn =
- new StatusBarNotification(adjustedSbn.getPackageName(),
- adjustedSbn.getOpPkg(),
- Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
- adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
- summaryNotification, adjustedSbn.getUser(), newAutoBundleKey,
- System.currentTimeMillis());
- summaryRecord = new NotificationRecord(getContext(), summarySbn);
- mAutobundledSummaries.put(adjustment.getPackage(), summarySbn.getKey());
- userId = adjustedSbn.getUser().getIdentifier();
+ final ApplicationInfo appInfo =
+ adjustedSbn.getNotification().extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO);
+ final Bundle extras = new Bundle();
+ extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
+ final Notification summaryNotification =
+ new Notification.Builder(getContext()).setSmallIcon(
+ adjustedSbn.getNotification().getSmallIcon())
+ .setGroupSummary(true)
+ .setGroup(newAutoBundleKey)
+ .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
+ .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
+ .build();
+ summaryNotification.extras.putAll(extras);
+ final StatusBarNotification summarySbn =
+ new StatusBarNotification(adjustedSbn.getPackageName(),
+ adjustedSbn.getOpPkg(),
+ Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
+ adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
+ summaryNotification, adjustedSbn.getUser(),
+ newAutoBundleKey,
+ System.currentTimeMillis());
+ summaryRecord = new NotificationRecord(getContext(), summarySbn);
+ mAutobundledSummaries.put(adjustment.getPackage(), summarySbn.getKey());
+ userId = adjustedSbn.getUser().getIdentifier();
+ }
}
- }
- if (summaryRecord != null) {
- mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
+ if (summaryRecord != null) {
+ mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
+ }
}
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5ce451f..f6f401a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -318,6 +318,7 @@
AccessibilityManager mAccessibilityManager;
BurnInProtectionHelper mBurnInProtectionHelper;
AppOpsManager mAppOpsManager;
+ private boolean mHasFeatureWatch;
// Vibrator pattern for haptic feedback of a long press.
long[] mLongPressVibePattern;
@@ -693,6 +694,7 @@
= new LogDecelerateInterpolator(100, 0);
private final MutableBoolean mTmpBoolean = new MutableBoolean(false);
+
private static final int MSG_ENABLE_POINTER_LOCATION = 1;
private static final int MSG_DISABLE_POINTER_LOCATION = 2;
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
@@ -1501,6 +1503,7 @@
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
// Init display burn-in protection
boolean burnInProtectionEnabled = context.getResources().getBoolean(
@@ -3393,7 +3396,9 @@
IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
if (shortcutService != null) {
try {
- shortcutService.notifyShortcutKeyPressed(shortcutCode);
+ if (isUserSetupComplete()) {
+ shortcutService.notifyShortcutKeyPressed(shortcutCode);
+ }
} catch (RemoteException e) {
mShortcutKeyServices.delete(shortcutCode);
}
@@ -5780,9 +5785,14 @@
}
private boolean shouldDispatchInputWhenNonInteractive() {
- // Send events to keyguard while the screen is on.
- if (isKeyguardShowingAndNotOccluded() && mDisplay != null
- && mDisplay.getState() != Display.STATE_OFF) {
+ final boolean displayOff = (mDisplay == null || mDisplay.getState() == Display.STATE_OFF);
+
+ if (displayOff && !mHasFeatureWatch) {
+ return false;
+ }
+
+ // Send events to keyguard while the screen is on and it's showing.
+ if (isKeyguardShowingAndNotOccluded() && !displayOff) {
return true;
}
@@ -6695,7 +6705,7 @@
@Override public void run() {
if (mBootMsgDialog == null) {
int theme;
- if (mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH)) {
+ if (mHasFeatureWatch) {
theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert;
} else if (mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION)) {
theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index a5d68da..361f0d4 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -59,15 +59,22 @@
private static final String TAG_AVAILABILITY = "availableByDefault";
private static final String TAG_SIGNATURE = "signature";
private static final String TAG_FALLBACK = "isFallback";
+ private final WebViewProviderInfo[] mWebViewProviderPackages;
- /**
- * Returns all packages declared in the framework resources as potential WebView providers.
- * @hide
- * */
- @Override
- public WebViewProviderInfo[] getWebViewPackages() {
+ // Initialization-on-demand holder idiom for getting the WebView provider packages once and
+ // for all in a thread-safe manner.
+ private static class LazyHolder {
+ private static final SystemImpl INSTANCE = new SystemImpl();
+ }
+
+ public static SystemImpl getInstance() {
+ return LazyHolder.INSTANCE;
+ }
+
+ private SystemImpl() {
int numFallbackPackages = 0;
int numAvailableByDefaultPackages = 0;
+ int numAvByDefaultAndNotFallback = 0;
XmlResourceParser parser = null;
List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
try {
@@ -111,6 +118,9 @@
}
if (currentProvider.availableByDefault) {
numAvailableByDefaultPackages++;
+ if (!currentProvider.isFallback) {
+ numAvByDefaultAndNotFallback++;
+ }
}
webViewProviders.add(currentProvider);
}
@@ -127,7 +137,20 @@
throw new AndroidRuntimeException("There must be at least one WebView package "
+ "that is available by default");
}
- return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+ if (numAvByDefaultAndNotFallback == 0) {
+ throw new AndroidRuntimeException("There must be at least one WebView package "
+ + "that is available by default and not a fallback");
+ }
+ mWebViewProviderPackages =
+ webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+ }
+ /**
+ * Returns all packages declared in the framework resources as potential WebView providers.
+ * @hide
+ * */
+ @Override
+ public WebViewProviderInfo[] getWebViewPackages() {
+ return mWebViewProviderPackages;
}
public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index bbb4951..9b971e0 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -55,7 +55,7 @@
public WebViewUpdateService(Context context) {
super(context);
- mImpl = new WebViewUpdateServiceImpl(context, new SystemImpl());
+ mImpl = new WebViewUpdateServiceImpl(context, SystemImpl.getInstance());
}
@Override
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index e17ea49..d90d922 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -291,6 +291,13 @@
try {
synchronized(mLock) {
mCurrentWebViewPackage = findPreferredWebViewPackage();
+ // Don't persist the user-chosen setting across boots if the package being
+ // chosen is not used (could be disabled or uninstalled) so that the user won't
+ // be surprised by the device switching to using a certain webview package,
+ // that was uninstalled/disabled a long time ago, if it is installed/enabled
+ // again.
+ mSystemInterface.updateUserSetting(mContext,
+ mCurrentWebViewPackage.packageName);
onWebViewProviderChanged(mCurrentWebViewPackage);
}
} catch (Throwable t) {
@@ -301,38 +308,42 @@
/**
* Change WebView provider and provider setting and kill packages using the old provider.
- * Return the new provider (in case we are in the middle of creating relro files this new
- * provider will not be in use directly, but will when the relros are done).
+ * Return the new provider (in case we are in the middle of creating relro files, or
+ * replacing that provider it will not be in use directly, but will be used when the relros
+ * or the replacement are done).
*/
public String changeProviderAndSetting(String newProviderName) {
PackageInfo oldPackage = null;
PackageInfo newPackage = null;
+ boolean providerChanged = false;
synchronized(mLock) {
oldPackage = mCurrentWebViewPackage;
mSystemInterface.updateUserSetting(mContext, newProviderName);
try {
newPackage = findPreferredWebViewPackage();
- if (oldPackage != null
- && newPackage.packageName.equals(oldPackage.packageName)) {
- // If we don't perform the user change, revert the settings change.
- mSystemInterface.updateUserSetting(mContext, newPackage.packageName);
- return newPackage.packageName;
- }
+ providerChanged = (oldPackage == null)
+ || !newPackage.packageName.equals(oldPackage.packageName);
} catch (WebViewFactory.MissingWebViewPackageException e) {
Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView " +
"package " + e);
// If we don't perform the user change but don't have an installed WebView
// package, we will have changed the setting and it will be used when a package
// is available.
- return newProviderName;
+ return "";
}
- onWebViewProviderChanged(newPackage);
+ // Perform the provider change if we chose a new provider
+ if (providerChanged) {
+ onWebViewProviderChanged(newPackage);
+ }
}
- // Kill apps using the old provider
- if (oldPackage != null) {
+ // Kill apps using the old provider only if we changed provider
+ if (providerChanged && oldPackage != null) {
mSystemInterface.killPackageDependents(oldPackage.packageName);
}
+ // Return the new provider, this is not necessarily the one we were asked to switch to
+ // But the persistent setting will now be pointing to the provider we were asked to
+ // switch to anyway
return newPackage.packageName;
}
@@ -345,7 +356,6 @@
mAnyWebViewInstalled = true;
if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
mCurrentWebViewPackage = newPackage;
- mSystemInterface.updateUserSetting(mContext, newPackage.packageName);
// The relro creations might 'finish' (not start at all) before
// WebViewFactory.onWebViewProviderChanged which means we might not know the
@@ -394,7 +404,7 @@
}
- private class ProviderAndPackageInfo {
+ private static class ProviderAndPackageInfo {
public final WebViewProviderInfo provider;
public final PackageInfo packageInfo;
@@ -432,9 +442,12 @@
}
}
- // Could not find any enabled package either, use the most stable provider.
+ // Could not find any enabled package either, use the most stable and default-available
+ // provider.
for (ProviderAndPackageInfo providerAndPackage : providers) {
- return providerAndPackage.packageInfo;
+ if (providerAndPackage.provider.availableByDefault) {
+ return providerAndPackage.packageInfo;
+ }
}
mAnyWebViewInstalled = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0a0f0f0..57dc97a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2107,6 +2107,11 @@
if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
reportNewConfig = true;
}
+ if (attrs.removeTimeoutMilliseconds > 0) {
+ mH.sendMessageDelayed(
+ mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
+ attrs.removeTimeoutMilliseconds);
+ }
}
if (reportNewConfig) {
@@ -7788,8 +7793,8 @@
public static final int NOTIFY_APP_TRANSITION_CANCELLED = 48;
public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
-
public static final int UPDATE_ANIMATION_SCALE = 51;
+ public static final int WINDOW_REMOVE_TIMEOUT = 52;
/**
* Used to denote that an integer field in a message will not be used.
@@ -8402,6 +8407,18 @@
mAmInternal.notifyStartingWindowDrawn();
}
break;
+ case WINDOW_REMOVE_TIMEOUT: {
+ final WindowState window = (WindowState) msg.obj;
+ synchronized(mWindowMap) {
+ // It's counterintuitive that we check that "mWindowRemovalAllowed"
+ // is false. But in fact if it's true, it means a remove has already
+ // been requested and we better just not do anything.
+ if (!window.mRemoved && !window.mWindowRemovalAllowed) {
+ removeWindowLocked(window);
+ }
+ }
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 406dd56..804fa03 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -336,17 +336,17 @@
class ReceiveThread extends Thread {
private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH];
- private boolean stopped = false;
+ private volatile boolean mStopped = false;
public void halt() {
- stopped = true;
+ mStopped = true;
closeSockets(); // Interrupts the read() call the thread is blocked in.
}
@Override
public void run() {
if (DBG) Log.d(TAG, "Receive thread started");
- while (!stopped) {
+ while (!mStopped) {
int length = 0; // Or compiler can't tell it's initialized if a parse error occurs.
try {
length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
@@ -355,7 +355,7 @@
if (DBG) Log.d(TAG, "Received packet: " + packet);
sendMessage(CMD_RECEIVED_PACKET, packet);
} catch (IOException|ErrnoException e) {
- if (!stopped) {
+ if (!mStopped) {
Log.e(TAG, "Read error", e);
}
DhcpClientEvent.logEvent(IpConnectivityEvent.IPCE_DHCP_RECV_ERROR,
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index a881408..b184fe5 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -3,6 +3,7 @@
import android.net.DhcpResults;
import android.net.LinkAddress;
import android.net.NetworkUtils;
+import android.net.metrics.DhcpErrorEvent;
import android.os.Build;
import android.os.SystemProperties;
import android.system.OsConstants;
@@ -765,6 +766,7 @@
// check to see if we need to parse L2, IP, and UDP encaps
if (pktType == ENCAP_L2) {
if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L2_TOO_SHORT);
throw new ParseException("L2 packet too short, %d < %d",
packet.remaining(), MIN_PACKET_LENGTH_L2);
}
@@ -777,13 +779,16 @@
short l2type = packet.getShort();
- if (l2type != OsConstants.ETH_P_IP)
+ if (l2type != OsConstants.ETH_P_IP) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L2_WRONG_ETH_TYPE);
throw new ParseException("Unexpected L2 type 0x%04x, expected 0x%04x",
l2type, OsConstants.ETH_P_IP);
+ }
}
if (pktType <= ENCAP_L3) {
if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_TOO_SHORT);
throw new ParseException("L3 packet too short, %d < %d",
packet.remaining(), MIN_PACKET_LENGTH_L3);
}
@@ -791,6 +796,7 @@
byte ipTypeAndLength = packet.get();
int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
if (ipVersion != 4) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_NOT_IPV4);
throw new ParseException("Invalid IP version %d", ipVersion);
}
@@ -808,6 +814,7 @@
ipDst = readIpAddress(packet);
if (ipProto != IP_TYPE_UDP) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_NOT_UDP);
throw new ParseException("Protocol not UDP: %d", ipProto);
}
@@ -834,12 +841,14 @@
// socket to drop packets that don't have the right source ports. However, it's
// possible that a packet arrives between when the socket is bound and when the
// filter is set. http://b/26696823 .
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_WRONG_PORT);
throw new ParseException("Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
}
}
// We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.BOOTP_TOO_SHORT);
throw new ParseException("Invalid type or BOOTP packet too short, %d < %d",
packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
}
@@ -864,6 +873,7 @@
packet.get(ipv4addr);
relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
} catch (UnknownHostException ex) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_INVALID_IP);
throw new ParseException("Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
}
@@ -888,6 +898,7 @@
int dhcpMagicCookie = packet.getInt();
if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE);
throw new ParseException("Bad magic cookie 0x%08x, should be 0x%08x", dhcpMagicCookie,
DHCP_MAGIC_COOKIE);
}
@@ -896,9 +907,8 @@
boolean notFinishedOptions = true;
while ((packet.position() < packet.limit()) && notFinishedOptions) {
+ final byte optionType = packet.get(); // cannot underflow because position < limit
try {
- byte optionType = packet.get();
-
if (optionType == DHCP_OPTION_END) {
notFinishedOptions = false;
} else if (optionType == DHCP_OPTION_PAD) {
@@ -999,11 +1009,14 @@
}
if (expectedLen != optionLen) {
+ DhcpErrorEvent.logEvent(
+ DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
throw new ParseException("Invalid length %d for option %d, expected %d",
optionLen, optionType, expectedLen);
}
}
} catch (BufferUnderflowException e) {
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
throw new ParseException("BufferUnderflowException");
}
}
@@ -1012,6 +1025,7 @@
switch(dhcpType) {
case (byte) 0xFF:
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_NO_MSG_TYPE);
throw new ParseException("No DHCP message type option");
case DHCP_MESSAGE_TYPE_DISCOVER:
newPacket = new DhcpDiscoverPacket(
@@ -1045,6 +1059,7 @@
clientMac);
break;
default:
+ DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE);
throw new ParseException("Unimplemented DHCP type %d", dhcpType);
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index b6ad25b..59ebf1b 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -30,10 +30,12 @@
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.dhcp.DhcpClient;
+import android.net.metrics.IpManagerEvent;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -52,6 +54,10 @@
import java.net.SocketException;
import java.util.Objects;
+import static android.net.metrics.IpConnectivityEvent.IPCE_IPMGR_PROVISIONING_OK;
+import static android.net.metrics.IpConnectivityEvent.IPCE_IPMGR_PROVISIONING_FAIL;
+import static android.net.metrics.IpConnectivityEvent.IPCE_IPMGR_COMPLETE_LIFECYCLE;
+
/**
* IpManager
@@ -264,6 +270,7 @@
private ProxyInfo mHttpProxy;
private ApfFilter mApfFilter;
private boolean mMulticastFiltering;
+ private long mStartTimeMillis;
/**
* Member variables accessed both from within the StateMachine thread
@@ -479,6 +486,12 @@
}
}
+ private void recordMetric(final int type) {
+ if (mStartTimeMillis <= 0) { Log.wtf(mTag, "Start time undefined!"); }
+ IpManagerEvent.logEvent(type, mInterfaceName,
+ SystemClock.elapsedRealtime() - mStartTimeMillis);
+ }
+
// For now: use WifiStateMachine's historical notion of provisioned.
private static boolean isProvisioned(LinkProperties lp) {
// For historical reasons, we should connect even if all we have is
@@ -536,6 +549,16 @@
delta = ProvisioningChange.LOST_PROVISIONING;
}
+ // Additionally:
+ //
+ // If the previous link properties had a global IPv6 address and an
+ // IPv6 default route then also consider the loss of that default route
+ // to be a loss of provisioning. See b/27962810.
+ if (oldLp.hasGlobalIPv6Address() && oldLp.hasIPv6DefaultRoute() &&
+ !newLp.hasIPv6DefaultRoute()) {
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
return delta;
}
@@ -544,11 +567,13 @@
switch (delta) {
case GAINED_PROVISIONING:
if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
+ recordMetric(IPCE_IPMGR_PROVISIONING_OK);
mCallback.onProvisioningSuccess(newLp);
break;
case LOST_PROVISIONING:
if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ recordMetric(IPCE_IPMGR_PROVISIONING_FAIL);
mCallback.onProvisioningFailure(newLp);
break;
@@ -724,6 +749,10 @@
}
resetLinkProperties();
+ if (mStartTimeMillis > 0) {
+ recordMetric(IPCE_IPMGR_COMPLETE_LIFECYCLE);
+ mStartTimeMillis = 0;
+ }
}
@Override
@@ -794,11 +823,16 @@
class StartedState extends State {
@Override
public void enter() {
+ mStartTimeMillis = SystemClock.elapsedRealtime();
+
mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
mCallback, mMulticastFiltering);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
- if (mApfFilter == null) mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+ if (mApfFilter == null) {
+ mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+ }
+
// Set privacy extensions.
try {
mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
@@ -829,6 +863,7 @@
handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
} else {
if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ recordMetric(IPCE_IPMGR_PROVISIONING_FAIL);
mCallback.onProvisioningFailure(getLinkProperties());
transitionTo(mStoppingState);
}
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index af3175a..c8dbe02 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -26,6 +26,7 @@
import android.net.RouteInfo;
import android.net.metrics.IpReachabilityMonitorMessageEvent;
import android.net.metrics.IpReachabilityMonitorProbeEvent;
+import android.net.metrics.IpReachabilityMonitorLostEvent;
import android.net.netlink.NetlinkConstants;
import android.net.netlink.NetlinkErrorMessage;
import android.net.netlink.NetlinkMessage;
@@ -353,6 +354,7 @@
}
if (delta == ProvisioningChange.LOST_PROVISIONING) {
+ IpReachabilityMonitorLostEvent.logEvent(mInterfaceName);
final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
Log.w(TAG, logMsg);
if (mCallback != null) {
@@ -521,7 +523,7 @@
final short msgType = neighMsg.getHeader().nlmsg_type;
final short nudState = ndMsg.ndm_state;
- IpReachabilityMonitorMessageEvent.logEvent(maybeGetInterfaceName(mInterfaceIndex),
+ IpReachabilityMonitorMessageEvent.logEvent(mInterfaceName,
destination.getHostAddress(), msgType, nudState);
final String eventMsg = "NeighborEvent{"
+ "elapsedMs=" + whenMs + ", "
@@ -553,11 +555,4 @@
}
}
}
-
- private String maybeGetInterfaceName(int index) {
- if (index == mInterfaceIndex) {
- return mInterfaceName;
- }
- return "ifindex-" + index;
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index 26b87c5..e33be40 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -24,7 +24,7 @@
import java.util.HashMap;
public class TestSystemImpl implements SystemInterface {
- private String mUserProvider = "";
+ private String mUserProvider = null;
private final WebViewProviderInfo[] mPackageConfigs;
HashMap<String, PackageInfo> mPackages = new HashMap();
private boolean mFallbackLogicEnabled;
@@ -105,6 +105,10 @@
mPackages.put(pi.packageName, pi);
}
+ public void removePackageInfo(String packageName) {
+ mPackages.remove(packageName);
+ }
+
@Override
public int getFactoryPackageVersion(String packageName) {
return 0;
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index c00520d..c03324a 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -90,12 +90,13 @@
}
}
- private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
+ private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
WebViewProviderInfo[] webviewPackages) {
- checkCertainPackageUsedAfterWebViewPreparation(expectedProviderName, webviewPackages, 1);
+ checkCertainPackageUsedAfterWebViewBootPreparation(
+ expectedProviderName, webviewPackages, 1);
}
- private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
+ private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
WebViewProviderInfo[] webviewPackages, int numRelros) {
setupWithPackages(webviewPackages, true, numRelros);
// Add (enabled and valid) package infos for each provider
@@ -156,6 +157,19 @@
return p;
}
+ private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) {
+ // Verify that onWebViewProviderChanged was called for the numPreparation'th time for the
+ // expected package
+ Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged(
+ Mockito.argThat(new IsPackageInfoWithName(expectedPackage)));
+
+ mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
+
+ WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+ assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
+ assertEquals(expectedPackage, response.packageInfo.packageName);
+ }
+
// ****************
// Tests
@@ -164,7 +178,7 @@
public void testWithSinglePackage() {
String testPackageName = "test.package.name";
- checkCertainPackageUsedAfterWebViewPreparation(testPackageName,
+ checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName,
new WebViewProviderInfo[] {
new WebViewProviderInfo(testPackageName, "",
true /*default available*/, false /* fallback */, null)});
@@ -176,12 +190,12 @@
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
new WebViewProviderInfo(nonDefaultPackage, "", false, false, null),
new WebViewProviderInfo(defaultPackage, "", true, false, null)};
- checkCertainPackageUsedAfterWebViewPreparation(defaultPackage, packages);
+ checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages);
}
public void testSeveralRelros() {
String singlePackage = "singlePackage";
- checkCertainPackageUsedAfterWebViewPreparation(
+ checkCertainPackageUsedAfterWebViewBootPreparation(
singlePackage,
new WebViewProviderInfo[] {
new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)},
@@ -215,14 +229,8 @@
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
- Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(validPackage)));
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
- WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
- assertEquals(validPackage, response.packageInfo.packageName);
+ checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */);
WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
assertEquals(1, validPackages.length);
@@ -261,14 +269,27 @@
}
public void testFailListingInvalidWebviewPackage() {
- WebViewProviderInfo wpi = new WebViewProviderInfo("", "", true, true, null);
+ WebViewProviderInfo wpi = new WebViewProviderInfo("package", "", true, true, null);
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi};
setupWithPackages(packages);
- mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true, false));
+ mTestSystemImpl.setPackageInfo(
+ createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */));
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+ Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
+ Matchers.anyObject());
+
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+
+ // Verify that we can recover from failing to list webview packages.
+ mTestSystemImpl.setPackageInfo(
+ createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */));
+ mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+
+ checkPreparationPhasesForPackage(wpi.packageName, 1);
}
// Test that switching provider using changeProviderAndSetting works.
@@ -292,18 +313,10 @@
private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage,
String finalPackage) {
- checkCertainPackageUsedAfterWebViewPreparation(initialPackage, packages);
+ checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages);
mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage);
-
- Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(finalPackage)));
-
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
- WebViewProviderResponse secondResponse = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, secondResponse.status);
- assertEquals(finalPackage, secondResponse.packageInfo.packageName);
+ checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */);
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage));
}
@@ -455,32 +468,20 @@
mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
Matchers.anyObject(), Matchers.anyObject());
- Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(fallbackPackage)));
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
- WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
- assertEquals(fallbackPackage, response.packageInfo.packageName);
+ checkPreparationPhasesForPackage(fallbackPackage,
+ 1 /* first preparation for this package*/);
// Install primary package
mTestSystemImpl.setPackageInfo(
createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */));
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
- WebViewUpdateService.PACKAGE_ADDED);
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED);
- // Verify fallback disabled and primary package used as provider
+ // Verify fallback disabled, primary package used as provider, and fallback package killed
Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
Matchers.anyObject(), Mockito.eq(fallbackPackage));
- Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
-
- // Finish the webview preparation and ensure primary package used and fallback killed
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
- response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
- assertEquals(primaryPackage, response.packageInfo.packageName);
+ checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/);
Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage));
}
@@ -502,16 +503,22 @@
Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
Matchers.anyInt());
+ checkPreparationPhasesForPackage(primaryPackage, 1);
+
+ // Disable primary package and ensure fallback becomes enabled and used
mTestSystemImpl.setPackageInfo(
createPackageInfo(primaryPackage, false /* enabled */, true /* valid */));
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
WebViewUpdateService.PACKAGE_CHANGED);
- // Verify fallback becomes enabled when primary package becomes disabled
Mockito.verify(mTestSystemImpl).enablePackageForUser(
Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
Matchers.anyInt());
+ checkPreparationPhasesForPackage(fallbackPackage, 1);
+
+
+ // Again enable primary package and verify primary is used and fallback becomes disabled
mTestSystemImpl.setPackageInfo(
createPackageInfo(primaryPackage, true /* enabled */, true /* valid */));
mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
@@ -521,6 +528,8 @@
Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser(
Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
Matchers.anyInt());
+
+ checkPreparationPhasesForPackage(primaryPackage, 2);
}
public void testAddUserWhenFallbackLogicEnabled() {
@@ -577,6 +586,9 @@
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
+ // Change provider during relro creation to enter a state where we are
+ // waiting for relro creation to complete just to re-run relro creation.
+ // (so that in next notifyRelroCreationCompleted() call we have to list webview packages)
mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
// Make packages invalid to cause exception to be thrown
@@ -596,18 +608,213 @@
true /* valid */));
mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
- WebViewUpdateService.PACKAGE_ADDED);
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED);
- // Second time we call onWebViewProviderChanged for firstPackage
- Mockito.verify(mTestSystemImpl, Mockito.times(2)).onWebViewProviderChanged(
- Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
-
- mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
- response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
- assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
- assertEquals(firstPackage, response.packageInfo.packageName);
+ // Ensure we use firstPackage
+ checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
}
- // TODO (gsennton) add more tests for ensuring killPackageDependents is called / not called
+ /**
+ * Verify that even if a user-chosen package is removed temporarily we start using it again when
+ * it is added back.
+ */
+ public void testTempRemovePackageDoesntSwitchProviderPermanently() {
+ String firstPackage = "first";
+ String secondPackage = "second";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(firstPackage, "", true /* default available */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(secondPackage, "", true /* default available */,
+ false /* fallback */, null)};
+ checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
+
+ // Explicitly use the second package
+ mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
+ checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */);
+
+ // Remove second package (invalidate it) and verify that first package is used
+ mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+ false /* valid */));
+ mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+ WebViewUpdateService.PACKAGE_ADDED);
+ checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */);
+
+ // Now make the second package valid again and verify that it is used again
+ mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+ true /* valid */));
+ mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+ WebViewUpdateService.PACKAGE_ADDED);
+ checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
+ }
+
+ /**
+ * Ensure that we update the user-chosen setting across boots if the chosen package is no
+ * longer installed and valid.
+ */
+ public void testProviderSettingChangedDuringBootIfProviderNotAvailable() {
+ String chosenPackage = "chosenPackage";
+ String nonChosenPackage = "non-chosenPackage";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(chosenPackage, "", true /* default available */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(nonChosenPackage, "", true /* default available */,
+ false /* fallback */, null)};
+
+ setupWithPackages(packages);
+ // Only 'install' nonChosenPackage
+ mTestSystemImpl.setPackageInfo(
+ createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */));
+
+ // Set user-chosen package
+ mTestSystemImpl.updateUserSetting(null, chosenPackage);
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+ // Verify that we switch the setting to point to the current package
+ Mockito.verify(mTestSystemImpl).updateUserSetting(
+ Mockito.anyObject(), Mockito.eq(nonChosenPackage));
+ assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null));
+
+ checkPreparationPhasesForPackage(nonChosenPackage, 1);
+ }
+
+ public void testRecoverFailedListingWebViewPackagesSettingsChange() {
+ checkRecoverAfterFailListingWebviewPackages(true);
+ }
+
+ public void testRecoverFailedListingWebViewPackagesAddedPackage() {
+ checkRecoverAfterFailListingWebviewPackages(false);
+ }
+
+ /**
+ * Test that we can recover correctly from failing to list WebView packages.
+ * settingsChange: whether to fail during changeProviderAndSetting or packageStateChanged
+ */
+ public void checkRecoverAfterFailListingWebviewPackages(boolean settingsChange) {
+ String firstPackage = "first";
+ String secondPackage = "second";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(firstPackage, "", true /* default available */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(secondPackage, "", true /* default available */,
+ false /* fallback */, null)};
+ checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
+
+ // Make both packages invalid so that we fail listing WebView packages
+ mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
+ false /* valid */));
+ mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+ false /* valid */));
+
+ // Change package to hit the webview packages listing problem.
+ if (settingsChange) {
+ mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
+ } else {
+ mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+ }
+
+ WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+ assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+
+ // Make second package valid and verify that we can load it again
+ mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+ true /* valid */));
+
+ mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+
+
+ checkPreparationPhasesForPackage(secondPackage, 1);
+ }
+
+ public void testDontKillIfPackageReplaced() {
+ checkDontKillIfPackageRemoved(true);
+ }
+
+ public void testDontKillIfPackageRemoved() {
+ checkDontKillIfPackageRemoved(false);
+ }
+
+ public void checkDontKillIfPackageRemoved(boolean replaced) {
+ String firstPackage = "first";
+ String secondPackage = "second";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(firstPackage, "", true /* default available */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(secondPackage, "", true /* default available */,
+ false /* fallback */, null)};
+ checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
+
+ // Replace or remove the current webview package
+ if (replaced) {
+ mTestSystemImpl.setPackageInfo(
+ createPackageInfo(firstPackage, true /* enabled */, false /* valid */));
+ mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
+ WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+ } else {
+ mTestSystemImpl.removePackageInfo(firstPackage);
+ mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
+ WebViewUpdateService.PACKAGE_REMOVED);
+ }
+
+ checkPreparationPhasesForPackage(secondPackage, 1);
+
+ Mockito.verify(mTestSystemImpl, Mockito.never()).killPackageDependents(
+ Mockito.anyObject());
+ }
+
+ public void testKillIfSettingChanged() {
+ String firstPackage = "first";
+ String secondPackage = "second";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(firstPackage, "", true /* default available */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(secondPackage, "", true /* default available */,
+ false /* fallback */, null)};
+ checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
+
+ mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
+
+ checkPreparationPhasesForPackage(secondPackage, 1);
+
+ Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
+ }
+
+ /**
+ * Test that we kill apps using an old provider when we change the provider setting, even if the
+ * new provider is not the one we intended to change to.
+ */
+ public void testKillIfChangeProviderIncorrectly() {
+ String firstPackage = "first";
+ String secondPackage = "second";
+ String thirdPackage = "third";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(firstPackage, "", true /* default available */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(secondPackage, "", true /* default available */,
+ false /* fallback */, null),
+ new WebViewProviderInfo(thirdPackage, "", true /* default available */,
+ false /* fallback */, null)};
+ setupWithPackages(packages);
+ setEnabledAndValidPackageInfos(packages);
+
+ // Start with the setting pointing to the third package
+ mTestSystemImpl.updateUserSetting(null, thirdPackage);
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+ checkPreparationPhasesForPackage(thirdPackage, 1);
+
+ mTestSystemImpl.setPackageInfo(
+ createPackageInfo(secondPackage, true /* enabled */, false /* valid */));
+
+ // Try to switch to the invalid second package, this should result in switching to the first
+ // package, since that is more preferred than the third one.
+ assertEquals(firstPackage,
+ mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage));
+
+ checkPreparationPhasesForPackage(firstPackage, 1);
+
+ Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(thirdPackage));
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f13e019..53377f9 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -84,22 +84,15 @@
private final PhoneStateListener mPhoneStateListener;
private final PowerManager mPowerManager;
- // The SoundTriggerManager layer handles multiple generic recognition models. We store the
- // ModelData here in a hashmap.
- private final HashMap<UUID, ModelData> mGenericModelDataMap;
+ // The SoundTriggerManager layer handles multiple recognition models of type generic and
+ // keyphrase. We store the ModelData here in a hashmap.
+ private final HashMap<UUID, ModelData> mModelDataMap;
- // This ModelData instance ensures that the keyphrase sound model is a singleton and
- // all other sound models are of type Generic. Any keyphrase sound model will be stored here
- // and any previously running instances will be replaced. This restriction was earlier
- // implemented by three instance variables which stored data about the keyphrase
- // model. That data now gets encapsulated in this ModelData instance.
- private ModelData mKeyphraseModelData;
-
- // The keyphrase ID for keyphrase sound models. We store this specially here since ModelData
- // does not support this.
- // TODO: The role of the keyphrase ID is a bit unclear. Its just used to ensure that
- // recognition events have the correct keyphrase ID check.
- private int mKeyphraseId = INVALID_VALUE;
+ // An index of keyphrase sound models so that we can reach them easily. We support indexing
+ // keyphrase sound models with a keyphrase ID. Sound model with the same keyphrase ID will
+ // replace an existing model, thus there is a 1:1 mapping from keyphrase ID to a voice
+ // sound model.
+ private HashMap<Integer, UUID> mKeyphraseUuidMap;
private boolean mCallActive = false;
private boolean mIsPowerSaveMode = false;
@@ -119,7 +112,8 @@
mContext = context;
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mGenericModelDataMap = new HashMap<UUID, ModelData>();
+ mModelDataMap = new HashMap<UUID, ModelData>();
+ mKeyphraseUuidMap = new HashMap<Integer, UUID>();
mPhoneStateListener = new MyCallStateListener();
if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
@@ -153,6 +147,10 @@
synchronized (mLock) {
ModelData modelData = getOrCreateGenericModelDataLocked(modelId);
+ if (modelData == null) {
+ Slog.w(TAG, "Irrecoverable error occurred, check UUID / sound model data.");
+ return STATUS_ERROR;
+ }
return startRecognition(soundModel, modelData, callback, recognitionConfig,
INVALID_VALUE /* keyphraseId */);
}
@@ -180,20 +178,48 @@
+ " soundModel=" + soundModel + ", callback=" + callback.asBinder()
+ ", recognitionConfig=" + recognitionConfig);
Slog.d(TAG, "moduleProperties=" + mModuleProperties);
- if (mKeyphraseModelData != null) {
- Slog.d(TAG, mKeyphraseModelData.toString());
- } else {
- Slog.d(TAG, "Null KeyphraseModelData.");
+ dumpModelStateLocked();
+ }
+
+ ModelData model = getKeyphraseModelDataLocked(keyphraseId);
+ if (model != null && !model.isKeyphraseModel()) {
+ Slog.e(TAG, "Generic model with same UUID exists.");
+ return STATUS_ERROR;
+ }
+
+ // Process existing model first.
+ if (model != null && model.getModelId() != soundModel.uuid) {
+ // The existing model has a different UUID, should be replaced.
+ int status = cleanUpExistingKeyphraseModel(model);
+ removeKeyphraseModelLocked(keyphraseId);
+ if (status != STATUS_OK) {
+ return status;
}
+ model = null;
}
- if (mKeyphraseModelData == null) {
- mKeyphraseModelData = ModelData.createKeyphraseModelData(soundModel.uuid);
+
+ // We need to create a new one: either no previous models existed for given keyphrase id
+ // or the existing model had a different UUID and was cleaned up.
+ if (model == null) {
+ model = createKeyphraseModelDataLocked(soundModel.uuid, keyphraseId);
}
- return startRecognition(soundModel, mKeyphraseModelData, callback, recognitionConfig,
+
+ return startRecognition(soundModel, model, callback, recognitionConfig,
keyphraseId);
}
}
+ private int cleanUpExistingKeyphraseModel(ModelData modelData) {
+ // Stop and clean up a previous ModelData if one exists. This usually is used when the
+ // previous model has a different UUID for the same keyphrase ID.
+ int status = tryStopAndUnloadLocked(modelData, true /* stop */, true /* unload */);
+ if (status != STATUS_OK) {
+ Slog.w(TAG, "Unable to stop or unload previous model: " +
+ modelData.toString());
+ }
+ return status;
+ }
+
/**
* Starts recognition for the given sound model. A single routine for both keyphrase and
* generic sound models.
@@ -228,17 +254,15 @@
initializeTelephonyAndPowerStateListeners();
}
- // If the previous model is different (for the same UUID), ensure that its unloaded
- // and stopped before proceeding. This works for both keyphrase and generic models.
- // Specifically for keyphrase since we have 'mKeyphraseModelData' holding a single
- // allowed instance of such a model, this ensures that a previously loaded (or started)
- // keyphrase model is appropriately stopped. This ensures no regression with the
- // previous version of this code as given in the startKeyphrase() routine.
- //
- // For generic sound models, all this means is that if we are given a different sound
- // model with the same UUID, then we will "replace" it.
+ // If the existing SoundModel is different (for the same UUID for Generic and same
+ // keyphrase ID for voice), ensure that it is unloaded and stopped before proceeding.
+ // This works for both keyphrase and generic models. This logic also ensures that a
+ // previously loaded (or started) model is appropriately stopped. Since this is a
+ // generalization of the previous logic with a single keyphrase model, we should have
+ // no regression with the previous version of this code as was given in the
+ // startKeyphrase() routine.
if (modelData.getSoundModel() != null) {
- boolean stopModel = false; // Stop the model after checking that its started.
+ boolean stopModel = false; // Stop the model after checking that it is started.
boolean unloadModel = false;
if (modelData.getSoundModel().equals(soundModel) && modelData.isModelStarted()) {
// The model has not changed, but the previous model is "started".
@@ -273,7 +297,7 @@
modelData.clearCallback();
}
- // Load the model if its not loaded.
+ // Load the model if it is not loaded.
if (!modelData.isModelLoaded()) {
// Load the model
int[] handle = new int[] { INVALID_VALUE };
@@ -291,9 +315,6 @@
Slog.d(TAG, "Sound model loaded with handle:" + handle[0]);
}
modelData.setCallback(callback);
- if (modelData.isKeyphraseModel()) {
- mKeyphraseId = keyphraseId;
- }
modelData.setRequested(true);
modelData.setRecognitionConfig(recognitionConfig);
modelData.setSoundModel(soundModel);
@@ -322,8 +343,8 @@
return STATUS_ERROR;
}
- ModelData modelData = mGenericModelDataMap.get(modelId);
- if (modelData == null) {
+ ModelData modelData = mModelDataMap.get(modelId);
+ if (modelData == null || !modelData.isGenericModel()) {
Slog.w(TAG, "Attempting stopRecognition on invalid model with id:" + modelId);
return STATUS_ERROR;
}
@@ -355,21 +376,23 @@
return STATUS_ERROR;
}
+ ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
+ if (modelData == null || !modelData.isKeyphraseModel()) {
+ Slog.e(TAG, "No model exists for given keyphrase Id.");
+ return STATUS_ERROR;
+ }
+
if (DBG) {
Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" +
callback.asBinder());
- Slog.d(TAG, "current callback=" + (mKeyphraseModelData == null ? "null" :
- mKeyphraseModelData.getCallback().asBinder()));
+ Slog.d(TAG, "current callback=" + (modelData == null ? "null" :
+ modelData.getCallback().asBinder()));
}
- int status = stopRecognition(mKeyphraseModelData, callback);
+ int status = stopRecognition(modelData, callback);
if (status != SoundTrigger.STATUS_OK) {
return status;
}
- // We leave the sound model loaded but not started, this helps us when we start
- // back.
- // Also clear the internal state once the recognition has been stopped.
- internalClearKeyphraseStateLocked();
return status;
}
}
@@ -424,9 +447,6 @@
internalClearGlobalStateLocked();
}
- if (modelData.isKeyphraseModel()) {
- mKeyphraseId = INVALID_VALUE;
- }
return status;
}
}
@@ -475,25 +495,18 @@
return;
}
- // Stop Keyphrase recognition if one exists.
- if (mKeyphraseModelData != null && mKeyphraseModelData.getHandle() != INVALID_VALUE) {
- mKeyphraseModelData.setRequested(false);
- int status = updateRecognitionLocked(mKeyphraseModelData, isRecognitionAllowed(),
- false /* don't notify for synchronous calls */);
- internalClearKeyphraseStateLocked();
- }
-
- // Stop all generic recognition models.
- for (ModelData model : mGenericModelDataMap.values()) {
+ // Stop all recognition models.
+ for (ModelData model : mModelDataMap.values()) {
if (model.isModelStarted()) {
+ model.setRequested(false);
int status = stopRecognitionLocked(model,
false /* do not notify for synchronous calls */);
if (status != STATUS_OK) {
- // What else can we do if there is an error here.
- Slog.w(TAG, "Error stopping generic model: " + model.getHandle());
+ Slog.w(TAG, "Error stopping keyphrase model: " + model.getHandle());
}
model.clearState();
model.clearCallback();
+ model.setRecognitionConfig(null);
}
}
internalClearGlobalStateLocked();
@@ -507,24 +520,27 @@
int unloadKeyphraseSoundModel(int keyphraseId) {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1);
- if (mModule == null || mKeyphraseModelData == null ||
- mKeyphraseModelData.getHandle() == INVALID_VALUE) {
+ ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
+ if (mModule == null || modelData == null || modelData.getHandle() == INVALID_VALUE ||
+ !modelData.isKeyphraseModel()) {
return STATUS_ERROR;
}
// Stop recognition if it's the current one.
- mKeyphraseModelData.setRequested(false);
- int status = updateRecognitionLocked(mKeyphraseModelData, isRecognitionAllowed(),
+ modelData.setRequested(false);
+ int status = updateRecognitionLocked(modelData, isRecognitionAllowed(),
false /* don't notify */);
if (status != SoundTrigger.STATUS_OK) {
Slog.w(TAG, "Stop recognition failed for keyphrase ID:" + status);
}
- status = mModule.unloadSoundModel(mKeyphraseModelData.getHandle());
+ status = mModule.unloadSoundModel(modelData.getHandle());
if (status != SoundTrigger.STATUS_OK) {
Slog.w(TAG, "unloadKeyphraseSoundModel call failed with " + status);
}
- mKeyphraseModelData.clearState();
+
+ // Remove it from existence.
+ removeKeyphraseModelLocked(keyphraseId);
return status;
}
}
@@ -535,8 +551,8 @@
if (modelId == null || mModule == null) {
return STATUS_ERROR;
}
- ModelData modelData = mGenericModelDataMap.get(modelId);
- if (modelData == null) {
+ ModelData modelData = mModelDataMap.get(modelId);
+ if (modelData == null || !modelData.isGenericModel()) {
Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" +
modelId);
return STATUS_ERROR;
@@ -559,8 +575,10 @@
Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status);
Slog.w(TAG, "unloadGenericSoundModel() force-marking model as unloaded.");
}
- mGenericModelDataMap.remove(modelId);
- if (DBG) dumpGenericModelStateLocked();
+
+ // Remove it from existence.
+ mModelDataMap.remove(modelId);
+ if (DBG) dumpModelStateLocked();
return status;
}
}
@@ -612,7 +630,7 @@
return;
}
ModelData model = getModelDataForLocked(event.soundModelHandle);
- if (model == null) {
+ if (model == null || !model.isGenericModel()) {
Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " +
event.soundModelHandle);
return;
@@ -723,67 +741,64 @@
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onError", e);
} finally {
- internalClearKeyphraseStateLocked();
- internalClearGenericModelStateLocked();
+ internalClearModelStateLocked();
internalClearGlobalStateLocked();
}
}
+ private int getKeyphraseIdFromEvent(KeyphraseRecognitionEvent event) {
+ if (event == null) {
+ Slog.w(TAG, "Null RecognitionEvent received.");
+ return INVALID_VALUE;
+ }
+ KeyphraseRecognitionExtra[] keyphraseExtras =
+ ((KeyphraseRecognitionEvent) event).keyphraseExtras;
+ if (keyphraseExtras == null || keyphraseExtras.length == 0) {
+ Slog.w(TAG, "Invalid keyphrase recognition event!");
+ return INVALID_VALUE;
+ }
+ // TODO: Handle more than one keyphrase extras.
+ return keyphraseExtras[0].id;
+ }
+
private void onKeyphraseRecognitionSuccessLocked(KeyphraseRecognitionEvent event) {
Slog.i(TAG, "Recognition success");
MetricsLogger.count(mContext, "sth_keyphrase_recognition_event", 1);
+ int keyphraseId = getKeyphraseIdFromEvent(event);
+ ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
- if (mKeyphraseModelData == null) {
- Slog.e(TAG, "Received onRecognition event for null keyphrase model data.");
+ if (modelData == null || !modelData.isKeyphraseModel()) {
+ Slog.e(TAG, "Keyphase model data does not exist for ID:" + keyphraseId);
return;
}
- if (mKeyphraseModelData.getCallback() == null) {
- Slog.w(TAG, "Received onRecognition event without any listener for it.");
- return;
- }
-
- KeyphraseRecognitionExtra[] keyphraseExtras =
- ((KeyphraseRecognitionEvent) event).keyphraseExtras;
- if (keyphraseExtras == null || keyphraseExtras.length == 0) {
- Slog.w(TAG, "Invalid keyphrase recognition event!");
- return;
- }
- // TODO: Handle more than one keyphrase extras.
- if (mKeyphraseId != keyphraseExtras[0].id) {
- Slog.w(TAG, "received onRecognition event for a different keyphrase");
+ if (modelData.getCallback() == null) {
+ Slog.w(TAG, "Received onRecognition event without callback for keyphrase model.");
return;
}
try {
- mKeyphraseModelData.getCallback().onKeyphraseDetected(
- (KeyphraseRecognitionEvent) event);
+ modelData.getCallback().onKeyphraseDetected((KeyphraseRecognitionEvent) event);
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onKeyphraseDetected", e);
}
- mKeyphraseModelData.setStopped();
+ modelData.setStopped();
- RecognitionConfig config = mKeyphraseModelData.getRecognitionConfig();
+ RecognitionConfig config = modelData.getRecognitionConfig();
if (config != null) {
// Whether we should continue by starting this again.
- mKeyphraseModelData.setRequested(config.allowMultipleTriggers);
+ modelData.setRequested(config.allowMultipleTriggers);
}
// TODO: Remove this block if the lower layer supports multiple triggers.
- if (mKeyphraseModelData.getRequested()) {
- updateRecognitionLocked(mKeyphraseModelData, isRecognitionAllowed(),
- true /* notify */);
+ if (modelData.getRequested()) {
+ updateRecognitionLocked(modelData, isRecognitionAllowed(), true /* notify */);
}
}
private void updateAllRecognitionsLocked(boolean notify) {
boolean isAllowed = isRecognitionAllowed();
- // Keyphrase model.
- if (mKeyphraseModelData != null) {
- updateRecognitionLocked(mKeyphraseModelData, isAllowed, notify);
- }
- for (UUID modelId : mGenericModelDataMap.keySet()) {
- ModelData modelData = mGenericModelDataMap.get(modelId);
+ for (ModelData modelData : mModelDataMap.values()) {
updateRecognitionLocked(modelData, isAllowed, notify);
}
}
@@ -809,11 +824,7 @@
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in onError", e);
} finally {
- if (mKeyphraseModelData != null) {
- mKeyphraseModelData.clearState();
- }
- internalClearKeyphraseStateLocked();
- internalClearGenericModelStateLocked();
+ internalClearModelStateLocked();
internalClearGlobalStateLocked();
if (mModule != null) {
mModule.detach();
@@ -822,10 +833,7 @@
}
}
- // internalClearGlobalStateLocked() gets split into two routines. Cleanup that is
- // specific to keyphrase sound models named as internalClearKeyphraseStateLocked() and
- // internalClearGlobalStateLocked() for global state. The global cleanup routine will be used
- // by the cleanup happening with the generic sound models.
+ // internalClearGlobalStateLocked() cleans up the telephony and power save listeners.
private void internalClearGlobalStateLocked() {
// Unregister from call state changes.
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
@@ -837,20 +845,9 @@
}
}
- private void internalClearKeyphraseStateLocked() {
- if (mKeyphraseModelData != null) {
- mKeyphraseModelData.setStopped();
- mKeyphraseModelData.setRequested(false);
- mKeyphraseModelData.setRecognitionConfig(null);
- mKeyphraseModelData.setCallback(null);
- }
-
- mKeyphraseId = INVALID_VALUE;
- }
-
- private void internalClearGenericModelStateLocked() {
- for (UUID modelId : mGenericModelDataMap.keySet()) {
- ModelData modelData = mGenericModelDataMap.get(modelId);
+ // Clears state for all models (generic and keyphrase).
+ private void internalClearModelStateLocked() {
+ for (ModelData modelData : mModelDataMap.values()) {
modelData.clearState();
modelData.clearCallback();
}
@@ -884,14 +881,10 @@
synchronized (mLock) {
pw.print(" module properties=");
pw.println(mModuleProperties == null ? "null" : mModuleProperties);
- pw.print(" keyphrase ID="); pw.println(mKeyphraseId);
pw.print(" call active="); pw.println(mCallActive);
pw.print(" power save mode active="); pw.println(mIsPowerSaveMode);
pw.print(" service disabled="); pw.println(mServiceDisabled);
- if (mKeyphraseModelData != null) {
- pw.println(mKeyphraseModelData.toString());
- }
}
}
@@ -914,34 +907,60 @@
// Sends an error callback to all models with a valid registered callback.
private void sendErrorCallbacksToAll(int errorCode) throws RemoteException {
- IRecognitionStatusCallback keyphraseListener = mKeyphraseModelData.getCallback();
- if (keyphraseListener != null) {
- keyphraseListener.onError(STATUS_ERROR);
- }
- for (UUID modelId: mGenericModelDataMap.keySet()) {
- ModelData modelData = mGenericModelDataMap.get(modelId);
- IRecognitionStatusCallback keyphraseCallback = mKeyphraseModelData.getCallback();
- if (keyphraseCallback != null) {
- keyphraseCallback.onError(STATUS_ERROR);
+ for (ModelData modelData : mModelDataMap.values()) {
+ IRecognitionStatusCallback callback = modelData.getCallback();
+ if (callback != null) {
+ callback.onError(STATUS_ERROR);
}
}
}
private ModelData getOrCreateGenericModelDataLocked(UUID modelId) {
- ModelData modelData = mGenericModelDataMap.get(modelId);
+ ModelData modelData = mModelDataMap.get(modelId);
if (modelData == null) {
modelData = ModelData.createGenericModelData(modelId);
- mGenericModelDataMap.put(modelId, modelData);
+ mModelDataMap.put(modelId, modelData);
+ } else if (!modelData.isGenericModel()) {
+ Slog.e(TAG, "UUID already used for non-generic model.");
+ return null;
}
return modelData;
}
+ private void removeKeyphraseModelLocked(int keyphraseId) {
+ UUID uuid = mKeyphraseUuidMap.get(keyphraseId);
+ if (uuid == null) {
+ return;
+ }
+ mModelDataMap.remove(uuid);
+ mKeyphraseUuidMap.remove(keyphraseId);
+ }
+
+ private ModelData getKeyphraseModelDataLocked(int keyphraseId) {
+ UUID uuid = mKeyphraseUuidMap.get(keyphraseId);
+ if (uuid == null) {
+ return null;
+ }
+ return mModelDataMap.get(uuid);
+ }
+
+ // Use this to create a new ModelData entry for a keyphrase Id. It will overwrite existing
+ // mapping if one exists.
+ private ModelData createKeyphraseModelDataLocked(UUID modelId, int keyphraseId) {
+ mKeyphraseUuidMap.remove(keyphraseId);
+ mModelDataMap.remove(modelId);
+ mKeyphraseUuidMap.put(keyphraseId, modelId);
+ ModelData modelData = ModelData.createKeyphraseModelData(modelId);
+ mModelDataMap.put(modelId, modelData);
+ return modelData;
+ }
+
// Instead of maintaining a second hashmap of modelHandle -> ModelData, we just
// iterate through to find the right object (since we don't expect 100s of models
// to be stored).
private ModelData getModelDataForLocked(int modelHandle) {
// Fetch ModelData object corresponding to the model handle.
- for (ModelData model : mGenericModelDataMap.values()) {
+ for (ModelData model : mModelDataMap.values()) {
if (model.getHandle() == modelHandle) {
return model;
}
@@ -1051,9 +1070,9 @@
return status;
}
- private void dumpGenericModelStateLocked() {
- for (UUID modelId : mGenericModelDataMap.keySet()) {
- ModelData modelData = mGenericModelDataMap.get(modelId);
+ private void dumpModelStateLocked() {
+ for (UUID modelId : mModelDataMap.keySet()) {
+ ModelData modelData = mModelDataMap.get(modelId);
Slog.i(TAG, "Model :" + modelData.toString());
}
}
@@ -1065,14 +1084,7 @@
mRecognitionRunning = false;
return mRecognitionRunning;
}
- if (mKeyphraseModelData != null && mKeyphraseModelData.getCallback() != null &&
- mKeyphraseModelData.isModelStarted() &&
- mKeyphraseModelData.getHandle() != INVALID_VALUE) {
- mRecognitionRunning = true;
- return mRecognitionRunning;
- }
- for (UUID modelId : mGenericModelDataMap.keySet()) {
- ModelData modelData = mGenericModelDataMap.get(modelId);
+ for (ModelData modelData : mModelDataMap.values()) {
if (modelData.isModelStarted()) {
mRecognitionRunning = true;
return mRecognitionRunning;
@@ -1233,6 +1245,10 @@
return mModelType == SoundModel.TYPE_KEYPHRASE;
}
+ synchronized boolean isGenericModel() {
+ return mModelType == SoundModel.TYPE_GENERIC_SOUND;
+ }
+
synchronized String stateToString() {
switch(mModelState) {
case MODEL_NOTLOADED: return "NOT_LOADED";
@@ -1259,7 +1275,17 @@
"ModelState: " + stateToString() + "\n" +
requestedToString() + "\n" +
callbackToString() + "\n" +
- uuidToString();
+ uuidToString() + "\n" + modelTypeToString();
+ }
+
+ synchronized String modelTypeToString() {
+ String type = null;
+ switch (mModelType) {
+ case SoundModel.TYPE_GENERIC_SOUND: type = "Generic"; break;
+ case SoundModel.TYPE_UNKNOWN: type = "Unknown"; break;
+ case SoundModel.TYPE_KEYPHRASE: type = "Keyphrase"; break;
+ }
+ return "Model type: " + type + "\n";
}
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 1544723..1e9db18 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -17,6 +17,7 @@
package com.android.server.voiceinteraction;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
@@ -42,9 +43,11 @@
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
+import com.android.server.LocalServices;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.List;
class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
final static String TAG = "VoiceInteractionServiceManager";
@@ -148,8 +151,14 @@
mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid, mHandler);
}
+ List<IBinder> activityTokens = null;
+ if (activityToken == null) {
+ // Let's get top activities from all visible stacks
+ activityTokens = LocalServices.getService(ActivityManagerInternal.class)
+ .getTopVisibleActivities();
+ }
return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback,
- activityToken);
+ activityToken, activityTokens);
}
public boolean hideSessionLocked() {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index e04f312..0922a12 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -45,6 +45,7 @@
import android.util.Slog;
import android.view.IWindowManager;
import android.view.WindowManager;
+
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
@@ -55,10 +56,15 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
final class VoiceInteractionSessionConnection implements ServiceConnection {
+
final static String TAG = "VoiceInteractionServiceManager";
+ private static final String KEY_RECEIVER_EXTRA_COUNT = "count";
+ private static final String KEY_RECEIVER_EXTRA_INDEX = "index";
+
final IBinder mToken = new Binder();
final Object mLock;
final ComponentName mSessionComponentName;
@@ -82,11 +88,27 @@
IVoiceInteractionSession mSession;
IVoiceInteractor mInteractor;
boolean mHaveAssistData;
- Bundle mAssistData;
+ int mPendingAssistDataCount;
+ ArrayList<AssistDataForActivity> mAssistData = new ArrayList<>();
boolean mHaveScreenshot;
Bitmap mScreenshot;
ArrayList<IVoiceInteractionSessionShowCallback> mPendingShowCallbacks = new ArrayList<>();
+ static class AssistDataForActivity {
+ int activityIndex;
+ int activityCount;
+ Bundle data;
+
+ public AssistDataForActivity(Bundle data) {
+ this.data = data;
+ Bundle receiverExtras = data.getBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS);
+ if (receiverExtras != null) {
+ activityIndex = receiverExtras.getInt(KEY_RECEIVER_EXTRA_INDEX);
+ activityCount = receiverExtras.getInt(KEY_RECEIVER_EXTRA_COUNT);
+ }
+ }
+ }
+
IVoiceInteractionSessionShowCallback mShowCallback =
new IVoiceInteractionSessionShowCallback.Stub() {
@Override
@@ -125,7 +147,7 @@
synchronized (mLock) {
if (mShown) {
mHaveAssistData = true;
- mAssistData = resultData;
+ mAssistData.add(new AssistDataForActivity(resultData));
deliverSessionDataLocked();
}
}
@@ -198,7 +220,8 @@
}
public boolean showLocked(Bundle args, int flags, int disabledContext,
- IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) {
+ IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken,
+ List<IBinder> topActivities) {
if (mBound) {
if (!mFullyBound) {
mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
@@ -220,30 +243,41 @@
mShowArgs = args;
mShowFlags = flags;
mHaveAssistData = false;
+ mPendingAssistDataCount = 0;
boolean needDisclosure = false;
if ((flags&VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
&& structureEnabled) {
- try {
- MetricsLogger.count(mContext, "assist_with_context", 1);
- if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
- mAssistReceiver, activityToken)) {
- needDisclosure = true;
- } else {
- // Wasn't allowed... given that, let's not do the screenshot either.
- mHaveAssistData = true;
- mAssistData = null;
- screenshotEnabled = false;
+ mAssistData.clear();
+ final int count = activityToken != null ? 1 : topActivities.size();
+ for (int i = 0; i < count; i++) {
+ IBinder topActivity = count == 1 ? activityToken : topActivities.get(i);
+ try {
+ MetricsLogger.count(mContext, "assist_with_context", 1);
+ Bundle receiverExtras = new Bundle();
+ receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
+ receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, count);
+ if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
+ mAssistReceiver, receiverExtras, topActivity, i == 0)) {
+ needDisclosure = true;
+ mPendingAssistDataCount++;
+ } else if (i == 0) {
+ // Wasn't allowed... given that, let's not do the screenshot either.
+ mHaveAssistData = true;
+ mAssistData.clear();
+ screenshotEnabled = false;
+ break;
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
}
} else {
mHaveAssistData = true;
- mAssistData = null;
+ mAssistData.clear();
}
} else {
- mAssistData = null;
+ mAssistData.clear();
}
mHaveScreenshot = false;
if ((flags&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) {
@@ -335,41 +369,26 @@
return;
}
if (mHaveAssistData) {
- Bundle assistData;
- AssistStructure structure;
- AssistContent content;
- if (mAssistData != null) {
- assistData = mAssistData.getBundle("data");
- structure = mAssistData.getParcelable("structure");
- content = mAssistData.getParcelable("content");
- int uid = mAssistData.getInt(Intent.EXTRA_ASSIST_UID, -1);
- if (uid >= 0 && content != null) {
- Intent intent = content.getIntent();
- if (intent != null) {
- ClipData data = intent.getClipData();
- if (data != null && Intent.isAccessUriMode(intent.getFlags())) {
- grantClipDataPermissions(data, intent.getFlags(), uid,
- mCallingUid, mSessionComponentName.getPackageName());
- }
- }
- ClipData data = content.getClipData();
- if (data != null) {
- grantClipDataPermissions(data,
- Intent.FLAG_GRANT_READ_URI_PERMISSION,
- uid, mCallingUid, mSessionComponentName.getPackageName());
- }
+ AssistDataForActivity assistData;
+ while (!mAssistData.isEmpty()) {
+ if (mPendingAssistDataCount <= 0) {
+ Slog.e(TAG, "mPendingAssistDataCount is " + mPendingAssistDataCount);
}
- } else {
- assistData = null;
- structure = null;
- content = null;
+ mPendingAssistDataCount--;
+ assistData = mAssistData.remove(0);
+ if (assistData.data == null) {
+ try {
+ mSession.handleAssist(null, null, null, assistData.activityIndex,
+ assistData.activityCount);
+ } catch (RemoteException e) {
+ }
+ } else {
+ deliverSessionDataLocked(assistData);
+ }
}
- try {
- mSession.handleAssist(assistData, structure, content);
- } catch (RemoteException e) {
- }
- mAssistData = null;
- mHaveAssistData = false;
+ if (mPendingAssistDataCount <= 0) {
+ mHaveAssistData = false;
+ } // else, more to come
}
if (mHaveScreenshot) {
try {
@@ -381,6 +400,37 @@
}
}
+ private void deliverSessionDataLocked(AssistDataForActivity assistDataForActivity) {
+ Bundle assistData = assistDataForActivity.data.getBundle(
+ VoiceInteractionSession.KEY_DATA);
+ AssistStructure structure = assistDataForActivity.data.getParcelable(
+ VoiceInteractionSession.KEY_STRUCTURE);
+ AssistContent content = assistDataForActivity.data.getParcelable(
+ VoiceInteractionSession.KEY_CONTENT);
+ int uid = assistDataForActivity.data.getInt(Intent.EXTRA_ASSIST_UID, -1);
+ if (uid >= 0 && content != null) {
+ Intent intent = content.getIntent();
+ if (intent != null) {
+ ClipData data = intent.getClipData();
+ if (data != null && Intent.isAccessUriMode(intent.getFlags())) {
+ grantClipDataPermissions(data, intent.getFlags(), uid,
+ mCallingUid, mSessionComponentName.getPackageName());
+ }
+ }
+ ClipData data = content.getClipData();
+ if (data != null) {
+ grantClipDataPermissions(data,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ uid, mCallingUid, mSessionComponentName.getPackageName());
+ }
+ }
+ try {
+ mSession.handleAssist(assistData, structure, content,
+ assistDataForActivity.activityIndex, assistDataForActivity.activityCount);
+ } catch (RemoteException e) {
+ }
+ }
+
public boolean hideLocked() {
if (mBound) {
if (mShown) {
@@ -388,7 +438,7 @@
mShowArgs = null;
mShowFlags = 0;
mHaveAssistData = false;
- mAssistData = null;
+ mAssistData.clear();
if (mSession != null) {
try {
mSession.hide();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c18c13c..26730de 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -548,6 +548,27 @@
public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
/**
+ * List operator-specific error codes and indices of corresponding error strings in
+ * wfcOperatorErrorAlertMessages and wfcOperatorErrorNotificationMessages.
+ *
+ * Example: "REG09|0" specifies error code "REG09" and index "0". This index will be
+ * used to find alert and notification messages in wfcOperatorErrorAlertMessages and
+ * wfcOperatorErrorNotificationMessages.
+ *
+ * @hide
+ */
+ public static final String KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY =
+ "wfc_operator_error_codes_string_array";
+
+ /**
+ * Indexes of SPN format strings in wfcSpnFormats and wfcDataSpnFormats.
+ * @hide
+ */
+ public static final String KEY_WFC_SPN_FORMAT_IDX_INT = "wfc_spn_format_idx_int";
+ /** @hide */
+ public static final String KEY_WFC_DATA_SPN_FORMAT_IDX_INT = "wfc_data_spn_format_idx_int";
+
+ /**
* If this is true, the SIM card (through Customer Service Profile EF file) will be able to
* prevent manual operator selection. If false, this SIM setting will be ignored and manual
* operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more
@@ -693,8 +714,8 @@
sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
sDefaults.putString(KEY_VVM_TYPE_STRING, "");
- sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN,false);
- sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOLEAN,true);
+ sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN, false);
+ sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOLEAN, true);
sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
sDefaults.putBoolean(KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, false);
sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
@@ -731,6 +752,9 @@
sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL, false);
sDefaults.putBoolean(KEY_EDITABLE_WFC_MODE_BOOL, true);
+ sDefaults.putStringArray(KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY, null);
+ sDefaults.putInt(KEY_WFC_SPN_FORMAT_IDX_INT, 0);
+ sDefaults.putInt(KEY_WFC_DATA_SPN_FORMAT_IDX_INT, 0);
// MMS defaults
sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
deleted file mode 100644
index 069fcbf..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.ITelephonyDebugSubscriber;
-
-import android.os.Bundle;
-
-/**
- * Interface used to interact with the Telephony debug service.
- *
- * {@hide}
- */
-interface ITelephonyDebug {
-
- /**
- * Write telephony event
- * @param timestamp returned by System.currentTimeMillis()
- * @param phoneId for which event is written
- * @param tag constant defined in TelephonyEventLog
- * @param param1 optional
- * @param param2 optional
- * @param data optional
- */
- void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
-
- void subscribe(in ITelephonyDebugSubscriber subscriber);
- void unsubscribe(in ITelephonyDebugSubscriber subscriber);
-}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
deleted file mode 100644
index 64eb0f1..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.internal.telephony;
-
-import com.android.internal.telephony.TelephonyEvent;
-
-import android.os.Bundle;
-
-/**
- * Interface used to subscribe for events from Telephony debug service.
- *
- * {@hide}
- */
-oneway interface ITelephonyDebugSubscriber {
-
- /**
- * Called when Telephony debug service has events.
- */
- void onEvents(in TelephonyEvent[] events);
-}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
deleted file mode 100644
index 1e74b31..0000000
--- a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.internal.telephony;
-
-parcelable TelephonyEvent;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.java b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
deleted file mode 100644
index 26d466d..0000000
--- a/telephony/java/com/android/internal/telephony/TelephonyEvent.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.internal.telephony;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A parcelable used in ITelephonyDebugSubscriber.aidl
- */
-public class TelephonyEvent implements Parcelable {
-
- final public long timestamp;
- final public int phoneId;
- final public int tag;
- final public int param1;
- final public int param2;
- final public Bundle data;
-
- public TelephonyEvent(long timestamp, int phoneId, int tag,
- int param1, int param2, Bundle data) {
- this.timestamp = timestamp;
- this.phoneId = phoneId;
- this.tag = tag;
- this.param1 = param1;
- this.param2 = param2;
- this.data = data;
- }
-
- /** Implement the Parcelable interface */
- public static final Parcelable.Creator<TelephonyEvent> CREATOR
- = new Parcelable.Creator<TelephonyEvent> (){
- public TelephonyEvent createFromParcel(Parcel source) {
- final long timestamp = source.readLong();
- final int phoneId = source.readInt();
- final int tag = source.readInt();
- final int param1 = source.readInt();
- final int param2 = source.readInt();
- final Bundle data = source.readBundle();
- return new TelephonyEvent(timestamp, phoneId, tag, param1, param2, data);
- }
-
- public TelephonyEvent[] newArray(int size) {
- return new TelephonyEvent[size];
- }
- };
-
- /** Implement the Parcelable interface */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(timestamp);
- dest.writeInt(phoneId);
- dest.writeInt(tag);
- dest.writeInt(param1);
- dest.writeInt(param2);
- dest.writeBundle(data);
- }
-
- public String toString() {
- return String.format("%d,%d,%d,%d,%d,%s",
- timestamp, phoneId, tag, param1, param2, data);
- }
-}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 6c8be39..a4aab7c 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -25,6 +25,7 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
+import android.media.AudioAttributes;
import android.os.Bundle;
import android.os.Vibrator;
import android.os.Handler;
@@ -86,6 +87,28 @@
}
private Test[] mTests = new Test[] {
+ new Test("Phone call") {
+ public void run()
+ {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle("phone call")
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"),
+ new AudioAttributes.Builder().setUsage(
+ AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build())
+ .setPriority(Notification.PRIORITY_MAX)
+ .setVibrate(new long[] {
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 })
+ .setFullScreenIntent(makeIntent2(), true)
+ .build();
+ mNM.notify(7001, n);
+ }
+ },
new Test("Post a group") {
public void run()
{
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 450334c..5767f11 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -194,6 +194,18 @@
}
@Override
+ public void onHandleAssistSecondary(final Bundle data, final AssistStructure structure,
+ final AssistContent content, int index, int count) {
+ Log.i(TAG, "Got secondary activity assist data " + index + " of " + count);
+ Log.i(TAG, "Showing assist structure after a few seconds...");
+ mContentView.postDelayed(new Runnable() {
+ public void run() {
+ onHandleAssist(data, structure, content);
+ }
+ }, 2000 * index);
+ }
+
+ @Override
public void onHandleScreenshot(Bitmap screenshot) {
if (screenshot != null) {
mScreenshot.setImageBitmap(screenshot);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index 308488a..e0d8249 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -24,6 +24,7 @@
import com.android.ide.common.rendering.api.ViewInfo;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import com.android.tools.layoutlib.java.System_Delegate;
+import com.android.util.PropertiesMap;
import android.view.View;
import android.view.ViewGroup;
@@ -70,6 +71,11 @@
}
@Override
+ public Map<Object, PropertiesMap> getDefaultProperties() {
+ return mSession.getDefaultProperties();
+ }
+
+ @Override
public Result render(long timeout, boolean forceMeasure) {
try {
Bridge.prepareThread();
@@ -196,10 +202,6 @@
}
}
- public RenderSessionImpl getSessionImpl() {
- return mSession;
- }
-
/*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
mSession = scene;
if (scene != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index fd95bd5..80e230c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -27,12 +27,13 @@
import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
-import com.android.layoutlib.bridge.android.PropertiesMap.Property;
import com.android.layoutlib.bridge.android.view.WindowManagerImpl;
import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.impl.Stack;
import com.android.resources.ResourceType;
import com.android.util.Pair;
+import com.android.util.PropertiesMap;
+import com.android.util.PropertiesMap.Property;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -153,7 +154,6 @@
private IBinder mBinder;
private PackageManager mPackageManager;
-
/**
* Some applications that target both pre API 17 and post API 17, set the newer attrs to
* reference the older ones. For example, android:paddingStart will resolve to
@@ -276,8 +276,8 @@
return mRenderResources;
}
- public PropertiesMap getDefaultPropMap(Object key) {
- return mDefaultPropMaps.get(key);
+ public Map<Object, PropertiesMap> getDefaultProperties() {
+ return mDefaultPropMaps;
}
public Configuration getConfiguration() {
@@ -1862,7 +1862,6 @@
return false;
}
-
/**
* The cached value depends on
* <ol>
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java
deleted file mode 100644
index a38d579..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.layoutlib.bridge.android;
-
-import com.android.layoutlib.bridge.android.PropertiesMap.Property;
-
-import java.util.HashMap;
-
-/**
- * An alias used for the value in {@link BridgeContext#mDefaultPropMaps}
- */
-public class PropertiesMap extends HashMap<String, Property> {
-
- public static class Property {
- public final String resource;
- public final String value;
-
- public Property(String resource, String value) {
- this.resource = resource;
- this.value = value;
- }
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 2d38831..0c53753 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -286,7 +286,7 @@
return mParams;
}
- public BridgeContext getContext() {
+ protected BridgeContext getContext() {
return mContext;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 11fabc6..3ef568c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -48,6 +48,7 @@
import com.android.resources.ResourceType;
import com.android.tools.layoutlib.java.System_Delegate;
import com.android.util.Pair;
+import com.android.util.PropertiesMap;
import android.animation.AnimationThread;
import android.animation.Animator;
@@ -1415,6 +1416,10 @@
return mSystemViewInfoList;
}
+ public Map<Object, PropertiesMap> getDefaultProperties() {
+ return getContext().getDefaultProperties();
+ }
+
public void setScene(RenderSession session) {
mScene = session;
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index fb2bdd4..b8ef150 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1636,6 +1636,9 @@
if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
}
+ if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
+ keyMgmt = KeyMgmt.strings[KeyMgmt.OSEN];
+ }
if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 394934f..b614a86 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -437,6 +437,7 @@
switch (eapMethod) {
/** Valid methods */
case Eap.TLS:
+ case Eap.UNAUTH_TLS:
setPhase2Method(Phase2.NONE);
/* fall through */
case Eap.PEAP: