Merge "Invalidate entire scene root when executing the transition." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 3fc1673..95eeeee 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -34577,7 +34577,7 @@
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public boolean onSearchRequested(android.view.SearchEvent);
method public boolean onSearchRequested();
method public void onWakeUp();
@@ -36008,9 +36008,11 @@
method public void playDtmfTone(char);
method public void postDialContinue(boolean);
method public void pullExternalCall();
+ method public final void putExtras(android.os.Bundle);
method public void registerCallback(android.telecom.Call.Callback);
method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
method public void reject(boolean, java.lang.String);
+ method public final void removeExtras(java.util.List<java.lang.String>);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
method public void splitFromConference();
method public void stopDtmfTone();
@@ -36151,6 +36153,7 @@
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onMerge(android.telecom.Connection);
method public void onMerge();
@@ -36159,14 +36162,16 @@
method public void onStopDtmfTone();
method public void onSwap();
method public void onUnhold();
+ method public final void putExtras(android.os.Bundle);
method public final void removeConnection(android.telecom.Connection);
+ method public final void removeExtras(java.util.List<java.lang.String>);
method public final void setActive();
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConnectionCapabilities(int);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
- method public final void setExtras(android.os.Bundle);
+ method public final deprecated void setExtras(android.os.Bundle);
method public final void setOnHold();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -36204,6 +36209,7 @@
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onCallEvent(java.lang.String, android.os.Bundle);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onPlayDtmfTone(char);
method public void onPostDialContinue(boolean);
@@ -36214,6 +36220,8 @@
method public void onStateChanged(int);
method public void onStopDtmfTone();
method public void onUnhold();
+ method public final void putExtras(android.os.Bundle);
+ method public final void removeExtras(java.util.List<java.lang.String>);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
@@ -36224,7 +36232,7 @@
method public final void setConnectionCapabilities(int);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
- method public final void setExtras(android.os.Bundle);
+ method public final deprecated void setExtras(android.os.Bundle);
method public final void setInitialized();
method public final void setInitializing();
method public final void setNextPostDialChar(char);
@@ -41641,9 +41649,11 @@
}
public final class KeyboardShortcutInfo implements android.os.Parcelable {
+ ctor public KeyboardShortcutInfo(java.lang.CharSequence, int, int);
ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
method public int describeContents();
method public char getBaseCharacter();
+ method public int getKeycode();
method public java.lang.CharSequence getLabel();
method public int getModifiers();
method public void writeToParcel(android.os.Parcel, int);
@@ -43654,7 +43664,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
diff --git a/api/system-current.txt b/api/system-current.txt
index 48e1bd0..507a1a7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -37027,7 +37027,7 @@
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public boolean onSearchRequested(android.view.SearchEvent);
method public boolean onSearchRequested();
method public void onWakeUp();
@@ -38571,9 +38571,11 @@
method public void playDtmfTone(char);
method public void postDialContinue(boolean);
method public void pullExternalCall();
+ method public final void putExtras(android.os.Bundle);
method public void registerCallback(android.telecom.Call.Callback);
method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
method public void reject(boolean, java.lang.String);
+ method public final void removeExtras(java.util.List<java.lang.String>);
method public deprecated void removeListener(android.telecom.Call.Listener);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
method public void splitFromConference();
@@ -38724,6 +38726,7 @@
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onMerge(android.telecom.Connection);
method public void onMerge();
@@ -38732,7 +38735,9 @@
method public void onStopDtmfTone();
method public void onSwap();
method public void onUnhold();
+ method public final void putExtras(android.os.Bundle);
method public final void removeConnection(android.telecom.Connection);
+ method public final void removeExtras(java.util.List<java.lang.String>);
method public final void setActive();
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final deprecated void setConnectTimeMillis(long);
@@ -38740,7 +38745,7 @@
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
- method public final void setExtras(android.os.Bundle);
+ method public final deprecated void setExtras(android.os.Bundle);
method public final void setOnHold();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -38780,6 +38785,7 @@
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onCallEvent(java.lang.String, android.os.Bundle);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onPlayDtmfTone(char);
method public void onPostDialContinue(boolean);
@@ -38790,6 +38796,8 @@
method public void onStateChanged(int);
method public void onStopDtmfTone();
method public void onUnhold();
+ method public final void putExtras(android.os.Bundle);
+ method public final void removeExtras(java.util.List<java.lang.String>);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
@@ -38800,7 +38808,7 @@
method public final void setConnectionCapabilities(int);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
- method public final void setExtras(android.os.Bundle);
+ method public final deprecated void setExtras(android.os.Bundle);
method public final void setInitialized();
method public final void setInitializing();
method public final void setNextPostDialChar(char);
@@ -44367,9 +44375,11 @@
}
public final class KeyboardShortcutInfo implements android.os.Parcelable {
+ ctor public KeyboardShortcutInfo(java.lang.CharSequence, int, int);
ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
method public int describeContents();
method public char getBaseCharacter();
+ method public int getKeycode();
method public java.lang.CharSequence getLabel();
method public int getModifiers();
method public void writeToParcel(android.os.Parcel, int);
@@ -46381,7 +46391,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
diff --git a/api/test-current.txt b/api/test-current.txt
index c1035af..c382c3d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -34648,7 +34648,7 @@
method public boolean onMenuOpened(int, android.view.Menu);
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public boolean onSearchRequested(android.view.SearchEvent);
method public boolean onSearchRequested();
method public void onWakeUp();
@@ -36079,9 +36079,11 @@
method public void playDtmfTone(char);
method public void postDialContinue(boolean);
method public void pullExternalCall();
+ method public final void putExtras(android.os.Bundle);
method public void registerCallback(android.telecom.Call.Callback);
method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
method public void reject(boolean, java.lang.String);
+ method public final void removeExtras(java.util.List<java.lang.String>);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
method public void splitFromConference();
method public void stopDtmfTone();
@@ -36222,6 +36224,7 @@
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onMerge(android.telecom.Connection);
method public void onMerge();
@@ -36230,14 +36233,16 @@
method public void onStopDtmfTone();
method public void onSwap();
method public void onUnhold();
+ method public final void putExtras(android.os.Bundle);
method public final void removeConnection(android.telecom.Connection);
+ method public final void removeExtras(java.util.List<java.lang.String>);
method public final void setActive();
method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
method public final void setConnectionCapabilities(int);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
- method public final void setExtras(android.os.Bundle);
+ method public final deprecated void setExtras(android.os.Bundle);
method public final void setOnHold();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -36275,6 +36280,7 @@
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onCallEvent(java.lang.String, android.os.Bundle);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onPlayDtmfTone(char);
method public void onPostDialContinue(boolean);
@@ -36285,6 +36291,8 @@
method public void onStateChanged(int);
method public void onStopDtmfTone();
method public void onUnhold();
+ method public final void putExtras(android.os.Bundle);
+ method public final void removeExtras(java.util.List<java.lang.String>);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
@@ -36295,7 +36303,7 @@
method public final void setConnectionCapabilities(int);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
- method public final void setExtras(android.os.Bundle);
+ method public final deprecated void setExtras(android.os.Bundle);
method public final void setInitialized();
method public final void setInitializing();
method public final void setNextPostDialChar(char);
@@ -41714,9 +41722,11 @@
}
public final class KeyboardShortcutInfo implements android.os.Parcelable {
+ ctor public KeyboardShortcutInfo(java.lang.CharSequence, int, int);
ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
method public int describeContents();
method public char getBaseCharacter();
+ method public int getKeycode();
method public java.lang.CharSequence getLabel();
method public int getModifiers();
method public void writeToParcel(android.os.Parcel, int);
@@ -43727,7 +43737,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cc1d68e..ee17e8a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -57,6 +57,7 @@
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
+import android.hardware.input.InputManager;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
@@ -91,6 +92,8 @@
import android.view.ContextThemeWrapper;
import android.view.DragEvent;
import android.view.DropPermissions;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@@ -1679,10 +1682,16 @@
}
@Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
+ public void onProvideKeyboardShortcuts(
+ List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
if (menu == null) {
return;
}
+ final InputDevice inputDevice = InputManager.getInstance().getInputDevice(deviceId);
+ if (inputDevice == null) {
+ return;
+ }
+ final KeyCharacterMap keyCharacterMap = inputDevice.getKeyCharacterMap();
KeyboardShortcutGroup group = null;
int menuSize = menu.size();
for (int i = 0; i < menuSize; ++i) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 79461b4..0bb1097 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -1082,13 +1082,6 @@
}
/**
- * {@inheritDoc}
- */
- @Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
- }
-
- /**
* @return The activity associated with this dialog, or null if there is no associated activity.
*/
private ComponentName getAssociatedActivity() {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 6870bbf..f7a4557 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1429,16 +1429,20 @@
final Context context = getContext();
final int version = context != null ? context.getApplicationInfo().targetSdkVersion : 0;
if (version >= Build.VERSION_CODES.N) {
- if (savedInstanceState != null) {
- Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
- if (p != null) {
- if (mChildFragmentManager == null) {
- instantiateChildFragmentManager();
- }
- mChildFragmentManager.restoreAllState(p, mChildNonConfig);
- mChildNonConfig = null;
- mChildFragmentManager.dispatchCreate();
+ restoreChildFragmentState(savedInstanceState, true);
+ }
+ }
+
+ void restoreChildFragmentState(@Nullable Bundle savedInstanceState, boolean provideNonConfig) {
+ if (savedInstanceState != null) {
+ Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
+ if (p != null) {
+ if (mChildFragmentManager == null) {
+ instantiateChildFragmentManager();
}
+ mChildFragmentManager.restoreAllState(p, provideNonConfig ? mChildNonConfig : null);
+ mChildNonConfig = null;
+ mChildFragmentManager.dispatchCreate();
}
}
}
@@ -1692,6 +1696,18 @@
*/
public void onDetach() {
mCalled = true;
+
+ // Destroy the child FragmentManager if we still have it here.
+ // We won't unless we're retaining our instance and if we do,
+ // our child FragmentManager instance state will have already been saved.
+ if (mChildFragmentManager != null) {
+ if (!mRetaining) {
+ throw new IllegalStateException("Child FragmentManager of " + this + " was not "
+ + " destroyed and this fragment is not retaining instance");
+ }
+ mChildFragmentManager.dispatchDestroy();
+ mChildFragmentManager = null;
+ }
}
/**
@@ -2252,16 +2268,7 @@
final Context context = getContext();
final int version = context != null ? context.getApplicationInfo().targetSdkVersion : 0;
if (version < Build.VERSION_CODES.N) {
- if (savedInstanceState != null) {
- Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
- if (p != null) {
- if (mChildFragmentManager == null) {
- instantiateChildFragmentManager();
- }
- mChildFragmentManager.restoreAllState(p, null);
- mChildFragmentManager.dispatchCreate();
- }
- }
+ restoreChildFragmentState(savedInstanceState, false);
}
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 0631943..2852baf 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -941,6 +941,9 @@
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState);
+ } else {
+ f.restoreChildFragmentState(f.mSavedFragmentState, true);
+ f.mState = Fragment.CREATED;
}
f.mRetaining = false;
if (f.mFromLayout) {
@@ -1009,6 +1012,9 @@
f.mSavedFragmentState = null;
}
case Fragment.ACTIVITY_CREATED:
+ if (newState > Fragment.ACTIVITY_CREATED) {
+ f.mState = Fragment.STOPPED;
+ }
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
@@ -1108,7 +1114,7 @@
if (!f.mRetaining) {
f.performDestroy();
} else {
- f.mState = Fragment.INITIALIZING;
+ f.mState = Fragment.CREATED;
}
f.mCalled = false;
@@ -1124,7 +1130,6 @@
f.mHost = null;
f.mParentFragment = null;
f.mFragmentManager = null;
- f.mChildFragmentManager = null;
}
}
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index dabc652..e3fb161 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -454,8 +454,21 @@
*/
boolean performDexOptIfNeeded(String packageName, String instructionSet);
- boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
- boolean extractOnly, boolean force);
+ /**
+ * Ask the package manager to perform a dex-opt for the given reason. The package
+ * manager will map the reason to a compiler filter according to the current system
+ * configuration.
+ */
+ boolean performDexOpt(String packageName, String instructionSet, boolean checkProfiles,
+ int compileReason, boolean force);
+ /**
+ * Ask the package manager to perform a dex-opt with the given compiler filter.
+ *
+ * Note: exposed only for the shell command to allow moving packages explicitly to a
+ * definite state.
+ */
+ boolean performDexOptMode(String packageName, String instructionSet, boolean checkProfiles,
+ String targetCompilerFilter, boolean force);
void forceDexOpt(String packageName);
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 3139151..e8a3438 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -216,6 +216,7 @@
lastLoggedInTime = orig.lastLoggedInTime;
partial = orig.partial;
profileGroupId = orig.profileGroupId;
+ restrictedProfileParentId = orig.restrictedProfileParentId;
guestToRemove = orig.guestToRemove;
}
diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java
index d57d0f5..4a5f827 100644
--- a/core/java/android/security/net/config/XmlConfigSource.java
+++ b/core/java/android/security/net/config/XmlConfigSource.java
@@ -111,7 +111,7 @@
if (parser.next() != XmlPullParser.TEXT) {
throw new ParserException(parser, "Missing pin digest");
}
- String digest = parser.getText();
+ String digest = parser.getText().trim();
byte[] decodedDigest = null;
try {
decodedDigest = Base64.decode(digest, 0);
@@ -168,7 +168,7 @@
if (parser.next() != XmlPullParser.TEXT) {
throw new ParserException(parser, "Domain name missing");
}
- String domain = parser.getText().toLowerCase(Locale.US);
+ String domain = parser.getText().trim().toLowerCase(Locale.US);
if (parser.next() != XmlPullParser.END_TAG) {
throw new ParserException(parser, "domain contains additional elements");
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 816ecde..7af0b05 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -367,11 +367,6 @@
@Override
public void onActionModeFinished(ActionMode mode) {
}
-
- /** {@inheritDoc} */
- @Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
- }
// end Window.Callback methods
// begin public api
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 70d0513..707300f 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -95,5 +95,5 @@
/**
* Called when Keyboard Shortcuts are requested for the window.
*/
- void requestAppKeyboardShortcuts(IResultReceiver receiver);
+ void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index d8b7421..7af4a1f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -387,7 +387,7 @@
*
* @param receiver The receiver to deliver the results to.
*/
- void requestAppKeyboardShortcuts(IResultReceiver receiver);
+ void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);
/**
* Retrieves the current stable insets from the primary display.
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
index 2c9006d..c2bd347 100644
--- a/core/java/android/view/KeyboardShortcutInfo.java
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -30,31 +30,46 @@
private final CharSequence mLabel;
private final Icon mIcon;
private final char mBaseCharacter;
+ private final int mKeycode;
private final int mModifiers;
/**
* @param label The label that identifies the action performed by this shortcut.
* @param icon An icon that identifies the action performed by this shortcut.
- * @param baseCharacter The character that triggers the shortcut.
+ * @param keycode The keycode that triggers the shortcut. This should be a valid constant
+ * defined in {@link KeyEvent}.
* @param modifiers The set of modifiers that, combined with the key, trigger the shortcut.
* These should be a combination of {@link KeyEvent#META_CTRL_ON},
- * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON} and
- * {@link KeyEvent#META_ALT_ON}.
+ * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON},
+ * {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_FUNCTION_ON} and
+ * {@link KeyEvent#META_SYM_ON}.
*
* @hide
*/
public KeyboardShortcutInfo(
- @Nullable CharSequence label, @Nullable Icon icon, char baseCharacter, int modifiers) {
+ @Nullable CharSequence label, @Nullable Icon icon, int keycode, int modifiers) {
mLabel = label;
mIcon = icon;
- checkArgument(baseCharacter != MIN_VALUE);
- mBaseCharacter = baseCharacter;
+ mBaseCharacter = MIN_VALUE;
+ checkArgument(keycode > KeyEvent.KEYCODE_UNKNOWN && keycode <= KeyEvent.getMaxKeyCode());
+ mKeycode = keycode;
mModifiers = modifiers;
}
/**
- * Convenience constructor for shortcuts with a label and no icon.
- *
+ * @param label The label that identifies the action performed by this shortcut.
+ * @param keycode The keycode that triggers the shortcut. This should be a valid constant
+ * defined in {@link KeyEvent}.
+ * @param modifiers The set of modifiers that, combined with the key, trigger the shortcut.
+ * These should be a combination of {@link KeyEvent#META_CTRL_ON},
+ * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_META_ON} and
+ * {@link KeyEvent#META_ALT_ON}.
+ */
+ public KeyboardShortcutInfo(CharSequence label, int keycode, int modifiers) {
+ this(label, null, keycode, modifiers);
+ }
+
+ /**
* @param label The label that identifies the action performed by this shortcut.
* @param baseCharacter The character that triggers the shortcut.
* @param modifiers The set of modifiers that, combined with the key, trigger the shortcut.
@@ -66,14 +81,16 @@
mLabel = label;
checkArgument(baseCharacter != MIN_VALUE);
mBaseCharacter = baseCharacter;
+ mKeycode = KeyEvent.KEYCODE_UNKNOWN;
mModifiers = modifiers;
mIcon = null;
}
private KeyboardShortcutInfo(Parcel source) {
mLabel = source.readCharSequence();
- mIcon = (Icon) source.readParcelable(null);
+ mIcon = source.readParcelable(null);
mBaseCharacter = (char) source.readInt();
+ mKeycode = source.readInt();
mModifiers = source.readInt();
}
@@ -96,7 +113,16 @@
}
/**
- * Returns the base character that, combined with the modifiers, triggers this shortcut.
+ * Returns the base keycode that, combined with the modifiers, triggers this shortcut. If the
+ * base character was set instead, returns {@link KeyEvent#KEYCODE_UNKNOWN}.
+ */
+ public int getKeycode() {
+ return mKeycode;
+ }
+
+ /**
+ * Returns the base character that, combined with the modifiers, triggers this shortcut. If the
+ * keycode was set instead, returns {@link Character#MIN_VALUE}.
*/
public char getBaseCharacter() {
return mBaseCharacter;
@@ -119,6 +145,7 @@
dest.writeCharSequence(mLabel);
dest.writeParcelable(mIcon, 0);
dest.writeInt(mBaseCharacter);
+ dest.writeInt(mKeycode);
dest.writeInt(mModifiers);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6d35a58..6fa2aad 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -22187,7 +22187,7 @@
/**
* @hide
*/
- public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data) {
+ public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) {
// Do nothing.
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a2295ce..ffebf71 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3287,7 +3287,6 @@
private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
- private final static int MSG_FINISH_INPUT_CONNECTION = 12;
private final static int MSG_CHECK_FOCUS = 13;
private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
private final static int MSG_DISPATCH_DRAG_EVENT = 15;
@@ -3327,8 +3326,6 @@
return "MSG_DISPATCH_GET_NEW_SURFACE";
case MSG_DISPATCH_KEY_FROM_IME:
return "MSG_DISPATCH_KEY_FROM_IME";
- case MSG_FINISH_INPUT_CONNECTION:
- return "MSG_FINISH_INPUT_CONNECTION";
case MSG_CHECK_FOCUS:
return "MSG_CHECK_FOCUS";
case MSG_CLOSE_SYSTEM_DIALOGS:
@@ -3549,12 +3546,6 @@
}
enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
} break;
- case MSG_FINISH_INPUT_CONNECTION: {
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) {
- imm.reportFinishInputConnection((InputConnection)msg.obj);
- }
- } break;
case MSG_CHECK_FOCUS: {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
@@ -3594,8 +3585,9 @@
handleDispatchWindowShown();
} break;
case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
- IResultReceiver receiver = (IResultReceiver) msg.obj;
- handleRequestKeyboardShortcuts(receiver);
+ final IResultReceiver receiver = (IResultReceiver) msg.obj;
+ final int deviceId = msg.arg1;
+ handleRequestKeyboardShortcuts(receiver, deviceId);
} break;
case MSG_UPDATE_POINTER_ICON: {
MotionEvent event = (MotionEvent) msg.obj;
@@ -5516,11 +5508,11 @@
mAttachInfo.mTreeObserver.dispatchOnWindowShown();
}
- public void handleRequestKeyboardShortcuts(IResultReceiver receiver) {
+ public void handleRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
Bundle data = new Bundle();
ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
if (mView != null) {
- mView.requestKeyboardShortcuts(list);
+ mView.requestKeyboardShortcuts(list, deviceId);
}
data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
try {
@@ -5864,11 +5856,6 @@
}
}
- public void dispatchFinishInputConnection(InputConnection connection) {
- Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
- mHandler.sendMessage(msg);
- }
-
public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Configuration newConfig, Rect backDropFrame, boolean forceLayout,
@@ -6482,8 +6469,9 @@
}
}
- public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver) {
- mHandler.obtainMessage(MSG_REQUEST_KEYBOARD_SHORTCUTS, receiver).sendToTarget();
+ public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
+ mHandler.obtainMessage(
+ MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
}
/**
@@ -7060,11 +7048,11 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
- ViewRootImpl viewAncestor = mViewAncestor.get();
- if (viewAncestor != null) {
- viewAncestor.dispatchRequestKeyboardShortcuts(receiver);
- }
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
+ ViewRootImpl viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchRequestKeyboardShortcuts(receiver, deviceId);
+ }
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 63f3744..36ee3e6 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -565,9 +565,10 @@
*
* @param data The data list to populate with shortcuts.
* @param menu The current menu, which may be null.
+ * @param deviceId The id for the connected device the shortcuts should be provided for.
*/
default public void onProvideKeyboardShortcuts(
- List<KeyboardShortcutGroup> data, @Nullable Menu menu) { };
+ List<KeyboardShortcutGroup> data, @Nullable Menu menu, int deviceId) { };
}
/** @hide */
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
index bed74e9..8f2d2e1 100644
--- a/core/java/android/view/WindowCallbackWrapper.java
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -154,8 +154,9 @@
}
@Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
- mWrapped.onProvideKeyboardShortcuts(data, menu);
+ public void onProvideKeyboardShortcuts(
+ List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
+ mWrapped.onProvideKeyboardShortcuts(data, menu, deviceId);
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 17f1991..03dcf99 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -158,7 +158,7 @@
*
* @hide
*/
- public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver);
+ public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver, int deviceId);
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
/**
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 6e11671..f8c7d68 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -125,7 +125,8 @@
}
@Override
- public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver) {
+ public void requestAppKeyboardShortcuts(
+ final KeyboardShortcutsReceiver receiver, int deviceId) {
IResultReceiver resultReceiver = new IResultReceiver.Stub() {
@Override
public void send(int resultCode, Bundle resultData) throws RemoteException {
@@ -136,7 +137,7 @@
};
try {
WindowManagerGlobal.getWindowManagerService()
- .requestAppKeyboardShortcuts(resultReceiver);
+ .requestAppKeyboardShortcuts(resultReceiver, deviceId);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 6a830f8..a3c49c5 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -158,8 +158,8 @@
*
* @hide
*/
- protected void reportFinish() {
- // Intentionaly empty
+ public void reportFinish() {
+ // Intentionally empty
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 1d89cd0..4bb0c3c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -531,22 +531,25 @@
private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
private final InputMethodManager mParentInputMethodManager;
- private boolean mActive;
public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
final InputMethodManager inputMethodManager) {
super(mainLooper, conn);
mParentInputMethodManager = inputMethodManager;
- mActive = true;
}
@Override
public boolean isActive() {
- return mParentInputMethodManager.mActive && mActive;
+ return mParentInputMethodManager.mActive && !isFinished();
}
void deactivate() {
- mActive = false;
+ if (isFinished()) {
+ // This is a small performance optimization. Still only the 1st call of
+ // reportFinish() will take effect.
+ return;
+ }
+ reportFinish();
}
@Override
@@ -563,7 +566,7 @@
public String toString() {
return "ControlledInputConnectionWrapper{"
+ "connection=" + getInputConnection()
- + " mActive=" + mActive
+ + " finished=" + isFinished()
+ " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
+ "}";
}
@@ -837,7 +840,6 @@
throw e.rethrowFromSystemServer();
}
}
- notifyInputConnectionFinished();
mServedView = null;
mCompletions = null;
mServedConnecting = false;
@@ -845,48 +847,6 @@
}
}
- /**
- * Notifies the served view that the current InputConnection will no longer be used.
- */
- private void notifyInputConnectionFinished() {
- if (mServedView == null || mServedInputConnectionWrapper == null) {
- return;
- }
- final InputConnection inputConnection = mServedInputConnectionWrapper.getInputConnection();
- if (inputConnection == null) {
- return;
- }
- // We need to tell the previously served view that it is no
- // longer the input target, so it can reset its state. Schedule
- // this call on its window's Handler so it will be on the correct
- // thread and outside of our lock.
- ViewRootImpl viewRootImpl = mServedView.getViewRootImpl();
- if (viewRootImpl != null) {
- // This will result in a call to reportFinishInputConnection() below.
- viewRootImpl.dispatchFinishInputConnection(inputConnection);
- }
- }
-
- /**
- * Called from the FINISH_INPUT_CONNECTION message above.
- * @hide
- */
- public void reportFinishInputConnection(InputConnection ic) {
- final InputConnection currentConnection;
- if (mServedInputConnectionWrapper == null) {
- currentConnection = null;
- } else {
- currentConnection = mServedInputConnectionWrapper.getInputConnection();
- }
- if (currentConnection != ic) {
- ic.finishComposingText();
- // To avoid modifying the public InputConnection interface
- if (ic instanceof BaseInputConnection) {
- ((BaseInputConnection) ic).reportFinish();
- }
- }
- }
-
public void displayCompletions(View view, CompletionInfo[] completions) {
checkFocus();
synchronized (mH) {
@@ -1252,8 +1212,10 @@
// Hook 'em up and let 'er rip.
mCurrentTextBoxAttribute = tba;
mServedConnecting = false;
- // Notify the served view that its previous input connection is finished
- notifyInputConnectionFinished();
+ if (mServedInputConnectionWrapper != null) {
+ mServedInputConnectionWrapper.deactivate();
+ mServedInputConnectionWrapper = null;
+ }
ControlledInputConnectionWrapper servedContext;
final int missingMethodFlags;
if (ic != null) {
@@ -1278,9 +1240,6 @@
servedContext = null;
missingMethodFlags = 0;
}
- if (mServedInputConnectionWrapper != null) {
- mServedInputConnectionWrapper.deactivate();
- }
mServedInputConnectionWrapper = servedContext;
try {
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index ed4722d..2a9264d 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -21,7 +21,6 @@
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Slog;
-import android.text.TextUtils;
import com.android.internal.util.Preconditions;
@@ -140,14 +139,14 @@
}
public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
- int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
+ int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException {
dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
- null /*outputPath*/, dexFlags, volumeUuid, useProfiles);
+ null /*outputPath*/, dexFlags, compilerFilter, volumeUuid);
}
public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
- int dexoptNeeded, String outputPath, int dexFlags, String volumeUuid,
- boolean useProfiles) throws InstallerException {
+ int dexoptNeeded, String outputPath, int dexFlags, String compilerFilter,
+ String volumeUuid) throws InstallerException {
execute("dexopt",
apkPath,
uid,
@@ -156,8 +155,27 @@
dexoptNeeded,
outputPath,
dexFlags,
- volumeUuid,
- useProfiles ? '1' : '0');
+ compilerFilter,
+ volumeUuid);
+ }
+
+ public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
+ String rawReply = executeForResult("merge_profiles", uid, pkgName);
+ if (rawReply == null) {
+ throw new IllegalStateException("Unexpected null reply");
+ }
+ final String res[] = rawReply.split(" ");
+
+ if ((res == null) || (res.length != 2)) {
+ throw new InstallerException("Invalid size result: " + rawReply);
+ }
+
+ // Just as a sanity check. Anything != "true" will be interpreted as false by parseBoolean.
+ if (!res[1].equals("true") && !res[1].equals("false")) {
+ throw new InstallerException("Invalid boolean result: " + rawReply);
+ }
+
+ return Boolean.parseBoolean(res[1]);
}
private boolean connect() {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index b658f87..5980ab6 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -501,12 +501,14 @@
for (String classPathElement : classPathElements) {
// System server is fully AOTed and never profiled
// for profile guided compilation.
+ // TODO: Make this configurable between INTERPRET_ONLY, SPEED, SPACE and EVERYTHING?
final int dexoptNeeded = DexFile.getDexOptNeeded(
- classPathElement, instructionSet, DexFile.COMPILATION_TYPE_FULL);
+ classPathElement, instructionSet, "speed",
+ false /* newProfile */);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
- dexoptNeeded, 0 /*dexFlags*/, null /*volumeUuid*/,
- false /*useProfiles*/);
+ dexoptNeeded, 0 /*dexFlags*/, "speed",
+ null /*volumeUuid*/);
}
}
} catch (IOException | InstallerException e) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index fbd8fb5..bdf2a21 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -2070,10 +2070,10 @@
* @hide
*/
@Override
- public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list) {
+ public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list, int deviceId) {
final PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
if (!mWindow.isDestroyed() && st != null && mWindow.getCallback() != null) {
- mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu);
+ mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu, deviceId);
}
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 64c5b8d..b243cac 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -65,7 +65,7 @@
void cancelPreloadRecentApps();
void showScreenPinningRequest();
- void toggleKeyboardShortcutsMenu();
+ void toggleKeyboardShortcutsMenu(int deviceId);
/**
* Notifies the status bar that an app transition is pending to delay applying some flags with
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 8acf5d3..ee3f937 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -71,7 +71,7 @@
void preloadRecentApps();
void cancelPreloadRecentApps();
- void toggleKeyboardShortcutsMenu();
+ void toggleKeyboardShortcutsMenu(int deviceId);
/**
* Notifies the status bar that an app transition is pending to delay applying some flags with
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index ab918c8..530e00c 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -111,6 +111,6 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
}
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index afa1554..02b9db3 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -16,6 +16,8 @@
package com.android.internal.view;
+import com.android.internal.annotations.GuardedBy;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
@@ -25,6 +27,7 @@
import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedTextRequest;
@@ -58,12 +61,16 @@
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
private static final int DO_CLEAR_META_KEY_STATES = 130;
private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
+ private static final int DO_REPORT_FINISH = 150;
@NonNull
private final WeakReference<InputConnection> mInputConnection;
private Looper mMainLooper;
private Handler mH;
+ private Object mLock = new Object();
+ @GuardedBy("mLock")
+ private boolean mFinished = false;
static class SomeArgs {
Object arg1;
@@ -94,6 +101,12 @@
return mInputConnection.get();
}
+ protected boolean isFinished() {
+ synchronized (mLock) {
+ return mFinished;
+ }
+ }
+
abstract protected boolean isActive();
/**
@@ -206,6 +219,10 @@
seq, callback));
}
+ public void reportFinish() {
+ dispatchMessage(obtainMessage(DO_REPORT_FINISH));
+ }
+
void dispatchMessage(Message msg) {
// If we are calling this from the main thread, then we can call
// right through. Otherwise, we need to send the message to the
@@ -218,7 +235,7 @@
mH.sendMessage(msg);
}
-
+
void executeMessage(Message msg) {
switch (msg.what) {
case DO_GET_TEXT_AFTER_CURSOR: {
@@ -481,6 +498,36 @@
}
return;
}
+ case DO_REPORT_FINISH: {
+ // Note that we do not need to worry about race condition here, because 1) mFinished
+ // is updated only inside this block, and 2) the code here is running on a Handler
+ // hence we assume multiple DO_REPORT_FINISH messages will not be handled at the
+ // same time.
+ if (isFinished()) {
+ return;
+ }
+ try {
+ InputConnection ic = mInputConnection.get();
+ // Note we do NOT check isActive() here, because this is safe
+ // for an IME to call at any time, and we need to allow it
+ // through to clean up our state after the IME has switched to
+ // another client.
+ if (ic == null) {
+ return;
+ }
+ ic.finishComposingText();
+ // TODO: Make reportFinish() public method of InputConnection to remove this
+ // check.
+ if (ic instanceof BaseInputConnection) {
+ ((BaseInputConnection) ic).reportFinish();
+ }
+ } finally {
+ synchronized (mLock) {
+ mFinished = true;
+ }
+ }
+ return;
+ }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index f211ff2..a96b5a0 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -83,8 +83,11 @@
return false;
}
+ /**
+ * @hide
+ */
@Override
- protected void reportFinish() {
+ public void reportFinish() {
super.reportFinish();
synchronized(this) {
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 2998c99..ab393f2 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -232,12 +232,6 @@
obj->addPath(*src, *matrix);
}
- static void offset__FFPath(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy, jlong dstHandle) {
- SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
- obj->offset(dx, dy, dst);
- }
-
static void offset__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->offset(dx, dy);
@@ -508,7 +502,6 @@
{"native_addPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF},
{"native_addPath","(JJ)V", (void*) SkPathGlue::addPath__Path},
{"native_addPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix},
- {"native_offset","(JFFJ)V", (void*) SkPathGlue::offset__FFPath},
{"native_offset","(JFF)V", (void*) SkPathGlue::offset__FF},
{"native_setLastPoint","(JFF)V", (void*) SkPathGlue::setLastPoint},
{"native_transform","(JJJ)V", (void*) SkPathGlue::transform__MatrixPath},
diff --git a/core/tests/coretests/src/android/graphics/PathOffsetTest.java b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
new file mode 100644
index 0000000..950f873
--- /dev/null
+++ b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 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.graphics;
+
+
+import android.graphics.Bitmap.Config;
+import android.graphics.Path.Direction;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class PathOffsetTest {
+
+ private static final int SQUARE = 10;
+ private static final int WIDTH = 100;
+ private static final int HEIGHT = 100;
+ private static final int START_X = 10;
+ private static final int START_Y = 20;
+ private static final int OFFSET_X = 30;
+ private static final int OFFSET_Y = 40;
+
+ @Test
+ @SmallTest
+ public void testPathOffset() {
+ Path actualPath = new Path();
+ actualPath.addRect(START_X, START_Y, START_X + SQUARE, START_Y + SQUARE, Direction.CW);
+ assertTrue(actualPath.isSimplePath);
+ actualPath.offset(OFFSET_X, OFFSET_Y);
+ assertTrue(actualPath.isSimplePath);
+
+ Path expectedPath = new Path();
+ expectedPath.addRect(START_X + OFFSET_X, START_Y + OFFSET_Y, START_X + OFFSET_X + SQUARE,
+ START_Y + OFFSET_Y + SQUARE, Direction.CW);
+
+ assertPaths(actualPath, expectedPath);
+ }
+
+ @Test
+ @SmallTest
+ public void testPathOffsetWithDestination() {
+ Path initialPath = new Path();
+ initialPath.addRect(START_X, START_Y, START_X + SQUARE, START_Y + SQUARE, Direction.CW);
+ Path actualPath = new Path();
+ assertTrue(initialPath.isSimplePath);
+ assertTrue(actualPath.isSimplePath);
+ initialPath.offset(OFFSET_X, OFFSET_Y, actualPath);
+ assertTrue(actualPath.isSimplePath);
+
+ Path expectedPath = new Path();
+ expectedPath.addRect(START_X + OFFSET_X, START_Y + OFFSET_Y, START_X + OFFSET_X + SQUARE,
+ START_Y + OFFSET_Y + SQUARE, Direction.CW);
+
+ assertPaths(actualPath, expectedPath);
+ }
+
+ private static void assertPaths(Path actual, Path expected) {
+ Bitmap actualBitmap = drawAndGetBitmap(actual);
+ Bitmap expectedBitmap = drawAndGetBitmap(expected);
+ assertTrue(actualBitmap.sameAs(expectedBitmap));
+ }
+
+ private static Bitmap drawAndGetBitmap(Path path) {
+ Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Config.ARGB_8888);
+ bitmap.eraseColor(Color.BLACK);
+ Paint paint = new Paint();
+ paint.setColor(Color.RED);
+ Canvas canvas = new Canvas(bitmap);
+ canvas.drawPath(path, paint);
+ return bitmap;
+ }
+
+}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index d554a50..cbed96c 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -20,6 +20,8 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.text.Layout.Alignment;
import static android.text.Layout.Alignment.*;
+import android.text.TextPaint;
+import android.text.method.EditorState;
import android.util.Log;
import junit.framework.TestCase;
@@ -33,6 +35,10 @@
* @Suppress
*/
public class StaticLayoutTest extends TestCase {
+ private static final int DEFAULT_OUTER_WIDTH = 150;
+ private static final Alignment DEFAULT_ALIGN = Alignment.ALIGN_CENTER;
+ private static final float SPACE_MULTI = 1.0f;
+ private static final float SPACE_ADD = 0.0f;
/**
* Basic test showing expected behavior and relationship between font
@@ -321,4 +327,91 @@
assertEquals(topPad, l.getTopPadding());
assertEquals(botPad, l.getBottomPadding());
}
+
+ private void moveCursorToRightCursorableOffset(EditorState state, TextPaint paint) {
+ assertEquals("The editor has selection", state.mSelectionStart, state.mSelectionEnd);
+ final Layout layout = builder().setText(state.mText.toString()).setPaint(paint).build();
+ final int newOffset = layout.getOffsetToRightOf(state.mSelectionStart);
+ state.mSelectionStart = state.mSelectionEnd = newOffset;
+ }
+
+ private void moveCursorToLeftCursorableOffset(EditorState state, TextPaint paint) {
+ assertEquals("The editor has selection", state.mSelectionStart, state.mSelectionEnd);
+ final Layout layout = builder().setText(state.mText.toString()).setPaint(paint).build();
+ final int newOffset = layout.getOffsetToLeftOf(state.mSelectionStart);
+ state.mSelectionStart = state.mSelectionEnd = newOffset;
+ }
+
+ /**
+ * Tests for keycap, variation selectors, flags are in CTS.
+ * See {@link android.text.cts.StaticLayoutTest}.
+ */
+ public void testEmojiOffset() {
+ EditorState state = new EditorState();
+ TextPaint paint = new TextPaint();
+
+ // Odd numbered regional indicator symbols.
+ // U+1F1E6 is REGIONAL INDICATOR SYMBOL LETTER A, U+1F1E8 is REGIONAL INDICATOR SYMBOL
+ // LETTER C.
+ state.setByString("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6");
+ moveCursorToRightCursorableOffset(state, paint);
+ state.setByString("U+1F1E6 U+1F1E8 | U+1F1E6 U+1F1E8 U+1F1E6");
+ moveCursorToRightCursorableOffset(state, paint);
+ state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 | U+1F1E6");
+ moveCursorToRightCursorableOffset(state, paint);
+ state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6 |");
+ moveCursorToRightCursorableOffset(state, paint);
+ state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6 |");
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 | U+1F1E6");
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.setByString("U+1F1E6 U+1F1E8 | U+1F1E6 U+1F1E8 U+1F1E6");
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.setByString("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6");
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.setByString("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6");
+ moveCursorToLeftCursorableOffset(state, paint);
+
+ // Zero width sequence
+ final String zwjSequence = "U+1F468 U+200D U+2764 U+FE0F U+200D U+1F468";
+ state.setByString("| " + zwjSequence + " " + zwjSequence + " " + zwjSequence);
+ moveCursorToRightCursorableOffset(state, paint);
+ state.assertEquals(zwjSequence + " | " + zwjSequence + " " + zwjSequence);
+ moveCursorToRightCursorableOffset(state, paint);
+ state.assertEquals(zwjSequence + " " + zwjSequence + " | " + zwjSequence);
+ moveCursorToRightCursorableOffset(state, paint);
+ state.assertEquals(zwjSequence + " " + zwjSequence + " " + zwjSequence + " |");
+ moveCursorToRightCursorableOffset(state, paint);
+ state.assertEquals(zwjSequence + " " + zwjSequence + " " + zwjSequence + " |");
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.assertEquals(zwjSequence + " " + zwjSequence + " | " + zwjSequence);
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.assertEquals(zwjSequence + " | " + zwjSequence + " " + zwjSequence);
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.assertEquals("| " + zwjSequence + " " + zwjSequence + " " + zwjSequence);
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.assertEquals("| " + zwjSequence + " " + zwjSequence + " " + zwjSequence);
+ moveCursorToLeftCursorableOffset(state, paint);
+
+ // Emoji modifiers
+ // U+261D is WHITE UP POINTING INDEX, U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
+ state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
+ moveCursorToRightCursorableOffset(state, paint);
+ state.setByString("U+261D U+1F3FB | U+261D U+1F3FB U+261D U+1F3FB");
+ moveCursorToRightCursorableOffset(state, paint);
+ state.setByString("U+261D U+1F3FB U+261D U+1F3FB | U+261D U+1F3FB");
+ moveCursorToRightCursorableOffset(state, paint);
+ state.setByString("U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB |");
+ moveCursorToRightCursorableOffset(state, paint);
+ state.setByString("U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB |");
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.setByString("U+261D U+1F3FB U+261D U+1F3FB | U+261D U+1F3FB");
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.setByString("U+261D U+1F3FB | U+261D U+1F3FB U+261D U+1F3FB");
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
+ moveCursorToLeftCursorableOffset(state, paint);
+ state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
+ moveCursorToLeftCursorableOffset(state, paint);
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 1966313..7519627 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -291,9 +291,6 @@
@Override
public void onActionModeFinished(ActionMode mode) {}
-
- @Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {}
}
private static final class MockActionModeCallback implements ActionMode.Callback {
diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
index 46db371..a745d00 100644
--- a/docs/html/guide/topics/data/data-storage.jd
+++ b/docs/html/guide/topics/data/data-storage.jd
@@ -178,6 +178,20 @@
android.content.Context#MODE_WORLD_READABLE}, and {@link
android.content.Context#MODE_WORLD_WRITEABLE}.</p>
+<p class="note"><strong>Note:</strong> The constants {@link
+android.content.Context#MODE_WORLD_READABLE} and {@link
+android.content.Context#MODE_WORLD_WRITEABLE} have been deprecated since API level 17.
+Starting from Android N their use will result in a {@link java.lang.SecurityException}
+to be thrown.
+This means that apps targeting Android N and higher
+cannot share private files by name, and attempts to share a "file://" URI will result in a
+{@link android.os.FileUriExposedException} to be thrown. If your app needs to share private
+files with other apps, it may use a {@link android.support.v4.content.FileProvider} with
+the {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}.
+See also <a
+href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.
+</p>
+
<p>To read a file from internal storage:</p>
<ol>
diff --git a/docs/html/training/basics/data-storage/files.jd b/docs/html/training/basics/data-storage/files.jd
index 49a9169..58a1d5f 100644
--- a/docs/html/training/basics/data-storage/files.jd
+++ b/docs/html/training/basics/data-storage/files.jd
@@ -59,7 +59,7 @@
<p><b>Internal storage:</b></p>
<ul>
<li>It's always available.</li>
-<li>Files saved here are accessible by only your app by default.</li>
+<li>Files saved here are accessible by only your app.</li>
<li>When the user uninstalls your app, the system removes all your app's files from
internal storage.</li>
</ul>
@@ -83,6 +83,12 @@
with other apps or allow the user to access with a computer.</p>
</div>
+<p class="note">
+<strong>Note:</strong> Before Android N, internal files could be made accessible to other
+apps by means of relaxing file system permissions. This is no longer the case. If you wish
+to make the content of a private file accessible to other apps, your app may use the
+{@link android.support.v4.content.FileProvider}. See <a
+href="{@docRoot}training/secure-file-sharing/index.html">Sharing Files</a>.</p>
<p class="note" style="clear:both">
<strong>Tip:</strong> Although apps are installed onto the internal storage by
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 5efc00c..b6a209f 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -45,15 +45,11 @@
int outlineLeft, int outlineTop, int outlineRight, int outlineBottom,
float outlineRadius, int outlineAlpha, float decodeScale) {
opticalRect = new Rect(opticalLeft, opticalTop, opticalRight, opticalBottom);
- outlineRect = new Rect(outlineLeft, outlineTop, outlineRight, outlineBottom);
+ opticalRect.scale(decodeScale);
- if (decodeScale != 1.0f) {
- // if bitmap was scaled when decoded, scale the insets from the metadata values
- opticalRect.scale(decodeScale);
+ outlineRect = scaleInsets(outlineLeft, outlineTop,
+ outlineRight, outlineBottom, decodeScale);
- // round inward while scaling outline, as the outline should always be conservative
- outlineRect.scaleRoundIn(decodeScale);
- }
this.outlineRadius = outlineRadius * decodeScale;
this.outlineAlpha = outlineAlpha / 255.0f;
}
@@ -62,6 +58,23 @@
public final Rect outlineRect;
public final float outlineRadius;
public final float outlineAlpha;
+
+ /**
+ * Scales up the rect by the given scale, ceiling values, so actual outline Rect
+ * grows toward the inside.
+ */
+ public static Rect scaleInsets(int left, int top, int right, int bottom, float scale) {
+ if (scale == 1.0f) {
+ return new Rect(left, top, right, bottom);
+ }
+
+ Rect result = new Rect();
+ result.left = (int) Math.ceil(left * scale);
+ result.top = (int) Math.ceil(top * scale);
+ result.right = (int) Math.ceil(right * scale);
+ result.bottom = (int) Math.ceil(bottom * scale);
+ return result;
+ }
}
private final Bitmap mBitmap;
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index da3deff..de391af 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -16,6 +16,9 @@
package android.graphics;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
/**
* The Path class encapsulates compound (multiple contour) geometric paths
* consisting of straight line segments, quadratic curves, and cubic curves.
@@ -91,10 +94,22 @@
/** Replace the contents of this with the contents of src.
*/
- public void set(Path src) {
- if (this != src) {
- isSimplePath = src.isSimplePath;
- native_set(mNativePath, src.mNativePath);
+ public void set(@NonNull Path src) {
+ if (this == src) {
+ return;
+ }
+ isSimplePath = src.isSimplePath;
+ native_set(mNativePath, src.mNativePath);
+ if (!isSimplePath) {
+ return;
+ }
+
+ if (rects != null && src.rects != null) {
+ rects.set(src.rects);
+ } else if (rects != null && src.rects == null) {
+ rects.setEmpty();
+ } else if (src.rects != null) {
+ rects = new Region(src.rects);
}
}
@@ -685,13 +700,13 @@
* @param dst The translated path is written here. If this is null, then
* the original path is modified.
*/
- public void offset(float dx, float dy, Path dst) {
- long dstNative = 0;
+ public void offset(float dx, float dy, @Nullable Path dst) {
if (dst != null) {
- dstNative = dst.mNativePath;
- dst.isSimplePath = false;
+ dst.set(this);
+ } else {
+ dst = this;
}
- native_offset(mNativePath, dx, dy, dstNative);
+ dst.offset(dx, dy);
}
/**
@@ -701,7 +716,15 @@
* @param dy The amount in the Y direction to offset the entire path
*/
public void offset(float dx, float dy) {
- isSimplePath = false;
+ if (isSimplePath && rects == null) {
+ // nothing to offset
+ return;
+ }
+ if (isSimplePath && dx == Math.rint(dx) && dy == Math.rint(dy)) {
+ rects.translate((int) dx, (int) dy);
+ } else {
+ isSimplePath = false;
+ }
native_offset(mNativePath, dx, dy);
}
@@ -823,7 +846,6 @@
private static native void native_addPath(long nPath, long src, float dx, float dy);
private static native void native_addPath(long nPath, long src);
private static native void native_addPath(long nPath, long src, long matrix);
- private static native void native_offset(long nPath, float dx, float dy, long dst_path);
private static native void native_offset(long nPath, float dx, float dy);
private static native void native_setLastPoint(long nPath, float dx, float dy);
private static native void native_transform(long nPath, long matrix, long dst_path);
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 93ef3f0..7f579a2 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -647,16 +647,4 @@
}
}
- /**
- * Scales up the rect by the given scale, rounding values toward the inside.
- * @hide
- */
- public void scaleRoundIn(float scale) {
- if (scale != 1.0f) {
- left = (int) Math.ceil(left * scale);
- top = (int) Math.ceil(top * scale);
- right = (int) Math.floor(right * scale);
- bottom = (int) Math.floor(bottom * scale);
- }
- }
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 5b1cc80..d962385 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -706,18 +706,9 @@
final NinePatch.InsetStruct insets = ninePatch.getBitmap().getNinePatchInsets();
if (insets != null) {
- if (mOutlineInsets == null) {
- mOutlineInsets = new Rect();
- }
- final Rect outlineInsets = insets.outlineRect;
- mOutlineInsets.left = Drawable.scaleFromDensity(
- outlineInsets.left, sourceDensity, targetDensity, false);
- mOutlineInsets.top = Drawable.scaleFromDensity(
- outlineInsets.top, sourceDensity, targetDensity, false);
- mOutlineInsets.right = Drawable.scaleFromDensity(
- outlineInsets.right, sourceDensity, targetDensity, false);
- mOutlineInsets.bottom = Drawable.scaleFromDensity(
- outlineInsets.bottom, sourceDensity, targetDensity, false);
+ Rect outlineRect = insets.outlineRect;
+ mOutlineInsets = NinePatch.InsetStruct.scaleInsets(outlineRect.left, outlineRect.top,
+ outlineRect.right, outlineRect.bottom, targetDensity / (float) sourceDensity);
mOutlineRadius = Drawable.scaleFromDensity(
insets.outlineRadius, sourceDensity, targetDensity);
} else {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
index 156f45f6..be390ff 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
@@ -193,12 +193,12 @@
putSignatureImpl("NONEwithECDSA",
PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$NONE");
- putSignatureImpl("ECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1");
- put("Alg.Alias.Signature.SHA1withECDSA", "ECDSA");
- put("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA");
+ putSignatureImpl("SHA1withECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1");
+ put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA");
+ put("Alg.Alias.Signature.ECDSAwithSHA1", "SHA1withECDSA");
// iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA1(1)
- put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
- put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "ECDSA");
+ put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "SHA1withECDSA");
// iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
putSignatureImpl("SHA224withECDSA",
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index a5b3179..4bf0852 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1888,6 +1888,19 @@
for (ExifTag tag : IFD_POINTER_TAGS) {
setAttribute(tag.name, null);
}
+ // Remove old thumbnail data
+ setAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name, null);
+ setAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, null);
+
+ // Remove null value tags.
+ for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
+ for (Object obj : mAttributes[hint].entrySet().toArray()) {
+ Map.Entry entry = (Map.Entry) obj;
+ if (entry.getValue() == null) {
+ mAttributes[hint].remove(entry.getKey());
+ }
+ }
+ }
// Add IFD pointer tags. The next offset of primary image TIFF IFD will have thumbnail IFD
// offset when there is one or more tags in the thumbnail IFD.
@@ -1900,25 +1913,12 @@
if (!mAttributes[IFD_GPS_HINT].isEmpty()) {
mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].name, "0");
}
- // Remove old thumbnail data
- setAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name, null);
- setAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, null);
if (mHasThumbnail) {
mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name, "0");
mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name,
String.valueOf(mThumbnailLength));
}
- // Remove null value tags.
- for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
- for (Object obj : mAttributes[hint].entrySet().toArray()) {
- Map.Entry entry = (Map.Entry) obj;
- if (entry.getValue() == null) {
- mAttributes[hint].remove(entry.getKey());
- }
- }
- }
-
// Calculate IFD group data area sizes. IFD group data area is assigned to save the entry
// value which has a bigger size than 4 bytes.
for (int i = 0; i < 5; ++i) {
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index be08385..14609b2 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -44,7 +44,7 @@
<activity
android:name=".LauncherActivity"
android:theme="@android:style/Theme.NoDisplay"
- android:icon="@drawable/ic_files_app"
+ android:icon="@mipmap/ic_launcher_download"
android:label="@string/downloads_label">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -55,7 +55,7 @@
<activity
android:name=".FilesActivity"
android:theme="@style/DocumentsTheme"
- android:icon="@drawable/ic_files_app"
+ android:icon="@mipmap/ic_launcher_download"
android:label="@string/downloads_label"
android:documentLaunchMode="intoExisting">
<intent-filter>
diff --git a/packages/DocumentsUI/res/color/item_root_primary_text.xml b/packages/DocumentsUI/res/color/item_root_primary_text.xml
index 551245f..a5a65b2 100644
--- a/packages/DocumentsUI/res/color/item_root_primary_text.xml
+++ b/packages/DocumentsUI/res/color/item_root_primary_text.xml
@@ -15,8 +15,8 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true" android:state_activated="true" android:color="?android:colorAccent" />
- <item android:state_focused="false" android:state_activated="true" android:color="?android:colorAccent" />
+ <item android:state_focused="true" android:state_activated="true" android:color="@color/root_activated_color" />
+ <item android:state_focused="false" android:state_activated="true" android:color="@color/root_activated_color" />
<item android:state_enabled="false" android:alpha="@*android:dimen/disabled_alpha_material_light" android:color="@*android:color/primary_text_default_material_light" />
<item android:color="@*android:color/primary_text_default_material_light" />
</selector>
diff --git a/packages/DocumentsUI/res/drawable/ic_files_app.xml b/packages/DocumentsUI/res/drawable/ic_files_app.xml
deleted file mode 100644
index 76e3ba6..0000000
--- a/packages/DocumentsUI/res/drawable/ic_files_app.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_launcher_download"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_launcher_download.png b/packages/DocumentsUI/res/mipmap-hdpi/ic_launcher_download.png
similarity index 100%
rename from packages/DocumentsUI/res/drawable-hdpi/ic_launcher_download.png
rename to packages/DocumentsUI/res/mipmap-hdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_launcher_download.png b/packages/DocumentsUI/res/mipmap-mdpi/ic_launcher_download.png
similarity index 100%
rename from packages/DocumentsUI/res/drawable-mdpi/ic_launcher_download.png
rename to packages/DocumentsUI/res/mipmap-mdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_launcher_download.png b/packages/DocumentsUI/res/mipmap-xhdpi/ic_launcher_download.png
similarity index 100%
rename from packages/DocumentsUI/res/drawable-xhdpi/ic_launcher_download.png
rename to packages/DocumentsUI/res/mipmap-xhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_launcher_download.png b/packages/DocumentsUI/res/mipmap-xxhdpi/ic_launcher_download.png
similarity index 100%
rename from packages/DocumentsUI/res/drawable-xxhdpi/ic_launcher_download.png
rename to packages/DocumentsUI/res/mipmap-xxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_launcher_download.png b/packages/DocumentsUI/res/mipmap-xxxhdpi/ic_launcher_download.png
similarity index 100%
rename from packages/DocumentsUI/res/drawable-xxxhdpi/ic_launcher_download.png
rename to packages/DocumentsUI/res/mipmap-xxxhdpi/ic_launcher_download.png
Binary files differ
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 04b7fee..51e04b6 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -16,6 +16,7 @@
<resources>
<color name="material_grey_400">#ffbdbdbd</color>
+ <color name="material_teal_700">#ff00796b</color>
<!-- This is the window background, but also the background for anything
else that needs to manually declare a background matching the "default"
@@ -36,6 +37,8 @@
<color name="item_doc_background_disabled">#fff4f4f4</color>
+ <color name="root_activated_color">@color/material_teal_700</color>
+
<!-- TODO: Would be nice to move this to a color-set, but not sure how to support animation -->
<color name="item_doc_background">#fffafafa</color>
<color name="item_doc_background_selected">#ffe0f2f1</color>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index b2fd9c4..062f2d1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -527,9 +527,13 @@
// Re-enable TalkBack for the toolbars, as they are no longer covered by action mode.
final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
- final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById(R.id.roots_toolbar);
toolbar.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
- rootsToolbar.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+
+ // This toolbar is not present in the fixed_layout
+ final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById(R.id.roots_toolbar);
+ if (rootsToolbar != null) {
+ rootsToolbar.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ }
}
@Override
@@ -544,13 +548,16 @@
// Hide the toolbars if action mode is enabled, so TalkBack doesn't navigate to
// these controls when using linear navigation.
final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
- final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById(
- R.id.roots_toolbar);
toolbar.setImportantForAccessibility(
View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
- rootsToolbar.setImportantForAccessibility(
- View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ // This toolbar is not present in the fixed_layout
+ final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById(
+ R.id.roots_toolbar);
+ if (rootsToolbar != null) {
+ rootsToolbar.setImportantForAccessibility(
+ View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ }
return true;
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
index 3536593..b816287 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -21,6 +21,7 @@
import android.content.ContextWrapper;
import android.database.Cursor;
import android.database.MatrixCursor;
+import android.database.MergeCursor;
import android.provider.DocumentsContract.Document;
import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver;
@@ -117,21 +118,25 @@
// Tests multiple authorities with clashing document IDs.
public void testModelIdIsUnique() {
- MatrixCursor cIn = new MatrixCursor(COLUMNS);
+ MatrixCursor cIn1 = new MatrixCursor(COLUMNS);
+ MatrixCursor cIn2 = new MatrixCursor(COLUMNS);
// Make two sets of items with the same IDs, under different authorities.
final String AUTHORITY0 = "auth0";
final String AUTHORITY1 = "auth1";
+
for (int i = 0; i < ITEM_COUNT; ++i) {
- MatrixCursor.RowBuilder row0 = cIn.newRow();
+ MatrixCursor.RowBuilder row0 = cIn1.newRow();
row0.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY0);
row0.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
- MatrixCursor.RowBuilder row1 = cIn.newRow();
+ MatrixCursor.RowBuilder row1 = cIn2.newRow();
row1.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY1);
row1.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
}
+ Cursor cIn = new MergeCursor(new Cursor[] { cIn1, cIn2 });
+
// Update the model, then make sure it contains all the expected items.
DirectoryResult r = new DirectoryResult();
r.cursor = cIn;
diff --git a/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml b/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml
deleted file mode 100644
index 7de4460..0000000
--- a/packages/SystemUI/res/anim/recents_from_search_launcher_enter.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-<!-- Recents Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="normal">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
- android:duration="1"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
deleted file mode 100644
index 23cedf8..0000000
--- a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-<!-- Launcher Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="top">
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/recents_from_launcher_exit_interpolator"
- android:duration="133"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
deleted file mode 100644
index 657b216..0000000
--- a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-<!-- Launcher Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="normal">
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/recents_to_launcher_enter_interpolator"
- android:duration="133"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
deleted file mode 100644
index 5182cab2..0000000
--- a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-<!-- Recents Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="top">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
- android:duration="1"/>
-</set>
diff --git a/packages/SystemUI/res/layout/recents_history.xml b/packages/SystemUI/res/layout/recents_history.xml
deleted file mode 100644
index dc2da72..0000000
--- a/packages/SystemUI/res/layout/recents_history.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<com.android.systemui.recents.history.RecentsHistoryView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <android.support.v7.widget.RecyclerView
- android:id="@+id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-</com.android.systemui.recents.history.RecentsHistoryView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history_clear_all_button.xml b/packages/SystemUI/res/layout/recents_history_clear_all_button.xml
deleted file mode 100644
index 05f0979..0000000
--- a/packages/SystemUI/res/layout/recents_history_clear_all_button.xml
+++ /dev/null
@@ -1,37 +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.
--->
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:paddingTop="14dp"
- android:paddingBottom="14dp"
- android:drawableStart="@drawable/recents_dismiss_all_history"
- android:contentDescription="@string/recents_history_clear_all_button_label"
- android:textSize="14sp"
- android:textColor="#FFFFFF"
- android:textAllCaps="true"
- android:shadowColor="#99000000"
- android:shadowDx="0"
- android:shadowDy="2"
- android:shadowRadius="5"
- android:fontFamily="sans-serif-medium"
- android:background="?android:selectableItemBackground"
- android:visibility="invisible" />
diff --git a/packages/SystemUI/res/layout/recents_history_date.xml b/packages/SystemUI/res/layout/recents_history_date.xml
deleted file mode 100644
index 13c7dbe..0000000
--- a/packages/SystemUI/res/layout/recents_history_date.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:paddingTop="12dp"
- android:paddingBottom="12dp"
- android:gravity="start"
- android:textSize="14sp"
- android:textColor="#009688"
- android:textAllCaps="true"
- android:fontFamily="sans-serif-medium"
- android:background="?android:selectableItemBackground"
- android:alpha="1" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history_task.xml b/packages/SystemUI/res/layout/recents_history_task.xml
deleted file mode 100644
index e92c24a..0000000
--- a/packages/SystemUI/res/layout/recents_history_task.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:orientation="horizontal"
- android:clickable="true"
- android:focusable="true"
- android:background="?android:selectableItemBackground">
- <ImageView
- android:id="@+id/icon"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_gravity="center"
- android:layout_marginStart="4dp"
- android:layout_marginEnd="12dp" />
- <TextView
- android:id="@+id/description"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:layout_gravity="end"
- android:paddingStart="16dp"
- android:gravity="start|center_vertical"
- android:textSize="14sp"
- android:textColor="#FFFFFF"
- android:fontFamily="sans-serif-medium" />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history_button.xml b/packages/SystemUI/res/layout/recents_stack_action_button.xml
similarity index 95%
rename from packages/SystemUI/res/layout/recents_history_button.xml
rename to packages/SystemUI/res/layout/recents_stack_action_button.xml
index 538bad1..8783261 100644
--- a/packages/SystemUI/res/layout/recents_history_button.xml
+++ b/packages/SystemUI/res/layout/recents_stack_action_button.xml
@@ -23,7 +23,7 @@
android:paddingEnd="14dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
- android:text="@string/recents_history_button_label"
+ android:text="@string/recents_stack_action_button_label"
android:textSize="14sp"
android:textColor="#FFFFFF"
android:textAllCaps="true"
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index fa65758..59a2bd9 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -18,7 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_view_bar"
android:layout_width="match_parent"
- android:layout_height="@dimen/recents_task_bar_height"
+ android:layout_height="@dimen/recents_task_view_header_height"
android:layout_gravity="top|center_horizontal">
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/icon"
@@ -28,8 +28,8 @@
android:layout_gravity="center_vertical|start"
android:paddingTop="8dp"
android:paddingBottom="8dp"
- android:paddingStart="12dp"
- android:paddingEnd="16dp" />
+ android:paddingStart="16dp"
+ android:paddingEnd="12dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -71,7 +71,7 @@
android:layout_height="@dimen/recents_task_view_header_button_height"
android:layout_marginEnd="@dimen/recents_task_view_header_button_width"
android:layout_gravity="center_vertical|end"
- android:padding="13dp"
+ android:padding="16dp"
android:src="@drawable/star"
android:background="?android:selectableItemBackground"
android:alpha="0"
@@ -81,7 +81,7 @@
android:layout_width="@dimen/recents_task_view_header_button_width"
android:layout_height="@dimen/recents_task_view_header_button_height"
android:layout_gravity="center_vertical|end"
- android:padding="13dp"
+ android:padding="16dp"
android:src="@drawable/recents_dismiss_light"
android:background="?android:selectableItemBackground"
android:alpha="0"
diff --git a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
index 1becdab..433e69e 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
@@ -25,8 +25,8 @@
android:layout_gravity="center_vertical|start"
android:paddingTop="8dp"
android:paddingBottom="8dp"
- android:paddingStart="12dp"
- android:paddingEnd="16dp" />
+ android:paddingStart="16dp"
+ android:paddingEnd="12dp" />
<TextView
android:id="@+id/app_title"
android:layout_width="match_parent"
@@ -45,9 +45,9 @@
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/app_info"
android:layout_width="@dimen/recents_task_view_header_button_width"
- android:layout_height="@dimen/recents_task_bar_height"
+ android:layout_height="@dimen/recents_task_view_header_button_height"
android:layout_gravity="center_vertical|end"
- android:padding="13dp"
+ android:padding="16dp"
android:background="?android:selectableItemBackground"
android:src="@drawable/recents_info_light" />
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 43e7bac..f7e2344 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -28,14 +28,4 @@
<!-- We have only space for one notification on phone landscape layouts. -->
<integer name="keyguard_max_notification_count">1</integer>
-
- <!-- Recents: The relative range of visible tasks from the current scroll position
- while the stack is focused. -->
- <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item>
- <item name="recents_layout_focused_range_max" format="float" type="integer">2</item>
-
- <!-- Recents: The relative range of visible tasks from the current scroll position
- while the stack is not focused. -->
- <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item>
- <item name="recents_layout_unfocused_range_max" format="float" type="integer">1.5</item>
</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 585984c..26a81c8 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -22,9 +22,6 @@
<!-- Standard notification gravity -->
<integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
- <!-- The size of the initial peek area at the bottom of the stack (above the nav bar). -->
- <dimen name="recents_initial_bottom_peek_size">@dimen/recents_task_bar_height</dimen>
-
<dimen name="docked_divider_handle_width">2dp</dimen>
<dimen name="docked_divider_handle_height">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index db4da10..1f6bbd3 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -33,16 +33,6 @@
<!-- Set to true to enable the user switcher on the keyguard. -->
<bool name="config_keyguardUserSwitcher">true</bool>
- <!-- Recents: The relative range of visible tasks from the current scroll position
- while the stack is focused. -->
- <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item>
- <item name="recents_layout_focused_range_max" format="float" type="integer">3</item>
-
- <!-- Recents: The relative range of visible tasks from the current scroll position
- while the stack is not focused. -->
- <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item>
- <item name="recents_layout_unfocused_range_max" format="float" type="integer">2.5</item>
-
<!-- Nav bar button default ordering/layout -->
<string name="config_navBarLayout" translatable="false">space;back,home,recent;menu_ime</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 66963c4..a2010be 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -96,15 +96,6 @@
<dimen name="qs_expand_margin">0dp</dimen>
- <!-- The top padding for the task stack. -->
- <dimen name="recents_stack_top_padding">40dp</dimen>
-
- <!-- The size of the initial peek area at the bottom of the stack (above the nav bar). -->
- <dimen name="recents_initial_bottom_peek_size">100dp</dimen>
-
- <!-- The side padding for the task stack. -->
- <dimen name="recents_stack_left_right_padding">64dp</dimen>
-
<!-- Keyboard shortcuts helper -->
<dimen name="ksh_layout_width">488dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 8fe6be9..25e96c8 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -29,11 +29,6 @@
<!-- Bottom margin (from display edge) for status bar panels -->
<dimen name="panel_float">56dp</dimen>
- <!-- The radius of the rounded corners on a task view. -->
- <dimen name="recents_task_view_rounded_corners_radius">3dp</dimen>
- <!-- The radius of the rounded corners on a task view's shadow. -->
- <dimen name="recents_task_view_shadow_rounded_corners_radius">12dp</dimen>
-
<!-- The fraction of the screen height where the clock on the Keyguard has its center. The
max value is used when no notifications are displaying, and the min value is when the
highest possible number of notifications are showing. -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 076ba00..4f3db05 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -63,7 +63,7 @@
<!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
<color name="recents_task_bar_dark_text_color">#cc000000</color>
<!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
- <color name="recents_task_bar_light_icon_color">#ffeeeeee</color>
+ <color name="recents_task_bar_light_icon_color">#ccffffff</color>
<!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
<color name="recents_task_bar_dark_icon_color">#99000000</color>
<!-- The lock to task button background color. -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 4e1680d..622ae71 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -86,9 +86,6 @@
<bool name="config_dead_zone_flash">false</bool>
- <!-- Min alpha % that recent items will fade to while being dismissed -->
- <integer name="config_recent_item_min_alpha">3</integer>
-
<!-- Whether QuickSettings is in a phone landscape -->
<bool name="quick_settings_wide">false</bool>
@@ -165,9 +162,6 @@
<!-- The animation duration for subsequent scrolling the stack to a particular item. -->
<integer name="recents_subsequent_auto_advance_duration">1000</integer>
- <!-- The animation duration for entering and exiting the history. -->
- <integer name="recents_history_transition_duration">250</integer>
-
<!-- The delay to enforce between each alt-tab key press. -->
<integer name="recents_alt_tab_key_delay">200</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8cd2167..5417480 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -234,85 +234,6 @@
<!-- Default distance from each snap target that GlowPadView considers a "hit" -->
<dimen name="glowpadview_inner_radius">15dip</dimen>
- <!-- The size of the icon in the recents task view header. -->
- <dimen name="recents_task_view_header_icon_width">56dp</dimen>
- <dimen name="recents_task_view_header_icon_height">@dimen/recents_task_bar_height</dimen>
-
- <!-- The size of a button in the recents task view header. -->
- <dimen name="recents_task_view_header_button_width">@dimen/recents_task_bar_height</dimen>
- <dimen name="recents_task_view_header_button_height">@dimen/recents_task_bar_height</dimen>
-
- <!-- The radius of the rounded corners on a task view. -->
- <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
- <!-- The radius of the rounded corners on a task view's shadow. -->
- <dimen name="recents_task_view_shadow_rounded_corners_radius">12dp</dimen>
-
- <!-- The min translation in the Z index for the last task. -->
- <dimen name="recents_task_view_z_min">3dp</dimen>
-
- <!-- The max translation in the Z index for the last task. -->
- <dimen name="recents_task_view_z_max">24dp</dimen>
-
- <!-- The amount to translate when animating the removal of a task. -->
- <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
-
- <!-- The amount of highlight to make on each task view. -->
- <dimen name="recents_task_view_highlight">1dp</dimen>
-
- <!-- The amount to offset when animating into an affiliate group. -->
- <dimen name="recents_task_view_affiliate_group_enter_offset">32dp</dimen>
-
- <!-- The height of a task view bar. -->
- <dimen name="recents_task_bar_height">50dp</dimen>
-
- <!-- The height of the search bar space. -->
- <dimen name="recents_search_bar_space_height">64dp</dimen>
-
- <!-- The overscroll percentage allowed on the stack. -->
- <item name="recents_stack_overscroll_percentage" format="float" type="dimen">0.0875</item>
-
- <!-- The top padding for the task stack. -->
- <dimen name="recents_stack_top_padding">16dp</dimen>
-
- <!-- The side padding for the task stack. -->
- <dimen name="recents_stack_left_right_padding">16dp</dimen>
-
- <!-- The dimesnsions of the dismiss all recents button. -->
- <dimen name="recents_dismiss_all_button_size">48dp</dimen>
-
- <!-- The min alpha to apply to a task affiliation group color. -->
- <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
-
- <!-- The size of the lock-to-app button. -->
- <dimen name="recents_lock_to_app_size">56dp</dimen>
-
- <!-- The size of the lock-to-app button icon. -->
- <dimen name="recents_lock_to_app_icon_size">28dp</dimen>
-
- <!-- The amount to allow the stack to overscroll. -->
- <dimen name="recents_stack_overscroll">24dp</dimen>
-
- <!-- The size of the initial peek area at the top of the stack (below the status bar). -->
- <dimen name="recents_initial_top_peek_size">8dp</dimen>
-
- <!-- The size of the initial peek area at the bottom of the stack (above the nav bar). -->
- <dimen name="recents_initial_bottom_peek_size">100dp</dimen>
-
- <!-- The size of the peek area at the top of the stack (below the status bar). -->
- <dimen name="recents_layout_focused_top_peek_size">@dimen/recents_history_button_height</dimen>
-
- <!-- The size of each task peek area at the bottom of the stack (above the nav bar). -->
- <dimen name="recents_layout_focused_bottom_task_peek_size">16dp</dimen>
-
- <!-- The height of the history button. -->
- <dimen name="recents_history_button_height">48dp</dimen>
-
- <!-- The padding between freeform workspace tasks -->
- <dimen name="recents_freeform_workspace_task_padding">8dp</dimen>
-
- <!-- The offsets the tasks animate from when recents is launched while docking -->
- <dimen name="recents_task_view_launched_while_docking_offset">144dp</dimen>
-
<!-- Space reserved for the cards behind the top card in the bottom stack -->
<dimen name="bottom_stack_peek_amount">12dp</dimen>
@@ -639,4 +560,85 @@
<!-- Keyboard shortcuts helper -->
<dimen name="ksh_layout_width">@dimen/match_parent</dimen>
+
+<!-- Recents Layout -->
+
+ <!-- The amount to inset the stack, specifically at the top and the other sides. 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_layout_min_margin">16dp</dimen>
+ <dimen name="recents_layout_top_margin_phone">16dp</dimen>
+ <dimen name="recents_layout_top_margin_tablet">32dp</dimen>
+ <dimen name="recents_layout_top_margin_tablet_xlarge">40dp</dimen>
+ <dimen name="recents_layout_bottom_margin">16dp</dimen>
+ <dimen name="recents_layout_side_margin_phone">16dp</dimen>
+ <dimen name="recents_layout_side_margin_tablet">48dp</dimen>
+ <dimen name="recents_layout_side_margin_tablet_xlarge">64dp</dimen>
+
+ <!-- The height between the top margin and the top of the focused task. -->
+ <dimen name="recents_layout_top_peek_size">56dp</dimen>
+ <!-- The height between the bottom margin and the top of task in front of the focused task. -->
+ <dimen name="recents_layout_bottom_peek_size">56dp</dimen>
+
+ <!-- The offset from the top and bottom of the stack of the focused task. The bottom offset
+ will be additionally offset by the bottom system insets since it goes under the nav bar
+ in certain orientations. -->
+ <dimen name="recents_layout_initial_top_offset_phone_port">128dp</dimen>
+ <dimen name="recents_layout_initial_bottom_offset_phone_port">80dp</dimen>
+ <dimen name="recents_layout_initial_top_offset_phone_land">72dp</dimen>
+ <dimen name="recents_layout_initial_bottom_offset_phone_land">72dp</dimen>
+ <dimen name="recents_layout_initial_top_offset_tablet">160dp</dimen>
+ <dimen name="recents_layout_initial_bottom_offset_tablet">112dp</dimen>
+
+ <!-- The min/max translationZ for the tasks in the stack. -->
+ <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
+ display sizes. -->
+ <dimen name="recents_freeform_layout_bottom_margin">16dp</dimen>
+
+ <!-- The padding between each freeform task. -->
+ <dimen name="recents_freeform_layout_task_padding">8dp</dimen>
+
+<!-- Recents Views -->
+
+ <!-- The height of a task view bar. -->
+ <dimen name="recents_task_view_header_height">56dp</dimen>
+
+ <!-- The size of the icon in the recents task view header. -->
+ <dimen name="recents_task_view_header_icon_width">@dimen/recents_task_view_header_height</dimen>
+ <dimen name="recents_task_view_header_icon_height">@dimen/recents_task_view_header_height</dimen>
+
+ <!-- The size of a button in the recents task view header. -->
+ <dimen name="recents_task_view_header_button_width">@dimen/recents_task_view_header_height</dimen>
+ <dimen name="recents_task_view_header_button_height">@dimen/recents_task_view_header_height</dimen>
+
+ <!-- The radius of the rounded corners on a task view and its shadow (which can be larger
+ to create a softer corner effect. -->
+ <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
+ <dimen name="recents_task_view_shadow_rounded_corners_radius">6dp</dimen>
+
+ <!-- The amount of highlight to make on each task view. -->
+ <dimen name="recents_task_view_highlight">1dp</dimen>
+
+ <!-- The size of the lock-to-app button and its icon. -->
+ <dimen name="recents_lock_to_app_size">56dp</dimen>
+ <dimen name="recents_lock_to_app_icon_size">28dp</dimen>
+
+ <!-- The amount of overscroll allowed when flinging to the end of the stack. -->
+ <dimen name="recents_fling_overscroll_distance">24dp</dimen>
+
+ <!-- The min alpha to apply to a task affiliation group color. -->
+ <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
+
+ <!-- The amount to offset when animating into an affiliate group. -->
+ <dimen name="recents_task_stack_animation_affiliate_enter_offset">32dp</dimen>
+
+ <!-- The offsets the tasks animate from when recents is launched while docking -->
+ <dimen name="recents_task_stack_animation_launched_while_docking_offset">144dp</dimen>
+
+ <!-- The amount to translate when animating the removal of a task. -->
+ <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 091ba51..6f0f30d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -731,10 +731,8 @@
<string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
<!-- Recents: Launch disabled string. [CHAR LIMIT=NONE] -->
<string name="recents_launch_disabled_message"><xliff:g id="app" example="Calendar">%s</xliff:g> is disabled in safe-mode.</string>
- <!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
- <string name="recents_history_button_label">History</string>
- <!-- Recents: History clear all string. [CHAR LIMIT=NONE] -->
- <string name="recents_history_clear_all_button_label">Clear</string>
+ <!-- Recents: Stack action button string. [CHAR LIMIT=NONE] -->
+ <string name="recents_stack_action_button_label">Clear all</string>
<!-- Recents: Non-dockable task drag message. [CHAR LIMIT=NONE] -->
<string name="recents_drag_non_dockable_task_message">This app does not support multi-window</string>
<!-- Recents: Non-dockable task launch sub header. [CHAR LIMIT=NONE] -->
@@ -1329,6 +1327,59 @@
<!-- Summary of switch for battery saver [CHAR LIMIT=NONE] -->
<string name="battery_detail_switch_summary">Reduces performance and background data</string>
+ <!-- Name used for certain Keyboard keys on gamepads, e.g. "Button L1". -->
+ <string name="keyboard_key_button_template">Button <xliff:g id="name">%1$s</xliff:g></string>
+ <!-- Name used to refer to the "Home" key on the keyboard. -->
+ <string name="keyboard_key_home">Home</string>
+ <!-- Name used to refer to the "Back" key on the keyboard. -->
+ <string name="keyboard_key_back">Back</string>
+ <!-- Name used to refer to the "Up" arrow key on the keyboard. -->
+ <string name="keyboard_key_dpad_up">Up</string>
+ <!-- Name used to refer to the "Down" arrow key on the keyboard. -->
+ <string name="keyboard_key_dpad_down">Down</string>
+ <!-- Name used to refer to the "Left" arrow key on the keyboard. -->
+ <string name="keyboard_key_dpad_left">Left</string>
+ <!-- Name used to refer to the "Right" arrow key on the keyboard. -->
+ <string name="keyboard_key_dpad_right">Right</string>
+ <!-- Name used to refer to the "Center" arrow key on the keyboard. -->
+ <string name="keyboard_key_dpad_center">Center</string>
+ <!-- Name used to refer to the "Tab" key on the keyboard. -->
+ <string name="keyboard_key_tab">Tab</string>
+ <!-- Name used to refer to the "Space" key on the keyboard. -->
+ <string name="keyboard_key_space">Space</string>
+ <!-- Name used to refer to the "Enter" key on the keyboard. -->
+ <string name="keyboard_key_enter">Enter</string>
+ <!-- Name used to refer to the "Backspace" key on the keyboard. -->
+ <string name="keyboard_key_backspace">Backspace</string>
+ <!-- Name used to refer to the "Play/Pause" media key on the keyboard. -->
+ <string name="keyboard_key_media_play_pause">Play/Pause</string>
+ <!-- Name used to refer to the "Stop" media key on the keyboard. -->
+ <string name="keyboard_key_media_stop">Stop</string>
+ <!-- Name used to refer to the "Next" media key on the keyboard. -->
+ <string name="keyboard_key_media_next">Next</string>
+ <!-- Name used to refer to the "Previous" media key on the keyboard. -->
+ <string name="keyboard_key_media_previous">Previous</string>
+ <!-- Name used to refer to the "Rewind" media key on the keyboard. -->
+ <string name="keyboard_key_media_rewind">Rewind</string>
+ <!-- Name used to refer to the "Fast Forward" media key on the keyboard. -->
+ <string name="keyboard_key_media_fast_forward">Fast Forward</string>
+ <!-- Name used to refer to the "Page Up" key on the keyboard. -->
+ <string name="keyboard_key_page_up">Page Up</string>
+ <!-- Name used to refer to the "Page Down" key on the keyboard. -->
+ <string name="keyboard_key_page_down">Page Down</string>
+ <!-- Name used to refer to the "Delete" key on the keyboard. -->
+ <string name="keyboard_key_forward_del">Delete</string>
+ <!-- Name used to refer to the "Home" move key on the keyboard. -->
+ <string name="keyboard_key_move_home">Home</string>
+ <!-- Name used to refer to the "End" move key on the keyboard. -->
+ <string name="keyboard_key_move_end">End</string>
+ <!-- Name used to refer to the "Insert" key on the keyboard. -->
+ <string name="keyboard_key_insert">Insert</string>
+ <!-- Name used to refer to the "Num Lock" key on the keyboard. -->
+ <string name="keyboard_key_num_lock">Num Lock</string>
+ <!-- Name used to refer to keys on the numeric pad of the keyboard, e.g. "Numpad 9". -->
+ <string name="keyboard_key_numpad_template">Numpad <xliff:g id="name">%1$s</xliff:g></string>
+
<!-- User visible title for the system-wide keyboard shortcuts list. -->
<string name="keyboard_shortcut_group_system">System</string>
<!-- User visible title for the keyboard shortcut that takes the user to the home screen. -->
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 9f2745b..28ed84f 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -30,8 +30,6 @@
@Retention(RetentionPolicy.SOURCE)
@StringDef({
- Key.OVERVIEW_SEARCH_APP_WIDGET_ID,
- Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE,
Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
Key.DEBUG_MODE_ENABLED,
Key.HOTSPOT_TILE_LAST_USED,
@@ -51,8 +49,6 @@
Key.QS_NIGHT_ADDED,
})
public @interface Key {
- String OVERVIEW_SEARCH_APP_WIDGET_ID = "searchAppWidgetId";
- String OVERVIEW_SEARCH_APP_WIDGET_PACKAGE = "searchAppWidgetPackage";
String OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME = "OverviewLastStackTaskActiveTime";
String DEBUG_MODE_ENABLED = "debugModeEnabled";
String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed";
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 2e94bc7..0d75fdd 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -25,6 +25,8 @@
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.NotificationIconAreaController;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
@@ -75,6 +77,11 @@
return new ScrimController(scrimBehind, scrimInFront, headsUpScrim);
}
+ public NotificationIconAreaController createNotificationIconAreaController(Context context,
+ PhoneStatusBar phoneStatusBar) {
+ return new NotificationIconAreaController(context, phoneStatusBar);
+ }
+
public <T> T createInstance(Class<T> classType) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 070b395..003379f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -27,6 +27,7 @@
public static final int DismissSourceKeyboard = 0;
public static final int DismissSourceSwipeGesture = 1;
public static final int DismissSourceHeaderButton = 2;
+ @Deprecated
public static final int DismissSourceHistorySwipeGesture = 3;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index da07aec..287bb22 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -180,7 +180,7 @@
@Override
public void start() {
sDebugFlags = new RecentsDebugFlags(mContext);
- sSystemServicesProxy = new SystemServicesProxy(mContext);
+ sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
sTaskLoader = new RecentsTaskLoader(mContext);
sConfiguration = new RecentsConfiguration(mContext);
mHandler = new Handler();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index aab45b5d..3fb3106 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -18,10 +18,7 @@
import android.app.Activity;
import android.app.ActivityOptions;
-import android.app.SearchManager;
import android.app.TaskStackBuilder;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -42,7 +39,6 @@
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
@@ -50,12 +46,10 @@
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
-import com.android.systemui.recents.events.activity.HideHistoryEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryEvent;
import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
@@ -89,9 +83,6 @@
private final static String TAG = "RecentsActivity";
private final static boolean DEBUG = false;
- private final static String KEY_SAVED_STATE_HISTORY_VISIBLE =
- "saved_instance_state_history_visible";
-
public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
private RecentsPackageMonitor mPackageMonitor;
@@ -104,11 +95,6 @@
private RecentsView mRecentsView;
private SystemBarScrimViews mScrimViews;
- // Search AppWidget
- private AppWidgetProviderInfo mSearchWidgetInfo;
- private RecentsAppWidgetHost mAppWidgetHost;
- private RecentsAppWidgetHostView mSearchWidgetHostView;
-
// Runnables to finish the Recents activity
private Intent mHomeIntent;
@@ -138,17 +124,10 @@
@Override
public void run() {
try {
- RecentsActivityLaunchState launchState =
- Recents.getConfiguration().getLaunchState();
ActivityOptions opts = mOpts;
if (opts == null) {
opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
- launchState.launchedFromSearchHome ?
- R.anim.recents_to_search_launcher_enter :
- R.anim.recents_to_launcher_enter,
- launchState.launchedFromSearchHome ?
- R.anim.recents_to_search_launcher_exit :
- R.anim.recents_to_launcher_exit);
+ R.anim.recents_to_launcher_enter, R.anim.recents_to_launcher_exit);
}
startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
} catch (Exception e) {
@@ -167,27 +146,11 @@
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
// When the screen turns off, dismiss Recents to Home
dismissRecentsToHomeIfVisible(false);
- } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) {
- // When the search activity changes, update the search widget view
- SystemServicesProxy ssp = Recents.getSystemServices();
- mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(context, mAppWidgetHost);
- refreshSearchWidgetView();
}
}
};
/**
- * Dismisses the history view back into the stack view.
- */
- boolean dismissHistory() {
- if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
- EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
- return true;
- }
- return false;
- }
-
- /**
* Dismisses recents if we are already visible and the intent is to toggle the recents view.
*/
boolean dismissRecentsToFocusedTask(int logCategory) {
@@ -285,10 +248,7 @@
// Register this activity with the event bus
EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
- // Initialize the widget host (the host id is static and does not change)
- if (RecentsDebugFlags.Static.EnableSearchBar) {
- mAppWidgetHost = new RecentsAppWidgetHost(this, RecentsAppWidgetHost.HOST_ID);
- }
+ // Initialize the package monitor
mPackageMonitor = new RecentsPackageMonitor();
mPackageMonitor.register(this);
@@ -317,17 +277,9 @@
mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- // Bind the search app widget when we first start up
- if (RecentsDebugFlags.Static.EnableSearchBar) {
- mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
- }
-
// Register the broadcast receiver to handle messages when the screen is turned off
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
- if (RecentsDebugFlags.Static.EnableSearchBar) {
- filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
- }
registerReceiver(mSystemBroadcastReceiver, filter);
}
@@ -372,7 +324,7 @@
loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
loader.loadTasks(this, loadPlan, loadOpts);
TaskStack stack = loadPlan.getTaskStack();
- mRecentsView.onResume(mIsVisible, stack);
+ mRecentsView.onResume(mIsVisible, false /* multiWindowChange */, stack);
// Animate the SystemUI scrims into view
Task launchTarget = stack.getLaunchTarget();
@@ -439,18 +391,13 @@
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- EventBus.getDefault().send(new ConfigurationChangedEvent());
+ EventBus.getDefault().post(new ConfigurationChangedEvent());
}
@Override
protected void onStop() {
super.onStop();
- // Only hide the history if Recents is completely hidden
- if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
- EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
- }
-
// Notify that recents is now hidden
mIsVisible = false;
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
@@ -479,11 +426,6 @@
// Unregister any broadcast receivers for the task loader
mPackageMonitor.unregister();
- // Stop listening for widget package changes if there was one bound
- if (RecentsDebugFlags.Static.EnableSearchBar) {
- mAppWidgetHost.stopListening();
- }
-
EventBus.getDefault().unregister(this);
}
@@ -500,23 +442,6 @@
}
@Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- if (RecentsDebugFlags.Static.EnableHistory) {
- outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
- }
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- if (RecentsDebugFlags.Static.EnableHistory &&
- savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
- EventBus.getDefault().send(new ShowHistoryEvent());
- }
- }
-
- @Override
public void onTrimMemory(int level) {
RecentsTaskLoader loader = Recents.getTaskLoader();
if (loader != null) {
@@ -541,7 +466,7 @@
loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
loader.loadTasks(this, loadPlan, loadOpts);
- mRecentsView.onResume(mIsVisible, loadPlan.getTaskStack());
+ mRecentsView.onResume(mIsVisible, true /* multiWindowChange */, loadPlan.getTaskStack());
EventBus.getDefault().send(new MultiWindowStateChangedEvent(inMultiWindow));
}
@@ -611,39 +536,35 @@
/**** EventBus events ****/
public final void onBusEvent(ToggleRecentsEvent event) {
- if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
- RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- if (launchState.launchedFromHome) {
- dismissRecentsToHome(true /* animateTaskViews */);
- } else {
- dismissRecentsToLaunchTargetTaskOrHome();
- }
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+ if (launchState.launchedFromHome) {
+ dismissRecentsToHome(true /* animateTaskViews */);
+ } else {
+ dismissRecentsToLaunchTargetTaskOrHome();
}
}
public final void onBusEvent(IterateRecentsEvent event) {
- if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
- final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+ final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- // Start dozing after the recents button is clicked
- int timerIndicatorDuration = 0;
- if (debugFlags.isFastToggleRecentsEnabled()) {
- timerIndicatorDuration = getResources().getInteger(
- R.integer.recents_subsequent_auto_advance_duration);
+ // Start dozing after the recents button is clicked
+ int timerIndicatorDuration = 0;
+ if (debugFlags.isFastToggleRecentsEnabled()) {
+ timerIndicatorDuration = getResources().getInteger(
+ R.integer.recents_subsequent_auto_advance_duration);
- mIterateTrigger.setDozeDuration(timerIndicatorDuration);
- if (!mIterateTrigger.isDozing()) {
- mIterateTrigger.startDozing();
- } else {
- mIterateTrigger.poke();
- }
+ mIterateTrigger.setDozeDuration(timerIndicatorDuration);
+ if (!mIterateTrigger.isDozing()) {
+ mIterateTrigger.startDozing();
+ } else {
+ mIterateTrigger.poke();
}
-
- // Focus the next task
- EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
-
- MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE);
}
+
+ // Focus the next task
+ EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
+
+ MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE);
}
public final void onBusEvent(UserInteractionEvent event) {
@@ -658,17 +579,7 @@
dismissRecentsToFocusedTaskOrHome();
}
} else if (event.triggeredFromHomeKey) {
- // Otherwise, dismiss Recents to Home
- if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
- // If the history view is visible, then just cross-fade home
- ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
- R.anim.recents_to_launcher_enter,
- R.anim.recents_to_launcher_exit);
- dismissRecentsToHome(false /* animate */, opts);
-
- } else {
- dismissRecentsToHome(true /* animateTaskViews */);
- }
+ dismissRecentsToHome(true /* animateTaskViews */);
// Cancel any pending dozes
EventBus.getDefault().send(mUserInteractionEvent);
@@ -677,23 +588,6 @@
}
}
- public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
- // Try and start the enter animation (or restart it on configuration changed)
- if (RecentsDebugFlags.Static.EnableSearchBar) {
- if (mSearchWidgetInfo != null) {
- event.addPostAnimationCallback(new Runnable() {
- @Override
- public void run() {
- // Start listening for widget package changes if there is one bound
- if (mAppWidgetHost != null) {
- mAppWidgetHost.startListening();
- }
- }
- });
- }
- }
- }
-
public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true));
mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
@@ -719,10 +613,6 @@
}
}
- public final void onBusEvent(AppWidgetProviderChangedEvent event) {
- refreshSearchWidgetView();
- }
-
public final void onBusEvent(ShowApplicationInfoEvent event) {
// Create a new task stack with the application info details activity
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
@@ -785,24 +675,6 @@
mIgnoreAltTabRelease = true;
}
- private void refreshSearchWidgetView() {
- if (mSearchWidgetInfo != null) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- int searchWidgetId = ssp.getSearchAppWidgetId(this);
- mSearchWidgetHostView = (RecentsAppWidgetHostView) mAppWidgetHost.createView(
- this, searchWidgetId, mSearchWidgetInfo);
- Bundle opts = new Bundle();
- opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
- AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
- mSearchWidgetHostView.updateAppWidgetOptions(opts);
- // Set the padding to 0 for this search widget
- mSearchWidgetHostView.setPadding(0, 0, 0, 0);
- mRecentsView.setSearchBar(mSearchWidgetHostView);
- } else {
- mRecentsView.setSearchBar(null);
- }
- }
-
@Override
public boolean onPreDraw() {
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index ec4820a..ab3b79e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -31,7 +31,6 @@
public boolean launchedFromApp;
public boolean launchedFromAppDocked;
public boolean launchedFromHome;
- public boolean launchedFromSearchHome;
public boolean launchedReuseTaskStackViews;
public boolean launchedHasConfigurationChanged;
public boolean launchedViaDragGesture;
@@ -42,7 +41,6 @@
public void reset() {
launchedFromHome = false;
- launchedFromSearchHome = false;
launchedFromApp = false;
launchedFromAppDocked = false;
launchedToTaskId = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
deleted file mode 100644
index 318c69f..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents;
-
-import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
-
-/** Our special app widget host for the Search widget */
-public class RecentsAppWidgetHost extends AppWidgetHost {
-
- public static final int HOST_ID = 1024;
-
- boolean mIsListening;
-
- public RecentsAppWidgetHost(Context context, int hostId) {
- super(context, hostId);
- }
-
- public void startListening() {
- if (!mIsListening) {
- mIsListening = true;
- super.startListening();
- }
- }
-
- @Override
- public void stopListening() {
- if (mIsListening) {
- mIsListening = false;
- super.stopListening();
- }
- }
-
- @Override
- protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
- AppWidgetProviderInfo appWidget) {
- return new RecentsAppWidgetHostView(context);
- }
-
- /**
- * Note: this is only called for packages that have updated, not removed.
- */
- @Override
- protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
- super.onProviderChanged(appWidgetId, appWidgetInfo);
- if (mIsListening) {
- EventBus.getDefault().send(new AppWidgetProviderChangedEvent());
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java
deleted file mode 100644
index 672d602..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java
+++ /dev/null
@@ -1,68 +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.systemui.recents;
-
-import android.appwidget.AppWidgetHostView;
-import android.content.Context;
-import android.view.View;
-import android.widget.RemoteViews;
-
-public class RecentsAppWidgetHostView extends AppWidgetHostView {
-
- private Context mContext;
- private int mPreviousOrientation;
-
- public RecentsAppWidgetHostView(Context context) {
- super(context);
- mContext = context;
- }
-
- @Override
- public void updateAppWidget(RemoteViews remoteViews) {
- // Store the orientation in which the widget was inflated
- updateLastInflationOrientation();
- super.updateAppWidget(remoteViews);
- }
-
- @Override
- protected View getErrorView() {
- // Just return an empty view as the error view when failing to inflate the Recents search
- // bar widget (this is mainly to catch the case where we try and inflate the widget view
- // while the search provider is updating)
- return new View(mContext);
- }
-
- /**
- * Updates the last orientation that this widget was inflated.
- */
- private void updateLastInflationOrientation() {
- mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
- }
-
- /**
- * @return whether the search widget was updated while Recents was in a different orientation
- * in the background.
- */
- public boolean isReinflateRequired() {
- // Re-inflate is required if the orientation has changed since last inflated.
- int orientation = mContext.getResources().getConfiguration().orientation;
- if (mPreviousOrientation != orientation) {
- return true;
- }
- return false;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index eec0411..2afb09a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -32,13 +32,6 @@
private static final int LARGE_SCREEN_MIN_DP = 600;
private static final int XLARGE_SCREEN_MIN_DP = 720;
- // Variables that are used for global calculations
- private static final float STACK_SIDE_PADDING_PHONES_PCT = 0.03333f;
- private static final float STACK_SIZE_PADDING_TABLETS_PCT = 0.075f;
- private static final float STACK_SIZE_PADDING_LARGE_TABLETS_PCT = 0.15f;
- private static final int SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS = 64;
- private static final int SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS = 72;
-
/** Levels of svelte in increasing severity/austerity. */
// No svelting.
public static final int SVELTE_NONE = 0;
@@ -57,9 +50,7 @@
// TODO: Values determined by the current context, needs to be refactored into something that is
// agnostic of the activity context, but still calculable from the Recents component for
// the transition into recents
- boolean hasTransposedSearchBar;
- boolean hasTransposedNavBar;
- public float taskStackWidthPaddingPct;
+ public boolean hasTransposedNavBar;
// Since the positions in Recents has to be calculated globally (before the RecentsActivity
// starts), we need to calculate some resource values ourselves, instead of relying on framework
@@ -71,7 +62,6 @@
/** Misc **/
public boolean fakeShadows;
public int svelteLevel;
- public int searchBarSpaceHeightPx;
public RecentsConfiguration(Context context) {
// Load only resources that can not change after the first load either through developer
@@ -82,20 +72,10 @@
fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
svelteLevel = res.getInteger(R.integer.recents_svelte_level);
- float density = context.getResources().getDisplayMetrics().density;
+ float screenDensity = context.getResources().getDisplayMetrics().density;
smallestWidth = ssp.getDeviceSmallestWidth();
- isLargeScreen = smallestWidth >= (int) (density * LARGE_SCREEN_MIN_DP);
- isXLargeScreen = smallestWidth >= (int) (density * XLARGE_SCREEN_MIN_DP);
- searchBarSpaceHeightPx = isLargeScreen ?
- (int) (density * SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS) :
- (int) (density * SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS);
- if (isLargeScreen) {
- taskStackWidthPaddingPct = STACK_SIZE_PADDING_TABLETS_PCT;
- } else if (isXLargeScreen) {
- taskStackWidthPaddingPct = STACK_SIZE_PADDING_LARGE_TABLETS_PCT;
- } else {
- taskStackWidthPaddingPct = STACK_SIDE_PADDING_PHONES_PCT;
- }
+ isLargeScreen = smallestWidth >= (int) (screenDensity * LARGE_SCREEN_MIN_DP);
+ isXLargeScreen = smallestWidth >= (int) (screenDensity * XLARGE_SCREEN_MIN_DP);
}
/**
@@ -103,7 +83,6 @@
*/
void update(Rect systemInsets) {
hasTransposedNavBar = systemInsets.right > 0;
- hasTransposedSearchBar = systemInsets.right > 0;
}
/**
@@ -121,40 +100,4 @@
public void updateOnConfigurationChange() {
mLaunchState.updateOnConfigurationChange();
}
-
- /**
- * Returns the task stack bounds in the current orientation. These bounds do not account for
- * the system insets.
- */
- public void getTaskStackBounds(Rect windowBounds, int topInset,
- int rightInset, Rect searchBarBounds, Rect taskStackBounds) {
- if (hasTransposedNavBar) {
- // In landscape phones, the search bar appears on the left, but we overlay it on top
- taskStackBounds.set(windowBounds.left, windowBounds.top + topInset,
- windowBounds.right - rightInset, windowBounds.bottom);
- } else {
- // In portrait, the search bar appears on the top (which already has the inset)
- int top = searchBarBounds.isEmpty() ? topInset : 0;
- taskStackBounds.set(windowBounds.left, windowBounds.top + searchBarBounds.bottom + top,
- windowBounds.right - rightInset, windowBounds.bottom);
- }
- }
-
- /**
- * Returns the search bar bounds in the current orientation. These bounds do not account for
- * the system insets.
- */
- public void getSearchBarBounds(Rect windowBounds, int topInset, Rect searchBarSpaceBounds) {
- // Return empty rects if search is not enabled
- int searchBarSize = searchBarSpaceHeightPx;
- if (hasTransposedSearchBar) {
- // In landscape phones, the search bar appears on the left
- searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset,
- windowBounds.left + searchBarSize, windowBounds.bottom);
- } else {
- // In portrait, the search bar appears on the top
- searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset,
- windowBounds.right, windowBounds.top + topInset + searchBarSize);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 40bf6d3..f67f099 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -31,14 +31,12 @@
public static class Static {
// Enables debug drawing for the transition thumbnail
public static final boolean EnableTransitionThumbnailDebugMode = false;
- // This enables the search bar integration
- public static final boolean EnableSearchBar = false;
// This disables the bitmap and icon caches
public static final boolean DisableBackgroundCache = false;
// Enables the task affiliations
public static final boolean EnableAffiliatedTaskGroups = true;
- // Enables the history
- public static final boolean EnableHistory = false;
+ // TODO: To be repurposed
+ public static final boolean EnableStackActionButton = false;
// Overrides the Tuner flags and enables the timeout
private static final boolean EnableFastToggleTimeout = false;
// Overrides the Tuner flags and enables the paging via the Recents button
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 880fe10..58216b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -20,8 +20,6 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.ITaskStackListener;
-import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
@@ -30,6 +28,7 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -41,7 +40,6 @@
import android.view.ViewConfiguration;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.recents.events.EventBus;
@@ -59,6 +57,7 @@
import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.ForegroundThread;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
@@ -95,37 +94,13 @@
public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
/**
- * An implementation of ITaskStackListener, that allows us to listen for changes to the system
+ * An implementation of TaskStackListener, that allows us to listen for changes to the system
* task stacks and update recents accordingly.
*/
- class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
- Handler mHandler;
-
- public TaskStackListenerImpl(Handler handler) {
- mHandler = handler;
- }
-
+ class TaskStackListenerImpl extends TaskStackListener {
@Override
public void onTaskStackChanged() {
- // Debounce any task stack changes
- mHandler.removeCallbacks(this);
- mHandler.post(this);
- }
-
- @Override
- public void onActivityPinned() {
- }
-
- @Override
- public void onPinnedActivityRestartAttempt() {
- }
-
- @Override
- public void onPinnedStackAnimationEnded() {
- }
-
- /** Preloads the next task */
- public void run() {
+ // Preloads the next task
RecentsConfiguration config = Recents.getConfiguration();
if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -156,13 +131,11 @@
protected Context mContext;
protected Handler mHandler;
TaskStackListenerImpl mTaskStackListener;
- RecentsAppWidgetHost mAppWidgetHost;
protected boolean mCanReuseTaskStackViews = true;
boolean mDraggingInRecents;
boolean mLaunchedWhileDocking;
// Task launching
- Rect mSearchBarBounds = new Rect();
Rect mTaskStackBounds = new Rect();
Rect mLastTaskViewBounds = new Rect();
TaskViewTransform mTmpTransform = new TaskViewTransform();
@@ -195,19 +168,18 @@
public RecentsImpl(Context context) {
mContext = context;
mHandler = new Handler();
- mAppWidgetHost = new RecentsAppWidgetHost(mContext, RecentsAppWidgetHost.HOST_ID);
// Initialize the static foreground thread
ForegroundThread.get();
// Register the task stack listener
- mTaskStackListener = new TaskStackListenerImpl(mHandler);
+ mTaskStackListener = new TaskStackListenerImpl();
SystemServicesProxy ssp = Recents.getSystemServices();
ssp.registerTaskStackListener(mTaskStackListener);
// Initialize the static configuration resources
reloadHeaderBarLayout();
- updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
+ updateHeaderBarLayout(null /* stack */);
// 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.
@@ -222,12 +194,12 @@
}
public void onBootCompleted() {
- updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
+ updateHeaderBarLayout(null /* stack */);
}
public void onConfigurationChanged() {
reloadHeaderBarLayout();
- updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
+ updateHeaderBarLayout(null /* stack */);
// Don't reuse task stack views if the configuration changes
mCanReuseTaskStackViews = false;
Recents.getConfiguration().updateOnConfigurationChange();
@@ -586,7 +558,7 @@
mNavBarWidth = res.getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_width);
mTaskBarHeight = res.getDimensionPixelSize(
- R.dimen.recents_task_bar_height);
+ R.dimen.recents_task_view_header_height);
mDummyStackView = new TaskStackView(mContext);
mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
null, false);
@@ -596,12 +568,9 @@
* Prepares the header bar layout for the next transition, if the task view bounds has changed
* since the last call, it will attempt to re-measure and layout the header bar to the new size.
*
- * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one
- * is not already bound (can be expensive)
* @param stack the stack to initialize the stack layout with
*/
- private void updateHeaderBarLayout(boolean tryAndBindSearchWidget, TaskStack stack) {
- RecentsConfiguration config = Recents.getConfiguration();
+ private void updateHeaderBarLayout(TaskStack stack) {
SystemServicesProxy ssp = Recents.getSystemServices();
Rect systemInsets = new Rect();
ssp.getStableInsets(systemInsets);
@@ -610,28 +579,20 @@
windowRect.offsetTo(0, 0);
// Update the configuration for the current state
- config.update(systemInsets);
+ Recents.getConfiguration().update(systemInsets);
- if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) {
- // Try and pre-emptively bind the search widget on startup to ensure that we
- // have the right thumbnail bounds to animate to.
- // Note: We have to reload the widget id before we get the task stack bounds below
- if (ssp.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
- config.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds);
- }
- }
- config.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
- mSearchBarBounds, mTaskStackBounds);
+ TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
+ stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
+ mTaskStackBounds);
// Rebind the header bar and draw it for the transition
- TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
Rect taskStackBounds = new Rect(mTaskStackBounds);
stackLayout.setSystemInsets(systemInsets);
if (stack != null) {
- stackLayout.initialize(taskStackBounds,
+ stackLayout.initialize(windowRect, taskStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
mDummyStackView.setTasks(stack, false /* notifyStackChanges */,
- false /* relayoutTaskStack */);
+ false /* relayoutTaskStack */, false /* multiWindowChange */);
}
Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
if (!taskViewBounds.equals(mLastTaskViewBounds)) {
@@ -688,7 +649,7 @@
preloadIcon(topTask);
// Update the header bar if necessary
- updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
+ updateHeaderBarLayout(stack);
// Update the destination rect
final Task toTask = new Task();
@@ -721,13 +682,7 @@
/**
* Creates the activity options for a home->recents transition.
*/
- protected ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
- if (fromSearchHome) {
- return ActivityOptions.makeCustomAnimation(mContext,
- R.anim.recents_from_search_launcher_enter,
- R.anim.recents_from_search_launcher_exit,
- mHandler, null);
- }
+ protected ActivityOptions getHomeTransitionActivityOptions() {
return ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_launcher_enter,
R.anim.recents_from_launcher_exit,
@@ -839,6 +794,12 @@
} else {
Canvas c = new Canvas(thumbnail);
c.scale(toTransform.scale, toTransform.scale);
+ // Workaround for b/27815919, reset the callback so that we do not trigger an
+ // invalidate on the header bar as a result of updating the icon
+ Drawable icon = mHeaderBar.getIconView().getDrawable();
+ if (icon != null) {
+ icon.setCallback(null);
+ }
mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */,
disabledInSafeMode);
mHeaderBar.setDimAlpha(toTransform.dimAlpha);
@@ -871,7 +832,7 @@
TaskStack stack = sInstanceLoadPlan.getTaskStack();
// Update the header bar if necessary
- updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
+ updateHeaderBarLayout(stack);
// Prepare the dummy stack for the transition
TaskStackLayoutAlgorithm.VisibilityReport stackVr =
@@ -879,8 +840,8 @@
if (!animate) {
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1);
- startRecentsActivity(topTask, opts, false /* fromHome */,
- false /* fromSearchHome */, false /* fromThumbnail*/, stackVr);
+ startRecentsActivity(topTask, opts, false /* fromHome */, false /* fromThumbnail*/,
+ stackVr);
return;
}
@@ -891,8 +852,8 @@
// Try starting with a thumbnail transition
ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, mDummyStackView);
if (opts != null) {
- startRecentsActivity(topTask, opts, false /* fromHome */,
- false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
+ startRecentsActivity(topTask, opts, false /* fromHome */, true /* fromThumbnail */,
+ stackVr);
} else {
// Fall through below to the non-thumbnail transition
useThumbnailTransition = false;
@@ -901,33 +862,12 @@
if (!useThumbnailTransition) {
// If there is no thumbnail transition, but is launching from home into recents, then
- // use a quick home transition and do the animation from home
- if (hasRecentTasks) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- String homeActivityPackage = ssp.getHomeActivityPackageName();
- String searchWidgetPackage = null;
- if (RecentsDebugFlags.Static.EnableSearchBar) {
- searchWidgetPackage = Prefs.getString(mContext,
- Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
- } else {
- AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget();
- if (searchWidgetInfo != null) {
- searchWidgetPackage = searchWidgetInfo.provider.getPackageName();
- }
- }
-
- // Determine whether we are coming from a search owned home activity
- boolean fromSearchHome = (homeActivityPackage != null) &&
- homeActivityPackage.equals(searchWidgetPackage);
- ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
- startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
- false /* fromThumbnail */, stackVr);
- } else {
- // Otherwise we do the normal fade from an unknown source
- ActivityOptions opts = getUnknownTransitionActivityOptions();
- startRecentsActivity(topTask, opts, true /* fromHome */,
- false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
- }
+ // use a quick home transition
+ ActivityOptions opts = hasRecentTasks
+ ? getHomeTransitionActivityOptions()
+ : getUnknownTransitionActivityOptions();
+ startRecentsActivity(topTask, opts, true /* fromHome */, false /* fromThumbnail */,
+ stackVr);
}
mLastToggleTime = SystemClock.elapsedRealtime();
}
@@ -936,13 +876,12 @@
* Starts the recents activity.
*/
private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
- ActivityOptions opts, boolean fromHome, boolean fromSearchHome,
- boolean fromThumbnail, TaskStackLayoutAlgorithm.VisibilityReport vr) {
+ ActivityOptions opts, boolean fromHome, boolean fromThumbnail,
+ TaskStackLayoutAlgorithm.VisibilityReport vr) {
// Update the configuration based on the launch options
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
- launchState.launchedFromHome = fromSearchHome || fromHome;
- launchState.launchedFromSearchHome = fromSearchHome;
+ launchState.launchedFromHome = fromHome;
launchState.launchedFromApp = fromThumbnail || mLaunchedWhileDocking;
launchState.launchedFromAppDocked = mLaunchedWhileDocking;
launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java
deleted file mode 100644
index 52cfe18..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java
+++ /dev/null
@@ -1,28 +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.systemui.recents.events.activity;
-
-import com.android.systemui.recents.RecentsAppWidgetHost;
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent by the {@link RecentsAppWidgetHost} whenever the search provider widget changes, and
- * subscribers can update accordingly.
- */
-public class AppWidgetProviderChangedEvent extends EventBus.Event {
- // Simple event
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
deleted file mode 100644
index 98c0a69..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.java
+++ /dev/null
@@ -1,26 +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.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history is to be cleared
- */
-public class ClearHistoryEvent extends EventBus.AnimatedEvent {
- // Simple event
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryButtonEvent.java
deleted file mode 100644
index 6c767e4..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryButtonEvent.java
+++ /dev/null
@@ -1,26 +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.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history view button should be hidden.
- */
-public class HideHistoryButtonEvent extends EventBus.Event {
- // Simple event
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
deleted file mode 100644
index bacf3bd..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
+++ /dev/null
@@ -1,31 +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.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history view will be closed.
- */
-public class HideHistoryEvent extends EventBus.Event {
-
- public final boolean animate;
-
- public HideHistoryEvent(boolean animate) {
- this.animate = animate;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
similarity index 85%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
rename to packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
index 469f336..e02fb14 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideStackActionButtonEvent.java
@@ -19,10 +19,8 @@
import com.android.systemui.recents.events.EventBus;
/**
- * This is sent when the history view button is clicked.
+ * This is sent when the stack action button should be hidden.
*/
-public class ShowHistoryEvent extends EventBus.Event {
-
+public class HideStackActionButtonEvent extends EventBus.Event {
// Simple event
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java
similarity index 75%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
rename to packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java
index ae803ea..d81f89c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowStackActionButtonEvent.java
@@ -19,14 +19,14 @@
import com.android.systemui.recents.events.EventBus;
/**
- * This is sent when the history view button should be shown.
+ * This is sent when the stack action view button should be shown.
*/
-public class ShowHistoryButtonEvent extends EventBus.Event {
+public class ShowStackActionButtonEvent extends EventBus.Event {
- // Whether or not to translate the history button when showing it
+ // Whether or not to translate the stack action button when showing it
public final boolean translate;
- public ShowHistoryButtonEvent(boolean translate) {
+ public ShowStackActionButtonEvent(boolean translate) {
this.translate = translate;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.java
deleted file mode 100644
index aaf77af..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.java
+++ /dev/null
@@ -1,28 +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.systemui.recents.events.activity;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * This is sent when the history view button is clicked.
- */
-public class ToggleHistoryEvent extends EventBus.AnimatedEvent {
-
- // Simple event
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
deleted file mode 100644
index 16385c9..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ /dev/null
@@ -1,378 +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.systemui.recents.history;
-
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.support.v7.widget.RecyclerView;
-import android.text.format.DateFormat;
-import android.util.SparseIntArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.HideHistoryEvent;
-import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.AnimationProps;
-
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-
-
-/**
- * An adapter for the list of recent tasks in the history view.
- */
-public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAdapter.ViewHolder> {
-
- private static final String TAG = "RecentsHistoryView";
- private static final boolean DEBUG = false;
-
- static final int DATE_ROW_VIEW_TYPE = 0;
- static final int TASK_ROW_VIEW_TYPE = 1;
-
- /**
- * View holder implementation. The {@param TaskCallbacks} are only called for TaskRow view
- * holders.
- */
- public static class ViewHolder extends RecyclerView.ViewHolder implements Task.TaskCallbacks {
- public final View content;
-
- private Task mTask;
-
- public ViewHolder(View content) {
- super(content);
- this.content = content;
- }
-
- /**
- * Binds this view holder to the given task.
- */
- public void bindToTask(Task newTask) {
- unbindFromTask();
- mTask = newTask;
- mTask.addCallback(this);
- }
-
- /**
- * Unbinds this view holder from the
- */
- public void unbindFromTask() {
- if (mTask != null) {
- mTask.removeCallback(this);
- mTask = null;
- }
- }
-
- @Override
- public void onTaskDataLoaded(Task task) {
- // This callback is only made for TaskRow view holders
- ImageView iv = (ImageView) content.findViewById(R.id.icon);
- iv.setImageDrawable(task.icon);
- iv.animate()
- .alpha(1f)
- .setDuration(100)
- .start();
- }
-
- @Override
- public void onTaskDataUnloaded() {
- // This callback is only made for TaskRow view holders
- ImageView iv = (ImageView) content.findViewById(R.id.icon);
- iv.setImageBitmap(null);
- iv.animate().cancel();
- }
-
- @Override
- public void onTaskStackIdChanged() {
- // Do nothing, this callback is only made for TaskRow view holders
- }
- }
-
- /**
- * A single row of content.
- */
- interface Row {
- int getViewType();
- }
-
- /**
- * A date row.
- */
- static class DateRow implements Row {
-
- public final String date;
-
- public DateRow(String date) {
- this.date = date;
- }
-
- @Override
- public int getViewType() {
- return RecentsHistoryAdapter.DATE_ROW_VIEW_TYPE;
- }
- }
-
- /**
- * A task row.
- */
- static class TaskRow implements Row, View.OnClickListener {
-
- public final Task task;
- public final int dateKey;
-
- public TaskRow(Task task, int dateKey) {
- this.task = task;
- this.dateKey = dateKey;
- }
-
- @Override
- public void onClick(View v) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startActivityFromRecents(v.getContext(), task.key.id, task.title,
- ActivityOptions.makeBasic());
-
- MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
- task.key.getComponent().toString());
- }
-
- @Override
- public int getViewType() {
- return RecentsHistoryAdapter.TASK_ROW_VIEW_TYPE;
- }
- }
-
- private Context mContext;
- private LayoutInflater mLayoutInflater;
- private final List<Row> mRows = new ArrayList<>();
- private final SparseIntArray mTaskRowCount = new SparseIntArray();
- private TaskStack mStack;
-
- public RecentsHistoryAdapter(Context context) {
- mLayoutInflater = LayoutInflater.from(context);
- }
-
- /**
- * Updates this adapter with the given tasks.
- */
- public void updateTasks(Context context, TaskStack stack) {
- mContext = context;
- mStack = stack;
-
- final Locale l = context.getResources().getConfiguration().locale;
- final String dateFormatStr = DateFormat.getBestDateTimePattern(l, "EEEEMMMMd");
- final List<Task> tasksMostRecent = new ArrayList<>(stack.getHistoricalTasks());
- Collections.reverse(tasksMostRecent);
- int prevDateKey = -1;
- int taskCount = tasksMostRecent.size();
- mRows.clear();
- mTaskRowCount.clear();
- Calendar cal = Calendar.getInstance(l);
- for (int i = 0; i < taskCount; i++) {
- Task task = tasksMostRecent.get(i);
- if (task.isFreeformTask()) {
- continue;
- }
-
- cal.setTimeInMillis(task.key.lastActiveTime);
- int dateKey = Objects.hash(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR));
- if (dateKey != prevDateKey) {
- prevDateKey = dateKey;
- mRows.add(new DateRow(DateFormat.format(dateFormatStr, cal).toString()));
- }
- mRows.add(new TaskRow(task, dateKey));
- mTaskRowCount.put(dateKey, mTaskRowCount.get(dateKey, 0) + 1);
- }
- notifyDataSetChanged();
- }
-
- /**
- * Removes historical tasks belonging to the specified package and user. We do not need to
- * remove the task from the TaskStack since the TaskStackView will also receive this event.
- */
- public void removeTasks(String packageName, int userId) {
- for (int i = mRows.size() - 1; i >= 0; i--) {
- Row row = mRows.get(i);
- if (row.getViewType() == TASK_ROW_VIEW_TYPE) {
- TaskRow taskRow = (TaskRow) row;
- Task task = taskRow.task;
- String taskPackage = task.key.getComponent().getPackageName();
- if (task.key.userId == userId && taskPackage.equals(packageName)) {
- i = removeTaskRow(i);
- }
- }
- }
- if (mRows.isEmpty()) {
- dismissHistory();
- }
- }
-
- /**
- * Removes all historical tasks.
- */
- public void removeAllTasks() {
- for (int i = mRows.size() - 1; i >= 0; i--) {
- Row row = mRows.get(i);
- if (row.getViewType() == TASK_ROW_VIEW_TYPE) {
- TaskRow taskRow = (TaskRow) row;
- Task task = taskRow.task;
- mStack.removeTask(task, AnimationProps.IMMEDIATE, false /* fromDockGesture */);
- EventBus.getDefault().send(new DeleteTaskDataEvent(task));
- i = removeTaskRow(i);
- }
- }
- dismissHistory();
- }
-
- /**
- * Returns the row at the given {@param position}.
- */
- public Row getRow(int position) {
- return mRows.get(position);
- }
-
- @Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- switch (viewType) {
- case DATE_ROW_VIEW_TYPE:
- return new ViewHolder(mLayoutInflater.inflate(R.layout.recents_history_date, parent,
- false));
- case TASK_ROW_VIEW_TYPE:
- return new ViewHolder(mLayoutInflater.inflate(R.layout.recents_history_task, parent,
- false));
- default:
- return new ViewHolder(null);
- }
- }
-
- @Override
- public void onBindViewHolder(ViewHolder holder, int position) {
- RecentsTaskLoader loader = Recents.getTaskLoader();
-
- Row row = mRows.get(position);
- int viewType = row.getViewType();
- switch (viewType) {
- case DATE_ROW_VIEW_TYPE: {
- TextView tv = (TextView) holder.content;
- tv.setText(((DateRow) row).date);
- break;
- }
- case TASK_ROW_VIEW_TYPE: {
- TaskRow taskRow = (TaskRow) row;
- TextView tv = (TextView) holder.content.findViewById(R.id.description);
- tv.setText(taskRow.task.title);
- ImageView iv = (ImageView) holder.content.findViewById(R.id.icon);
- iv.setAlpha(0f);
- holder.content.setOnClickListener(taskRow);
-
- holder.bindToTask(taskRow.task);
- loader.loadTaskData(taskRow.task, false /* fetchAndInvalidateThumbnails */);
- break;
- }
- }
- }
-
- @Override
- public void onViewRecycled(ViewHolder holder) {
- RecentsTaskLoader loader = Recents.getTaskLoader();
- int position = holder.getAdapterPosition();
- if (position != RecyclerView.NO_POSITION) {
- Row row = mRows.get(position);
- int viewType = row.getViewType();
- if (viewType == TASK_ROW_VIEW_TYPE) {
- TaskRow taskRow = (TaskRow) row;
- loader.unloadTaskData(taskRow.task);
- holder.unbindFromTask();
- }
- }
- }
-
- @Override
- public boolean onFailedToRecycleView(ViewHolder holder) {
- // Always recycle views, even if it is animating
- onViewRecycled(holder);
- return true;
- }
-
- public void onTaskRemoved(Task task, int position) {
- // Since this is removed from the history, we need to update the stack as well to ensure
- // that the model is correct. Since the stack is hidden, we can update it immediately.
- mStack.removeTask(task, AnimationProps.IMMEDIATE, false /* fromDockGesture */);
- removeTaskRow(position);
- if (mRows.isEmpty()) {
- dismissHistory();
- }
- }
-
- @Override
- public int getItemCount() {
- return mRows.size();
- }
-
- @Override
- public int getItemViewType(int position) {
- return mRows.get(position).getViewType();
- }
-
- /**
- * Removes a task row, also removing the associated {@link DateRow} if there are no more tasks
- * in that date group.
- *
- * @param position an adapter position of a task row such that 0 < position < num rows.
- * @return the index of the last removed row
- */
- private int removeTaskRow(int position) {
- // Remove the task at that row
- TaskRow taskRow = (TaskRow) mRows.remove(position);
- int numTasks = mTaskRowCount.get(taskRow.dateKey) - 1;
- mTaskRowCount.put(taskRow.dateKey, numTasks);
- notifyItemRemoved(position);
-
- if (numTasks == 0) {
- // If that was the last task row in the group, then remove the date as well
- mRows.remove(position - 1);
- mTaskRowCount.removeAt(mTaskRowCount.indexOfKey(taskRow.dateKey));
- notifyItemRemoved(position - 1);
- return position - 1;
- } else {
- return position;
- }
- }
-
- /**
- * Dismisses history back to the stack view.
- */
- private void dismissHistory() {
- EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
- EventBus.getDefault().send(new HideHistoryButtonEvent());
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
deleted file mode 100644
index 3d1ea8e..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
+++ /dev/null
@@ -1,80 +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.systemui.recents.history;
-
-import android.content.Context;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
-
-
-/**
- * An item touch handler for items in the history view.
- */
-public class RecentsHistoryItemTouchCallbacks extends ItemTouchHelper.SimpleCallback {
-
- private Context mContext;
- private RecentsHistoryAdapter mAdapter;
-
- public RecentsHistoryItemTouchCallbacks(Context context, RecentsHistoryAdapter adapter) {
- super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
- mContext = context;
- mAdapter = adapter;
- }
-
- @Override
- public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
- RecyclerView.ViewHolder target) {
- return false;
- }
-
- @Override
- public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
- int viewType = mAdapter.getItemViewType(viewHolder.getAdapterPosition());
- switch (viewType) {
- case RecentsHistoryAdapter.DATE_ROW_VIEW_TYPE:
- // Disallow swiping
- return 0;
- default:
- return super.getSwipeDirs(recyclerView, viewHolder);
- }
- }
-
- @Override
- public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
- int position = viewHolder.getAdapterPosition();
- if (position != RecyclerView.NO_POSITION) {
- RecentsHistoryAdapter.Row row = mAdapter.getRow(position);
- RecentsHistoryAdapter.TaskRow taskRow = (RecentsHistoryAdapter.TaskRow) row;
-
- // Remove the task from the system
- EventBus.getDefault().send(new DeleteTaskDataEvent(taskRow.task));
- mAdapter.onTaskRemoved(taskRow.task, position);
-
- // Keep track of deletions by swiping within history
- MetricsLogger.histogram(mContext, "overview_task_dismissed_source",
- Constants.Metrics.DismissSourceHistorySwipeGesture);
- MetricsLogger.action(mContext, MetricsEvent.OVERVIEW_DISMISS,
- taskRow.task.key.getComponent().toString());
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
deleted file mode 100644
index 3c4adb2..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ /dev/null
@@ -1,253 +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.systemui.recents.history;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowInsets;
-import android.widget.LinearLayout;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsActivity;
-import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.ClearHistoryEvent;
-import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
-import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.AnimateableViewBounds;
-
-/**
- * A list of the recent tasks that are not in the stack.
- */
-public class RecentsHistoryView extends LinearLayout
- implements ValueAnimator.AnimatorUpdateListener {
-
- private static final float TRANSLATION_Y_PCT = 0.25f;
- private static final float BG_SCRIM_ALPHA = 0.625f;
-
- private RecyclerView mRecyclerView;
- private RecentsHistoryAdapter mAdapter;
- private RecentsHistoryItemTouchCallbacks mItemTouchHandler;
- private AnimateableViewBounds mViewBounds;
- private boolean mIsVisible;
- private Rect mSystemInsets = new Rect();
- private int mHeaderHeight;
-
- private int mHistoryTransitionDuration;
-
- public RecentsHistoryView(Context context) {
- super(context);
- }
-
- public RecentsHistoryView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public RecentsHistoryView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public RecentsHistoryView(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- Resources res = context.getResources();
- mAdapter = new RecentsHistoryAdapter(context);
- mItemTouchHandler = new RecentsHistoryItemTouchCallbacks(context, mAdapter);
- mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration);
- mViewBounds = new AnimateableViewBounds(this, 0);
- setOutlineProvider(mViewBounds);
- }
-
- /**
- * Updates this history view with the recent tasks, and then shows it.
- */
- public void show(TaskStack stack, int stackHeight, View clearAllButton) {
- setVisibility(View.VISIBLE);
- setAlpha(0f);
- setTranslationY(-stackHeight * TRANSLATION_Y_PCT);
- animate()
- .alpha(1f)
- .translationY(0f)
- .setDuration(mHistoryTransitionDuration)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setUpdateListener(this)
- .start();
- clearAllButton.setVisibility(View.VISIBLE);
- clearAllButton.setAlpha(0f);
- clearAllButton.animate()
- .alpha(1f)
- .setDuration(mHistoryTransitionDuration)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .withLayer()
- .start();
- mAdapter.updateTasks(getContext(), stack);
- mIsVisible = true;
- EventBus.getDefault().send(new UpdateBackgroundScrimEvent(BG_SCRIM_ALPHA));
-
- MetricsLogger.visible(mRecyclerView.getContext(), MetricsEvent.OVERVIEW_HISTORY);
- }
-
- /**
- * Hides this history view.
- */
- public void hide(boolean animate, int stackHeight, final View clearAllButton) {
- if (animate) {
- animate()
- .alpha(0f)
- .translationY(-stackHeight * TRANSLATION_Y_PCT)
- .setDuration(mHistoryTransitionDuration)
- .setInterpolator(Interpolators.FAST_OUT_LINEAR_IN)
- .setUpdateListener(this)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- setVisibility(View.INVISIBLE);
- }
- })
- .start();
- clearAllButton.animate()
- .alpha(0f)
- .translationY(0f)
- .setDuration(mHistoryTransitionDuration)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- clearAllButton.setVisibility(View.INVISIBLE);
- }
- })
- .withLayer()
- .start();
- } else {
- setAlpha(0f);
- setVisibility(View.INVISIBLE);
- clearAllButton.setAlpha(0f);
- clearAllButton.setVisibility(View.INVISIBLE);
- }
- mIsVisible = false;
- EventBus.getDefault().send(new ResetBackgroundScrimEvent());
-
- MetricsLogger.hidden(mRecyclerView.getContext(), MetricsEvent.OVERVIEW_HISTORY);
- }
-
- /**
- * Updates the system insets of this history view to the provided values.
- */
- public void setSystemInsets(Rect systemInsets) {
- mSystemInsets.set(systemInsets);
- requestLayout();
- }
-
- /**
- * Updates the header height to account for the history button bar.
- */
- public void setHeaderHeight(int height) {
- mHeaderHeight = height;
- requestLayout();
- }
-
- /**
- * Returns whether this view is visible.
- */
- public boolean isVisible() {
- return mIsVisible;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mRecyclerView = (RecyclerView) findViewById(R.id.list);
- mRecyclerView.setAdapter(mAdapter);
- mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
- mRecyclerView.getItemAnimator().setRemoveDuration(100);
- ItemTouchHelper touchHelper = new ItemTouchHelper(mItemTouchHandler);
- touchHelper.attachToRecyclerView(mRecyclerView);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- RecentsConfiguration config = Recents.getConfiguration();
- int width = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
-
- // Pad the view to align the history with the stack layout
- Rect taskStackBounds = new Rect();
- config.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
- mSystemInsets.right, new Rect() /* searchBarSpaceBounds */, taskStackBounds);
- int stackWidthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
- int stackHeightPadding = mContext.getResources().getDimensionPixelSize(
- R.dimen.recents_stack_top_padding);
- mRecyclerView.setPadding(stackWidthPadding + mSystemInsets.left,
- stackHeightPadding + mSystemInsets.top + mHeaderHeight,
- stackWidthPadding + mSystemInsets.right, mSystemInsets.bottom);
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- @Override
- protected void onAttachedToWindow() {
- EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
- super.onAttachedToWindow();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- EventBus.getDefault().unregister(this);
- }
-
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- setSystemInsets(insets.getSystemWindowInsets());
- return insets;
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- // Clip the top of the view by the header bar height
- int top = Math.max(0, (int) -getTranslationY()) + mSystemInsets.top + mHeaderHeight;
- mViewBounds.setClipTop(top);
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-
- /**** EventBus Events ****/
-
- public final void onBusEvent(PackagesChangedEvent event) {
- mAdapter.removeTasks(event.packageName, event.userId);
- }
-
- public final void onBusEvent(ClearHistoryEvent event) {
- mAdapter.removeAllTasks();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 330d138..8f149d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -16,15 +16,18 @@
package com.android.systemui.recents.misc;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.ITaskStackListener;
-import android.appwidget.AppWidgetHost;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -34,6 +37,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -47,7 +51,9 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -57,9 +63,9 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.MutableBoolean;
-import android.util.Pair;
import android.view.Display;
import android.view.IDockedStackListener;
+import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.KeyboardShortcutsReceiver;
@@ -68,7 +74,6 @@
import com.android.internal.app.AssistUtils;
import com.android.internal.os.BackgroundThread;
-import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.RecentsImpl;
@@ -80,12 +85,6 @@
import java.util.List;
import java.util.Random;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
-
/**
* Acts as a shim around the real system services that we need to access data from, and provides
* a point of injection when testing UI.
@@ -106,10 +105,11 @@
sRecentsBlacklist.add("com.android.systemui.tv.pip.PipMenuActivity");
}
+ private static SystemServicesProxy sSystemServicesProxy;
+
AccessibilityManager mAccm;
ActivityManager mAm;
IActivityManager mIam;
- AppWidgetManager mAwm;
PackageManager mPm;
IPackageManager mIpm;
AssistUtils mAssistUtils;
@@ -128,12 +128,61 @@
Paint mBgProtectionPaint;
Canvas mBgProtectionCanvas;
+ private final Handler mHandler = new H();
+
+ /**
+ * An abstract class to track task stack changes.
+ * Classes should implement this instead of {@link android.app.ITaskStackListener}
+ * to reduce IPC calls from system services. These callbacks will be called on the main thread.
+ */
+ public abstract static class TaskStackListener {
+ public void onTaskStackChanged() { }
+ public void onActivityPinned() { }
+ public void onPinnedActivityRestartAttempt() { }
+ public void onPinnedStackAnimationEnded() { }
+ }
+
+ /**
+ * Implementation of {@link android.app.ITaskStackListener} to listen task stack changes from
+ * ActivityManagerNative.
+ * This simply passes callbacks to listeners through {@link H}.
+ * */
+ private ITaskStackListener.Stub mTaskStackListener = new ITaskStackListener.Stub() {
+ @Override
+ public void onTaskStackChanged() throws RemoteException {
+ mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
+ mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
+ }
+
+ @Override
+ public void onActivityPinned() throws RemoteException {
+ mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
+ mHandler.sendEmptyMessage(H.ON_ACTIVITY_PINNED);
+ }
+
+ @Override
+ public void onPinnedActivityRestartAttempt() throws RemoteException{
+ mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
+ mHandler.sendEmptyMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
+ }
+
+ @Override
+ public void onPinnedStackAnimationEnded() throws RemoteException {
+ mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED);
+ mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED);
+ }
+ };
+
+ /**
+ * List of {@link TaskStackListener} registered from {@link registerTaskStackListener}.
+ */
+ private List<TaskStackListener> mTaskStackListeners = new ArrayList<>();
+
/** Private constructor */
- public SystemServicesProxy(Context context) {
+ private SystemServicesProxy(Context context) {
mAccm = AccessibilityManager.getInstance(context);
mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
mIam = ActivityManagerNative.getDefault();
- mAwm = AppWidgetManager.getInstance(context);
mPm = context.getPackageManager();
mIpm = AppGlobals.getPackageManager();
mAssistUtils = new AssistUtils(context);
@@ -170,6 +219,20 @@
}
}
+ /**
+ * Returns the single instance of the {@link SystemServicesProxy}.
+ * This should only be called on the main thread.
+ */
+ public static SystemServicesProxy getInstance(Context context) {
+ if (!Looper.getMainLooper().isCurrentThread()) {
+ throw new RuntimeException("Must be called on the UI thread");
+ }
+ if (sSystemServicesProxy == null) {
+ sSystemServicesProxy = new SystemServicesProxy(context);
+ }
+ return sSystemServicesProxy;
+ }
+
/** Returns a list of the recents tasks */
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,
boolean isTopTaskHome, ArraySet<Integer> quietProfileIds) {
@@ -785,89 +848,6 @@
}
/**
- * Returns the current search widget id.
- */
- public int getSearchAppWidgetId(Context context) {
- return Prefs.getInt(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID, -1);
- }
-
- /**
- * Returns the current search widget info, binding a new one if necessary.
- */
- public AppWidgetProviderInfo getOrBindSearchAppWidget(Context context, AppWidgetHost host) {
- int searchWidgetId = Prefs.getInt(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID, -1);
- AppWidgetProviderInfo searchWidgetInfo = mAwm.getAppWidgetInfo(searchWidgetId);
- AppWidgetProviderInfo resolvedSearchWidgetInfo = resolveSearchAppWidget();
-
- // Return the search widget info if it hasn't changed
- if (searchWidgetInfo != null && resolvedSearchWidgetInfo != null &&
- searchWidgetInfo.provider.equals(resolvedSearchWidgetInfo.provider)) {
- if (Prefs.getString(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null) == null) {
- Prefs.putString(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE,
- searchWidgetInfo.provider.getPackageName());
- }
- return searchWidgetInfo;
- }
-
- // Delete the old widget
- if (searchWidgetId != -1) {
- host.deleteAppWidgetId(searchWidgetId);
- }
-
- // And rebind a new search widget
- if (resolvedSearchWidgetInfo != null) {
- Pair<Integer, AppWidgetProviderInfo> widgetInfo = bindSearchAppWidget(host,
- resolvedSearchWidgetInfo);
- if (widgetInfo != null) {
- Prefs.putInt(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID, widgetInfo.first);
- Prefs.putString(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE,
- widgetInfo.second.provider.getPackageName());
- return widgetInfo.second;
- }
- }
-
- // If we fall through here, then there is no resolved search widget, so clear the state
- Prefs.remove(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID);
- Prefs.remove(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE);
- return null;
- }
-
- /**
- * Returns the first Recents widget from the same package as the global assist activity.
- */
- public AppWidgetProviderInfo resolveSearchAppWidget() {
- if (mAssistComponent == null) return null;
- List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
- AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
- for (AppWidgetProviderInfo info : widgets) {
- if (info.provider.getPackageName().equals(mAssistComponent.getPackageName())) {
- return info;
- }
- }
- return null;
- }
-
- /**
- * Resolves and binds the search app widget that is to appear in the recents.
- */
- private Pair<Integer, AppWidgetProviderInfo> bindSearchAppWidget(AppWidgetHost host,
- AppWidgetProviderInfo resolvedSearchWidgetInfo) {
- if (mAwm == null) return null;
- if (mAssistComponent == null) return null;
-
- // Allocate a new widget id and try and bind the app widget (if that fails, then just skip)
- int searchWidgetId = host.allocateAppWidgetId();
- Bundle opts = new Bundle();
- opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
- AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
- if (!mAwm.bindAppWidgetIdIfAllowed(searchWidgetId, resolvedSearchWidgetInfo.provider, opts)) {
- host.deleteAppWidgetId(searchWidgetId);
- return null;
- }
- return new Pair<>(searchWidgetId, resolvedSearchWidgetInfo);
- }
-
- /**
* Returns whether touch exploration is currently enabled.
*/
public boolean isTouchExplorationEnabled() {
@@ -916,28 +896,40 @@
* Returns the smallest width/height.
*/
public int getDeviceSmallestWidth() {
- if (mWm == null) return 0;
+ if (mDisplay == null) return 0;
Point smallestSizeRange = new Point();
Point largestSizeRange = new Point();
- mWm.getDefaultDisplay().getCurrentSizeRange(smallestSizeRange, largestSizeRange);
+ mDisplay.getCurrentSizeRange(smallestSizeRange, largestSizeRange);
return smallestSizeRange.x;
}
/**
- * Returns the display rect.
+ * Returns the current display rect in the current display orientation.
*/
public Rect getDisplayRect() {
Rect displayRect = new Rect();
- if (mWm == null) return displayRect;
+ if (mDisplay == null) return displayRect;
Point p = new Point();
- mWm.getDefaultDisplay().getRealSize(p);
+ mDisplay.getRealSize(p);
displayRect.set(0, 0, p.x, p.y);
return displayRect;
}
/**
+ * Returns the current display orientation.
+ */
+ public int getDisplayOrientation() {
+ // Because of multi-window, the configuration orientation does not necessarily reflect the
+ // orientation of the display, instead we just use the display's real-size.
+ Rect displayRect = getDisplayRect();
+ return displayRect.width() > displayRect.height()
+ ? Configuration.ORIENTATION_LANDSCAPE
+ : Configuration.ORIENTATION_PORTRAIT;
+ }
+
+ /**
* Returns the window rect for the RecentsActivity, based on the dimensions of the home stack.
*/
public Rect getWindowRect() {
@@ -982,14 +974,21 @@
}
}
- /** Registers a task stack listener with the system. */
- public void registerTaskStackListener(ITaskStackListener listener) {
+ /**
+ * Registers a task stack listener with the system.
+ * This should be called on the main thread.
+ */
+ public void registerTaskStackListener(TaskStackListener listener) {
if (mIam == null) return;
- try {
- mIam.registerTaskStackListener(listener);
- } catch (Exception e) {
- e.printStackTrace();
+ mTaskStackListeners.add(listener);
+ if (mTaskStackListeners.size() == 1) {
+ // Register mTaskStackListener to IActivityManager only once if needed.
+ try {
+ mIam.registerTaskStackListener(mTaskStackListener);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to call registerTaskStackListener", e);
+ }
}
}
@@ -1026,8 +1025,9 @@
return dividerWindowWidth - 2 * dividerInsets;
}
- public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) {
- mWm.requestAppKeyboardShortcuts(receiver);
+ public void requestKeyboardShortcuts(
+ Context context, KeyboardShortcutsReceiver receiver, int deviceId) {
+ mWm.requestAppKeyboardShortcuts(receiver, deviceId);
}
public void getStableInsets(Rect outStableInsets) {
@@ -1039,4 +1039,41 @@
e.printStackTrace();
}
}
+
+ private final class H extends Handler {
+ private static final int ON_TASK_STACK_CHANGED = 1;
+ private static final int ON_ACTIVITY_PINNED = 2;
+ private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 3;
+ private static final int ON_PINNED_STACK_ANIMATION_ENDED = 4;
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case ON_TASK_STACK_CHANGED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskStackChanged();
+ }
+ break;
+ }
+ case ON_ACTIVITY_PINNED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityPinned();
+ }
+ break;
+ }
+ case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onPinnedActivityRestartAttempt();
+ }
+ break;
+ }
+ case ON_PINNED_STACK_ANIMATION_ENDED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
+ }
+ break;
+ }
+ }
+ }
+ }
}
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 72b1cab..e28612a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.annotation.FloatRange;
+import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -26,6 +27,7 @@
import android.util.ArraySet;
import android.util.IntProperty;
import android.util.Property;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewParent;
@@ -67,6 +69,8 @@
public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
+ public static final Rect EMPTY_RECT = new Rect();
+
/**
* @return the first parent walking up the view hierarchy that has the given class type.
*
@@ -232,4 +236,11 @@
transforms.subList(taskCount, taskTransformCount).clear();
}
}
+
+ /**
+ * Used for debugging, converts DP to PX.
+ */
+ public static float dpToPx(Resources res, float dp) {
+ return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 6ae07fc..c863471 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -39,7 +39,6 @@
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Formatter;
import java.util.List;
@@ -196,7 +195,7 @@
// Add the task to the stack
Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
thumbnail, title, contentDescription, dismissDescription, activityColor,
- backgroundColor, !isStackTask, isLaunchTarget, isSystemApp, t.isDockable,
+ backgroundColor, isLaunchTarget, isStackTask, isSystemApp, t.isDockable,
t.bounds, t.taskDescription);
allTasks.add(task);
@@ -273,7 +272,7 @@
}
/**
- * Returns whether this task is considered a task to be shown in the history.
+ * Returns whether this task is too old to be shown.
*/
private boolean isHistoricalTask(ActivityManager.RecentTaskInfo t) {
return t.lastActiveTime < (System.currentTimeMillis() - SESSION_BEGIN_TIME);
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 b5a5949..3e858a8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -161,7 +161,7 @@
@ViewDebug.ExportedProperty(category="recents")
public boolean isLaunchTarget;
@ViewDebug.ExportedProperty(category="recents")
- public boolean isHistorical;
+ public boolean isStackTask;
@ViewDebug.ExportedProperty(category="recents")
public boolean isSystemApp;
@ViewDebug.ExportedProperty(category="recents")
@@ -176,7 +176,7 @@
public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
Bitmap thumbnail, String title, String contentDescription,
String dismissDescription, int colorPrimary, int colorBackground,
- boolean isHistorical, boolean isLaunchTarget, boolean isSystemApp,
+ boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp,
boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription) {
boolean isInAffiliationGroup = (affiliationTaskId != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
@@ -195,7 +195,7 @@
this.bounds = bounds;
this.taskDescription = taskDescription;
this.isLaunchTarget = isLaunchTarget;
- this.isHistorical = isHistorical;
+ this.isStackTask = isStackTask;
this.isSystemApp = isSystemApp;
this.isDockable = isDockable;
}
@@ -218,7 +218,7 @@
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
this.bounds = o.bounds;
this.isLaunchTarget = o.isLaunchTarget;
- this.isHistorical = o.isHistorical;
+ this.isStackTask = o.isStackTask;
this.isSystemApp = o.isSystemApp;
this.isDockable = o.isDockable;
}
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 193bfff..930e2d0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -16,6 +16,16 @@
package com.android.systemui.recents.model;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
@@ -37,13 +47,13 @@
import com.android.internal.policy.DockedDividerUtils;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.misc.NamedCounter;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.views.DropTarget;
import com.android.systemui.recents.views.AnimationProps;
+import com.android.systemui.recents.views.DropTarget;
+import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import java.util.ArrayList;
import java.util.Collections;
@@ -51,16 +61,6 @@
import java.util.List;
import java.util.Random;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-
/**
* An interface for a task filter to query whether a particular task should show in a stack.
@@ -220,11 +220,6 @@
*/
void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture);
-
- /**
- * Notifies when a task has been removed from the history.
- */
- void onHistoryTaskRemoved(TaskStack stack, Task removedTask, AnimationProps animation);
}
/**
@@ -375,29 +370,24 @@
* {@param height}.
*/
public Rect getDockedTaskStackBounds(int width, int height, int dividerSize, Rect insets,
- Resources res) {
- RecentsConfiguration config = Recents.getConfiguration();
-
+ TaskStackLayoutAlgorithm layoutAlgorithm, Resources res, Rect windowRectOut) {
// Calculate the inverse docked task bounds
boolean isHorizontalDivision =
res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
insets, width, height, dividerSize);
- Rect newWindowBounds = new Rect();
DockedDividerUtils.calculateBoundsForPosition(position,
- DockedDividerUtils.invertDockSide(dockSide), newWindowBounds, width, height,
+ DockedDividerUtils.invertDockSide(dockSide), windowRectOut, width, height,
dividerSize);
// Calculate the task stack bounds from the new window bounds
- Rect searchBarSpaceBounds = new Rect();
Rect taskStackBounds = new Rect();
// If the task stack bounds is specifically under the dock area, then ignore the top
// inset
int top = dockArea.bottom < 1f
? 0
: insets.top;
- config.getTaskStackBounds(newWindowBounds, top, insets.right,
- searchBarSpaceBounds, taskStackBounds);
+ layoutAlgorithm.getTaskStackBounds(windowRectOut, top, insets.right, taskStackBounds);
return taskStackBounds;
}
}
@@ -429,7 +419,6 @@
ArrayList<Task> mRawTaskList = new ArrayList<>();
FilteredTaskList mStackTaskList = new FilteredTaskList();
- FilteredTaskList mHistoryTaskList = new FilteredTaskList();
TaskStackCallbacks mCb;
ArrayList<TaskGrouping> mGroups = new ArrayList<>();
@@ -448,21 +437,7 @@
t = parentTask;
}
}
- return !t.isHistorical;
- }
- });
- mHistoryTaskList.setFilter(new TaskFilter() {
- @Override
- public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
- if (t.isAffiliatedTask()) {
- // If this task is affiliated with another parent in the stack, then the
- // historical state of this task depends on the state of the parent task
- Task parentTask = taskIdMap.get(t.affiliationTaskId);
- if (parentTask != null) {
- t = parentTask;
- }
- }
- return t.isHistorical;
+ return t.isStackTask;
}
});
}
@@ -523,12 +498,6 @@
mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask, animation,
fromDockGesture);
}
- } else if (mHistoryTaskList.contains(t)) {
- removeTaskImpl(mHistoryTaskList, t);
- if (mCb != null) {
- // Notify that a task has been removed
- mCb.onHistoryTaskRemoved(this, t, animation);
- }
}
mRawTaskList.remove(t);
}
@@ -586,21 +555,7 @@
// Sort all the tasks to ensure they are ordered correctly
Collections.sort(allTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
- // Filter out the historical tasks from this new list
- ArrayList<Task> stackTasks = new ArrayList<>();
- ArrayList<Task> historyTasks = new ArrayList<>();
- int newTaskCount = allTasks.size();
- for (int i = 0; i < newTaskCount; i++) {
- Task task = allTasks.get(i);
- if (task.isHistorical) {
- historyTasks.add(task);
- } else {
- stackTasks.add(task);
- }
- }
-
- mStackTaskList.set(stackTasks);
- mHistoryTaskList.set(historyTasks);
+ mStackTaskList.set(allTasks);
mRawTaskList = allTasks;
// Only callback for the newly added tasks after this stack has been updated
@@ -650,14 +605,6 @@
}
/**
- * Returns the set of tasks that are inactive. These tasks will be presented in a separate
- * history view.
- */
- public ArrayList<Task> getHistoricalTasks() {
- return mHistoryTaskList.getTasks();
- }
-
- /**
* Returns the set of "freeform" tasks in the stack.
*/
public ArrayList<Task> getFreeformTasks() {
@@ -679,7 +626,6 @@
public ArrayList<Task> computeAllTasksList() {
ArrayList<Task> tasks = new ArrayList<>();
tasks.addAll(mStackTaskList.getTasks());
- tasks.addAll(mHistoryTaskList.getTasks());
Collections.sort(tasks, LAST_ACTIVE_TIME_COMPARATOR);
return tasks;
}
@@ -927,10 +873,6 @@
for (Task t : mStackTaskList.getTasks()) {
str += " " + t.toString() + "\n";
}
- str += "Historical Tasks(" + mHistoryTaskList.size() + "):\n";
- for (Task t : mHistoryTaskList.getTasks()) {
- str += " " + t.toString() + "\n";
- }
return str;
}
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 960bd8c..d8e82d9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -126,15 +126,8 @@
@Override
public void run() {
try {
- RecentsActivityLaunchState launchState =
- Recents.getConfiguration().getLaunchState();
ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsTvActivity.this,
- launchState.launchedFromSearchHome ?
- R.anim.recents_to_search_launcher_enter :
- R.anim.recents_to_launcher_enter,
- launchState.launchedFromSearchHome ?
- R.anim.recents_to_search_launcher_exit :
- R.anim.recents_to_launcher_exit);
+ R.anim.recents_to_launcher_enter, R.anim.recents_to_launcher_exit);
startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
} catch (Exception e) {
Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
index 9fd5d55..aa27325 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
@@ -81,8 +81,7 @@
// If there is no thumbnail transition, but is launching from home into recents, then
// use a quick home transition and do the animation from home
if (hasRecentTasks) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- ActivityOptions opts = getHomeTransitionActivityOptions(false);
+ ActivityOptions opts = getHomeTransitionActivityOptions();
startRecentsActivity(topTask, opts, true /* fromHome */, false /* fromThumbnail */);
} else {
// Otherwise we do the normal fade from an unknown source
@@ -99,7 +98,6 @@
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
launchState.launchedFromHome = fromHome;
- launchState.launchedFromSearchHome = false;
launchState.launchedFromApp = fromThumbnail;
launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
launchState.launchedWithAltTab = mTriggeredFromAltTab;
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 bf6229c..3d5176f 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
@@ -104,28 +104,6 @@
requestLayout();
}
- public Task getNextTaskOrTopTask(Task taskToSearch) {
- Task returnTask = null;
- boolean found = false;
- if (mTaskStackHorizontalView != null) {
- TaskStack stack = mTaskStackHorizontalView.getStack();
- ArrayList<Task> taskList = stack.getStackTasks();
- // Iterate the stack views and try and find the focused task
- for (int j = taskList.size() - 1; j >= 0; --j) {
- Task task = taskList.get(j);
- // Return the next task in the line.
- if (found)
- return task;
- // Remember the first possible task as the top task.
- if (returnTask == null)
- returnTask = task;
- if (task == taskToSearch)
- found = true;
- }
- }
- return returnTask;
- }
-
public boolean launchFocusedTask() {
if (mTaskStackHorizontalView != null) {
Task task = mTaskStackHorizontalView.getFocusedTask();
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 5c2de8e..22ade9f 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
@@ -156,9 +156,4 @@
}
}
}
-
- @Override
- public void onHistoryTaskRemoved(TaskStack stack, Task removedTask, AnimationProps animation) {
- //No history task on tv
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 72b914c..035c058 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -46,7 +46,7 @@
public void reloadOnConfigurationChange(Context context) {
// This is applied to the edges of each task
mTaskPadding = context.getResources().getDimensionPixelSize(
- R.dimen.recents_freeform_workspace_task_padding) / 2;
+ R.dimen.recents_freeform_layout_task_padding) / 2;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index a91bbd4..29da476 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -16,6 +16,11 @@
package com.android.systemui.recents.views;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
import android.annotation.Nullable;
import android.app.ActivityManager.StackId;
import android.app.ActivityOptions;
@@ -49,11 +54,6 @@
import java.util.ArrayList;
import java.util.List;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
/**
* A helper class to create transitions to/from Recents
*/
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 db97e8f..70c4c81 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -48,19 +48,14 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsActivityLaunchState;
-import com.android.systemui.recents.RecentsAppWidgetHostView;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.ClearHistoryEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
-import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.HideHistoryEvent;
+import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.ToggleHistoryEvent;
+import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
@@ -68,7 +63,6 @@
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
-import com.android.systemui.recents.history.RecentsHistoryView;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
@@ -94,11 +88,8 @@
private TaskStack mStack;
private TaskStackView mTaskStackView;
- private RecentsAppWidgetHostView mSearchBar;
- private TextView mHistoryButton;
- private TextView mHistoryClearAllButton;
+ private TextView mStackActionButton;
private TextView mEmptyView;
- private RecentsHistoryView mHistoryView;
private boolean mAwaitingFirstLayout = true;
private boolean mLastTaskLaunchedWasFreeform;
@@ -141,18 +132,18 @@
final float cornerRadius = context.getResources().getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
LayoutInflater inflater = LayoutInflater.from(context);
- if (RecentsDebugFlags.Static.EnableHistory) {
- mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this,
+ if (RecentsDebugFlags.Static.EnableStackActionButton) {
+ mStackActionButton = (TextView) inflater.inflate(R.layout.recents_stack_action_button, this,
false);
- mHistoryButton.setOnClickListener(new View.OnClickListener() {
+ mStackActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- EventBus.getDefault().send(new ToggleHistoryEvent());
+ // TODO: To be implemented
}
});
- addView(mHistoryButton);
- mHistoryButton.setClipToOutline(true);
- mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
+ addView(mStackActionButton);
+ mStackActionButton.setClipToOutline(true);
+ mStackActionButton.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
@@ -166,14 +157,17 @@
}
/** Set/get the bsp root node */
- public void onResume(boolean isResumingFromVisible, TaskStack stack) {
+ public void onResume(boolean isResumingFromVisible, boolean multiWindowChange,
+ TaskStack stack) {
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
- if (mTaskStackView == null || !launchState.launchedReuseTaskStackViews) {
+ if (!multiWindowChange &&
+ (mTaskStackView == null || !launchState.launchedReuseTaskStackViews)) {
isResumingFromVisible = false;
removeView(mTaskStackView);
mTaskStackView = new TaskStackView(getContext());
+ mTaskStackView.setSystemInsets(mSystemInsets);
mStack = mTaskStackView.getStack();
addView(mTaskStackView);
}
@@ -185,7 +179,7 @@
// Update the stack
mTaskStackView.onResume(isResumingFromVisible);
mTaskStackView.setTasks(stack, isResumingFromVisible /* notifyStackChanges */,
- true /* relayoutTaskStack */);
+ true /* relayoutTaskStack */, multiWindowChange);
if (isResumingFromVisible) {
// If we are already visible, then restore the background scrim
@@ -217,43 +211,6 @@
return mLastTaskLaunchedWasFreeform;
}
- /**
- * Returns whether the history is visible or not.
- */
- public boolean isHistoryVisible() {
- return mHistoryView != null && mHistoryView.isVisible();
- }
-
- /**
- * Returns the currently set task stack.
- */
- public TaskStack getTaskStack() {
- return mStack;
- }
-
- /** Gets the next task in the stack - or if the last - the top task */
- public Task getNextTaskOrTopTask(Task taskToSearch) {
- Task returnTask = null;
- boolean found = false;
- if (mTaskStackView != null) {
- TaskStack stack = mTaskStackView.getStack();
- ArrayList<Task> taskList = stack.getStackTasks();
- // Iterate the stack views and try and find the focused task
- for (int j = taskList.size() - 1; j >= 0; --j) {
- Task task = taskList.get(j);
- // Return the next task in the line.
- if (found)
- return task;
- // Remember the first possible task as the top task.
- if (returnTask == null)
- returnTask = task;
- if (task == taskToSearch)
- found = true;
- }
- }
- return returnTask;
- }
-
/** Launches the focused task from the first stack if possible */
public boolean launchFocusedTask(int logEvent) {
if (mTaskStackView != null) {
@@ -306,37 +263,16 @@
return false;
}
- /** Adds the search bar */
- public void setSearchBar(RecentsAppWidgetHostView searchBar) {
- // Remove the previous search bar if one exists
- if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
- removeView(mSearchBar);
- }
- // Add the new search bar
- if (searchBar != null) {
- mSearchBar = searchBar;
- addView(mSearchBar);
- }
- }
-
- /** Returns whether there is currently a search bar */
- public boolean hasValidSearchBar() {
- return mSearchBar != null && !mSearchBar.isReinflateRequired();
- }
-
/**
* Hides the task stack and shows the empty view.
*/
public void showEmptyView(int msgResId) {
- if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
- mSearchBar.setVisibility(View.INVISIBLE);
- }
mTaskStackView.setVisibility(View.INVISIBLE);
mEmptyView.setText(msgResId);
mEmptyView.setVisibility(View.VISIBLE);
mEmptyView.bringToFront();
- if (RecentsDebugFlags.Static.EnableHistory) {
- mHistoryButton.bringToFront();
+ if (RecentsDebugFlags.Static.EnableStackActionButton) {
+ mStackActionButton.bringToFront();
}
}
@@ -346,15 +282,9 @@
public void hideEmptyView() {
mEmptyView.setVisibility(View.INVISIBLE);
mTaskStackView.setVisibility(View.VISIBLE);
- if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
- mSearchBar.setVisibility(View.VISIBLE);
- }
mTaskStackView.bringToFront();
- if (mSearchBar != null) {
- mSearchBar.bringToFront();
- }
- if (RecentsDebugFlags.Static.EnableHistory) {
- mHistoryButton.bringToFront();
+ if (RecentsDebugFlags.Static.EnableStackActionButton) {
+ mStackActionButton.bringToFront();
}
}
@@ -377,25 +307,10 @@
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- RecentsConfiguration config = Recents.getConfiguration();
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
- // Get the search bar bounds and measure the search bar layout
- Rect searchBarSpaceBounds = new Rect();
- if (mSearchBar != null) {
- config.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top,
- searchBarSpaceBounds);
- mSearchBar.measure(
- MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY));
- }
-
- Rect taskStackBounds = new Rect();
- config.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
- mSystemInsets.right, searchBarSpaceBounds, taskStackBounds);
- if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
- mTaskStackView.setTaskStackBounds(taskStackBounds, mSystemInsets);
+ if (mTaskStackView.getVisibility() != GONE) {
mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
}
@@ -405,23 +320,12 @@
MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
}
- if (RecentsDebugFlags.Static.EnableHistory) {
- // Measure the history view
- if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
- measureChild(mHistoryView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
- }
-
- // Measure the history button within the constraints of the space above the stack
- Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
- measureChild(mHistoryButton,
- MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
- if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
- measureChild(mHistoryClearAllButton,
- MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
- }
+ if (RecentsDebugFlags.Static.EnableStackActionButton) {
+ // Measure the stack action button within the constraints of the space above the stack
+ Rect actionButtonRect = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
+ measureChild(mStackActionButton,
+ MeasureSpec.makeMeasureSpec(actionButtonRect.width(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(actionButtonRect.height(), MeasureSpec.AT_MOST));
}
setMeasuredDimension(width, height);
@@ -432,19 +336,7 @@
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- RecentsConfiguration config = Recents.getConfiguration();
-
- // Get the search bar bounds so that we lay it out
- Rect measuredRect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
- Rect searchBarSpaceBounds = new Rect();
- if (mSearchBar != null) {
- config.getSearchBarBounds(measuredRect,
- mSystemInsets.top, searchBarSpaceBounds);
- mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top,
- searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
- }
-
- if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
+ if (mTaskStackView.getVisibility() != GONE) {
mTaskStackView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
}
@@ -459,39 +351,19 @@
mEmptyView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
}
- if (RecentsDebugFlags.Static.EnableHistory) {
- // Layout the history view
- if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
- mHistoryView.layout(left, top, right, bottom);
- }
-
- // Layout the history button such that its drawable is start-aligned with the stack,
- // vertically centered in the available space above the stack
- Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
- int historyLeft = isLayoutRtl()
- ? historyButtonRect.right + mHistoryButton.getPaddingStart()
- - mHistoryButton.getMeasuredWidth()
- : historyButtonRect.left - mHistoryButton.getPaddingStart();
- int historyTop = historyButtonRect.top +
- (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
- mHistoryButton.layout(historyLeft, historyTop,
- historyLeft + mHistoryButton.getMeasuredWidth(),
- historyTop + mHistoryButton.getMeasuredHeight());
-
- // Layout the history clear all button such that it is end-aligned with the stack,
- // vertically centered in the available space above the stack
- if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
- int clearAllLeft = isLayoutRtl()
- ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
- : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
- - mHistoryClearAllButton.getMeasuredWidth();
- int clearAllTop = historyButtonRect.top +
- (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) /
- 2;
- mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
- clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
- clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
- }
+ if (RecentsDebugFlags.Static.EnableStackActionButton) {
+ // Layout the stack action button such that its drawable is start-aligned with the
+ // stack, vertically centered in the available space above the stack
+ Rect actionButtonRect = mTaskStackView.mLayoutAlgorithm.mStackActionButtonRect;
+ int buttonLeft = isLayoutRtl()
+ ? actionButtonRect.right + mStackActionButton.getPaddingStart()
+ - mStackActionButton.getMeasuredWidth()
+ : actionButtonRect.left - mStackActionButton.getPaddingStart();
+ int buttonTop = actionButtonRect.top +
+ (actionButtonRect.height() - mStackActionButton.getMeasuredHeight()) / 2;
+ mStackActionButton.layout(buttonLeft, buttonTop,
+ buttonLeft + mStackActionButton.getMeasuredWidth(),
+ buttonTop + mStackActionButton.getMeasuredHeight());
}
if (mAwaitingFirstLayout) {
@@ -511,6 +383,7 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mSystemInsets.set(insets.getSystemWindowInsets());
+ mTaskStackView.setSystemInsets(mSystemInsets);
requestLayout();
return insets;
}
@@ -560,9 +433,9 @@
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
- if (RecentsDebugFlags.Static.EnableHistory) {
- // Hide the history button
- hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+ if (RecentsDebugFlags.Static.EnableStackActionButton) {
+ // Hide the stack action button
+ hideStackActionButton(taskViewExitToHomeDuration, false /* translate */);
}
animateBackgroundScrim(0f, taskViewExitToHomeDuration);
}
@@ -687,144 +560,47 @@
animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
}
- public final void onBusEvent(ToggleHistoryEvent event) {
- if (!RecentsDebugFlags.Static.EnableHistory) {
+ public final void onBusEvent(ShowStackActionButtonEvent event) {
+ if (!RecentsDebugFlags.Static.EnableStackActionButton) {
return;
}
- if (mHistoryView != null && mHistoryView.isVisible()) {
- EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
- } else {
- EventBus.getDefault().send(new ShowHistoryEvent());
- }
+ showStackActionButton(150, event.translate);
}
- public final void onBusEvent(ShowHistoryEvent event) {
- if (!RecentsDebugFlags.Static.EnableHistory) {
+ public final void onBusEvent(HideStackActionButtonEvent event) {
+ if (!RecentsDebugFlags.Static.EnableStackActionButton) {
return;
}
- if (mHistoryView == null) {
- LayoutInflater inflater = LayoutInflater.from(getContext());
- mHistoryView = (RecentsHistoryView) inflater.inflate(R.layout.recents_history, this,
- false);
- addView(mHistoryView);
-
- final float cornerRadius = getResources().getDimensionPixelSize(
- R.dimen.recents_task_view_rounded_corners_radius);
- mHistoryClearAllButton = (TextView) inflater.inflate(
- R.layout.recents_history_clear_all_button, this, false);
- mHistoryClearAllButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- EventBus.getDefault().send(new ClearHistoryEvent());
- }
- });
- mHistoryClearAllButton.setClipToOutline(true);
- mHistoryClearAllButton.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
- }
- });
- addView(mHistoryClearAllButton);
-
- // Since this history view is inflated by a view stub after the insets have already
- // been applied, we have to set them ourselves initial from the insets that were last
- // provided.
- mHistoryView.setSystemInsets(mSystemInsets);
- mHistoryView.setHeaderHeight(mHistoryButton.getMeasuredHeight());
- mHistoryButton.bringToFront();
- mHistoryClearAllButton.bringToFront();
- }
-
- // Animate the empty view in parallel with the history view (the task view animations are
- // handled in TaskStackView)
- Rect stackRect = mTaskStackView.mLayoutAlgorithm.mStackRect;
- if (mEmptyView.getVisibility() == View.VISIBLE) {
- int historyTransitionDuration = getResources().getInteger(
- R.integer.recents_history_transition_duration);
- mEmptyView.animate()
- .alpha(0f)
- .translationY(stackRect.height() / 2)
- .setDuration(historyTransitionDuration)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- mEmptyView.setVisibility(View.INVISIBLE);
- }
- })
- .start();
- }
-
- mHistoryView.show(mStack, stackRect.height(), mHistoryClearAllButton);
- }
-
- public final void onBusEvent(HideHistoryEvent event) {
- if (!RecentsDebugFlags.Static.EnableHistory) {
- return;
- }
-
- // Animate the empty view in parallel with the history view (the task view animations are
- // handled in TaskStackView)
- Rect stackRect = mTaskStackView.mLayoutAlgorithm.mStackRect;
- if (mStack.getTaskCount() == 0) {
- int historyTransitionDuration = getResources().getInteger(
- R.integer.recents_history_transition_duration);
- mEmptyView.setVisibility(View.VISIBLE);
- mEmptyView.animate()
- .alpha(1f)
- .translationY(0)
- .setDuration(historyTransitionDuration)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .start();
- }
-
- mHistoryView.hide(event.animate, stackRect.height(), mHistoryClearAllButton);
- }
-
- public final void onBusEvent(ShowHistoryButtonEvent event) {
- if (!RecentsDebugFlags.Static.EnableHistory) {
- return;
- }
-
- showHistoryButton(150, event.translate);
- }
-
- public final void onBusEvent(HideHistoryButtonEvent event) {
- if (!RecentsDebugFlags.Static.EnableHistory) {
- return;
- }
-
- hideHistoryButton(100, true /* translate */);
+ hideStackActionButton(100, true /* translate */);
}
/**
- * Shows the history button.
+ * Shows the stack action button.
*/
- private void showHistoryButton(final int duration, final boolean translate) {
- if (!RecentsDebugFlags.Static.EnableHistory) {
+ private void showStackActionButton(final int duration, final boolean translate) {
+ if (!RecentsDebugFlags.Static.EnableStackActionButton) {
return;
}
final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
- if (mHistoryButton.getVisibility() == View.INVISIBLE) {
- mHistoryButton.setVisibility(View.VISIBLE);
- mHistoryButton.setAlpha(0f);
+ if (mStackActionButton.getVisibility() == View.INVISIBLE) {
+ mStackActionButton.setVisibility(View.VISIBLE);
+ mStackActionButton.setAlpha(0f);
if (translate) {
- mHistoryButton.setTranslationY(-mHistoryButton.getMeasuredHeight() * 0.25f);
+ mStackActionButton.setTranslationY(-mStackActionButton.getMeasuredHeight() * 0.25f);
} else {
- mHistoryButton.setTranslationY(0f);
+ mStackActionButton.setTranslationY(0f);
}
postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
@Override
public void run() {
if (translate) {
- mHistoryButton.animate()
+ mStackActionButton.animate()
.translationY(0f);
}
- mHistoryButton.animate()
+ mStackActionButton.animate()
.alpha(1f)
.setDuration(duration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
@@ -837,40 +613,40 @@
}
/**
- * Hides the history button.
+ * Hides the stack action button.
*/
- private void hideHistoryButton(int duration, boolean translate) {
- if (!RecentsDebugFlags.Static.EnableHistory) {
+ private void hideStackActionButton(int duration, boolean translate) {
+ if (!RecentsDebugFlags.Static.EnableStackActionButton) {
return;
}
final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
- hideHistoryButton(duration, translate, postAnimationTrigger);
+ hideStackActionButton(duration, translate, postAnimationTrigger);
postAnimationTrigger.flushLastDecrementRunnables();
}
/**
- * Hides the history button.
+ * Hides the stack action button.
*/
- private void hideHistoryButton(int duration, boolean translate,
- final ReferenceCountedTrigger postAnimationTrigger) {
- if (!RecentsDebugFlags.Static.EnableHistory) {
+ private void hideStackActionButton(int duration, boolean translate,
+ final ReferenceCountedTrigger postAnimationTrigger) {
+ if (!RecentsDebugFlags.Static.EnableStackActionButton) {
return;
}
- if (mHistoryButton.getVisibility() == View.VISIBLE) {
+ if (mStackActionButton.getVisibility() == View.VISIBLE) {
if (translate) {
- mHistoryButton.animate()
- .translationY(-mHistoryButton.getMeasuredHeight() * 0.25f);
+ mStackActionButton.animate()
+ .translationY(-mStackActionButton.getMeasuredHeight() * 0.25f);
}
- mHistoryButton.animate()
+ mStackActionButton.animate()
.alpha(0f)
.setDuration(duration)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(new Runnable() {
@Override
public void run() {
- mHistoryButton.setVisibility(View.INVISIBLE);
+ mStackActionButton.setVisibility(View.INVISIBLE);
postAnimationTrigger.decrement();
}
})
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 19b219a..6bdaaf9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -16,11 +16,9 @@
package com.android.systemui.recents.views;
-import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.content.Context;
import android.view.View;
-import android.view.ViewPropertyAnimator;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index b36d5d1..4155dd2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -65,6 +65,12 @@
*/
void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested,
ReferenceCountedTrigger postAnimationTrigger);
+
+ /**
+ * Callback to start the animation for the front {@link TaskView} if there is no launch
+ * target.
+ */
+ void onStartFrontTaskEnterAnimation(boolean screenPinningEnabled);
}
private static final int FRAME_OFFSET_MS = 16;
@@ -126,9 +132,9 @@
int offscreenYOffset = stackLayout.mStackRect.height();
int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
- R.dimen.recents_task_view_affiliate_group_enter_offset);
+ R.dimen.recents_task_stack_animation_affiliate_enter_offset);
int launchedWhileDockingOffset = res.getDimensionPixelSize(
- R.dimen.recents_task_view_launched_while_docking_offset);
+ R.dimen.recents_task_stack_animation_launched_while_docking_offset);
// Prepare each of the task views for their enter animation from front to back
List<TaskView> taskViews = mStackView.getTaskViews();
@@ -164,6 +170,7 @@
// Move the task view off screen (below) so we can animate it in
RectF bounds = new RectF(mTmpTransform.rect);
bounds.offset(0, offscreenYOffset);
+ tv.setAlpha(0f);
tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right,
(int) bounds.bottom);
} else if (launchState.launchedWhileDocking) {
@@ -232,7 +239,7 @@
@Override
public void onAnimationEnd(Animator animation) {
postAnimationTrigger.decrement();
- tv.setClipViewInStack(false);
+ tv.setClipViewInStack(true);
}
});
postAnimationTrigger.increment();
@@ -254,6 +261,9 @@
.setListener(postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
+ if (i == taskViewCount - 1) {
+ tv.onStartFrontTaskEnterAnimation(mStackView.mScreenPinningEnabled);
+ }
} else if (launchState.launchedWhileDocking) {
// Animate the tasks up
AnimationProps taskAnimation = new AnimationProps()
@@ -312,6 +322,7 @@
stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
null);
+ mTmpTransform.alpha = 0f;
mTmpTransform.rect.offset(0, offscreenYOffset);
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
}
@@ -330,7 +341,7 @@
int taskViewExitToAppDuration = res.getInteger(
R.integer.recents_task_exit_to_app_duration);
int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
- R.dimen.recents_task_view_affiliate_group_enter_offset);
+ R.dimen.recents_task_stack_animation_affiliate_enter_offset);
Task launchingTask = launchingTaskView.getTask();
List<TaskView> taskViews = mStackView.getTaskViews();
@@ -399,62 +410,6 @@
}
/**
- * Starts the animation to hide the {@link TaskView}s when the history is shown.
- */
- public void startShowHistoryAnimation(ReferenceCountedTrigger postAnimationTrigger) {
- Resources res = mStackView.getResources();
- TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
- TaskStackViewScroller stackScroller = mStackView.getScroller();
-
- int offscreenY = stackLayout.mStackRect.bottom;
- int historyTransitionDuration = res.getInteger(
- R.integer.recents_history_transition_duration);
- int startDelayIncr = 16;
-
- List<TaskView> taskViews = mStackView.getTaskViews();
- int taskViewCount = taskViews.size();
- for (int i = taskViewCount - 1; i >= 0; i--) {
- TaskView tv = taskViews.get(i);
- Task task = tv.getTask();
- AnimationProps taskAnimation = new AnimationProps(startDelayIncr * i,
- historyTransitionDuration, Interpolators.FAST_OUT_SLOW_IN,
- postAnimationTrigger.decrementOnAnimationEnd());
- postAnimationTrigger.increment();
-
- stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
- null);
- mTmpTransform.alpha = 0f;
- mTmpTransform.rect.offsetTo(mTmpTransform.rect.left, offscreenY);
- mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
- }
- }
-
- /**
- * Starts the animation to show the {@link TaskView}s when the history is hidden.
- */
- public void startHideHistoryAnimation() {
- Resources res = mStackView.getResources();
- TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
- TaskStackViewScroller stackScroller = mStackView.getScroller();
-
- int historyTransitionDuration = res.getInteger(
- R.integer.recents_history_transition_duration);
- int startDelayIncr = 16;
-
- List<TaskView> taskViews = mStackView.getTaskViews();
- int taskViewCount = taskViews.size();
- for (int i = taskViewCount - 1; i >= 0; i--) {
- TaskView tv = taskViews.get(i);
- AnimationProps taskAnimation = new AnimationProps(startDelayIncr * i,
- historyTransitionDuration, Interpolators.FAST_OUT_SLOW_IN);
- stackLayout.getStackTransform(tv.getTask(), stackScroller.getStackScroll(),
- mTmpTransform, null);
- mTmpTransform.alpha = 1f;
- mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
- }
- }
-
- /**
* Starts the animation to focus the next {@link TaskView} when paging through recents.
*
* @return whether or not this will trigger a scroll in the stack
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 6df5884..93c5fc9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -16,7 +16,9 @@
package com.android.systemui.recents.views;
+import android.annotation.IntDef;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Path;
import android.graphics.Rect;
@@ -36,6 +38,8 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
@@ -97,8 +101,10 @@
}
/**
- * The layout logic for a TaskStackView. This layout can have two states focused and unfocused,
- * and in the focused state, there is a task that is displayed more prominently in the stack.
+ * The layout logic for a TaskStackView. This layout needs to be able to calculate the stack layout
+ * without an activity-specific context only with the information passed in. This layout can have
+ * two states focused and unfocused, and in the focused state, there is a task that is displayed
+ * more prominently in the stack.
*/
public class TaskStackLayoutAlgorithm {
@@ -107,13 +113,28 @@
public static final float OUTLINE_ALPHA_MIN_VALUE = 0f;
public static final float OUTLINE_ALPHA_MAX_VALUE = 2f;
- // The maximum dim on the tasks
+ // The medium/maximum dim on the tasks
+ private static final float MED_DIM = 0.15f;
private static final float MAX_DIM = 0.25f;
// The various focus states
public static final int STATE_FOCUSED = 1;
public static final int STATE_UNFOCUSED = 0;
+ // The side that an offset is anchored
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({FROM_TOP, FROM_BOTTOM})
+ public @interface AnchorSide {}
+ private static final int FROM_TOP = 0;
+ private static final int FROM_BOTTOM = 1;
+
+ // The extent that we care about when calculating fractions
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({WIDTH, HEIGHT})
+ public @interface Extent {}
+ private static final int WIDTH = 0;
+ private static final int HEIGHT = 1;
+
public interface TaskStackLayoutAlgorithmCallbacks {
void onFocusStateChanged(int prevFocusState, int curFocusState);
}
@@ -165,22 +186,24 @@
* @param taskStackBounds the full rect that the freeform rect can take up
*/
public void computeRects(Rect freeformRectOut, Rect stackRectOut,
- Rect taskStackBounds, int widthPadding, int heightPadding, int stackBottomOffset) {
- int availableHeight = taskStackBounds.height() - stackBottomOffset;
+ Rect taskStackBounds, int topMargin, int freeformGap, int stackBottomOffset) {
+ // The freeform height is the visible height (not including system insets) - padding
+ // above freeform and below stack - gap between the freeform and stack
+ int availableHeight = taskStackBounds.height() - topMargin - stackBottomOffset;
int ffPaddedHeight = (int) (availableHeight * freeformHeightPct);
- int ffHeight = Math.max(0, ffPaddedHeight - (2 * heightPadding));
- freeformRectOut.set(taskStackBounds.left + widthPadding,
- taskStackBounds.top + heightPadding,
- taskStackBounds.right - widthPadding,
- taskStackBounds.top + heightPadding + ffHeight);
- stackRectOut.set(taskStackBounds.left + widthPadding,
+ int ffHeight = Math.max(0, ffPaddedHeight - freeformGap);
+ freeformRectOut.set(taskStackBounds.left,
+ taskStackBounds.top + topMargin,
+ taskStackBounds.right,
+ taskStackBounds.top + topMargin + ffHeight);
+ stackRectOut.set(taskStackBounds.left,
taskStackBounds.top,
- taskStackBounds.right - widthPadding,
+ taskStackBounds.right,
taskStackBounds.bottom);
if (ffPaddedHeight > 0) {
stackRectOut.top += ffPaddedHeight;
} else {
- stackRectOut.top += heightPadding;
+ stackRectOut.top += topMargin;
}
}
}
@@ -204,44 +227,53 @@
// The task bounds (untransformed) for layout. This rect is anchored at mTaskRoot.
@ViewDebug.ExportedProperty(category="recents")
public Rect mTaskRect = new Rect();
- // The freeform workspace bounds, inset from the top by the search bar, and is a fixed height
+ // The freeform workspace bounds, inset by the top system insets and is a fixed height
@ViewDebug.ExportedProperty(category="recents")
public Rect mFreeformRect = new Rect();
- // The stack bounds, inset from the top by the search bar, and runs to
- // the bottom of the screen
+ // The stack bounds, inset from the top system insets, and runs to the bottom of the screen
@ViewDebug.ExportedProperty(category="recents")
public Rect mStackRect = new Rect();
// This is the current system insets
@ViewDebug.ExportedProperty(category="recents")
public Rect mSystemInsets = new Rect();
- // This is the bounds of the history button above the stack rect
+ // This is the bounds of the stack action above the stack rect
@ViewDebug.ExportedProperty(category="recents")
- public Rect mHistoryButtonRect = new Rect();
+ public Rect mStackActionButtonRect = new Rect();
// The visible ranges when the stack is focused and unfocused
private Range mUnfocusedRange;
private Range mFocusedRange;
- // The initial offset from the top and bottom of the stack
+ // The base top margin for the stack from the system insets
@ViewDebug.ExportedProperty(category="recents")
- private int mInitialTopPeekHeight;
+ private int mBaseTopMargin;
+ // The base side margin for the stack from the system insets
@ViewDebug.ExportedProperty(category="recents")
- private int mInitialBottomPeekHeight;
+ private int mBaseSideMargin;
+ // The base bottom margin for the stack from the system insets
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mBaseBottomMargin;
+ private int mMinMargin;
- // The offset from the top when scrolled to the top of the stack
+ // The gap between the freeform and stack layouts
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mFreeformStackGap;
+
+ // The initial offset that the focused task is from the top
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mInitialTopOffset;
+ private int mBaseInitialTopOffset;
+ // The initial offset that the launch-from task is from the bottom
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mInitialBottomOffset;
+ private int mBaseInitialBottomOffset;
+
+ // The height between the top margin and the top of the focused task
@ViewDebug.ExportedProperty(category="recents")
private int mFocusedTopPeekHeight;
+ // The height between the bottom margin and the top of task in front of the focused task
@ViewDebug.ExportedProperty(category="recents")
- private int mFocusedBottomTaskPeekHeight;
-
- // The offset from the top of the stack to the top of the bounds when the stack is scrolled to
- // the end
- @ViewDebug.ExportedProperty(category="recents")
- private int mStackTopOffset;
-
- // The height of the header bar
- @ViewDebug.ExportedProperty(category="recents")
- private int mHeaderBarHeight;
+ private int mFocusedBottomPeekHeight;
// The offset from the bottom of the stack to the bottom of the bounds when the stack is
// scrolled to the front
@@ -307,9 +339,23 @@
TaskViewTransform mFrontOfStackTransform = new TaskViewTransform();
public TaskStackLayoutAlgorithm(Context context, TaskStackLayoutAlgorithmCallbacks cb) {
+ Resources res = context.getResources();
mContext = context;
mCb = cb;
mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
+ mMinMargin = res.getDimensionPixelSize(R.dimen.recents_layout_min_margin);
+ mBaseTopMargin = getDimensionForDevice(res,
+ R.dimen.recents_layout_top_margin_phone,
+ R.dimen.recents_layout_top_margin_tablet,
+ R.dimen.recents_layout_top_margin_tablet_xlarge);
+ mBaseSideMargin = getDimensionForDevice(res,
+ R.dimen.recents_layout_side_margin_phone,
+ R.dimen.recents_layout_side_margin_tablet,
+ R.dimen.recents_layout_side_margin_tablet_xlarge);
+ mBaseBottomMargin = res.getDimensionPixelSize(R.dimen.recents_layout_bottom_margin);
+ mFreeformStackGap =
+ res.getDimensionPixelSize(R.dimen.recents_freeform_layout_bottom_margin);
+
reloadOnConfigurationChange(context);
}
@@ -323,17 +369,25 @@
mUnfocusedRange = new Range(res.getFloat(R.integer.recents_layout_unfocused_range_min),
res.getFloat(R.integer.recents_layout_unfocused_range_max));
mFocusState = getInitialFocusState();
- mInitialTopPeekHeight = res.getDimensionPixelSize(R.dimen.recents_initial_top_peek_size);
- mInitialBottomPeekHeight =
- res.getDimensionPixelSize(R.dimen.recents_initial_bottom_peek_size);
- mFocusedTopPeekHeight =
- res.getDimensionPixelSize(R.dimen.recents_layout_focused_top_peek_size);
- mFocusedBottomTaskPeekHeight =
- res.getDimensionPixelSize(R.dimen.recents_layout_focused_bottom_task_peek_size);
- mHeaderBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
-
- mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
- mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
+ mFocusedTopPeekHeight = res.getDimensionPixelSize(R.dimen.recents_layout_top_peek_size);
+ mFocusedBottomPeekHeight =
+ res.getDimensionPixelSize(R.dimen.recents_layout_bottom_peek_size);
+ mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_layout_z_min);
+ mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_layout_z_max);
+ mBaseInitialTopOffset = getDimensionForDevice(res,
+ R.dimen.recents_layout_initial_top_offset_phone_port,
+ R.dimen.recents_layout_initial_top_offset_phone_land,
+ R.dimen.recents_layout_initial_top_offset_tablet,
+ R.dimen.recents_layout_initial_top_offset_tablet,
+ R.dimen.recents_layout_initial_top_offset_tablet,
+ R.dimen.recents_layout_initial_top_offset_tablet);
+ mBaseInitialBottomOffset = getDimensionForDevice(res,
+ R.dimen.recents_layout_initial_bottom_offset_phone_port,
+ R.dimen.recents_layout_initial_bottom_offset_phone_land,
+ R.dimen.recents_layout_initial_bottom_offset_tablet,
+ R.dimen.recents_layout_initial_bottom_offset_tablet,
+ R.dimen.recents_layout_initial_bottom_offset_tablet,
+ R.dimen.recents_layout_initial_bottom_offset_tablet);
mFreeformLayoutAlgorithm.reloadOnConfigurationChange(context);
}
@@ -372,52 +426,52 @@
}
/**
- * Computes the stack and task rects. The given task stack bounds is the whole bounds not
- * including the search bar.
+ * Computes the stack and task rects. The given task stack bounds already has the top/right
+ * insets and left/right padding already applied.
*/
- public void initialize(Rect taskStackBounds, StackState state) {
- RecentsConfiguration config = Recents.getConfiguration();
- int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
- int heightPadding = mContext.getResources().getDimensionPixelSize(
- R.dimen.recents_stack_top_padding);
+ public void initialize(Rect windowRect, Rect taskStackBounds, StackState state) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
Rect lastStackRect = new Rect(mStackRect);
+ Rect displayRect = ssp.getDisplayRect();
- // The freeform height is the visible height (not including system insets) - padding above
- // freeform and below stack - gap between the freeform and stack
+ int topMargin = getScaleForExtent(windowRect, displayRect, mBaseTopMargin, mMinMargin, HEIGHT);
+ int bottomMargin = getScaleForExtent(windowRect, displayRect, mBaseBottomMargin, mMinMargin,
+ HEIGHT);
+ mInitialTopOffset = getScaleForExtent(windowRect, displayRect, mBaseInitialTopOffset,
+ mMinMargin, HEIGHT);
+ mInitialBottomOffset = mBaseInitialBottomOffset;
+
+ // Compute the stack bounds
mState = state;
- mStackTopOffset = mFocusedTopPeekHeight + heightPadding;
- mStackBottomOffset = mSystemInsets.bottom + heightPadding;
- state.computeRects(mFreeformRect, mStackRect, taskStackBounds, widthPadding, heightPadding,
- mStackBottomOffset);
- // The history button will take the full un-padded header space above the stack
- mHistoryButtonRect.set(mStackRect.left, mStackRect.top - heightPadding,
+ mStackBottomOffset = mSystemInsets.bottom + bottomMargin;
+ state.computeRects(mFreeformRect, mStackRect, taskStackBounds, topMargin,
+ mFreeformStackGap, mStackBottomOffset);
+
+ // The stack action button will take the full un-padded header space above the stack
+ mStackActionButtonRect.set(mStackRect.left, mStackRect.top - topMargin,
mStackRect.right, mStackRect.top + mFocusedTopPeekHeight);
- // Anchor the task rect to the top-center of the non-freeform stack rect
- float aspect = (float) (taskStackBounds.width() - mSystemInsets.left - mSystemInsets.right)
- / (taskStackBounds.height() - mSystemInsets.bottom);
- int width = mStackRect.width();
- int minHeight = mStackRect.height() - mFocusedTopPeekHeight - mStackBottomOffset;
- int height = (int) Math.min(width / aspect, minHeight);
- mTaskRect.set(mStackRect.left, mStackRect.top,
- mStackRect.left + width, mStackRect.top + height);
+ // Anchor the task rect top aligned to the non-freeform stack rect
+ float aspect = (float) (windowRect.width() - (mSystemInsets.left + mSystemInsets.right)) /
+ (windowRect.height() - (mSystemInsets.top + mSystemInsets.bottom));
+ int minHeight = mStackRect.height() - mInitialTopOffset - mStackBottomOffset;
+ int height = (int) Math.min(mStackRect.width() / aspect, minHeight);
+ mTaskRect.set(mStackRect.left, mStackRect.top, mStackRect.right, mStackRect.top + height);
// Short circuit here if the stack rects haven't changed so we don't do all the work below
- if (lastStackRect.equals(mStackRect)) {
- return;
+ if (!lastStackRect.equals(mStackRect)) {
+ // Reinitialize the focused and unfocused curves
+ mUnfocusedCurve = constructUnfocusedCurve();
+ mUnfocusedCurveInterpolator = new FreePathInterpolator(mUnfocusedCurve);
+ mFocusedCurve = constructFocusedCurve();
+ mFocusedCurveInterpolator = new FreePathInterpolator(mFocusedCurve);
+ mUnfocusedDimCurve = constructUnfocusedDimCurve();
+ mUnfocusedDimCurveInterpolator = new FreePathInterpolator(mUnfocusedDimCurve);
+ mFocusedDimCurve = constructFocusedDimCurve();
+ mFocusedDimCurveInterpolator = new FreePathInterpolator(mFocusedDimCurve);
+
+ updateFrontBackTransforms();
}
-
- // Reinitialize the focused and unfocused curves
- mUnfocusedCurve = constructUnfocusedCurve();
- mUnfocusedCurveInterpolator = new FreePathInterpolator(mUnfocusedCurve);
- mFocusedCurve = constructFocusedCurve();
- mFocusedCurveInterpolator = new FreePathInterpolator(mFocusedCurve);
- mUnfocusedDimCurve = constructUnfocusedDimCurve();
- mUnfocusedDimCurveInterpolator = new FreePathInterpolator(mUnfocusedDimCurve);
- mFocusedDimCurve = constructFocusedDimCurve();
- mFocusedDimCurveInterpolator = new FreePathInterpolator(mFocusedDimCurve);
-
- updateFrontBackTransforms();
}
/**
@@ -435,7 +489,7 @@
ArrayList<Task> tasks = stack.getStackTasks();
if (tasks.isEmpty()) {
mFrontMostTaskP = 0;
- mMinScrollP = mMaxScrollP = 0;
+ mMinScrollP = mMaxScrollP = mInitialScrollP = 0;
mNumStackTasks = mNumFreeformTasks = 0;
return;
}
@@ -492,8 +546,7 @@
// Set the max scroll to be the point where the front most task is visible with the
// stack bottom offset
int maxBottomOffset = mStackBottomOffset + mTaskRect.height();
- float maxBottomOffsetPct = (float) maxBottomOffset / mStackRect.height();
- float maxBottomNormX = mUnfocusedCurveInterpolator.getX(maxBottomOffsetPct);
+ float maxBottomNormX = getNormalizedXFromUnfocusedY(maxBottomOffset, FROM_BOTTOM);
mUnfocusedRange.offset(0f);
mMinScrollP = 0;
mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
@@ -502,34 +555,19 @@
launchState.launchedFromAppDocked;
if (scrollToFront) {
mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
+ mInitialNormX = null;
} else {
- mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
- }
+ float normX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
+ mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2)) -
+ Math.max(0, mUnfocusedRange.getAbsoluteX(normX)));
- // Set the initial scroll to the predefined state (which differs from the stack)
- int initialPeekOffset = mStackRect.height() - mInitialTopPeekHeight;
- float initialPeekOffsetPct = (float) initialPeekOffset / mStackRect.height();
- float initialPeekOffsetNormX = mUnfocusedCurveInterpolator.getX(initialPeekOffsetPct);
- float initialFocusedOffset = mStackRect.height() - mInitialTopPeekHeight -
- (mHeaderBarHeight * 1f) + 1;
- float initialFocusedOffsetPct = initialFocusedOffset / mStackRect.height();
- float initialFocusedNormX = mUnfocusedCurveInterpolator.getX(initialFocusedOffsetPct);
- float initialBottomOffset = mStackBottomOffset +
- (ssp.hasDockedTask()
- ? mHeaderBarHeight
- : mInitialBottomPeekHeight);
- float initialBottomOffsetPct = initialBottomOffset / mStackRect.height();
- float initialBottomNormX = mUnfocusedCurveInterpolator.getX(initialBottomOffsetPct);
- /*
- // If we want to offset the top card slightly
- mInitialNormX = scrollToFront
- ? new float[] { initialFocusedNormX, initialPeekOffsetNormX, 0f }
- : new float[] { initialBottomNormX, initialFocusedNormX,
- initialPeekOffsetNormX, 0f };
- */
- mInitialNormX = scrollToFront
- ? new float[] { initialFocusedNormX, initialPeekOffsetNormX, 0f }
- : new float[] { initialBottomNormX, 0.5f, 0f };
+ // Set the initial scroll to the predefined state (which differs from the stack)
+ mInitialNormX = new float[] {
+ getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset,
+ FROM_BOTTOM),
+ normX
+ };
+ }
}
}
@@ -669,7 +707,7 @@
Range currentRange = getInitialFocusState() > 0f ? mFocusedRange : mUnfocusedRange;
currentRange.offset(mInitialScrollP);
int taskBarHeight = mContext.getResources().getDimensionPixelSize(
- R.dimen.recents_task_bar_height);
+ R.dimen.recents_task_view_header_height);
int numVisibleTasks = Math.max(mNumFreeformTasks, 1);
int numVisibleThumbnails = Math.max(mNumFreeformTasks, 1);
float prevScreenY = Integer.MAX_VALUE;
@@ -869,6 +907,25 @@
}
/**
+ * Returns the original scroll progress to scroll to such that the top of the task is at the top
+ * of the stack.
+ */
+ float getStackScrollForTaskIgnoreOverrides(Task t) {
+ return (float) mTaskIndexMap.get(t.key.id, 0);
+ }
+
+ /**
+ * Returns the scroll progress to scroll to such that the top of the task at the initial top
+ * offset (which is at the task's brightest point).
+ */
+ float getStackScrollForTaskAtInitialOffset(Task t) {
+ float normX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
+ mUnfocusedRange.offset(0f);
+ return Utilities.clamp((float) mTaskIndexMap.get(t.key.id, 0) - Math.max(0,
+ mUnfocusedRange.getAbsoluteX(normX)), mMinScrollP, mMaxScrollP);
+ }
+
+ /**
* Maps a movement in screen y, relative to {@param downY}, to a movement in along the arc
* length of the curve. We know the curve is mostly flat, so we just map the length of the
* screen along the arc-length proportionally (1/arclength).
@@ -890,6 +947,76 @@
}
/**
+ * Returns the task stack bounds in the current orientation. This rect takes into account the
+ * top and right system insets (but not the bottom inset) and left/right paddings, but _not_
+ * the top/bottom padding or insets.
+ */
+ public void getTaskStackBounds(Rect windowRect, int topInset, int rightInset,
+ Rect taskStackBounds) {
+ RecentsConfiguration config = Recents.getConfiguration();
+ if (config.hasTransposedNavBar) {
+ taskStackBounds.set(windowRect.left, windowRect.top + topInset,
+ windowRect.right - rightInset, windowRect.bottom);
+ } else {
+ taskStackBounds.set(windowRect.left, windowRect.top + topInset,
+ windowRect.right - rightInset, windowRect.bottom);
+ }
+
+ // Ensure that the new width is at most the smaller display edge size
+ Rect displayRect = Recents.getSystemServices().getDisplayRect();
+ int sideMargin = getScaleForExtent(windowRect, displayRect, mBaseSideMargin, mMinMargin,
+ WIDTH);
+ int targetStackWidth = Math.min(taskStackBounds.width() - 2 * sideMargin,
+ Math.min(displayRect.width(), displayRect.height()));
+ taskStackBounds.inset((taskStackBounds.width() - targetStackWidth) / 2, 0);
+ }
+
+ /**
+ * Retrieves resources that are constant regardless of the current configuration of the device.
+ */
+ public static int getDimensionForDevice(Resources res, int phoneResId,
+ int tabletResId, int xlargeTabletResId) {
+ return getDimensionForDevice(res, phoneResId, phoneResId, tabletResId, tabletResId,
+ xlargeTabletResId, xlargeTabletResId);
+ }
+
+ /**
+ * Retrieves resources that are constant regardless of the current configuration of the device.
+ */
+ public static int getDimensionForDevice(Resources res, int phonePortResId, int phoneLandResId,
+ int tabletPortResId, int tabletLandResId, int xlargeTabletPortResId,
+ int xlargeTabletLandResId) {
+ RecentsConfiguration config = Recents.getConfiguration();
+ boolean isLandscape = Recents.getSystemServices().getDisplayOrientation() ==
+ Configuration.ORIENTATION_LANDSCAPE;
+ if (config.isXLargeScreen) {
+ return res.getDimensionPixelSize(isLandscape
+ ? xlargeTabletLandResId
+ : xlargeTabletPortResId);
+ } else if (config.isLargeScreen) {
+ return res.getDimensionPixelSize(isLandscape
+ ? tabletLandResId
+ : tabletPortResId);
+ } else {
+ return res.getDimensionPixelSize(isLandscape
+ ? phoneLandResId
+ : phonePortResId);
+ }
+ }
+
+ /**
+ * Returns the normalized x on the unfocused curve given an absolute Y position (relative to the
+ * stack height).
+ */
+ private float getNormalizedXFromUnfocusedY(float y, @AnchorSide int fromSide) {
+ float offset = (fromSide == FROM_TOP)
+ ? mStackRect.height() - y
+ : y;
+ float offsetPct = offset / mStackRect.height();
+ return mUnfocusedCurveInterpolator.getX(offsetPct);
+ }
+
+ /**
* Creates a new path for the focused curve.
*/
private Path constructFocusedCurve() {
@@ -897,13 +1024,12 @@
// linear pieces that goes from (0,1) through (0.5, peek height offset),
// (0.5, bottom task offsets), and (1,0).
float topPeekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
- float bottomPeekHeightPct = Math.max(
- mSystemInsets.bottom + mFocusedRange.relativeMax * mFocusedBottomTaskPeekHeight,
- mStackBottomOffset + mFocusedBottomTaskPeekHeight) / mStackRect.height();
+ float bottomPeekHeightPct = (float) (mStackBottomOffset + mFocusedBottomPeekHeight) /
+ mStackRect.height();
Path p = new Path();
p.moveTo(0f, 1f);
p.lineTo(0.5f, 1f - topPeekHeightPct);
- p.lineTo(0.5f + (0.5f / mFocusedRange.relativeMax), bottomPeekHeightPct);
+ p.lineTo(1f - (0.5f / mFocusedRange.relativeMax), bottomPeekHeightPct);
p.lineTo(1f, 0f);
return p;
}
@@ -919,16 +1045,16 @@
// the control point of the second bezier such that between it and a first known point,
// there is a tangent at (0.5, peek height offset).
float cpoint1X = 0.4f;
- float cpoint1Y = 1f;
- float peekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
- float slope = ((1f - peekHeightPct) - cpoint1Y) / (0.5f - cpoint1X);
+ float cpoint1Y = 0.975f;
+ float topPeekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height();
+ float slope = ((1f - topPeekHeightPct) - cpoint1Y) / (0.5f - cpoint1X);
float b = 1f - slope * cpoint1X;
float cpoint2X = 0.65f;
float cpoint2Y = slope * cpoint2X + b;
Path p = new Path();
p.moveTo(0f, 1f);
- p.cubicTo(0f, 1f, cpoint1X, cpoint1Y, 0.5f, 1f - peekHeightPct);
- p.cubicTo(0.5f, 1f - peekHeightPct, cpoint2X, cpoint2Y, 1f, 0f);
+ p.cubicTo(0f, 1f, cpoint1X, cpoint1Y, 0.5f, 1f - topPeekHeightPct);
+ p.cubicTo(0.5f, 1f - topPeekHeightPct, cpoint2X, cpoint2Y, 1f, 0f);
return p;
}
@@ -950,15 +1076,30 @@
* Creates a new path for the unfocused dim curve.
*/
private Path constructUnfocusedDimCurve() {
+ float focusX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
+ float cpoint2X = focusX + (1f - focusX) / 2;
Path p = new Path();
// The unfocused dim interpolator starts at max dim, reduces to zero at 0.5 (the focused
// task), then goes back to max dim towards the front of the stack
p.moveTo(0f, MAX_DIM);
- p.cubicTo(0.1f, MAX_DIM, 0.4f, 0.0f, 0.5f, 0f);
- p.cubicTo(0.6f, 0f, 0.9f, MAX_DIM / 2f, 1f, MAX_DIM / 2f);
+ p.cubicTo(focusX * 0.5f, MAX_DIM, focusX * 0.75f, MAX_DIM * 0.75f, focusX, 0f);
+ p.cubicTo(cpoint2X, 0f, cpoint2X, MED_DIM, 1f, MED_DIM);
return p;
}
+ /**
+ * Scales the given {@param value} to the scale of the {@param instance} rect relative to the
+ * {@param other} rect in the {@param extent} side.
+ */
+ private int getScaleForExtent(Rect instance, Rect other, int value, int minValue,
+ @Extent int extent) {
+ if (extent == WIDTH) {
+ return Math.max(minValue, (int) (((float) instance.width() / other.width()) * value));
+ } else if (extent == HEIGHT) {
+ return Math.max(minValue, (int) (((float) instance.height() / other.height()) * value));
+ }
+ return value;
+ }
/**
* Updates the current transforms that would put a TaskView at the front and back of the stack.
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 0b20d21..c9cc1e9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -59,8 +59,7 @@
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsTaskStackAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
-import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.HideHistoryEvent;
+import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
@@ -68,8 +67,7 @@
import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
-import com.android.systemui.recents.events.activity.ShowHistoryEvent;
+import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
@@ -84,7 +82,6 @@
import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
import com.android.systemui.recents.misc.DozeTrigger;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
@@ -106,15 +103,15 @@
private final static String KEY_SAVED_STATE_LAYOUT_STACK_SCROLL =
"saved_instance_state_layout_stack_scroll";
- // The thresholds at which to show/hide the history button.
- private static final float SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
- private static final float HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
+ // 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;
public static final int DEFAULT_SYNC_STACK_DURATION = 200;
private static final int DRAG_SCALE_DURATION = 175;
private static final float DRAG_SCALE_FACTOR = 1.05f;
- private static final int LAUNCH_NEXT_SCROLL_BASE_DURATION = 200;
+ private static final int LAUNCH_NEXT_SCROLL_BASE_DURATION = 216;
private static final int LAUNCH_NEXT_SCROLL_INCR_DURATION = 32;
private static final ArraySet<Task.TaskKey> EMPTY_TASK_SET = new ArraySet<>();
@@ -165,11 +162,18 @@
// The current stack bounds are dynamic and may change as the user drags and drops
@ViewDebug.ExportedProperty(category="recents")
private Rect mStackBounds = new Rect();
+ // The current window bounds at the point we were measured
+ @ViewDebug.ExportedProperty(category="recents")
+ private Rect mStableWindowRect = new Rect();
+ // The current window bounds are dynamic and may change as the user drags and drops
+ @ViewDebug.ExportedProperty(category="recents")
+ private Rect mWindowRect = new Rect();
private Rect mTmpRect = new Rect();
private ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
private List<TaskView> mTmpTaskViews = new ArrayList<>();
private TaskViewTransform mTmpTransform = new TaskViewTransform();
+ private ArrayList<TaskViewTransform> mTmpTaskTransforms = new ArrayList<>();
private int[] mTmpIntPair = new int[2];
// A convenience update listener to request updating clipping of tasks
@@ -302,7 +306,8 @@
/**
* Sets the stack tasks of this TaskStackView from the given TaskStack.
*/
- public void setTasks(TaskStack stack, boolean notifyStackChanges, boolean relayoutTaskStack) {
+ public void setTasks(TaskStack stack, boolean notifyStackChanges, boolean relayoutTaskStack,
+ boolean multiWindowChange) {
boolean isInitialized = mLayoutAlgorithm.isInitialized();
mStack.setTasks(getContext(), stack.computeAllTasksList(),
notifyStackChanges && isInitialized);
@@ -310,7 +315,9 @@
// Only update the layout if we are notifying, otherwise, we will update it in the next
// measure/layout pass
updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
- updateToInitialState();
+ if (!multiWindowChange) {
+ updateToInitialState();
+ }
if (relayoutTaskStack) {
relayoutTaskViews(AnimationProps.IMMEDIATE);
@@ -622,15 +629,17 @@
}
/**
- * 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
- * {@link TaskView}s will match the set of visible tasks in the stack.
- *
- * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>)
+ * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean)
*/
void relayoutTaskViews(AnimationProps animation) {
- relayoutTaskViews(animation, mIgnoreTasks);
+ 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 */);
}
/**
@@ -641,13 +650,14 @@
*
* @param ignoreTasksSet the set of tasks to ignore in the relayout
*/
- void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet) {
+ void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet,
+ boolean ignoreTaskOverrides) {
// If we had a deferred animation, cancel that
mDeferredTaskViewLayoutAnimation = null;
// Synchronize the current set of TaskViews
bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTasksSet,
- false /* ignoreTaskOverrides */);
+ ignoreTaskOverrides /* ignoreTaskOverrides */);
// Animate them to their final transforms with the given animation
List<TaskView> taskViews = getTaskViews();
@@ -1059,8 +1069,10 @@
event.setContentDescription(frontMostTask.getTask().title);
}
event.setItemCount(mStack.getTaskCount());
- event.setScrollY(mStackScroller.mScroller.getCurrY());
- event.setMaxScrollY(mStackScroller.progressToScrollRange(mLayoutAlgorithm.mMaxScrollP));
+
+ int stackHeight = mLayoutAlgorithm.mStackRect.height();
+ event.setScrollY((int) (mStackScroller.getStackScroll() * stackHeight));
+ event.setMaxScrollY((int) (mLayoutAlgorithm.mMaxScrollP * stackHeight));
}
@Override
@@ -1161,23 +1173,11 @@
}
/**
- * Updates the expected task stack bounds for this stack view.
+ * Updates the system insets.
*/
- public void setTaskStackBounds(Rect taskStackBounds, Rect systemInsets) {
- // We can get spurious measure passes with the old bounds when docking, and since we are
- // using the current stack bounds during drag and drop, don't overwrite them until we
- // actually get new bounds
- boolean requiresLayout = false;
- if (!taskStackBounds.equals(mStableStackBounds)) {
- mStableStackBounds.set(taskStackBounds);
- mStackBounds.set(taskStackBounds);
- requiresLayout = true;
- }
+ public void setSystemInsets(Rect systemInsets) {
if (!systemInsets.equals(mLayoutAlgorithm.mSystemInsets)) {
mLayoutAlgorithm.setSystemInsets(systemInsets);
- requiresLayout = true;
- }
- if (requiresLayout) {
requestLayout();
}
}
@@ -1192,8 +1192,20 @@
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
+ // Update the stable stack bounds, but only update the current stack bounds if the stable
+ // bounds have changed. This is because we may get spurious measures while dragging where
+ // our current stack bounds reflect the target drop region.
+ mLayoutAlgorithm.getTaskStackBounds(new Rect(0, 0, width, height),
+ mLayoutAlgorithm.mSystemInsets.top, mLayoutAlgorithm.mSystemInsets.right, mTmpRect);
+ if (!mTmpRect.equals(mStableStackBounds)) {
+ mStableStackBounds.set(mTmpRect);
+ mStackBounds.set(mTmpRect);
+ mStableWindowRect.set(0, 0, width, height);
+ mWindowRect.set(0, 0, width, height);
+ }
+
// Compute the rects in the stack algorithm
- mLayoutAlgorithm.initialize(mStackBounds,
+ mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
@@ -1241,11 +1253,6 @@
MeasureSpec.EXACTLY));
}
- /**
- * This is called with the size of the space not including the top or right insets, or the
- * search bar height in portrait (but including the search bar width in landscape, since we want
- * to draw under it.
- */
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// Layout each of the TaskViews
@@ -1282,6 +1289,7 @@
mTmpRect.setEmpty();
}
Rect taskRect = mLayoutAlgorithm.mTaskRect;
+ tv.cancelTransformAnimation();
tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
}
@@ -1306,12 +1314,11 @@
false /* requestViewFocus */);
}
- // Update the history button visibility
- if (shouldShowHistoryButton() &&
- mStackScroller.getStackScroll() < SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
- EventBus.getDefault().send(new ShowHistoryButtonEvent(false /* translate */));
+ // Update the stack action button visibility
+ if (mStackScroller.getStackScroll() < SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) {
+ EventBus.getDefault().send(new ShowStackActionButtonEvent(false /* translate */));
} else {
- EventBus.getDefault().send(new HideHistoryButtonEvent());
+ EventBus.getDefault().send(new HideStackActionButtonEvent());
}
}
@@ -1432,12 +1439,6 @@
}
}
- @Override
- public void onHistoryTaskRemoved(TaskStack stack, Task removedTask,
- AnimationProps animation) {
- // To be implemented
- }
-
/**** ViewPoolConsumer Implementation ****/
@Override
@@ -1572,13 +1573,12 @@
mLayoutAlgorithm.updateFocusStateOnScroll(curScroll, curScroll - prevScroll);
if (mEnterAnimationComplete) {
- if (shouldShowHistoryButton() &&
- prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
- curScroll <= SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
- EventBus.getDefault().send(new ShowHistoryButtonEvent(true /* translate */));
- } else if (prevScroll < HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD &&
- curScroll >= HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD) {
- EventBus.getDefault().send(new HideHistoryButtonEvent());
+ if (prevScroll > SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
+ curScroll <= SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) {
+ EventBus.getDefault().send(new ShowStackActionButtonEvent(true /* translate */));
+ } else if (prevScroll < HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
+ curScroll >= HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) {
+ EventBus.getDefault().send(new HideStackActionButtonEvent());
}
}
}
@@ -1625,15 +1625,13 @@
cancelAllTaskViewAnimations();
final Task launchTask = mStack.getStackTasks().get(launchTaskIndex);
- if (getChildViewForTask(launchTask) == null) {
- List<TaskView> taskViews = getTaskViews();
- int lastTaskIndex = !taskViews.isEmpty()
- ? mStack.indexOfStackTask(taskViews.get(taskViews.size() - 1).getTask())
- : mStack.getTaskCount() - 1;
- int duration = LAUNCH_NEXT_SCROLL_BASE_DURATION +
- Math.abs(mStack.indexOfStackTask(launchTask) - lastTaskIndex)
- * LAUNCH_NEXT_SCROLL_INCR_DURATION;
- mStackScroller.animateScroll(mLayoutAlgorithm.getStackScrollForTask(launchTask),
+ float curScroll = mStackScroller.getStackScroll();
+ float targetScroll = mLayoutAlgorithm.getStackScrollForTaskAtInitialOffset(launchTask);
+ float absScrollDiff = Math.abs(targetScroll - curScroll);
+ if (getChildViewForTask(launchTask) == null || absScrollDiff > 0.35f) {
+ int duration = (int) (LAUNCH_NEXT_SCROLL_BASE_DURATION +
+ absScrollDiff * LAUNCH_NEXT_SCROLL_INCR_DURATION);
+ mStackScroller.animateScroll(targetScroll,
duration, new Runnable() {
@Override
public void run() {
@@ -1757,32 +1755,38 @@
public final void onBusEvent(DragDropTargetChangedEvent event) {
AnimationProps animation = new AnimationProps(250, Interpolators.FAST_OUT_SLOW_IN);
+ boolean ignoreTaskOverrides = false;
if (event.dropTarget instanceof TaskStack.DockState) {
// 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;
mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(),
getMeasuredHeight(), mDividerSize, mLayoutAlgorithm.mSystemInsets,
- getResources()));
- mLayoutAlgorithm.initialize(mStackBounds,
+ mLayoutAlgorithm, getResources(), mWindowRect));
+ mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
updateLayoutAlgorithm(true /* boundScroll */);
+ ignoreTaskOverrides = true;
} else {
// Restore the pre-drag task stack bounds, but ensure that we don't layout the dragging
// task view, so add it back to the ignore set after updating the layout
+ mWindowRect.set(mStableWindowRect);
mStackBounds.set(mStableStackBounds);
removeIgnoreTask(event.task);
- mLayoutAlgorithm.initialize(mStackBounds,
+ mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
updateLayoutAlgorithm(true /* boundScroll */);
addIgnoreTask(event.task);
}
- relayoutTaskViews(animation);
+ relayoutTaskViews(animation, mIgnoreTasks, ignoreTaskOverrides);
}
public final void onBusEvent(final DragEndEvent event) {
// We don't handle drops on the dock regions
if (event.dropTarget instanceof TaskStack.DockState) {
+ // However, we do need to reset the overrides, since the last state of this task stack
+ // view layout was ignoring task overrides (see DragDropTargetChangedEvent handler)
+ mLayoutAlgorithm.clearUnfocusedTaskOverrides();
return;
}
@@ -1888,22 +1892,6 @@
}
}
- public final void onBusEvent(ShowHistoryEvent event) {
- ReferenceCountedTrigger postAnimTrigger = new ReferenceCountedTrigger();
- postAnimTrigger.addLastDecrementRunnable(new Runnable() {
- @Override
- public void run() {
- setVisibility(View.INVISIBLE);
- }
- });
- mAnimationHelper.startShowHistoryAnimation(postAnimTrigger);
- }
-
- public final void onBusEvent(HideHistoryEvent event) {
- setVisibility(View.VISIBLE);
- mAnimationHelper.startHideHistoryAnimation();
- }
-
public final void onBusEvent(MultiWindowStateChangedEvent event) {
if (!event.inMultiWindow) {
// Scroll the stack to the front to see the undocked task
@@ -1924,7 +1912,7 @@
public final void onBusEvent(ConfigurationChangedEvent event) {
mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
- mLayoutAlgorithm.initialize(mStackBounds,
+ mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
}
@@ -1993,13 +1981,6 @@
}
/**
- * @return whether the history button should be visible
- */
- private boolean shouldShowHistoryButton() {
- return !mStack.getHistoricalTasks().isEmpty();
- }
-
- /**
* Reads current system flags related to accessibility and screen pinning.
*/
private void readSystemFlags() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 9be3542..583fb88 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -28,8 +28,6 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
/* The scrolling logic for a TaskStackView */
@@ -189,7 +187,7 @@
// Finish any current scrolling animations
if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
setStackScroll(mFinalAnimatedScroll);
- mScroller.startScroll(0, progressToScrollRange(mFinalAnimatedScroll), 0, 0, 0);
+ mScroller.forceFinished(true);
}
stopScroller();
stopBoundScrollAnimation();
@@ -223,12 +221,6 @@
/**** OverScroller ****/
- // TODO: Remove
- @Deprecated
- int progressToScrollRange(float p) {
- return (int) (p * mLayoutAlgorithm.mStackRect.height());
- }
-
/** Called from the view draw, computes the next scroll. */
boolean computeScroll() {
if (mScroller.computeScrollOffset()) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 8635911..aed19c3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -121,7 +121,7 @@
mScrollTouchSlop = configuration.getScaledTouchSlop();
mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
mFlingAnimUtils = new FlingAnimationUtils(context, 0.2f);
- mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_stack_overscroll);
+ mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_fling_overscroll_distance);
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context) {
@Override
protected float getSize(View v) {
@@ -458,12 +458,13 @@
newStackScroll = stackScroller.getBoundedStackScroll(newStackScroll);
} else if (pullStackForward) {
// Otherwise, offset the scroll by the movement of the anchor task
- float anchorTaskScroll = layoutAlgorithm.getStackScrollForTask(anchorTask);
+ float anchorTaskScroll =
+ layoutAlgorithm.getStackScrollForTaskIgnoreOverrides(anchorTask);
float stackScrollOffset = (anchorTaskScroll - prevAnchorTaskScroll);
if (layoutAlgorithm.getFocusState() != TaskStackLayoutAlgorithm.STATE_FOCUSED) {
// If we are focused, we don't want the front task to move, but otherwise, we
// allow the back task to move up, and the front task to move back
- stackScrollOffset /= 2;
+ stackScrollOffset *= 0.75f;
}
newStackScroll = stackScroller.getBoundedStackScroll(stackScroller.getStackScroll()
+ stackScrollOffset);
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 7584a2e..107d8d4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,13 +16,14 @@
package com.android.systemui.recents.views;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Point;
@@ -59,8 +60,6 @@
import java.util.ArrayList;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
/**
* A {@link TaskView} represents a fixed view of a task. Because the TaskView's layout is directed
* solely by the {@link TaskStackView}, we make it a fixed size layout which allows relayouts down
@@ -559,6 +558,13 @@
postAnimationTrigger.decrementOnAnimationEnd());
}
+ @Override
+ public void onStartFrontTaskEnterAnimation(boolean screenPinningEnabled) {
+ if (screenPinningEnabled) {
+ showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
+ }
+ }
+
/**** TaskCallbacks Implementation ****/
public void onTaskBound(Task t) {
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 b2a7d90..a2e9573 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -337,6 +337,11 @@
}
}
+ /** Only exposed for the workaround for b/27815919. */
+ public ImageView getIconView() {
+ return mIconView;
+ }
+
/** Returns the secondary color for a primary color. */
int getSecondaryColor(int primaryColor, boolean useLightOverlayColor) {
int overlayColor = useLightOverlayColor ? Color.WHITE : Color.BLACK;
@@ -350,6 +355,7 @@
public void setDimAlpha(float dimAlpha) {
if (Float.compare(mDimAlpha, dimAlpha) != 0) {
mDimAlpha = dimAlpha;
+ mTitleView.setAlpha(1f - dimAlpha);
updateBackgroundColor(mBackground.getColor(), dimAlpha);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2d2a08a..1c5d28a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1206,10 +1206,10 @@
}
@Override
- public void toggleKeyboardShortcutsMenu() {
+ public void toggleKeyboardShortcutsMenu(int deviceId) {
int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
+ mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
}
/** Jumps to the next affiliated task in the group. */
@@ -1295,8 +1295,8 @@
}
}
- protected void toggleKeyboardShortcuts() {
- getKeyboardShortcuts().toggleKeyboardShortcuts();
+ protected void toggleKeyboardShortcuts(int deviceId) {
+ getKeyboardShortcuts().toggleKeyboardShortcuts(deviceId);
}
protected void cancelPreloadingRecents() {
@@ -1469,7 +1469,7 @@
showRecentsPreviousAffiliatedTask();
break;
case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
- toggleKeyboardShortcuts();
+ toggleKeyboardShortcuts(m.arg1);
break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 6a98488..0ffab5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -107,7 +107,7 @@
public void toggleRecentApps();
public void toggleSplitScreen();
public void preloadRecentApps();
- public void toggleKeyboardShortcutsMenu();
+ public void toggleKeyboardShortcutsMenu(int deviceId);
public void cancelPreloadRecentApps();
public void setWindowState(int window, int state);
public void buzzBeepBlinked();
@@ -254,10 +254,10 @@
}
@Override
- public void toggleKeyboardShortcutsMenu() {
+ public void toggleKeyboardShortcutsMenu(int deviceId) {
synchronized (mLock) {
mHandler.removeMessages(MSG_TOGGLE_KEYBOARD_SHORTCUTS);
- mHandler.obtainMessage(MSG_TOGGLE_KEYBOARD_SHORTCUTS).sendToTarget();
+ mHandler.obtainMessage(MSG_TOGGLE_KEYBOARD_SHORTCUTS, deviceId, 0).sendToTarget();
}
}
@@ -425,7 +425,7 @@
mCallbacks.cancelPreloadRecentApps();
break;
case MSG_TOGGLE_KEYBOARD_SHORTCUTS:
- mCallbacks.toggleKeyboardShortcutsMenu();
+ mCallbacks.toggleKeyboardShortcutsMenu(msg.arg1);
break;
case MSG_SET_WINDOW_STATE:
mCallbacks.setWindowState(msg.arg1, msg.arg2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 60c2fa6..8fe60a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -21,9 +21,14 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
+import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.Looper;
+import android.util.Log;
+import android.util.SparseArray;
import android.view.ContextThemeWrapper;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@@ -42,16 +47,163 @@
import java.util.List;
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
-import static android.view.Gravity.TOP;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
/**
* Contains functionality for handling keyboard shortcuts.
*/
public class KeyboardShortcuts {
- private static final char SYSTEM_HOME_BASE_CHARACTER = '\u2386';
- private static final char SYSTEM_BACK_BASE_CHARACTER = '\u007F';
- private static final char SYSTEM_RECENTS_BASE_CHARACTER = '\u0009';
+ private static final String TAG = KeyboardShortcuts.class.getSimpleName();
+
+ private static final SparseArray<String> SPECIAL_CHARACTER_NAMES = new SparseArray<>();
+ private static final SparseArray<String> MODIFIER_NAMES = new SparseArray<>();
+
+ private static void loadSpecialCharacterNames(Context context) {
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_HOME, context.getString(R.string.keyboard_key_home));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_BACK, context.getString(R.string.keyboard_key_back));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_DPAD_UP, context.getString(R.string.keyboard_key_dpad_up));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_DPAD_DOWN, context.getString(R.string.keyboard_key_dpad_down));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_DPAD_LEFT, context.getString(R.string.keyboard_key_dpad_left));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_DPAD_RIGHT, context.getString(R.string.keyboard_key_dpad_right));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_DPAD_CENTER, context.getString(R.string.keyboard_key_dpad_center));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_PERIOD, ".");
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_TAB, context.getString(R.string.keyboard_key_tab));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_SPACE, context.getString(R.string.keyboard_key_space));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_ENTER, context.getString(R.string.keyboard_key_enter));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_DEL, context.getString(R.string.keyboard_key_backspace));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
+ context.getString(R.string.keyboard_key_media_play_pause));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_MEDIA_STOP, context.getString(R.string.keyboard_key_media_stop));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_MEDIA_NEXT, context.getString(R.string.keyboard_key_media_next));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS,
+ context.getString(R.string.keyboard_key_media_previous));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MEDIA_REWIND,
+ context.getString(R.string.keyboard_key_media_rewind));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD,
+ context.getString(R.string.keyboard_key_media_fast_forward));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_PAGE_UP, context.getString(R.string.keyboard_key_page_up));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_PAGE_DOWN, context.getString(R.string.keyboard_key_page_down));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_A,
+ context.getString(R.string.keyboard_key_button_template, "A"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_B,
+ context.getString(R.string.keyboard_key_button_template, "B"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_C,
+ context.getString(R.string.keyboard_key_button_template, "C"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_X,
+ context.getString(R.string.keyboard_key_button_template, "X"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_Y,
+ context.getString(R.string.keyboard_key_button_template, "Y"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_Z,
+ context.getString(R.string.keyboard_key_button_template, "Z"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_L1,
+ context.getString(R.string.keyboard_key_button_template, "L1"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_R1,
+ context.getString(R.string.keyboard_key_button_template, "R1"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_L2,
+ context.getString(R.string.keyboard_key_button_template, "L2"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_R2,
+ context.getString(R.string.keyboard_key_button_template, "R2"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_START,
+ context.getString(R.string.keyboard_key_button_template, "Start"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_SELECT,
+ context.getString(R.string.keyboard_key_button_template, "Select"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BUTTON_MODE,
+ context.getString(R.string.keyboard_key_button_template, "Mode"));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_FORWARD_DEL, context.getString(R.string.keyboard_key_forward_del));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_ESCAPE, "Esc");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_SYSRQ, "SysRq");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_BREAK, "Break");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_SCROLL_LOCK, "Scroll Lock");
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_MOVE_HOME, context.getString(R.string.keyboard_key_move_home));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_MOVE_END, context.getString(R.string.keyboard_key_move_end));
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_INSERT, context.getString(R.string.keyboard_key_insert));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F1, "F1");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F2, "F2");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F3, "F3");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F4, "F4");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F5, "F5");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F6, "F6");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F7, "F7");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F8, "F8");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F9, "F9");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F10, "F10");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F11, "F11");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_F12, "F12");
+ SPECIAL_CHARACTER_NAMES.put(
+ KeyEvent.KEYCODE_NUM_LOCK, context.getString(R.string.keyboard_key_num_lock));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_0,
+ context.getString(R.string.keyboard_key_numpad_template, "0"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_1,
+ context.getString(R.string.keyboard_key_numpad_template, "1"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_2,
+ context.getString(R.string.keyboard_key_numpad_template, "2"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_3,
+ context.getString(R.string.keyboard_key_numpad_template, "3"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_4,
+ context.getString(R.string.keyboard_key_numpad_template, "4"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_5,
+ context.getString(R.string.keyboard_key_numpad_template, "5"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_6,
+ context.getString(R.string.keyboard_key_numpad_template, "6"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_7,
+ context.getString(R.string.keyboard_key_numpad_template, "7"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_8,
+ context.getString(R.string.keyboard_key_numpad_template, "8"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_9,
+ context.getString(R.string.keyboard_key_numpad_template, "9"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_DIVIDE,
+ context.getString(R.string.keyboard_key_numpad_template, "/"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_MULTIPLY,
+ context.getString(R.string.keyboard_key_numpad_template, "*"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_SUBTRACT,
+ context.getString(R.string.keyboard_key_numpad_template, "-"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_ADD,
+ context.getString(R.string.keyboard_key_numpad_template, "+"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_DOT,
+ context.getString(R.string.keyboard_key_numpad_template, "."));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_COMMA,
+ context.getString(R.string.keyboard_key_numpad_template, ","));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_ENTER,
+ context.getString(R.string.keyboard_key_numpad_template,
+ context.getString(R.string.keyboard_key_enter)));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_EQUALS,
+ context.getString(R.string.keyboard_key_numpad_template, "="));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN,
+ context.getString(R.string.keyboard_key_numpad_template, "("));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN,
+ context.getString(R.string.keyboard_key_numpad_template, ")"));
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_ZENKAKU_HANKAKU, "半角/全角");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_EISU, "英数");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_MUHENKAN, "無変換");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_HENKAN, "変換");
+ SPECIAL_CHARACTER_NAMES.put(KeyEvent.KEYCODE_KATAKANA_HIRAGANA, "かな");
+
+ MODIFIER_NAMES.put(KeyEvent.META_META_ON, "Meta");
+ MODIFIER_NAMES.put(KeyEvent.META_CTRL_ON, "Ctrl");
+ MODIFIER_NAMES.put(KeyEvent.META_ALT_ON, "Alt");
+ MODIFIER_NAMES.put(KeyEvent.META_SHIFT_ON, "Shift");
+ MODIFIER_NAMES.put(KeyEvent.META_SYM_ON, "Sym");
+ MODIFIER_NAMES.put(KeyEvent.META_FUNCTION_ON, "Fn");
+ }
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Context mContext;
@@ -62,12 +214,20 @@
};
private Dialog mKeyboardShortcutsDialog;
+ private KeyCharacterMap mKeyCharacterMap;
public KeyboardShortcuts(Context context) {
this.mContext = new ContextThemeWrapper(context, android.R.style.Theme_Material_Light);
+ if (SPECIAL_CHARACTER_NAMES.size() == 0) {
+ loadSpecialCharacterNames(context);
+ }
}
- public void toggleKeyboardShortcuts() {
+ public void toggleKeyboardShortcuts(int deviceId) {
+ InputDevice inputDevice = InputManager.getInstance().getInputDevice(deviceId);
+ if (inputDevice != null) {
+ mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+ }
if (mKeyboardShortcutsDialog == null) {
Recents.getSystemServices().requestKeyboardShortcuts(mContext,
new KeyboardShortcutsReceiver() {
@@ -75,20 +235,20 @@
public void onKeyboardShortcutsReceived(
final List<KeyboardShortcutGroup> result) {
KeyboardShortcutGroup systemGroup = new KeyboardShortcutGroup(
- mContext.getString(R.string.keyboard_shortcut_group_system), true);
+ mContext.getString(R.string.keyboard_shortcut_group_system), true);
systemGroup.addItem(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_system_home),
- SYSTEM_HOME_BASE_CHARACTER, KeyEvent.META_META_ON));
+ mContext.getString(R.string.keyboard_shortcut_group_system_home),
+ KeyEvent.KEYCODE_ENTER, KeyEvent.META_META_ON));
systemGroup.addItem(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_system_back),
- SYSTEM_BACK_BASE_CHARACTER, KeyEvent.META_META_ON));
+ mContext.getString(R.string.keyboard_shortcut_group_system_back),
+ KeyEvent.KEYCODE_DEL, KeyEvent.META_META_ON));
systemGroup.addItem(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_system_recents),
- SYSTEM_RECENTS_BASE_CHARACTER, KeyEvent.META_ALT_ON));
+ mContext.getString(R.string.keyboard_shortcut_group_system_recents),
+ KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON));
result.add(systemGroup);
showKeyboardShortcutsDialog(result);
}
- });
+ }, deviceId);
} else {
dismissKeyboardShortcutsDialog();
}
@@ -148,6 +308,18 @@
final int itemsSize = group.getItems().size();
for (int j = 0; j < itemsSize; j++) {
KeyboardShortcutInfo info = group.getItems().get(j);
+ if (info.getKeycode() != KeyEvent.KEYCODE_UNKNOWN
+ && !KeyCharacterMap.deviceHasKey(info.getKeycode())) {
+ // The user can't achieve this shortcut, so skipping.
+ Log.w(TAG, "Keyboard Shortcut contains key not on device, skipping.");
+ continue;
+ }
+ List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
+ if (shortcutKeys == null) {
+ // Ignore shortcuts we can't display keys for.
+ Log.w(TAG, "Keyboard Shortcut contains unsupported keys, skipping.");
+ continue;
+ }
View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item,
shortcutContainer, false);
TextView textView = (TextView) shortcutView
@@ -156,7 +328,6 @@
ViewGroup shortcutItemsContainer = (ViewGroup) shortcutView
.findViewById(R.id.keyboard_shortcuts_item_container);
- List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
final int shortcutKeysSize = shortcutKeys.size();
for (int k = 0; k < shortcutKeysSize; k++) {
String shortcutKey = shortcutKeys.get(k);
@@ -178,11 +349,46 @@
}
private List<String> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
- // TODO: fix the shortcuts. Find or build an util which can produce human readable
- // names of the baseCharacter and the modifiers.
- List<String> shortcutKeys = new ArrayList<>();
- shortcutKeys.add(KeyEvent.metaStateToString(info.getModifiers()).toUpperCase());
- shortcutKeys.add(Character.getName(info.getBaseCharacter()).toUpperCase());
+ List<String> shortcutKeys = getHumanReadableModifiers(info);
+ if (shortcutKeys == null) {
+ return null;
+ }
+ String displayLabelString;
+ if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+ displayLabelString = String.valueOf(info.getBaseCharacter());
+ } else if (SPECIAL_CHARACTER_NAMES.get(info.getKeycode()) != null) {
+ displayLabelString = SPECIAL_CHARACTER_NAMES.get(info.getKeycode());
+ } else {
+ // TODO: Have a generic map for when we don't have the device's.
+ char displayLabel = mKeyCharacterMap == null
+ ? 0 : mKeyCharacterMap.getDisplayLabel(info.getKeycode());
+ if (displayLabel != 0) {
+ displayLabelString = String.valueOf(displayLabel);
+ } else {
+ return null;
+ }
+ }
+ shortcutKeys.add(displayLabelString.toUpperCase());
+ return shortcutKeys;
+ }
+
+ private List<String> getHumanReadableModifiers(KeyboardShortcutInfo info) {
+ final List<String> shortcutKeys = new ArrayList<>();
+ int modifiers = info.getModifiers();
+ if (modifiers == 0) {
+ return shortcutKeys;
+ }
+ for(int i = 0; i < MODIFIER_NAMES.size(); ++i) {
+ final int supportedModifier = MODIFIER_NAMES.keyAt(i);
+ if ((modifiers & supportedModifier) != 0) {
+ shortcutKeys.add(MODIFIER_NAMES.get(supportedModifier).toUpperCase());
+ modifiers &= ~supportedModifier;
+ }
+ }
+ if (modifiers != 0) {
+ // Remaining unsupported modifiers, don't show anything.
+ return null;
+ }
return shortcutKeys;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index c32ef0e..726aed3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.car;
import android.app.ActivityManager;
-import android.app.ITaskStackListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -33,6 +32,7 @@
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -40,9 +40,7 @@
* A status bar (and navigation bar) tailored for the automotive use case.
*/
public class CarStatusBar extends PhoneStatusBar {
- private SystemServicesProxy mSystemServicesProxy;
private TaskStackListenerImpl mTaskStackListener;
- private Handler mHandler;
private CarNavigationBarView mCarNavigationBar;
private CarNavigationBarController mController;
@@ -51,10 +49,8 @@
@Override
public void start() {
super.start();
- mHandler = new Handler();
- mTaskStackListener = new TaskStackListenerImpl(mHandler);
- mSystemServicesProxy = new SystemServicesProxy(mContext);
- mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+ mTaskStackListener = new TaskStackListenerImpl();
+ SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
registerPackageChangeReceivers();
}
@@ -114,47 +110,16 @@
}
/**
- * An implementation of ITaskStackListener, that listens for changes in the system task
+ * An implementation of TaskStackListener, that listens for changes in the system task
* stack and notifies the navigation bar.
*/
- private class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable {
- private Handler mHandler;
-
- public TaskStackListenerImpl(Handler handler) {
- this.mHandler = handler;
- }
-
- @Override
- public void onActivityPinned() {
- }
-
- @Override
- public void onPinnedActivityRestartAttempt() {
- }
-
- @Override
- public void onPinnedStackAnimationEnded() {
- }
-
+ private class TaskStackListenerImpl extends TaskStackListener {
@Override
public void onTaskStackChanged() {
- mHandler.removeCallbacks(this);
- mHandler.post(this);
- }
-
- @Override
- public void run() {
- ensureMainThread();
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
mController.taskChanged(runningTaskInfo.baseActivity.getPackageName());
}
-
- private void ensureMainThread() {
- if (!Looper.getMainLooper().isCurrentThread()) {
- throw new RuntimeException("Must be called on the UI thread");
- }
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
index 50ead3d..225751a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
@@ -27,14 +28,17 @@
private static final String TAG = "IconMerger";
private static final boolean DEBUG = false;
- private int mIconSize;
+ private final int mIconSize;
+ private final int mIconHPadding;
+
private View mMoreView;
public IconMerger(Context context, AttributeSet attrs) {
super(context, attrs);
- mIconSize = context.getResources().getDimensionPixelSize(
- R.dimen.status_bar_icon_size);
+ Resources res = context.getResources();
+ mIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
+ mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
if (DEBUG) {
setBackgroundColor(0x800099FF);
@@ -45,12 +49,16 @@
mMoreView = v;
}
+ private int getFullIconWidth() {
+ return mIconSize + 2 * mIconHPadding;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// we need to constrain this to an integral multiple of our children
int width = getMeasuredWidth();
- setMeasuredDimension(width - (width % mIconSize), getMeasuredHeight());
+ setMeasuredDimension(width - (width % getFullIconWidth()), getMeasuredHeight());
}
@Override
@@ -70,7 +78,7 @@
final boolean overflowShown = (mMoreView.getVisibility() == View.VISIBLE);
// let's assume we have one more slot if the more icon is already showing
if (overflowShown) visibleChildren --;
- final boolean moreRequired = visibleChildren * mIconSize > width;
+ final boolean moreRequired = visibleChildren * getFullIconWidth() > width;
if (moreRequired != overflowShown) {
post(new Runnable() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index a605a81..c4917a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -17,6 +17,7 @@
import com.android.systemui.statusbar.notification.NotificationUtils;
import java.util.ArrayList;
+import java.util.List;
/**
* A controller for the space in the status bar to the left of the system icons. This area is
@@ -42,6 +43,10 @@
initializeNotificationAreaViews(context);
}
+ protected View inflateIconArea(LayoutInflater inflater) {
+ return inflater.inflate(R.layout.notification_icon_area, null);
+ }
+
/**
* Initializes the views that will represent the notification area.
*/
@@ -51,14 +56,16 @@
mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
LayoutInflater layoutInflater = LayoutInflater.from(context);
- mNotificationIconArea = layoutInflater.inflate(R.layout.notification_icon_area, null);
-
- mMoreIcon = (ImageView) mNotificationIconArea.findViewById(R.id.moreIcon);
- mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+ mNotificationIconArea = inflateIconArea(layoutInflater);
mNotificationIcons =
(IconMerger) mNotificationIconArea.findViewById(R.id.notificationIcons);
- mNotificationIcons.setOverflowIndicator(mMoreIcon);
+
+ mMoreIcon = (ImageView) mNotificationIconArea.findViewById(R.id.moreIcon);
+ if (mMoreIcon != null) {
+ mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+ mNotificationIcons.setOverflowIndicator(mMoreIcon);
+ }
}
/**
@@ -88,16 +95,38 @@
*/
public void setIconTint(int iconTint) {
mIconTint = iconTint;
- mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+ if (mMoreIcon != null) {
+ mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+ }
applyNotificationIconsTint();
}
+ protected int getHeight() {
+ return mPhoneStatusBar.getStatusBarHeight();
+ }
+
+ protected boolean shouldShowNotification(NotificationData.Entry entry,
+ NotificationData notificationData) {
+ if (notificationData.isAmbient(entry.key)
+ && !NotificationData.showNotificationEvenIfUnprovisioned(entry.notification)) {
+ return false;
+ }
+ if (!PhoneStatusBar.isTopLevelChild(entry)) {
+ return false;
+ }
+ if (entry.row.getVisibility() == View.GONE) {
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Updates the notifications with the given list of notifications to display.
*/
public void updateNotificationIcons(NotificationData notificationData) {
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
- mIconSize + 2 * mIconHPadding, mPhoneStatusBar.getStatusBarHeight());
+ mIconSize + 2 * mIconHPadding, getHeight());
ArrayList<NotificationData.Entry> activeNotifications =
notificationData.getActiveNotifications();
@@ -107,17 +136,9 @@
// Filter out ambient notifications and notification children.
for (int i = 0; i < size; i++) {
NotificationData.Entry ent = activeNotifications.get(i);
- if (notificationData.isAmbient(ent.key)
- && !NotificationData.showNotificationEvenIfUnprovisioned(ent.notification)) {
- continue;
+ if (shouldShowNotification(ent, notificationData)) {
+ toShow.add(ent.icon);
}
- if (!PhoneStatusBar.isTopLevelChild(ent)) {
- continue;
- }
- if (ent.row.getVisibility() == View.GONE) {
- continue;
- }
- toShow.add(ent.icon);
}
ArrayList<View> toRemove = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index e5e3caf..560dbac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1731,7 +1731,7 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- mNavigationBarBottomHeight = insets.getSystemWindowInsetBottom();
+ mNavigationBarBottomHeight = insets.getStableInsetBottom();
updateMaxHeadsUpTranslation();
return insets;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index f0df706..960515b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -75,7 +75,7 @@
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
+ setPadding(0, 0, 0, insets.getStableInsetBottom());
return insets;
}
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 e84d8fc..86031e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -48,7 +48,6 @@
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.media.AudioAttributes;
import android.media.MediaMetadata;
@@ -132,7 +131,6 @@
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
@@ -305,7 +303,7 @@
Point mCurrentDisplaySize = new Point();
protected StatusBarWindowView mStatusBarWindow;
- PhoneStatusBarView mStatusBarView;
+ protected PhoneStatusBarView mStatusBarView;
private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
protected StatusBarWindowManager mStatusBarWindowManager;
private UnlockMethodCache mUnlockMethodCache;
@@ -317,7 +315,7 @@
int mPixelFormat;
Object mQueueLock = new Object();
- StatusBarIconController mIconController;
+ protected StatusBarIconController mIconController;
// expanded notifications
protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -329,7 +327,7 @@
// top bar
BaseStatusBarHeader mHeader;
- KeyguardStatusBarView mKeyguardStatusBar;
+ protected KeyguardStatusBarView mKeyguardStatusBar;
View mKeyguardStatusView;
KeyguardBottomAreaView mKeyguardBottomArea;
boolean mLeaveOpenOnKeyguardHide;
@@ -678,6 +676,11 @@
mFalsingManager = FalsingManager.getInstance(mContext);
}
+ protected void createIconController() {
+ mIconController = new StatusBarIconController(
+ mContext, mStatusBarView, mKeyguardStatusBar, this);
+ }
+
// ================================================================================
// Constructing the view
// ================================================================================
@@ -811,8 +814,7 @@
// set the initial view visibility
setAreThereNotifications();
- mIconController = new StatusBarIconController(
- mContext, mStatusBarView, mKeyguardStatusBar, this);
+ createIconController();
// Background thread for any controllers that need it.
mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
@@ -1989,7 +1991,7 @@
}
}
- private int adjustDisableFlags(int state) {
+ protected int adjustDisableFlags(int state) {
if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway
&& (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index f61f31e..a40aa83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -42,6 +42,7 @@
import com.android.systemui.FontSizeUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
@@ -116,8 +117,8 @@
mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
- mNotificationIconAreaController =
- new NotificationIconAreaController(context, phoneStatusBar);
+ mNotificationIconAreaController = SystemUIFactory.getInstance()
+ .createNotificationIconAreaController(context, phoneStatusBar);
mNotificationIconAreaInner =
mNotificationIconAreaController.getNotificationInnerAreaView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index ada7450..b271380 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -138,11 +138,7 @@
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
}
- if (state.remoteInputActive) {
- mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
- } else {
- mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
- }
+ mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
}
private void applyHeight(State state) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 3a0336b..1f4ef4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -46,7 +46,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.stack.LongPressCancelable;
+import com.android.systemui.statusbar.stack.ScrollContainer;
/**
* Host for the remote input.
@@ -67,7 +67,9 @@
private RemoteInputController mController;
private NotificationData.Entry mEntry;
- private LongPressCancelable mLongPressCancelable;
+
+ private ScrollContainer mScrollContainer;
+ private View mScrollContainerChild;
public RemoteInputView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -106,7 +108,7 @@
mEditText.setOnClickListener(this);
mEditText.addTextChangedListener(this);
mEditText.setInnerFocusable(false);
- mEditText.mDefocusListener = this;
+ mEditText.mRemoteInputView = this;
}
private void sendRemoteInput() {
@@ -237,23 +239,34 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (mLongPressCancelable == null) {
- ViewParent p = getParent();
- while (p != null) {
- if (p instanceof LongPressCancelable) {
- mLongPressCancelable = (LongPressCancelable) p;
- break;
- }
- p = p.getParent();
- }
- }
- if (mLongPressCancelable != null) {
- mLongPressCancelable.requestDisallowLongPress();
+ findScrollContainer();
+ if (mScrollContainer != null) {
+ mScrollContainer.requestDisallowLongPress();
}
}
return super.onInterceptTouchEvent(ev);
}
+ public boolean requestScrollTo() {
+ findScrollContainer();
+ mScrollContainer.scrollTo(mScrollContainerChild);
+ return true;
+ }
+
+ private void findScrollContainer() {
+ if (mScrollContainer == null) {
+ ViewParent p = this;
+ while (p != null) {
+ if (p.getParent() instanceof ScrollContainer) {
+ mScrollContainer = (ScrollContainer) p.getParent();
+ mScrollContainerChild = (View) p;
+ break;
+ }
+ p = p.getParent();
+ }
+ }
+ }
+
/**
* An EditText that changes appearance based on whether it's focusable and becomes
* un-focusable whenever the user navigates away from it or it becomes invisible.
@@ -261,7 +274,7 @@
public static class RemoteEditText extends EditText {
private final Drawable mBackground;
- private RemoteInputView mDefocusListener;
+ private RemoteInputView mRemoteInputView;
boolean mShowImeOnInputConnection;
public RemoteEditText(Context context, AttributeSet attrs) {
@@ -270,13 +283,13 @@
}
private void defocusIfNeeded() {
- if (mDefocusListener.mEntry.row.isChangingPosition()) {
+ if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()) {
return;
}
if (isFocusable() && isEnabled()) {
setInnerFocusable(false);
- if (mDefocusListener != null) {
- mDefocusListener.onDefocus();
+ if (mRemoteInputView != null) {
+ mRemoteInputView.onDefocus();
}
mShowImeOnInputConnection = false;
}
@@ -300,13 +313,6 @@
}
@Override
- public boolean requestRectangleOnScreen(Rect r) {
- r.top = mScrollY;
- r.bottom = mScrollY + (mBottom - mTop);
- return super.requestRectangleOnScreen(r);
- }
-
- @Override
public void getFocusedRect(Rect r) {
super.getFocusedRect(r);
r.top = mScrollY;
@@ -314,6 +320,11 @@
}
@Override
+ public boolean requestRectangleOnScreen(Rect rectangle) {
+ return mRemoteInputView.requestScrollTo();
+ }
+
+ @Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
defocusIfNeeded();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index bc276b7..632ce21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -43,6 +43,7 @@
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.OverScroller;
@@ -83,7 +84,7 @@
public class NotificationStackScrollLayout extends ViewGroup
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
- SettingsIconRowListener, LongPressCancelable {
+ SettingsIconRowListener, ScrollContainer {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -134,7 +135,7 @@
private int mPaddingBetweenElements;
private int mIncreasedPaddingBetweenElements;
private int mTopPadding;
- private int mCollapseSecondCardPadding;
+ private int mBottomInset = 0;
/**
* The algorithm which calculates the properties for our children
@@ -206,6 +207,7 @@
private float mStackTranslation;
private float mTopPaddingOverflow;
private boolean mDontReportNextOverScroll;
+ private boolean mDontClampNextScroll;
private boolean mRequestViewResizeAnimationOnLayout;
private boolean mNeedViewResizeAnimation;
private View mExpandedGroupView;
@@ -919,6 +921,45 @@
mScrollingEnabled = enable;
}
+ public void scrollTo(View v) {
+ ExpandableView expandableView = (ExpandableView) v;
+ int positionInLinearLayout = getPositionInLinearLayout(v);
+
+ int targetScroll = positionInLinearLayout + expandableView.getActualHeight() +
+ mBottomInset - getHeight() + getTopPadding();
+ if (mOwnScrollY < targetScroll) {
+ mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScroll - mOwnScrollY);
+ mDontReportNextOverScroll = true;
+ postInvalidateOnAnimation();
+ }
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mBottomInset = Math.max(0, insets.getSystemWindowInsetBottom()
+ - (getRootView().getHeight() - getHeight()));
+
+ int range = getScrollRange();
+ if (mOwnScrollY > range) {
+ // HACK: We're repeatedly getting staggered insets here while the IME is
+ // animating away. To work around that we'll wait until things have settled.
+ removeCallbacks(mReclamp);
+ postDelayed(mReclamp, 50);
+ }
+ return insets;
+ }
+
+ private Runnable mReclamp = new Runnable() {
+ @Override
+ public void run() {
+ int range = getScrollRange();
+ mScroller.startScroll(mScrollX, mOwnScrollY, 0, range - mOwnScrollY);
+ mDontReportNextOverScroll = true;
+ mDontClampNextScroll = true;
+ postInvalidateOnAnimation();
+ }
+ };
+
public void setExpandingEnabled(boolean enable) {
mExpandHelper.setEnabled(enable);
}
@@ -1256,7 +1297,7 @@
int y = mScroller.getCurrY();
if (oldX != x || oldY != y) {
- final int range = getScrollRange();
+ int range = getScrollRange();
if (y < 0 && oldY >= 0 || y > range && oldY <= range) {
float currVelocity = mScroller.getCurrVelocity();
if (currVelocity >= mMinimumVelocity) {
@@ -1264,6 +1305,9 @@
}
}
+ if (mDontClampNextScroll) {
+ range = Math.max(range, oldY);
+ }
overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, range,
0, (int) (mMaxOverScroll), false);
onScrollChanged(mScrollX, mOwnScrollY, oldX, oldY);
@@ -1271,6 +1315,8 @@
// Keep on drawing until the animation has finished.
postInvalidateOnAnimation();
+ } else {
+ mDontClampNextScroll = false;
}
}
@@ -1474,7 +1520,9 @@
- firstChild.getMinHeight());
}
}
- return scrollRange;
+ int imeOverlap = Math.max(0,
+ getContentHeight() - (getHeight() - mBottomInset));
+ return scrollRange + imeOverlap;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/LongPressCancelable.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
similarity index 72%
rename from packages/SystemUI/src/com/android/systemui/statusbar/stack/LongPressCancelable.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
index 05f0c07..a35465e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/LongPressCancelable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java
@@ -16,13 +16,21 @@
package com.android.systemui.statusbar.stack;
+import android.view.View;
+
/**
- * Interface for container layouts that listen for long presses. A child that
- * wants to handle long press can use this to cancel the parents long press logic.
+ * Interface for container layouts that scroll and listen for long presses. A child that
+ * wants to handle long press can use this to cancel the parents long press logic or request
+ * to be made visible by scrolling to it.
*/
-public interface LongPressCancelable {
+public interface ScrollContainer {
/**
* Request that the view does not perform long press for the current touch.
*/
void requestDisallowLongPress();
+
+ /**
+ * Request that the view is made visible by scrolling to it.
+ */
+ void scrollTo(View v);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 95cee4c..acb1a7f 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -21,7 +21,6 @@
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.IActivityManager;
-import android.app.ITaskStackListener;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -38,6 +37,8 @@
import android.util.Log;
import com.android.systemui.Prefs;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import java.util.ArrayList;
import java.util.List;
@@ -95,89 +96,6 @@
private boolean mIsRecentsShown;
private boolean mIsPipFocusedInRecent;
- private final Runnable mOnActivityPinnedRunnable = new Runnable() {
- @Override
- public void run() {
- StackInfo stackInfo = null;
- try {
- stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
- if (stackInfo == null) {
- Log.w(TAG, "Cannot find pinned stack");
- return;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "getStackInfo failed", e);
- return;
- }
- if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
- mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
- mPipComponentName = ComponentName.unflattenFromString(
- stackInfo.taskNames[stackInfo.taskNames.length - 1]);
- // Set state to overlay so we show it when the pinned stack animation ends.
- mState = STATE_PIP_OVERLAY;
- mCurrentPipBounds = mPipBounds;
- launchPipOnboardingActivityIfNeeded();
- mMediaSessionManager.addOnActiveSessionsChangedListener(
- mActiveMediaSessionListener, null);
- updateMediaController(mMediaSessionManager.getActiveSessions(null));
- if (mIsRecentsShown) {
- // If an activity becomes PIPed again after the fullscreen, the Recents is shown
- // behind so we need to resize the pinned stack and show the correct overlay.
- resizePinnedStack(STATE_PIP_OVERLAY);
- }
- for (int i = mListeners.size() - 1; i >= 0; i--) {
- mListeners.get(i).onPipEntered();
- }
- }
- };
- private final Runnable mOnTaskStackChanged = new Runnable() {
- @Override
- public void run() {
- if (mState != STATE_NO_PIP) {
- StackInfo stackInfo = null;
- try {
- stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
- if (stackInfo == null) {
- Log.w(TAG, "There is no pinned stack");
- closePipInternal(false);
- return;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "getStackInfo failed", e);
- return;
- }
- for (int i = stackInfo.taskIds.length - 1; i >= 0; --i) {
- if (stackInfo.taskIds[i] == mPipTaskId) {
- // PIP task is still alive.
- return;
- }
- }
- // PIP task doesn't exist anymore in PINNED_STACK.
- closePipInternal(true);
- }
- }
- };
- private final Runnable mOnPinnedActivityRestartAttempt = new Runnable() {
- @Override
- public void run() {
- // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
- movePipToFullscreen();
- }
- };
- private final Runnable mOnPinnedStackAnimationEnded = new Runnable() {
- @Override
- public void run() {
- switch (mState) {
- case STATE_PIP_OVERLAY:
- showPipOverlay();
- break;
- case STATE_PIP_MENU:
- showPipMenu();
- break;
- }
- }
- };
-
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
public void run() {
@@ -241,13 +159,7 @@
(int) (mRecentsPipBounds.bottom + scaleBy * mRecentsPipBounds.height()));
mActivityManager = ActivityManagerNative.getDefault();
- TaskStackListener taskStackListener = new TaskStackListener();
- IActivityManager iam = ActivityManagerNative.getDefault();
- try {
- iam.registerTaskStackListener(taskStackListener);
- } catch (RemoteException e) {
- Log.e(TAG, "registerTaskStackListener failed", e);
- }
+ SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
@@ -566,33 +478,88 @@
return mPipMediaController;
}
- private class TaskStackListener extends ITaskStackListener.Stub {
+ TaskStackListener mTaskStackListener = new TaskStackListener() {
@Override
- public void onTaskStackChanged() throws RemoteException {
- // Post the message back to the UI thread.
- mHandler.post(mOnTaskStackChanged);
+ public void onTaskStackChanged() {
+ if (mState != STATE_NO_PIP) {
+ StackInfo stackInfo = null;
+ try {
+ stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ if (stackInfo == null) {
+ Log.w(TAG, "There is no pinned stack");
+ closePipInternal(false);
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "getStackInfo failed", e);
+ return;
+ }
+ for (int i = stackInfo.taskIds.length - 1; i >= 0; --i) {
+ if (stackInfo.taskIds[i] == mPipTaskId) {
+ // PIP task is still alive.
+ return;
+ }
+ }
+ // PIP task doesn't exist anymore in PINNED_STACK.
+ closePipInternal(true);
+ }
}
@Override
- public void onActivityPinned() throws RemoteException {
- // Post the message back to the UI thread.
+ public void onActivityPinned() {
if (DEBUG) Log.d(TAG, "onActivityPinned()");
- mHandler.post(mOnActivityPinnedRunnable);
+ StackInfo stackInfo = null;
+ try {
+ stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ if (stackInfo == null) {
+ Log.w(TAG, "Cannot find pinned stack");
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "getStackInfo failed", e);
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
+ mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
+ mPipComponentName = ComponentName.unflattenFromString(
+ stackInfo.taskNames[stackInfo.taskNames.length - 1]);
+ // Set state to overlay so we show it when the pinned stack animation ends.
+ mState = STATE_PIP_OVERLAY;
+ mCurrentPipBounds = mPipBounds;
+ launchPipOnboardingActivityIfNeeded();
+ mMediaSessionManager.addOnActiveSessionsChangedListener(
+ mActiveMediaSessionListener, null);
+ updateMediaController(mMediaSessionManager.getActiveSessions(null));
+ if (mIsRecentsShown) {
+ // If an activity becomes PIPed again after the fullscreen, the Recents is shown
+ // behind so we need to resize the pinned stack and show the correct overlay.
+ resizePinnedStack(STATE_PIP_OVERLAY);
+ }
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onPipEntered();
+ }
}
@Override
public void onPinnedActivityRestartAttempt() {
- // Post the message back to the UI thread.
if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
- mHandler.post(mOnPinnedActivityRestartAttempt);
+ // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
+ movePipToFullscreen();
}
@Override
public void onPinnedStackAnimationEnded() {
if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
- mHandler.post(mOnPinnedStackAnimationEnded);
+ switch (mState) {
+ case STATE_PIP_OVERLAY:
+ showPipOverlay();
+ break;
+ case STATE_PIP_MENU:
+ showPipMenu();
+ break;
+ }
}
- }
+ };
/**
* A listener interface to receive notification on changes in PIP.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5b01062..b1398f1 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -630,7 +630,7 @@
mDefaultRequest = createInternetRequestForTransport(-1);
NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest,
- new Binder(), NetworkRequestInfo.REQUEST);
+ new Binder(), NetworkRequestType.REQUEST);
mNetworkRequests.put(mDefaultRequest, defaultNRI);
mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
@@ -806,7 +806,7 @@
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- null, mDefaultMobileDataRequest, new Binder(), NetworkRequestInfo.REQUEST));
+ null, mDefaultMobileDataRequest, new Binder(), NetworkRequestType.REQUEST));
} else {
handleReleaseNetworkRequest(mDefaultMobileDataRequest, Process.SYSTEM_UID);
}
@@ -1945,7 +1945,7 @@
}
private boolean isRequest(NetworkRequest request) {
- return mNetworkRequests.get(request).isRequest;
+ return mNetworkRequests.get(request).isRequest();
}
// must be stateless - things change under us.
@@ -2164,7 +2164,7 @@
if (VDBG) log("NetworkFactory connected");
// A network factory has connected. Send it all current NetworkRequests.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.isRequest == false) continue;
+ if (!nri.isRequest()) continue;
NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
(nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
@@ -2301,7 +2301,7 @@
private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
mNetworkRequests.put(nri.request, nri);
mNetworkRequestInfoLogs.log("REGISTER " + nri);
- if (!nri.isRequest) {
+ if (!nri.isRequest()) {
for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
if (nri.request.networkCapabilities.hasSignalStrength() &&
network.satisfiesImmutableCapabilitiesOf(nri.request)) {
@@ -2310,7 +2310,7 @@
}
}
rematchAllNetworksAndRequests(null, 0);
- if (nri.isRequest && mNetworkForRequestId.get(nri.request.requestId) == null) {
+ if (nri.isRequest() && mNetworkForRequestId.get(nri.request.requestId) == null) {
sendUpdatedScoreToFactories(nri.request, 0);
}
}
@@ -2331,7 +2331,7 @@
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
// If this Network is already the highest scoring Network for a request, or if
// there is hope for it to become one if it validated, then it is needed.
- if (nri.isRequest && nai.satisfies(nri.request) &&
+ if (nri.isRequest() && nai.satisfies(nri.request) &&
(nai.networkRequests.get(nri.request.requestId) != null ||
// Note that this catches two important cases:
// 1. Unvalidated cellular will not be reaped when unvalidated WiFi
@@ -2359,7 +2359,7 @@
nri.unlinkDeathRecipient();
mNetworkRequests.remove(request);
mNetworkRequestInfoLogs.log("RELEASE " + nri);
- if (nri.isRequest) {
+ if (nri.isRequest()) {
// Find all networks that are satisfying this request and remove the request
// from their request lists.
// TODO - it's my understanding that for a request there is only a single
@@ -3736,13 +3736,36 @@
}
/**
+ * A NetworkRequest as registered by an application can be one of three
+ * types:
+ *
+ * - "listen", for which the framework will issue callbacks about any
+ * and all networks that match the specified NetworkCapabilities,
+ *
+ * - "request", capable of causing a specific network to be created
+ * first (e.g. a telephony DUN request), the framework will issue
+ * callbacks about the single, highest scoring current network
+ * (if any) that matches the specified NetworkCapabilities, or
+ *
+ * - "track the default network", a hybrid of the two designed such
+ * that the framework will issue callbacks for the single, highest
+ * scoring current network (if any) that matches the capabilities of
+ * the default Internet request (mDefaultRequest), but which cannot
+ * cause the framework to either create or retain the existence of
+ * any specific network.
+ *
+ */
+ private static enum NetworkRequestType {
+ LISTEN,
+ TRACK_DEFAULT,
+ REQUEST
+ };
+
+ /**
* Tracks info about the requester.
* Also used to notice when the calling process dies so we can self-expire
*/
private class NetworkRequestInfo implements IBinder.DeathRecipient {
- static final boolean REQUEST = true;
- static final boolean LISTEN = false;
-
final NetworkRequest request;
final PendingIntent mPendingIntent;
boolean mPendingIntentSent;
@@ -3750,26 +3773,26 @@
final int mPid;
final int mUid;
final Messenger messenger;
- final boolean isRequest;
+ private final NetworkRequestType mType;
- NetworkRequestInfo(NetworkRequest r, PendingIntent pi, boolean isRequest) {
+ NetworkRequestInfo(NetworkRequest r, PendingIntent pi, NetworkRequestType type) {
request = r;
mPendingIntent = pi;
messenger = null;
mBinder = null;
mPid = getCallingPid();
mUid = getCallingUid();
- this.isRequest = isRequest;
+ mType = type;
}
- NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, boolean isRequest) {
+ NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, NetworkRequestType type) {
super();
messenger = m;
request = r;
mBinder = binder;
mPid = getCallingPid();
mUid = getCallingUid();
- this.isRequest = isRequest;
+ mType = type;
mPendingIntent = null;
try {
@@ -3779,6 +3802,16 @@
}
}
+ private String typeString() {
+ switch (mType) {
+ case LISTEN: return "Listen";
+ case REQUEST: return "Request";
+ case TRACK_DEFAULT: return "Track default";
+ default:
+ return "unknown type";
+ }
+ }
+
void unlinkDeathRecipient() {
if (mBinder != null) {
mBinder.unlinkToDeath(this, 0);
@@ -3791,8 +3824,27 @@
releaseNetworkRequest(request);
}
+ /**
+ * Returns true iff. the contained NetworkRequest is one that:
+ *
+ * - should be associated with at most one satisfying network
+ * at a time;
+ *
+ * - should cause a network to be kept up if it is the only network
+ * which can satisfy the NetworkReqeust.
+ *
+ * For full detail of how isRequest() is used for pairing Networks with
+ * NetworkRequests read rematchNetworkAndRequests().
+ *
+ * TODO: Rename to something more properly descriptive.
+ */
+ public boolean isRequest() {
+ return (mType == NetworkRequestType.TRACK_DEFAULT) ||
+ (mType == NetworkRequestType.REQUEST);
+ }
+
public String toString() {
- return (isRequest ? "Request" : "Listen") +
+ return typeString() +
" from uid/pid:" + mUid + "/" + mPid +
" for " + request +
(mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
@@ -3845,10 +3897,13 @@
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
+ final NetworkRequestType type = (networkCapabilities == null)
+ ? NetworkRequestType.TRACK_DEFAULT
+ : NetworkRequestType.REQUEST;
// If the requested networkCapabilities is null, take them instead from
// the default network request. This allows callers to keep track of
// the system default network.
- if (networkCapabilities == null) {
+ if (type == NetworkRequestType.TRACK_DEFAULT) {
networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities);
enforceAccessPermission();
} else {
@@ -3870,8 +3925,7 @@
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId());
- NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
- NetworkRequestInfo.REQUEST);
+ NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, type);
if (DBG) log("requestNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
@@ -3936,7 +3990,7 @@
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId());
NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation,
- NetworkRequestInfo.REQUEST);
+ NetworkRequestType.REQUEST);
if (DBG) log("pendingRequest for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
nri));
@@ -3988,7 +4042,7 @@
NetworkRequest networkRequest = new NetworkRequest(
new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId());
NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
- NetworkRequestInfo.LISTEN);
+ NetworkRequestType.LISTEN);
if (DBG) log("listenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -4006,7 +4060,7 @@
NetworkRequest networkRequest = new NetworkRequest(
new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId());
NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation,
- NetworkRequestInfo.LISTEN);
+ NetworkRequestType.LISTEN);
if (DBG) log("pendingListenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -4523,7 +4577,7 @@
// check if it satisfies the NetworkCapabilities
if (VDBG) log(" checking if request is satisfied: " + nri.request);
if (satisfies) {
- if (!nri.isRequest) {
+ if (!nri.isRequest()) {
// This is not a request, it's a callback listener.
// Add it to newNetwork regardless of score.
if (newNetwork.addRequest(nri.request)) addedRequests.add(nri);
@@ -4583,7 +4637,7 @@
mNetworkForRequestId.remove(nri.request.requestId);
sendUpdatedScoreToFactories(nri.request, 0);
} else {
- if (nri.isRequest == true) {
+ if (nri.isRequest()) {
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
newNetwork.name() +
" without updating mNetworkForRequestId or factories!");
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 0eacd13..d449ce5 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -16,6 +16,8 @@
package com.android.server.pm;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_BACKGROUND_DEXOPT;
+
import android.app.AlarmManager;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
@@ -51,8 +53,6 @@
final AtomicBoolean mIdleTime = new AtomicBoolean(false);
- private boolean useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
-
public static void schedule(Context context) {
JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName)
@@ -93,8 +93,8 @@
// skip previously failing package
continue;
}
- if (!pm.performDexOpt(pkg, /* instruction set */ null, useJitProfiles,
- /* extractOnly */ false, /* force */ false)) {
+ if (!pm.performDexOpt(pkg, /* instruction set */ null, /* checkProfiles */ true,
+ REASON_BACKGROUND_DEXOPT, /* force */ false)) {
// there was a problem running dexopt,
// remember this so we do not keep retrying.
sFailedPackageNames.add(pkg);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 206a143..a1f937ab 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.content.pm.PackageStats;
import android.os.Build;
-import android.os.storage.StorageManager;
import android.util.Slog;
import com.android.internal.os.InstallerConnection;
@@ -37,17 +36,17 @@
* frameworks/native/cmds/installd/installd.h
* **************************************************************************/
/** Application should be visible to everyone */
- public static final int DEXOPT_PUBLIC = 1 << 1;
+ public static final int DEXOPT_PUBLIC = 1 << 1;
/** Application wants to run in VM safe mode */
- public static final int DEXOPT_SAFEMODE = 1 << 2;
+ public static final int DEXOPT_SAFEMODE = 1 << 2;
/** Application wants to allow debugging of its code */
- public static final int DEXOPT_DEBUGGABLE = 1 << 3;
+ public static final int DEXOPT_DEBUGGABLE = 1 << 3;
/** The system boot has finished */
- public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
- /** Do not compile, only extract bytecode into an OAT file */
- public static final int DEXOPT_EXTRACTONLY = 1 << 5;
+ public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
+ /** Hint that the dexopt type is profile-guided. */
+ public static final int DEXOPT_PROFILE_GUIDED = 1 << 5;
/** This is an OTA update dexopt */
- public static final int DEXOPT_OTA = 1 << 6;
+ public static final int DEXOPT_OTA = 1 << 6;
// NOTE: keep in sync with installd
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
@@ -137,19 +136,23 @@
}
public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
- int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
+ int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException {
assertValidInstructionSet(instructionSet);
mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags,
- volumeUuid, useProfiles);
+ compilerFilter, volumeUuid);
}
public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
- String volumeUuid, boolean useProfiles)
+ String compilerFilter, String volumeUuid)
throws InstallerException {
assertValidInstructionSet(instructionSet);
mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
- outputPath, dexFlags, volumeUuid, useProfiles);
+ outputPath, dexFlags, compilerFilter, volumeUuid);
+ }
+
+ public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
+ return mInstaller.mergeProfiles(uid, pkgName);
}
public void idmap(String targetApkPath, String overlayApkPath, int uid)
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 67aeed1..03e838b 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -19,11 +19,12 @@
import static com.android.server.pm.Installer.DEXOPT_OTA;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_AB_OTA;
import android.content.Context;
import android.content.pm.IOtaDexopt;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -130,6 +131,7 @@
// TODO: If apps are not installed in the internal /data partition, we should compare
// against that storage's free capacity.
File dataDir = Environment.getDataDirectory();
+ @SuppressWarnings("deprecation")
long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
if (lowThreshold == 0) {
throw new IllegalStateException("Invalid low memory threshold");
@@ -142,7 +144,7 @@
}
mPackageDexOptimizer.performDexOpt(nextPackage, null /* ISAs */, false /* useProfiles */,
- false /* extractOnly */);
+ getCompilerFilterForReason(REASON_AB_OTA));
}
private void moveAbArtifacts(Installer installer) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 561682c..5ceb65f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -20,13 +20,10 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
import android.os.Environment;
import android.os.PowerManager;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.os.storage.StorageManager;
-import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -34,18 +31,18 @@
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.List;
import dalvik.system.DexFile;
import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
+import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
-import static com.android.server.pm.Installer.DEXOPT_EXTRACTONLY;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter;
/**
* Helper class for running dexopt command on packages.
@@ -59,8 +56,6 @@
static final int DEX_OPT_DEFERRED = 2;
static final int DEX_OPT_FAILED = -1;
- private static final boolean DEBUG_DEXOPT = PackageManagerService.DEBUG_DEXOPT;
-
private final Installer mInstaller;
private final Object mInstallLock;
@@ -94,8 +89,8 @@
* <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
* synchronized on {@link #mInstallLock}.
*/
- int performDexOpt(PackageParser.Package pkg, String[] instructionSets, boolean useProfiles,
- boolean extractOnly) {
+ int performDexOpt(PackageParser.Package pkg, String[] instructionSets, boolean checkProfiles,
+ String targetCompilationFilter) {
synchronized (mInstallLock) {
final boolean useLock = mSystemReady;
if (useLock) {
@@ -103,7 +98,8 @@
mDexoptWakeLock.acquire();
}
try {
- return performDexOptLI(pkg, instructionSets, useProfiles, extractOnly);
+ return performDexOptLI(pkg, instructionSets, checkProfiles,
+ targetCompilationFilter);
} finally {
if (useLock) {
mDexoptWakeLock.release();
@@ -128,7 +124,7 @@
}
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
- boolean useProfiles, boolean extractOnly) {
+ boolean checkProfiles, String targetCompilerFilter) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
@@ -136,36 +132,51 @@
return DEX_OPT_SKIPPED;
}
+ final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+
+ boolean isProfileGuidedFilter = DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter);
+ // If any part of the app is used by other apps, we cannot use profile-guided
+ // compilation.
+ // TODO: This needs to be refactored to be also checked when the target mode is
+ // profile-guided.
+ if (isProfileGuidedFilter) {
+ for (String path : paths) {
+ if (isUsedByOtherApps(path)) {
+ checkProfiles = false;
+
+ // TODO: Should we only upgrade to the non-profile-guided version? That is,
+ // given verify-profile, should we move to interpret-only?
+ targetCompilerFilter = getFullCompilerFilter();
+ isProfileGuidedFilter = false;
+
+ break;
+ }
+ }
+ }
+
+ // If we're asked to take profile updates into account, check now.
+ boolean newProfile = false;
+ if (checkProfiles && isProfileGuidedFilter) {
+ // Merge profiles, see if we need to do anything.
+ try {
+ newProfile = mInstaller.mergeProfiles(sharedGid, pkg.packageName);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to merge profiles", e);
+ }
+ }
+
final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
boolean performedDexOpt = false;
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (String path : paths) {
- if (useProfiles && isUsedByOtherApps(path)) {
- // We cannot use profile guided compilation if the apk was used by another app.
- useProfiles = false;
- }
int dexoptNeeded;
-
try {
- int compilationTypeMask = 0;
- if (extractOnly) {
- // For extract only, any type of compilation is good.
- compilationTypeMask = DexFile.COMPILATION_TYPE_FULL
- | DexFile.COMPILATION_TYPE_PROFILE_GUIDE
- | DexFile.COMPILATION_TYPE_EXTRACT_ONLY;
- } else {
- // Branch taken for profile guide and full compilation.
- // Profile guide compilation should only recompile a previous
- // profile compiled/extract only file and should not be attempted if the
- // apk is already fully compiled. So test against a full compilation type.
- compilationTypeMask = DexFile.COMPILATION_TYPE_FULL;
- }
dexoptNeeded = DexFile.getDexOptNeeded(path,
- dexCodeInstructionSet, compilationTypeMask);
+ dexCodeInstructionSet, targetCompilerFilter, newProfile);
} catch (IOException ioe) {
Slog.w(TAG, "IOException reading apk: " + path, ioe);
return DEX_OPT_FAILED;
@@ -194,20 +205,20 @@
Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+ pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
- + " extractOnly=" + extractOnly + " oatDir = " + oatDir);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ + " target-filter=" + targetCompilerFilter + " oatDir = " + oatDir);
// Profile guide compiled oat files should not be public.
- final boolean isPublic = !pkg.isForwardLocked() && !useProfiles;
+ final boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
+ final int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
final int dexFlags = adjustDexoptFlags(
( isPublic ? DEXOPT_PUBLIC : 0)
| (vmSafeMode ? DEXOPT_SAFEMODE : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
- | (extractOnly ? DEXOPT_EXTRACTONLY : 0)
+ | profileFlag
| DEXOPT_BOOTCOMPLETE);
try {
mInstaller.dexopt(path, sharedGid, pkg.packageName, dexCodeInstructionSet,
- dexoptNeeded, oatDir, dexFlags, pkg.volumeUuid, useProfiles);
+ dexoptNeeded, oatDir, dexFlags, targetCompilerFilter, pkg.volumeUuid);
performedDexOpt = true;
} catch (InstallerException e) {
Slog.w(TAG, "Failed to dexopt", e);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9335116..b73d8f3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -92,6 +92,13 @@
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_BOOT;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_FORCED_DEXOPT;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_INSTALL;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_NON_SYSTEM_LIBRARY;
+import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_SHARED_APK;
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE;
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS;
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
@@ -1956,6 +1963,9 @@
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
+ // Self-check for initial settings.
+ PackageManagerServiceCompilerMapping.checkProperties();
+
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
@@ -2168,12 +2178,13 @@
// AOT compilation (if needed).
int dexoptNeeded = DexFile.getDexOptNeeded(
lib, dexCodeInstructionSet,
- DexFile.COMPILATION_TYPE_FULL);
+ getCompilerFilterForReason(REASON_SHARED_APK),
+ false /* newProfile */);
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
- StorageManager.UUID_PRIVATE_INTERNAL,
- false /*useProfiles*/);
+ getCompilerFilterForReason(REASON_SHARED_APK),
+ StorageManager.UUID_PRIVATE_INTERNAL);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
@@ -6928,7 +6939,7 @@
// and would have to be patched (would be SELF_PATCHOAT, which is deprecated).
// Instead, force the extraction in this case.
performDexOpt(pkg.packageName, null /* instructionSet */,
- false /* useProfiles */, true /* extractOnly */, prunedCache);
+ false /* checkProfiles */, REASON_BOOT, prunedCache);
}
}
}
@@ -6947,29 +6958,37 @@
// TODO: this is not used nor needed. Delete it.
@Override
public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
- return performDexOptTraced(packageName, instructionSet, false /* useProfiles */,
- false /* extractOnly */, false /* force */);
+ return performDexOptTraced(packageName, instructionSet, false /* checkProfiles */,
+ getFullCompilerFilter(), false /* force */);
}
@Override
- public boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
- boolean extractOnly, boolean force) {
- return performDexOptTraced(packageName, instructionSet, useProfiles, extractOnly, force);
+ public boolean performDexOpt(String packageName, String instructionSet,
+ boolean checkProfiles, int compileReason, boolean force) {
+ return performDexOptTraced(packageName, instructionSet, checkProfiles,
+ getCompilerFilterForReason(compileReason), force);
+ }
+
+ @Override
+ public boolean performDexOptMode(String packageName, String instructionSet,
+ boolean checkProfiles, String targetCompilerFilter, boolean force) {
+ return performDexOptTraced(packageName, instructionSet, checkProfiles,
+ targetCompilerFilter, force);
}
private boolean performDexOptTraced(String packageName, String instructionSet,
- boolean useProfiles, boolean extractOnly, boolean force) {
+ boolean checkProfiles, String targetCompilerFilter, boolean force) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
try {
- return performDexOptInternal(packageName, instructionSet, useProfiles, extractOnly,
- force);
+ return performDexOptInternal(packageName, instructionSet, checkProfiles,
+ targetCompilerFilter, force);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private boolean performDexOptInternal(String packageName, String instructionSet,
- boolean useProfiles, boolean extractOnly, boolean force) {
+ boolean checkProfiles, String targetCompilerFilter, boolean force) {
PackageParser.Package p;
final String targetInstructionSet;
synchronized (mPackages) {
@@ -6987,7 +7006,7 @@
synchronized (mInstallLock) {
final String[] instructionSets = new String[] { targetInstructionSet };
int result = performDexOptInternalWithDependenciesLI(p, instructionSets,
- useProfiles, extractOnly, force);
+ checkProfiles, targetCompilerFilter, force);
return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
}
} finally {
@@ -7008,7 +7027,8 @@
}
private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
- String instructionSets[], boolean useProfiles, boolean extractOnly, boolean force) {
+ String instructionSets[], boolean checkProfiles, String targetCompilerFilter,
+ boolean force) {
// Select the dex optimizer based on the force parameter.
// Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
// allocate an object here.
@@ -7022,13 +7042,13 @@
if (!deps.isEmpty()) {
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
- // Currently this will do a full compilation of the library.
- pdo.performDexOpt(depPackage, instructionSets, false /* useProfiles */,
- false /* extractOnly */);
+ // Currently this will do a full compilation of the library by default.
+ pdo.performDexOpt(depPackage, instructionSets, false /* checkProfiles */,
+ getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY));
}
}
- return pdo.performDexOpt(p, instructionSets, useProfiles, extractOnly);
+ return pdo.performDexOpt(p, instructionSets, checkProfiles, targetCompilerFilter);
}
Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
@@ -7106,7 +7126,8 @@
// Whoever is calling forceDexOpt wants a fully compiled package.
// Don't use profiles since that may cause compilation to be skipped.
final int res = performDexOptInternalWithDependenciesLI(pkg, instructionSets,
- false /* useProfiles */, false /* extractOnly */, true /* force */);
+ false /* checkProfiles */, getCompilerFilterForReason(REASON_FORCED_DEXOPT),
+ true /* force */);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -13973,7 +13994,7 @@
// Do not run PackageDexOptimizer through the local performDexOpt
// method because `pkg` is not in `mPackages` yet.
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
- false /* useProfiles */, true /* extractOnly */);
+ false /* checkProfiles */, getCompilerFilterForReason(REASON_INSTALL));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
String msg = "Extracking package failed for " + pkgName;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
new file mode 100644
index 0000000..b53f8d1
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -0,0 +1,139 @@
+/*
+ * 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.server.pm;
+
+import android.os.SystemProperties;
+
+import dalvik.system.DexFile;
+
+/**
+ * Manage (retrieve) mappings from compilation reason to compilation filter.
+ */
+class PackageManagerServiceCompilerMapping {
+ // Compilation reasons.
+ public static final int REASON_BOOT = 0;
+ public static final int REASON_INSTALL = 1;
+ public static final int REASON_BACKGROUND_DEXOPT = 2;
+ public static final int REASON_AB_OTA = 3;
+ public static final int REASON_NON_SYSTEM_LIBRARY = 4;
+ public static final int REASON_SHARED_APK = 5;
+ public static final int REASON_FORCED_DEXOPT = 6;
+
+ private static final int REASON_LAST = REASON_FORCED_DEXOPT;
+
+ // Names for compilation reasons.
+ static final String REASON_STRINGS[] = {
+ "boot", "install", "bg-dexopt", "ab-ota", "nsys-library", "shared-apk", "forced-dexopt"
+ };
+
+ // Static block to ensure the strings array is of the right length.
+ static {
+ if (REASON_LAST + 1 != REASON_STRINGS.length) {
+ throw new IllegalStateException("REASON_STRINGS not correct");
+ }
+ }
+
+ private static String getSystemPropertyName(int reason) {
+ if (reason < 0 || reason >= REASON_STRINGS.length) {
+ throw new IllegalArgumentException("reason " + reason + " invalid");
+ }
+
+ return "pm.dexopt." + REASON_STRINGS[reason];
+ }
+
+ // Load the property for the given reason and check for validity. This will throw an
+ // exception in case the reason or value are invalid.
+ private static String getAndCheckValidity(int reason) {
+ String sysPropValue = SystemProperties.get(getSystemPropertyName(reason));
+ if (sysPropValue == null || sysPropValue.isEmpty() ||
+ !DexFile.isValidCompilerFilter(sysPropValue)) {
+ throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
+ + "(reason " + REASON_STRINGS[reason] + ")");
+ }
+
+ // Ensure that some reasons are not mapped to profile-guided filters.
+ switch (reason) {
+ case REASON_SHARED_APK:
+ case REASON_FORCED_DEXOPT:
+ if (DexFile.isProfileGuidedCompilerFilter(sysPropValue)) {
+ throw new IllegalStateException("\"" + sysPropValue + "\" is profile-guided, "
+ + "but not allowed for " + REASON_STRINGS[reason]);
+ }
+ break;
+ }
+
+ return sysPropValue;
+ }
+
+ // Check that the properties are set and valid.
+ // Note: this is done in a separate method so this class can be statically initialized.
+ static void checkProperties() {
+ // We're gonna check all properties and collect the exceptions, so we can give a general
+ // overview. Store the exceptions here.
+ RuntimeException toThrow = null;
+
+ for (int reason = 0; reason <= REASON_LAST; reason++) {
+ try {
+ // Check that the system property name is legal.
+ String sysPropName = getSystemPropertyName(reason);
+ if (sysPropName == null ||
+ sysPropName.isEmpty() ||
+ sysPropName.length() > SystemProperties.PROP_NAME_MAX) {
+ throw new IllegalStateException("Reason system property name \"" +
+ sysPropName +"\" for reason " + REASON_STRINGS[reason]);
+ }
+
+ // Check validity, ignore result.
+ getAndCheckValidity(reason);
+ } catch (Exception exc) {
+ if (toThrow == null) {
+ toThrow = new IllegalStateException("PMS compiler filter settings are bad.");
+ }
+ toThrow.addSuppressed(exc);
+ }
+ }
+
+ if (toThrow != null) {
+ throw toThrow;
+ }
+ }
+
+ public static String getCompilerFilterForReason(int reason) {
+ return getAndCheckValidity(reason);
+ }
+
+ /**
+ * Return the compiler filter for "full" compilation.
+ *
+ * We derive that from the traditional "dalvik.vm.dex2oat-filter" property and just make
+ * sure this isn't profile-guided. Returns "speed" in case of invalid (or missing) values.
+ */
+ public static String getFullCompilerFilter() {
+ String value = SystemProperties.get("dalvik.vm.dex2oat-filter");
+ if (value == null || value.isEmpty()) {
+ return "speed";
+ }
+
+ if (!DexFile.isValidCompilerFilter(value) ||
+ DexFile.isProfileGuidedCompilerFilter(value)) {
+ return "speed";
+ }
+
+ return value;
+ }
+
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 319fc37..7f626b2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -50,6 +50,8 @@
import android.util.PrintWriterPrinter;
import com.android.internal.util.SizedInputStream;
+import dalvik.system.DexFile;
+
import libcore.io.IoUtils;
import java.io.File;
@@ -249,11 +251,38 @@
private int runCompile() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
boolean useJitProfiles = false;
- boolean extractOnly = false;
boolean forceCompilation = false;
boolean allPackages = false;
boolean clearProfileData = false;
- String compilationMode = "default";
+ String compilerFilter = null;
+ String compilationReason = null;
+
+ if (peekNextArg() == null) {
+ // No arguments, show help.
+ pw.println("Usage: cmd package compile [-c] [-f] [--reset] [-m mode] " +
+ "[-r reason] [-a|pkg]");
+ pw.println();
+ pw.println(" -c Clear profile data");
+ pw.println(" -f Force compilation");
+ pw.println(" --reset Reset package");
+ pw.println(" -m mode Compilation mode, one of the dex2oat compiler filters");
+ pw.println(" verify-none");
+ pw.println(" verify-at-runtime");
+ pw.println(" verify-profile");
+ pw.println(" interpret-only");
+ pw.println(" space-profile");
+ pw.println(" space");
+ pw.println(" speed-profile");
+ pw.println(" speed");
+ pw.println(" everything");
+ pw.println(" -r reason Compiler reason, one of the package manager reasons");
+ for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
+ pw.println(" " +
+ PackageManagerServiceCompilerMapping.REASON_STRINGS[i]);
+ }
+ pw.println(" -a Apply to all packages");
+ return 1;
+ }
String opt;
while ((opt = getNextOption()) != null) {
@@ -268,12 +297,15 @@
forceCompilation = true;
break;
case "-m":
- compilationMode = getNextArgRequired();
+ compilerFilter = getNextArgRequired();
+ break;
+ case "-r":
+ compilationReason = getNextArgRequired();
break;
case "--reset":
forceCompilation = true;
clearProfileData = true;
- compilationMode = "extract";
+ compilerFilter = "reset";
break;
default:
pw.println("Error: Unknown option: " + opt);
@@ -281,27 +313,55 @@
}
}
- switch (compilationMode) {
- case "default":
- useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
- extractOnly = false;
- break;
- case "full":
- useJitProfiles = false;
- extractOnly = false;
- break;
- case "profile":
- useJitProfiles = true;
- extractOnly = false;
- break;
- case "extract":
- useJitProfiles = false;
- extractOnly = true;
- break;
- default:
- pw.println("Error: Unknown compilation mode: " + compilationMode);
- return 1;
+ if (compilerFilter != null && compilationReason != null) {
+ pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
+ "at the same time");
+ return 1;
}
+ if (compilerFilter == null && compilationReason == null) {
+ pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " +
+ "reason (\"-r\") at the same time");
+ return 1;
+ }
+
+ String targetCompilerFilter;
+ if (compilerFilter != null) {
+ // Specially recognize default and reset. Otherwise, only accept valid modes.
+ if ("default".equals(compilerFilter)) {
+ // Use the default mode for background dexopt.
+ targetCompilerFilter =
+ PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+ PackageManagerServiceCompilerMapping.REASON_BACKGROUND_DEXOPT);
+ } else if ("reset".equals(compilerFilter)) {
+ // Use the default mode for install.
+ targetCompilerFilter =
+ PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+ PackageManagerServiceCompilerMapping.REASON_INSTALL);
+ } else {
+ if (!DexFile.isValidCompilerFilter(compilerFilter)) {
+ pw.println("Error: \"" + compilerFilter +
+ "\" is not a valid compilation filter.");
+ return 1;
+ }
+ targetCompilerFilter = compilerFilter;
+ }
+ } else {
+ int reason = -1;
+ for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
+ if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals(
+ compilationReason)) {
+ reason = i;
+ break;
+ }
+ }
+ if (reason == -1) {
+ pw.println("Error: Unknown compilation reason: " + compilationReason);
+ return 1;
+ }
+ targetCompilerFilter =
+ PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason);
+ }
+
List<String> packageNames = null;
if (allPackages) {
@@ -321,8 +381,8 @@
mInterface.clearApplicationProfileData(packageName);
}
- boolean result = mInterface.performDexOpt(packageName, null /* instructionSet */,
- useJitProfiles, extractOnly, forceCompilation);
+ boolean result = mInterface.performDexOptMode(packageName, null /* instructionSet */,
+ useJitProfiles, targetCompilerFilter, forceCompilation);
if (!result) {
failedPackages.add(packageName);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 715f1e5..ac19e24 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -458,7 +458,7 @@
continue;
}
if (!excludeDying || !mRemovingUserIds.get(ui.id)) {
- users.add(ui);
+ users.add(userWithName(ui));
}
}
return users;
@@ -500,7 +500,7 @@
if (mRemovingUserIds.get(profile.id)) {
continue;
}
- users.add(profile);
+ users.add(userWithName(profile));
}
return users;
}
@@ -653,7 +653,21 @@
public UserInfo getUserInfo(int userId) {
checkManageUsersPermission("query user");
synchronized (mUsersLock) {
- return getUserInfoLU(userId);
+ return userWithName(getUserInfoLU(userId));
+ }
+ }
+
+ /**
+ * Returns a UserInfo object with the name filled in, for Owner, or the original
+ * if the name is already set.
+ */
+ private UserInfo userWithName(UserInfo orig) {
+ if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) {
+ UserInfo withName = new UserInfo(orig);
+ withName.name = getOwnerName();
+ return withName;
+ } else {
+ return orig;
}
}
@@ -1459,9 +1473,7 @@
flags |= UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY;
}
// Create the system user
- UserInfo system = new UserInfo(UserHandle.USER_SYSTEM,
- mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
- flags);
+ UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
UserData userData = new UserData();
userData.info = system;
synchronized (mUsersLock) {
@@ -1482,6 +1494,10 @@
writeUserLP(userData);
}
+ private String getOwnerName() {
+ return mContext.getResources().getString(com.android.internal.R.string.owner_name);
+ }
+
private void scheduleWriteUser(UserData UserData) {
if (DBG) {
debug("scheduleWriteUser");
@@ -1551,9 +1567,11 @@
serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType);
}
}
- serializer.startTag(null, TAG_NAME);
- serializer.text(userInfo.name);
- serializer.endTag(null, TAG_NAME);
+ if (userInfo.name != null) {
+ serializer.startTag(null, TAG_NAME);
+ serializer.text(userInfo.name);
+ serializer.endTag(null, TAG_NAME);
+ }
synchronized (mRestrictionsLock) {
UserRestrictionsUtils.writeRestrictions(serializer,
mBaseUserRestrictions.get(userInfo.id), TAG_RESTRICTIONS);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0115a08..d92d942 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3101,7 +3101,7 @@
} else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
if (down) {
if (repeatCount == 0) {
- toggleKeyboardShortcutsMenu();
+ toggleKeyboardShortcutsMenu(event.getDeviceId());
}
}
} else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
@@ -3576,11 +3576,11 @@
}
}
- private void toggleKeyboardShortcutsMenu() {
+ private void toggleKeyboardShortcutsMenu(int deviceId) {
try {
IStatusBarService statusbar = getStatusBarService();
if (statusbar != null) {
- statusbar.toggleKeyboardShortcutsMenu();
+ statusbar.toggleKeyboardShortcutsMenu(deviceId);
}
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException when showing keyboard shortcuts menu", e);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index d24e1af..403a4c6 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -564,10 +564,10 @@
}
@Override
- public void toggleKeyboardShortcutsMenu() {
+ public void toggleKeyboardShortcutsMenu(int deviceId) {
if (mBar != null) {
try {
- mBar.toggleKeyboardShortcutsMenu();
+ mBar.toggleKeyboardShortcutsMenu(deviceId);
} catch (RemoteException ex) {}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index d843a8c..e018a4e 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -77,28 +77,22 @@
int oldLayer = w.mLayer;
if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {
curLayer += WINDOW_LAYER_MULTIPLIER;
- w.mLayer = curLayer;
} else {
curBaseLayer = curLayer = w.mBaseLayer;
- w.mLayer = curLayer;
}
- if (w.mLayer != oldLayer) {
- layerChanged = true;
- anyLayerChanged = true;
- }
+ assignAnimLayer(w, curLayer);
- final WindowStateAnimator winAnimator = w.mWinAnimator;
- oldLayer = winAnimator.mAnimLayer;
- winAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
- getSpecialWindowAnimLayerAdjustment(w);
- if (winAnimator.mAnimLayer != oldLayer) {
+ // TODO: Preserved old behavior of code here but not sure comparing
+ // oldLayer to mAnimLayer and mLayer makes sense...though the
+ // worst case would be unintentionalp layer reassignment.
+ if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
layerChanged = true;
anyLayerChanged = true;
}
if (w.mAppToken != null) {
mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
- winAnimator.mAnimLayer);
+ w.mWinAnimator.mAnimLayer);
}
collectSpecialWindows(w);
@@ -223,12 +217,17 @@
private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
if (win != null) {
- win.mLayer = layer;
- win.mWinAnimator.mAnimLayer = layer;
+ assignAnimLayer(win, layer);
layer++;
}
return layer;
}
+
+ private void assignAnimLayer(WindowState w, int layer) {
+ w.mLayer = layer;
+ w.mWinAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
+ getSpecialWindowAnimLayerAdjustment(w);
+ }
void dump(PrintWriter pw, String s) {
if (mInputMethodAnimLayerAdjustment != 0 ||
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 14291ca..20a583c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -10515,9 +10515,9 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+ public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
try {
- getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver);
+ getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver, deviceId);
} catch (RemoteException e) {
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1695615..04bd7fc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -71,6 +71,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
@@ -655,8 +656,7 @@
}
if (mInsetFrame.isEmpty() && (fullscreenTask
- || (isChildWindow() && (mAttrs.privateFlags
- & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0))) {
+ || layoutInParentFrame())) {
// We use the parent frame as the containing frame for fullscreen and child windows
mContainingFrame.set(pf);
mDisplayFrame.set(df);
@@ -1883,6 +1883,13 @@
}
private boolean shouldSaveSurface() {
+ if ((mAttrs.flags & FLAG_SECURE) != 0) {
+ // We don't save secure surfaces since their content shouldn't be shown while the app
+ // isn't on screen and content might leak through during the transition animation with
+ // saved surface.
+ return false;
+ }
+
if (ActivityManager.isLowRamDeviceStatic()) {
// Don't save surfaces on Svelte devices.
return false;
@@ -2595,6 +2602,10 @@
return mAttachedWindow != null;
}
+ boolean layoutInParentFrame() {
+ return isChildWindow() && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0;
+ }
+
void setReplacing(boolean animate) {
if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) != 0
|| mAttrs.type == TYPE_APPLICATION_STARTING) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 41eafe7..22d3f98 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -994,6 +994,17 @@
if (appTransformation.hasClipRect()) {
mClipRect.set(appTransformation.getClipRect());
mHasClipRect = true;
+ // The app transformation clip will be in the coordinate space of the main
+ // activity window, which the animation correctly assumes will be placed at
+ // (0,0)+(insets) relative to the containing frame. This isn't necessarily
+ // true for child windows though which can have an arbitrary frame position
+ // relative to their containing frame. We need to offset the difference
+ // between the containing frame as used to calculate the crop and our
+ // bounds to compensate for this.
+ if (mWin.isChildWindow() && mWin.layoutInParentFrame()) {
+ mClipRect.offset( (mWin.mContainingFrame.left - mWin.mFrame.left),
+ mWin.mContainingFrame.top - mWin.mFrame.top );
+ }
}
}
if (screenAnimation) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c362c9c..7da0a9a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7513,7 +7513,9 @@
/**
* Sets which packages may enter lock task mode.
*
- * This function can only be called by the device owner.
+ * <p>This function can only be called by the device owner or alternatively by the profile owner
+ * in case the user is affiliated.
+ *
* @param packages The list of packages allowed to enter lock task mode.
*/
@Override
@@ -7521,10 +7523,17 @@
throws SecurityException {
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-
- int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
- setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
+ ActiveAdmin deviceOwner = getActiveAdminWithPolicyForUidLocked(
+ who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, mInjector.binderGetCallingUid());
+ ActiveAdmin profileOwner = getActiveAdminWithPolicyForUidLocked(
+ who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid());
+ if (deviceOwner != null || (profileOwner != null && isAffiliatedUser())) {
+ int userHandle = mInjector.userHandleGetCallingUserId();
+ setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
+ } else {
+ throw new SecurityException("Admin " + who +
+ " is neither the device owner or affiliated user's profile owner.");
+ }
}
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index afb7d93..e26e54b 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -813,6 +813,7 @@
private String mRemainingPostDialSequence;
private VideoCallImpl mVideoCallImpl;
private Details mDetails;
+ private Bundle mExtras;
/**
* Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
@@ -988,6 +989,89 @@
}
/**
+ * Adds some extras to this {@link Call}. Existing keys are replaced and new ones are
+ * added.
+ * <p>
+ * No assumptions should be made as to how an In-Call UI or service will handle these
+ * extras. Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
+ *
+ * @param extras The extras to add.
+ */
+ public final void putExtras(Bundle extras) {
+ if (extras == null) {
+ return;
+ }
+
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+ mInCallAdapter.putExtras(mTelecomCallId, extras);
+ }
+
+ /**
+ * Adds a boolean extra to this {@link Call}.
+ *
+ * @param key The extra key.
+ * @param value The value.
+ * @hide
+ */
+ public final void putExtra(String key, boolean value) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putBoolean(key, value);
+ mInCallAdapter.putExtra(mTelecomCallId, key, value);
+ }
+
+ /**
+ * Adds an integer extra to this {@code Connection}.
+ *
+ * @param key The extra key.
+ * @param value The value.
+ * @hide
+ */
+ public final void putExtra(String key, int value) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putInt(key, value);
+ mInCallAdapter.putExtra(mTelecomCallId, key, value);
+ }
+
+ /**
+ * Adds a string extra to this {@code Connection}.
+ *
+ * @param key The extra key.
+ * @param value The value.
+ * @hide
+ */
+ public final void putExtra(String key, String value) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putString(key, value);
+ mInCallAdapter.putExtra(mTelecomCallId, key, value);
+ }
+
+ /**
+ * Removes extras from this {@code Connection}.
+ *
+ * @param keys The keys of the extras to remove.
+ */
+ public final void removeExtras(List<String> keys) {
+ if (mExtras != null) {
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
+ if (mExtras.size() == 0) {
+ mExtras = null;
+ }
+ }
+ mInCallAdapter.removeExtras(mTelecomCallId, keys);
+ }
+
+ /**
* Obtains the parent of this {@code Call} in a conference, if any.
*
* @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 1b70d65..00e07af 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -16,10 +16,12 @@
package android.telecom;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Bundle;
import android.telecom.Connection.VideoProvider;
+import android.util.ArraySet;
import java.util.ArrayList;
import java.util.Collections;
@@ -54,7 +56,8 @@
public void onVideoStateChanged(Conference c, int videoState) { }
public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {}
public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {}
- public void onExtrasChanged(Conference conference, Bundle extras) {}
+ public void onExtrasChanged(Conference c, Bundle extras) {}
+ public void onExtrasRemoved(Conference c, List<String> keys) {}
}
private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
@@ -75,6 +78,7 @@
private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
private StatusHints mStatusHints;
private Bundle mExtras;
+ private Set<String> mPreviousExtraKeys;
private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
@Override
@@ -640,23 +644,171 @@
}
/**
- * Set some extras that can be associated with this {@code Conference}. No assumptions should
- * be made as to how an In-Call UI or service will handle these extras.
+ * Replaces all the extras associated with this {@code Conference}.
+ * <p>
+ * New or existing keys are replaced in the {@code Conference} extras. Keys which are no longer
+ * in the new extras, but were present the last time {@code setExtras} was called are removed.
+ * <p>
+ * No assumptions should be made as to how an In-Call UI or service will handle these extras.
* Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
*
- * @param extras The extras associated with this {@code Connection}.
+ * @param extras The extras associated with this {@code Conference}.
+ * @deprecated Use {@link #putExtras(Bundle)} to add extras. Use {@link #removeExtras(List)}
+ * to remove extras.
*/
public final void setExtras(@Nullable Bundle extras) {
- mExtras = extras;
+ // Add/replace any new or changed extras values.
+ putExtras(extras);
+
+ // If we have used "setExtras" in the past, compare the key set from the last invocation to
+ // the current one and remove any keys that went away.
+ if (mPreviousExtraKeys != null) {
+ List<String> toRemove = new ArrayList<String>();
+ for (String oldKey : mPreviousExtraKeys) {
+ if (!extras.containsKey(oldKey)) {
+ toRemove.add(oldKey);
+ }
+ }
+
+ if (!toRemove.isEmpty()) {
+ removeExtras(toRemove);
+ }
+ }
+
+ // Track the keys the last time set called setExtras. This way, the next time setExtras is
+ // called we can see if the caller has removed any extras values.
+ if (mPreviousExtraKeys == null) {
+ mPreviousExtraKeys = new ArraySet<String>();
+ }
+ mPreviousExtraKeys.clear();
+ mPreviousExtraKeys.addAll(extras.keySet());
+ }
+
+ /**
+ * Adds some extras to this {@link Conference}. Existing keys are replaced and new ones are
+ * added.
+ * <p>
+ * No assumptions should be made as to how an In-Call UI or service will handle these extras.
+ * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
+ *
+ * @param extras The extras to add.
+ */
+ public final void putExtras(@NonNull Bundle extras) {
+ if (extras == null) {
+ return;
+ }
+
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+
for (Listener l : mListeners) {
l.onExtrasChanged(this, extras);
}
}
/**
- * @return The extras associated with this conference.
+ * Adds a boolean extra to this {@link Conference}.
+ *
+ * @param key The extra key.
+ * @param value The value.
+ * @hide
+ */
+ public final void putExtra(String key, boolean value) {
+ Bundle newExtras = new Bundle();
+ newExtras.putBoolean(key, value);
+ putExtras(newExtras);
+ }
+
+ /**
+ * Adds an integer extra to this {@link Conference}.
+ *
+ * @param key The extra key.
+ * @param value The value.
+ * @hide
+ */
+ public final void putExtra(String key, int value) {
+ Bundle newExtras = new Bundle();
+ newExtras.putInt(key, value);
+ putExtras(newExtras);
+ }
+
+ /**
+ * Adds a string extra to this {@link Conference}.
+ *
+ * @param key The extra key.
+ * @param value The value.
+ * @hide
+ */
+ public final void putExtra(String key, String value) {
+ Bundle newExtras = new Bundle();
+ newExtras.putString(key, value);
+ putExtras(newExtras);
+ }
+
+ /**
+ * Removes an extra from this {@link Conference}.
+ *
+ * @param keys The key of the extra key to remove.
+ */
+ public final void removeExtras(List<String> keys) {
+ if (keys == null || keys.isEmpty()) {
+ return;
+ }
+
+ if (mExtras != null) {
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
+ if (mExtras.size() == 0) {
+ mExtras = null;
+ }
+ }
+
+ for (Listener l : mListeners) {
+ l.onExtrasRemoved(this, keys);
+ }
+ }
+
+ /**
+ * Returns the extras associated with this conference.
+ * <p>
+ * Extras should be updated using {@link #putExtras(Bundle)} and {@link #removeExtras(List)}.
+ * <p>
+ * Telecom or an {@link InCallService} can also update the extras via
+ * {@link android.telecom.Call#putExtras(Bundle)}, and
+ * {@link Call#removeExtras(List)}.
+ * <p>
+ * The conference is notified of changes to the extras made by Telecom or an
+ * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
+ *
+ * @return The extras associated with this connection.
*/
public final Bundle getExtras() {
return mExtras;
}
+
+ /**
+ * Notifies this {@link Conference} of a change to the extras made outside the
+ * {@link ConnectionService}.
+ * <p>
+ * These extras changes can originate from Telecom itself, or from an {@link InCallService} via
+ * {@link android.telecom.Call#putExtras(Bundle)}, and
+ * {@link Call#removeExtras(List)}.
+ *
+ * @param extras The new extras bundle.
+ */
+ public void onExtrasChanged(Bundle extras) {}
+
+ /**
+ * Handles a change to extras received from Telecom.
+ *
+ * @param extras The new extras.
+ * @hide
+ */
+ final void handleExtrasChanged(Bundle extras) {
+ mExtras = extras;
+ onExtrasChanged(mExtras);
+ }
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 51a6588..3ea1c6a 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -20,6 +20,7 @@
import com.android.internal.telecom.IVideoCallback;
import com.android.internal.telecom.IVideoProvider;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.hardware.camera2.CameraManager;
@@ -30,6 +31,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.view.Surface;
import java.util.ArrayList;
@@ -516,6 +518,7 @@
public void onConferenceStarted() {}
public void onConferenceMergeFailed(Connection c) {}
public void onExtrasChanged(Connection c, Bundle extras) {}
+ public void onExtrasRemoved(Connection c, List<String> keys) {}
public void onConnectionEvent(Connection c, String event, Bundle extras) {}
}
@@ -1183,6 +1186,13 @@
private Bundle mExtras;
/**
+ * Tracks the key set for the extras bundle provided on the last invocation of
+ * {@link #setExtras(Bundle)}. Used so that on subsequent invocations we can remove any extras
+ * keys which were set previously but are no longer present in the replacement Bundle.
+ */
+ private Set<String> mPreviousExtraKeys;
+
+ /**
* Create a new Connection.
*/
public Connection() {}
@@ -1318,6 +1328,17 @@
}
/**
+ * Returns the extras associated with this connection.
+ * <p>
+ * Extras should be updated using {@link #putExtras(Bundle)}.
+ * <p>
+ * Telecom or an {@link InCallService} can also update the extras via
+ * {@link android.telecom.Call#putExtras(Bundle)}, and
+ * {@link Call#removeExtras(List)}.
+ * <p>
+ * The connection is notified of changes to the extras made by Telecom or an
+ * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
+ *
* @return The extras associated with this connection.
*/
public final Bundle getExtras() {
@@ -1777,21 +1798,133 @@
}
/**
- * Set some extras that can be associated with this {@code Connection}. No assumptions should
- * be made as to how an In-Call UI or service will handle these extras.
+ * Set some extras that can be associated with this {@code Connection}.
+ * <p>
+ * New or existing keys are replaced in the {@code Connection} extras. Keys which are no longer
+ * in the new extras, but were present the last time {@code setExtras} was called are removed.
+ * <p>
+ * No assumptions should be made as to how an In-Call UI or service will handle these extras.
* Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
*
* @param extras The extras associated with this {@code Connection}.
+ * @deprecated Use {@link #putExtras(Bundle)} to add extras. Use {@link #removeExtras(List)}
+ * to remove extras.
*/
public final void setExtras(@Nullable Bundle extras) {
checkImmutable();
- mExtras = extras;
+
+ // Add/replace any new or changed extras values.
+ putExtras(extras);
+
+ // If we have used "setExtras" in the past, compare the key set from the last invocation to
+ // the current one and remove any keys that went away.
+ if (mPreviousExtraKeys != null) {
+ List<String> toRemove = new ArrayList<String>();
+ for (String oldKey : mPreviousExtraKeys) {
+ if (!extras.containsKey(oldKey)) {
+ toRemove.add(oldKey);
+ }
+ }
+ if (!toRemove.isEmpty()) {
+ removeExtras(toRemove);
+ }
+ }
+
+ // Track the keys the last time set called setExtras. This way, the next time setExtras is
+ // called we can see if the caller has removed any extras values.
+ if (mPreviousExtraKeys == null) {
+ mPreviousExtraKeys = new ArraySet<String>();
+ }
+ mPreviousExtraKeys.clear();
+ mPreviousExtraKeys.addAll(extras.keySet());
+ }
+
+ /**
+ * Adds some extras to this {@code Connection}. Existing keys are replaced and new ones are
+ * added.
+ * <p>
+ * No assumptions should be made as to how an In-Call UI or service will handle these extras.
+ * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
+ *
+ * @param extras The extras to add.
+ */
+ public final void putExtras(@NonNull Bundle extras) {
+ checkImmutable();
+ if (extras == null) {
+ return;
+ }
+
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+
for (Listener l : mListeners) {
l.onExtrasChanged(this, extras);
}
}
/**
+ * Adds a boolean extra to this {@code Connection}.
+ *
+ * @param key The extra key.
+ * @param value The value.
+ * @hide
+ */
+ public final void putExtra(String key, boolean value) {
+ Bundle newExtras = new Bundle();
+ newExtras.putBoolean(key, value);
+ putExtras(newExtras);
+ }
+
+ /**
+ * Adds an integer extra to this {@code Connection}.
+ *
+ * @param key The extra key.
+ * @param value The value.
+ * @hide
+ */
+ public final void putExtra(String key, int value) {
+ Bundle newExtras = new Bundle();
+ newExtras.putInt(key, value);
+ putExtras(newExtras);
+ }
+
+ /**
+ * Adds a string extra to this {@code Connection}.
+ *
+ * @param key The extra key.
+ * @param value The value.
+ * @hide
+ */
+ public final void putExtra(String key, String value) {
+ Bundle newExtras = new Bundle();
+ newExtras.putString(key, value);
+ putExtras(newExtras);
+ }
+
+ /**
+ * Removes an extra from this {@code Connection}.
+ *
+ * @param keys The key of the extra key to remove.
+ */
+ public final void removeExtras(List<String> keys) {
+ if (mExtras != null) {
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
+
+ if (mExtras.size() == 0) {
+ mExtras = null;
+ }
+ }
+
+ for (Listener l : mListeners) {
+ l.onExtrasRemoved(this, keys);
+ }
+ }
+
+ /**
* Notifies this Connection that the {@link #getAudioState()} property has a new value.
*
* @param state The new connection audio state.
@@ -1928,6 +2061,18 @@
*/
public void onCallEvent(String event, Bundle extras) {}
+ /**
+ * Notifies this {@link Connection} of a change to the extras made outside the
+ * {@link ConnectionService}.
+ * <p>
+ * These extras changes can originate from Telecom itself, or from an {@link InCallService} via
+ * the {@link android.telecom.Call#putExtras(Bundle)} and
+ * {@link Call#removeExtras(List)}.
+ *
+ * @param extras The new extras bundle.
+ */
+ public void onExtrasChanged(Bundle extras) {}
+
static String toLogSafePhoneNumber(String number) {
// For unknown number, log empty string.
if (number == null) {
@@ -2048,6 +2193,17 @@
}
/**
+ * Handles a change to extras received from Telecom.
+ *
+ * @param extras The new extras.
+ * @hide
+ */
+ final void handleExtrasChanged(Bundle extras) {
+ mExtras = extras;
+ onExtrasChanged(mExtras);
+ }
+
+ /**
* Notifies listeners that the merge request failed.
*
* @hide
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index d18b317..e092095 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -105,6 +105,7 @@
private static final int MSG_SILENCE = 21;
private static final int MSG_PULL_EXTERNAL_CALL = 22;
private static final int MSG_SEND_CALL_EVENT = 23;
+ private static final int MSG_ON_EXTRAS_CHANGED = 24;
private static Connection sNullConnection;
@@ -261,6 +262,14 @@
args.arg3 = extras;
mHandler.obtainMessage(MSG_SEND_CALL_EVENT, args).sendToTarget();
}
+
+ @Override
+ public void onExtrasChanged(String callId, Bundle extras) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = extras;
+ mHandler.obtainMessage(MSG_ON_EXTRAS_CHANGED, args).sendToTarget();
+ }
};
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -414,6 +423,17 @@
}
break;
}
+ case MSG_ON_EXTRAS_CHANGED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ Bundle extras = (Bundle) args.arg2;
+ handleExtrasChanged(callId, extras);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
default:
break;
}
@@ -492,13 +512,25 @@
@Override
public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {
String id = mIdByConference.get(conference);
- mAdapter.setStatusHints(id, statusHints);
+ if (id != null) {
+ mAdapter.setStatusHints(id, statusHints);
+ }
}
@Override
- public void onExtrasChanged(Conference conference, Bundle extras) {
- String id = mIdByConference.get(conference);
- mAdapter.setExtras(id, extras);
+ public void onExtrasChanged(Conference c, Bundle extras) {
+ String id = mIdByConference.get(c);
+ if (id != null) {
+ mAdapter.putExtras(id, extras);
+ }
+ }
+
+ @Override
+ public void onExtrasRemoved(Conference c, List<String> keys) {
+ String id = mIdByConference.get(c);
+ if (id != null) {
+ mAdapter.removeExtras(id, keys);
+ }
}
};
@@ -639,12 +671,20 @@
}
@Override
- public void onExtrasChanged(Connection connection, Bundle extras) {
- String id = mIdByConnection.get(connection);
+ public void onExtrasChanged(Connection c, Bundle extras) {
+ String id = mIdByConnection.get(c);
if (id != null) {
- mAdapter.setExtras(id, extras);
+ mAdapter.putExtras(id, extras);
}
}
+
+ public void onExtrasRemoved(Connection c, List<String> keys) {
+ String id = mIdByConnection.get(c);
+ if (id != null) {
+ mAdapter.removeExtras(id, keys);
+ }
+ }
+
@Override
public void onConnectionEvent(Connection connection, String event, Bundle extras) {
@@ -929,6 +969,27 @@
}
+ /**
+ * Notifies a {@link Connection} or {@link Conference} of a change to the extras from Telecom.
+ * <p>
+ * These extra changes can originate from Telecom itself, or from an {@link InCallService} via
+ * the {@link android.telecom.Call#putExtra(String, boolean)},
+ * {@link android.telecom.Call#putExtra(String, int)},
+ * {@link android.telecom.Call#putExtra(String, String)},
+ * {@link Call#removeExtras(List)}.
+ *
+ * @param callId The ID of the call receiving the event.
+ * @param extras The new extras bundle.
+ */
+ private void handleExtrasChanged(String callId, Bundle extras) {
+ Log.d(this, "handleExtrasChanged(%s, %s)", callId, extras);
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
+ } else if (mConferenceById.containsKey(callId)) {
+ findConferenceForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
+ }
+ }
+
private void onPostDialContinue(String callId, boolean proceed) {
Log.d(this, "onPostDialContinue(%s)", callId);
findConnectionForAction(callId, "stopDtmfTone").onPostDialContinue(proceed);
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index e91128f..81e4c22 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -398,16 +398,88 @@
}
/**
- * Sets extras associated with a connection.
+ * Adds some extras associated with a {@code Connection}.
*
* @param callId The unique ID of the call.
- * @param extras The extras to associate with this call.
+ * @param extras The extras to add.
*/
- void setExtras(String callId, Bundle extras) {
- Log.v(this, "setExtras: %s", extras);
+ void putExtras(String callId, Bundle extras) {
+ Log.v(this, "putExtras: %s", callId);
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
- adapter.setExtras(callId, extras);
+ adapter.putExtras(callId, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Adds an extra associated with a {@code Connection}.
+ *
+ * @param callId The unique ID of the call.
+ * @param key The extra key.
+ * @param value The extra value.
+ */
+ void putExtra(String callId, String key, boolean value) {
+ Log.v(this, "putExtra: %s %s=%b", callId, key, value);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(key, value);
+ adapter.putExtras(callId, bundle);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Adds an extra associated with a {@code Connection}.
+ *
+ * @param callId The unique ID of the call.
+ * @param key The extra key.
+ * @param value The extra value.
+ */
+ void putExtra(String callId, String key, int value) {
+ Log.v(this, "putExtra: %s %s=%d", callId, key, value);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ Bundle bundle = new Bundle();
+ bundle.putInt(key, value);
+ adapter.putExtras(callId, bundle);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Adds an extra associated with a {@code Connection}.
+ *
+ * @param callId The unique ID of the call.
+ * @param key The extra key.
+ * @param value The extra value.
+ */
+ void putExtra(String callId, String key, String value) {
+ Log.v(this, "putExtra: %s %s=%s", callId, key, value);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ Bundle bundle = new Bundle();
+ bundle.putString(key, value);
+ adapter.putExtras(callId, bundle);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Removes extras associated with a {@code Connection}.
+ * @param callId The unique ID of the call.
+ * @param keys The extra keys to remove.
+ */
+ void removeExtras(String callId, List<String> keys) {
+ Log.v(this, "removeExtras: %s %s", callId, keys);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.removeExtras(callId, keys);
} catch (RemoteException ignored) {
}
}
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 4b15e54..3e46557 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -61,8 +61,9 @@
private static final int MSG_ADD_EXISTING_CONNECTION = 21;
private static final int MSG_ON_POST_DIAL_CHAR = 22;
private static final int MSG_SET_CONFERENCE_MERGE_FAILED = 23;
- private static final int MSG_SET_EXTRAS = 24;
- private static final int MSG_ON_CONNECTION_EVENT = 25;
+ private static final int MSG_PUT_EXTRAS = 24;
+ private static final int MSG_REMOVE_EXTRAS = 25;
+ private static final int MSG_ON_CONNECTION_EVENT = 26;
private final IConnectionServiceAdapter mDelegate;
@@ -233,10 +234,19 @@
}
break;
}
- case MSG_SET_EXTRAS: {
+ case MSG_PUT_EXTRAS: {
SomeArgs args = (SomeArgs) msg.obj;
try {
- mDelegate.setExtras((String) args.arg1, (Bundle) args.arg2);
+ mDelegate.putExtras((String) args.arg1, (Bundle) args.arg2);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_REMOVE_EXTRAS: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ mDelegate.removeExtras((String) args.arg1, (List<String>) args.arg2);
} finally {
args.recycle();
}
@@ -425,11 +435,19 @@
}
@Override
- public final void setExtras(String connectionId, Bundle extras) {
+ public final void putExtras(String connectionId, Bundle extras) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = connectionId;
args.arg2 = extras;
- mHandler.obtainMessage(MSG_SET_EXTRAS, args).sendToTarget();
+ mHandler.obtainMessage(MSG_PUT_EXTRAS, args).sendToTarget();
+ }
+
+ @Override
+ public final void removeExtras(String connectionId, List<String> keys) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = connectionId;
+ args.arg2 = keys;
+ mHandler.obtainMessage(MSG_REMOVE_EXTRAS, args).sendToTarget();
}
@Override
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 52ef4a7..3f270d9 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -21,6 +21,8 @@
import com.android.internal.telecom.IInCallAdapter;
+import java.util.List;
+
/**
* Receives commands from {@link InCallService} implementations which should be executed by
* Telecom. When Telecom binds to a {@link InCallService}, an instance of this class is given to
@@ -278,6 +280,79 @@
}
/**
+ * Intructs Telecom to add extras to a call.
+ *
+ * @param callId The callId to add the extras to.
+ * @param extras The extras.
+ */
+ public void putExtras(String callId, Bundle extras) {
+ try {
+ mAdapter.putExtras(callId, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Intructs Telecom to add an extra to a call.
+ *
+ * @param callId The callId to add the extras to.
+ * @param key The extra key.
+ * @param value The extra value.
+ */
+ public void putExtra(String callId, String key, boolean value) {
+ try {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(key, value);
+ mAdapter.putExtras(callId, bundle);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Intructs Telecom to add an extra to a call.
+ *
+ * @param callId The callId to add the extras to.
+ * @param key The extra key.
+ * @param value The extra value.
+ */
+ public void putExtra(String callId, String key, int value) {
+ try {
+ Bundle bundle = new Bundle();
+ bundle.putInt(key, value);
+ mAdapter.putExtras(callId, bundle);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Intructs Telecom to add an extra to a call.
+ *
+ * @param callId The callId to add the extras to.
+ * @param key The extra key.
+ * @param value The extra value.
+ */
+ public void putExtra(String callId, String key, String value) {
+ try {
+ Bundle bundle = new Bundle();
+ bundle.putString(key, value);
+ mAdapter.putExtras(callId, bundle);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Intructs Telecom to remove extras from a call.
+ * @param callId The callId to remove the extras from.
+ * @param keys The extra keys to remove.
+ */
+ public void removeExtras(String callId, List<String> keys) {
+ try {
+ mAdapter.removeExtras(callId, keys);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
* Instructs Telecom to turn the proximity sensor on.
*/
public void turnProximitySensorOn() {
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index ae5cd46..b03cb51 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -279,15 +279,35 @@
}
/** @hide */
- void setExtras(final Bundle extras) {
- mExtras = extras;
+ void putExtras(final Bundle extras) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+
+ notifyExtrasChanged();
+ }
+
+ /** @hide */
+ void removeExtras(List<String> keys) {
+ if (mExtras == null || keys == null || keys.isEmpty()) {
+ return;
+ }
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
+
+ notifyExtrasChanged();
+ }
+
+ private void notifyExtrasChanged() {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final RemoteConference conference = this;
final Callback callback = record.getCallback();
record.getHandler().post(new Runnable() {
@Override
public void run() {
- callback.onExtrasChanged(conference, extras);
+ callback.onExtrasChanged(conference, mExtras);
}
});
}
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 5b602eb..7df6678 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -1302,15 +1302,35 @@
}
/** @hide */
- void setExtras(final Bundle extras) {
- mExtras = extras;
+ void putExtras(final Bundle extras) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+
+ notifyExtrasChanged();
+ }
+
+ /** @hide */
+ void removeExtras(List<String> keys) {
+ if (mExtras == null || keys == null || keys.isEmpty()) {
+ return;
+ }
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
+
+ notifyExtrasChanged();
+ }
+
+ private void notifyExtrasChanged() {
for (CallbackRecord record : mCallbackRecords) {
final RemoteConnection connection = this;
final Callback callback = record.getCallback();
record.getHandler().post(new Runnable() {
@Override
public void run() {
- callback.onExtrasChanged(connection, extras);
+ callback.onExtrasChanged(connection, mExtras);
}
});
}
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index fa7183a..d88d007 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -321,13 +321,20 @@
}
@Override
- public void setExtras(String callId, Bundle extras) {
- if (mConnectionById.containsKey(callId)) {
- findConnectionForAction(callId, "setExtras")
- .setExtras(extras);
+ public void putExtras(String callId, Bundle extras) {
+ if (hasConnection(callId)) {
+ findConnectionForAction(callId, "putExtras").putExtras(extras);
} else {
- findConferenceForAction(callId, "setExtras")
- .setExtras(extras);
+ findConferenceForAction(callId, "putExtras").putExtras(extras);
+ }
+ }
+
+ @Override
+ public void removeExtras(String callId, List<String> keys) {
+ if (hasConnection(callId)) {
+ findConnectionForAction(callId, "removeExtra").removeExtras(keys);
+ } else {
+ findConferenceForAction(callId, "removeExtra").removeExtras(keys);
}
}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 3ee0e9f..a4c1798 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -79,4 +79,6 @@
void pullExternalCall(String callId);
void sendCallEvent(String callId, String event, in Bundle extras);
+
+ void onExtrasChanged(String callId, in Bundle extras);
}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index dff1b11..6804805 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -85,7 +85,9 @@
void addExistingConnection(String callId, in ParcelableConnection connection);
- void setExtras(String callId, in Bundle extras);
+ void putExtras(String callId, in Bundle extras);
+
+ void removeExtras(String callId, in List<String> keys);
void onConnectionEvent(String callId, String event, in Bundle extras);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 0678fe2..49f9b3b 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -65,4 +65,8 @@
void pullExternalCall(String callId);
void sendCallEvent(String callId, String event, in Bundle extras);
+
+ void putExtras(String callId, in Bundle extras);
+
+ void removeExtras(String callId, in List<String> keys);
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index ae130d4..bb2b447 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -32,6 +32,7 @@
import com.android.internal.telephony.IPhoneStateListener;
import java.util.List;
+import java.lang.ref.WeakReference;
/**
* A listener class for monitoring changes in specific telephony states
@@ -533,84 +534,101 @@
/**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
+ *
+ * Using a static class and weak reference here to avoid memory leak caused by the
+ * IPhoneStateListener.Stub callback retaining references to the outside PhoneStateListeners:
+ * even caller has been destroyed and "un-registered" the PhoneStateListener, it is still not
+ * eligible for GC given the references coming from:
+ * Native Stack --> PhoneStateListener --> Context (Activity).
+ * memory of caller's context will be collected after GC from service side get triggered
*/
- IPhoneStateListener callback = new IPhoneStateListener.Stub() {
+ private static class IPhoneStateListenerStub extends IPhoneStateListener.Stub {
+ private WeakReference<PhoneStateListener> mPhoneStateListenerWeakRef;
+
+ public IPhoneStateListenerStub(PhoneStateListener phoneStateListener) {
+ mPhoneStateListenerWeakRef = new WeakReference<PhoneStateListener>(phoneStateListener);
+ }
+
+ private void send(int what, int arg1, int arg2, Object obj) {
+ PhoneStateListener listener = mPhoneStateListenerWeakRef.get();
+ if (listener != null) {
+ Message.obtain(listener.mHandler, what, arg1, arg2, obj).sendToTarget();
+ }
+ }
+
public void onServiceStateChanged(ServiceState serviceState) {
- Message.obtain(mHandler, LISTEN_SERVICE_STATE, 0, 0, serviceState).sendToTarget();
+ send(LISTEN_SERVICE_STATE, 0, 0, serviceState);
}
public void onSignalStrengthChanged(int asu) {
- Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTH, asu, 0, null).sendToTarget();
+ send(LISTEN_SIGNAL_STRENGTH, asu, 0, null);
}
public void onMessageWaitingIndicatorChanged(boolean mwi) {
- Message.obtain(mHandler, LISTEN_MESSAGE_WAITING_INDICATOR, mwi ? 1 : 0, 0, null)
- .sendToTarget();
+ send(LISTEN_MESSAGE_WAITING_INDICATOR, mwi ? 1 : 0, 0, null);
}
public void onCallForwardingIndicatorChanged(boolean cfi) {
- Message.obtain(mHandler, LISTEN_CALL_FORWARDING_INDICATOR, cfi ? 1 : 0, 0, null)
- .sendToTarget();
+ send(LISTEN_CALL_FORWARDING_INDICATOR, cfi ? 1 : 0, 0, null);
}
public void onCellLocationChanged(Bundle bundle) {
CellLocation location = CellLocation.newFromBundle(bundle);
- Message.obtain(mHandler, LISTEN_CELL_LOCATION, 0, 0, location).sendToTarget();
+ send(LISTEN_CELL_LOCATION, 0, 0, location);
}
public void onCallStateChanged(int state, String incomingNumber) {
- Message.obtain(mHandler, LISTEN_CALL_STATE, state, 0, incomingNumber).sendToTarget();
+ send(LISTEN_CALL_STATE, state, 0, incomingNumber);
}
public void onDataConnectionStateChanged(int state, int networkType) {
- Message.obtain(mHandler, LISTEN_DATA_CONNECTION_STATE, state, networkType).
- sendToTarget();
+ send(LISTEN_DATA_CONNECTION_STATE, state, networkType, null);
}
public void onDataActivity(int direction) {
- Message.obtain(mHandler, LISTEN_DATA_ACTIVITY, direction, 0, null).sendToTarget();
+ send(LISTEN_DATA_ACTIVITY, direction, 0, null);
}
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
- Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength).sendToTarget();
+ send(LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength);
}
public void onOtaspChanged(int otaspMode) {
- Message.obtain(mHandler, LISTEN_OTASP_CHANGED, otaspMode, 0).sendToTarget();
+ send(LISTEN_OTASP_CHANGED, otaspMode, 0, null);
}
public void onCellInfoChanged(List<CellInfo> cellInfo) {
- Message.obtain(mHandler, LISTEN_CELL_INFO, 0, 0, cellInfo).sendToTarget();
+ send(LISTEN_CELL_INFO, 0, 0, cellInfo);
}
public void onPreciseCallStateChanged(PreciseCallState callState) {
- Message.obtain(mHandler, LISTEN_PRECISE_CALL_STATE, 0, 0, callState).sendToTarget();
+ send(LISTEN_PRECISE_CALL_STATE, 0, 0, callState);
}
public void onPreciseDataConnectionStateChanged(
PreciseDataConnectionState dataConnectionState) {
- Message.obtain(mHandler, LISTEN_PRECISE_DATA_CONNECTION_STATE, 0, 0,
- dataConnectionState).sendToTarget();
+ send(LISTEN_PRECISE_DATA_CONNECTION_STATE, 0, 0, dataConnectionState);
}
public void onDataConnectionRealTimeInfoChanged(
DataConnectionRealTimeInfo dcRtInfo) {
- Message.obtain(mHandler, LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0,
- dcRtInfo).sendToTarget();
+ send(LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0, dcRtInfo);
}
public void onVoLteServiceStateChanged(VoLteServiceState lteState) {
- Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget();
+ send(LISTEN_VOLTE_STATE, 0, 0, lteState);
}
public void onOemHookRawEvent(byte[] rawData) {
- Message.obtain(mHandler, LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData).sendToTarget();
+ send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData);
}
public void onCarrierNetworkChange(boolean active) {
- Message.obtain(mHandler, LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active).sendToTarget();
+ send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active);
}
- };
+ }
+
+ IPhoneStateListener callback = new IPhoneStateListenerStub(this);
private void log(String s) {
Rlog.d(LOG_TAG, s);
diff --git a/telephony/java/com/android/ims/ImsExternalCallState.java b/telephony/java/com/android/ims/ImsExternalCallState.java
index edb6bfc..71c1837 100644
--- a/telephony/java/com/android/ims/ImsExternalCallState.java
+++ b/telephony/java/com/android/ims/ImsExternalCallState.java
@@ -28,7 +28,7 @@
*/
/**
- * Parcelable object to handle VICE Dialog Information
+ * Parcelable object to handle MultiEndpoint Dialog Information
* @hide
*/
public class ImsExternalCallState implements Parcelable {
@@ -39,19 +39,30 @@
public static final int CALL_STATE_CONFIRMED = 1;
public static final int CALL_STATE_TERMINATED = 2;
// Dialog Id
- public int mCallId;
+ private int mCallId;
// Number
- public Uri mAddress;
- public boolean mIsPullable;
+ private Uri mAddress;
+ private boolean mIsPullable;
// CALL_STATE_CONFIRMED / CALL_STATE_TERMINATED
- public int mCallState;
+ private int mCallState;
// ImsCallProfile#CALL_TYPE_*
- public int mCallType;
- public boolean mIsHeld;
+ private int mCallType;
+ private boolean mIsHeld;
public ImsExternalCallState() {
}
+ public ImsExternalCallState(int callId, Uri address, boolean isPullable, int callState,
+ int callType, boolean isCallheld) {
+ mCallId = callId;
+ mAddress = address;
+ mIsPullable = isPullable;
+ mCallState = callState;
+ mCallType = callType;
+ mIsHeld = isCallheld;
+ Rlog.d(TAG, "ImsExternalCallState = " + this);
+ }
+
public ImsExternalCallState(Parcel in) {
mCallId = in.readInt();
ClassLoader classLoader = ImsExternalCallState.class.getClassLoader();
@@ -60,12 +71,7 @@
mCallState = in.readInt();
mCallType = in.readInt();
mIsHeld = (in.readInt() != 0);
- Rlog.d(TAG, "ImsExternalCallState const = " +
- "callid = " + getCallId() +
- ", address = " + getAddress() +
- ", mCallState = " + getCallState() +
- ", calltype = " + getCallType() +
- ", isheld = " + isCallHeld());
+ Rlog.d(TAG, "ImsExternalCallState const = " + this);
}
@Override
@@ -81,6 +87,7 @@
out.writeInt(mCallState);
out.writeInt(mCallType);
out.writeInt(mIsHeld ? 1 : 0);
+ Rlog.d(TAG, "ImsExternalCallState writeToParcel = " + out.toString());
}
public static final Parcelable.Creator<ImsExternalCallState> CREATOR =
diff --git a/telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl b/telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl
index 70a474e..27b8fa1 100644
--- a/telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl
@@ -32,7 +32,7 @@
*
* @return void.
*/
- void notifyRefreshExternalCallState(in List<ImsExternalCallState> externalCallDialogs);
+ void onImsExternalCallStateUpdate(in List<ImsExternalCallState> externalCallDialogs);
}
diff --git a/telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl b/telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl
index 1bfb9b2..1374caa 100644
--- a/telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl
+++ b/telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl
@@ -34,5 +34,5 @@
* Query api to get the latest Dialog Event Package information
* Should be invoked only after setListener is done
*/
- void requestDialogEventPackageState();
+ void requestImsExternalCallStateInfo();
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index ea3b5c9..6567ea7 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -218,11 +218,4 @@
*/
static final String PROPERTY_VIDEOCALL_AUDIO_OUTPUT = "persist.radio.call.audio.output";
- /**
- * For MultiEndpoint Feature
- * If true: Dial intent is for call pull functionality
- * if false: normal dial
- */
- static final String EXTRA_IS_CALL_PULL =
- "android.telephony.extra.IS_CALL_PULL";
}
diff --git a/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
new file mode 100644
index 0000000..5d23d36e
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+ <domain-config>
+ <domain>android.com
+ </domain>
+ <domain> developer.android.com </domain>
+ <pin-set>
+ <pin digest="SHA-256"> 7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= </pin>
+ </pin-set>
+ </domain-config>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
index 10bcc18..f7066a6 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
@@ -464,4 +464,16 @@
} catch (RuntimeException expected) {
}
}
+
+ public void testDomainWhitespaceTrimming() throws Exception {
+ XmlConfigSource source =
+ new XmlConfigSource(getContext(), R.xml.domain_whitespace, false);
+ ApplicationConfig appConfig = new ApplicationConfig(source);
+ NetworkSecurityConfig defaultConfig = appConfig.getConfigForHostname("");
+ MoreAsserts.assertNotEqual(defaultConfig, appConfig.getConfigForHostname("developer.android.com"));
+ MoreAsserts.assertNotEqual(defaultConfig, appConfig.getConfigForHostname("android.com"));
+ SSLContext context = TestUtils.getSSLContext(source);
+ TestUtils.assertConnectionSucceeds(context, "android.com", 443);
+ TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 7f41348..309c1b8 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -564,7 +564,8 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
+ public void requestAppKeyboardShortcuts(
+ IResultReceiver receiver, int deviceId) throws RemoteException {
}
@Override
diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
index 411417c..1ea8a9f 100644
--- a/tools/layoutlib/bridge/src/android/view/WindowCallback.java
+++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
@@ -141,9 +141,4 @@
public void onActionModeFinished(ActionMode mode) {
}
-
- @Override
- public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, @Nullable Menu menu) {
-
- }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index 533a10a..a83f100 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -103,7 +103,8 @@
}
@Override
- public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
+ public void requestAppKeyboardShortcuts(
+ IResultReceiver receiver, int deviceId) throws RemoteException {
}
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
index d417eb7..3031701 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
@@ -66,6 +66,6 @@
@Override
public void requestAppKeyboardShortcuts(
- KeyboardShortcutsReceiver receiver) {
+ KeyboardShortcutsReceiver receiver, int deviceId) {
}
}