Merge "Add missing accessors on GradientDrawable, NinePatchDrawable"
diff --git a/api/current.txt b/api/current.txt
index 5b7800b..0394d56 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11276,6 +11276,7 @@
method public static int blue(int);
method public static void colorToHSV(int, float[]);
method public static int green(int);
+ method public static float luminance(int);
method public static int parseColor(java.lang.String);
method public static int red(int);
method public static int rgb(int, int, int);
@@ -41451,6 +41452,8 @@
method public void dispatchDraw(android.graphics.Canvas);
method public void focusCurrentTab(int);
method public android.view.View getChildTabViewAt(int);
+ method public android.graphics.drawable.Drawable getLeftStripDrawable();
+ method public android.graphics.drawable.Drawable getRightStripDrawable();
method public int getTabCount();
method public boolean isStripEnabled();
method public void onFocusChange(android.view.View, boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 875c823..a1aa042 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -11613,6 +11613,7 @@
method public static int blue(int);
method public static void colorToHSV(int, float[]);
method public static int green(int);
+ method public static float luminance(int);
method public static int parseColor(java.lang.String);
method public static int red(int);
method public static int rgb(int, int, int);
@@ -44097,6 +44098,8 @@
method public void dispatchDraw(android.graphics.Canvas);
method public void focusCurrentTab(int);
method public android.view.View getChildTabViewAt(int);
+ method public android.graphics.drawable.Drawable getLeftStripDrawable();
+ method public android.graphics.drawable.Drawable getRightStripDrawable();
method public int getTabCount();
method public boolean isStripEnabled();
method public void onFocusChange(android.view.View, boolean);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 964b776..f66a4c7 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import android.app.ActivityManager;
@@ -844,7 +845,7 @@
return Integer.toString(result);
}
- // pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}
+ // pm set-app-link [--user USER_ID] PACKAGE {always|ask|always-ask|never|undefined}
private int runSetAppLink() {
int userId = UserHandle.USER_SYSTEM;
@@ -893,6 +894,10 @@
newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
break;
+ case "always-ask":
+ newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
+ break;
+
case "never":
newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
break;
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 474154b..2caec369 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -43,6 +43,8 @@
void clearWindowAnimationFrameStats();
WindowAnimationFrameStats getWindowAnimationFrameStats();
void executeShellCommand(String command, in ParcelFileDescriptor fd);
+ void grantRuntimePermission(String packageName, String permission, int userId);
+ void revokeRuntimePermission(String packageName, String permission, int userId);
// Called from the system process.
oneway void shutdown();
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index a8494fb..efed2e0 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -30,6 +30,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.Log;
import android.view.Display;
import android.view.InputEvent;
@@ -846,6 +847,62 @@
}
/**
+ * Grants a runtime permission to a package for a user.
+ * @param packageName The package to which to grant.
+ * @param permission The permission to grant.
+ * @return Whether granting succeeded.
+ *
+ * @hide
+ */
+ public boolean grantRuntimePermission(String packageName, String permission,
+ UserHandle userHandle) {
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ }
+ try {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Granting runtime permission");
+ }
+ // Calling out without a lock held.
+ mUiAutomationConnection.grantRuntimePermission(packageName,
+ permission, userHandle.getIdentifier());
+ // TODO: The package manager API should return boolean.
+ return true;
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error granting runtime permission", re);
+ }
+ return false;
+ }
+
+ /**
+ * Revokes a runtime permission from a package for a user.
+ * @param packageName The package from which to revoke.
+ * @param permission The permission to revoke.
+ * @return Whether revoking succeeded.
+ *
+ * @hide
+ */
+ public boolean revokeRuntimePermission(String packageName, String permission,
+ UserHandle userHandle) {
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ }
+ try {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Revoking runtime permission");
+ }
+ // Calling out without a lock held.
+ mUiAutomationConnection.revokeRuntimePermission(packageName,
+ permission, userHandle.getIdentifier());
+ // TODO: The package manager API should return boolean.
+ return true;
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error revoking runtime permission", re);
+ }
+ return false;
+ }
+
+ /**
* Executes a shell command. This method returs a file descriptor that points
* to the standard output stream. The command execution is similar to running
* "adb shell <command>" from a host connected to the device.
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 39cd3bc..13e27e2 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -19,6 +19,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.content.Context;
+import android.content.pm.IPackageManager;
import android.graphics.Bitmap;
import android.hardware.input.InputManager;
import android.os.Binder;
@@ -60,6 +61,9 @@
private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub
.asInterface(ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
+ private final IPackageManager mPackageManager = IPackageManager.Stub
+ .asInterface(ServiceManager.getService("package"));
+
private final Object mLock = new Object();
private final Binder mToken = new Binder();
@@ -227,6 +231,38 @@
}
@Override
+ public void grantRuntimePermission(String packageName, String permission, int userId)
+ throws RemoteException {
+ synchronized (mLock) {
+ throwIfCalledByNotTrustedUidLocked();
+ throwIfShutdownLocked();
+ throwIfNotConnectedLocked();
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mPackageManager.grantRuntimePermission(packageName, permission, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void revokeRuntimePermission(String packageName, String permission, int userId)
+ throws RemoteException {
+ synchronized (mLock) {
+ throwIfCalledByNotTrustedUidLocked();
+ throwIfShutdownLocked();
+ throwIfNotConnectedLocked();
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mPackageManager.revokeRuntimePermission(packageName, permission, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void executeShellCommand(final String command, final ParcelFileDescriptor sink)
throws RemoteException {
synchronized (mLock) {
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index 4dbac05..953b051 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import android.os.Parcel;
@@ -199,6 +200,10 @@
sb.append("never");
break;
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK:
+ sb.append("always-ask");
+ break;
+
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
default:
sb.append("undefined");
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0f936fd..c8e9402 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1073,6 +1073,18 @@
public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER = 3;
/**
+ * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus}
+ * to indicate that this app should always be considered as an ambiguous candidate for
+ * handling the matching Intent even if there are other candidate apps in the "always"
+ * state. Put another way: if there are any 'always ask' apps in a set of more than
+ * one candidate app, then a disambiguation is *always* presented even if there is
+ * another candidate app with the 'always' state.
+ *
+ * @hide
+ */
+ public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK = 4;
+
+ /**
* Can be used as the {@code millisecondsToDelay} argument for
* {@link PackageManager#extendVerificationTimeout}. This is the
* maximum time {@code PackageManager} waits for the verification
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index d9cff4e..0cc630a 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -16,8 +16,10 @@
package android.widget;
-import android.R;
+import com.android.internal.R;
+
import android.annotation.DrawableRes;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -33,21 +35,25 @@
/**
*
* Displays a list of tab labels representing each page in the parent's tab
- * collection. The container object for this widget is
- * {@link android.widget.TabHost TabHost}. When the user selects a tab, this
- * object sends a message to the parent container, TabHost, to tell it to switch
- * the displayed page. You typically won't use many methods directly on this
- * object. The container TabHost is used to add labels, add the callback
- * handler, and manage callbacks. You might call this object to iterate the list
- * of tabs, or to tweak the layout of the tab list, but most methods should be
- * called on the containing TabHost object.
- *
+ * collection.
+ * <p>
+ * The container object for this widget is {@link android.widget.TabHost TabHost}.
+ * When the user selects a tab, this object sends a message to the parent
+ * container, TabHost, to tell it to switch the displayed page. You typically
+ * won't use many methods directly on this object. The container TabHost is
+ * used to add labels, add the callback handler, and manage callbacks. You
+ * might call this object to iterate the list of tabs, or to tweak the layout
+ * of the tab list, but most methods should be called on the containing TabHost
+ * object.
+ *
* @attr ref android.R.styleable#TabWidget_divider
* @attr ref android.R.styleable#TabWidget_tabStripEnabled
* @attr ref android.R.styleable#TabWidget_tabStripLeft
* @attr ref android.R.styleable#TabWidget_tabStripRight
*/
public class TabWidget extends LinearLayout implements OnFocusChangeListener {
+ private final Rect mBounds = new Rect();
+
private OnTabSelectionChanged mSelectionChangedListener;
// This value will be set to 0 as soon as the first tab is added to TabHost.
@@ -59,9 +65,8 @@
private boolean mDrawBottomStrips = true;
private boolean mStripMoved;
- private final Rect mBounds = new Rect();
-
- // When positive, the widths and heights of tabs will be imposed so that they fit in parent
+ // When positive, the widths and heights of tabs will be imposed so that
+ // they fit in parent.
private int mImposedTabsHeight = -1;
private int[] mImposedTabWidths;
@@ -81,20 +86,48 @@
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.TabWidget, defStyleAttr, defStyleRes);
+ attrs, R.styleable.TabWidget, defStyleAttr, defStyleRes);
- setStripEnabled(a.getBoolean(R.styleable.TabWidget_tabStripEnabled, true));
- setLeftStripDrawable(a.getDrawable(R.styleable.TabWidget_tabStripLeft));
- setRightStripDrawable(a.getDrawable(R.styleable.TabWidget_tabStripRight));
+ mDrawBottomStrips = a.getBoolean(R.styleable.TabWidget_tabStripEnabled, mDrawBottomStrips);
+
+ // Tests the target SDK version, as set in the Manifest. Could not be
+ // set using styles.xml in a values-v? directory which targets the
+ // current platform SDK version instead.
+ final boolean isTargetSdkDonutOrLower =
+ context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT;
+
+ final boolean hasExplicitLeft = a.hasValueOrEmpty(R.styleable.TabWidget_tabStripLeft);
+ if (hasExplicitLeft) {
+ mLeftStrip = a.getDrawable(R.styleable.TabWidget_tabStripLeft);
+ } else if (isTargetSdkDonutOrLower) {
+ mLeftStrip = context.getDrawable(R.drawable.tab_bottom_left_v4);
+ } else {
+ mLeftStrip = context.getDrawable(R.drawable.tab_bottom_left);
+ }
+
+ final boolean hasExplicitRight = a.hasValueOrEmpty(R.styleable.TabWidget_tabStripRight);
+ if (hasExplicitRight) {
+ mRightStrip = a.getDrawable(R.styleable.TabWidget_tabStripRight);
+ } else if (isTargetSdkDonutOrLower) {
+ mRightStrip = context.getDrawable(R.drawable.tab_bottom_right_v4);
+ } else {
+ mRightStrip = context.getDrawable(R.drawable.tab_bottom_right);
+ }
a.recycle();
- initTabWidget();
+ setChildrenDrawingOrderEnabled(true);
+
+ // Deal with focus, as we don't want the focus to go by default
+ // to a tab other than the current tab
+ setFocusable(true);
+ setOnFocusChangeListener(this);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mStripMoved = true;
+
super.onSizeChanged(w, h, oldw, oldh);
}
@@ -115,44 +148,8 @@
}
}
- private void initTabWidget() {
- setChildrenDrawingOrderEnabled(true);
-
- final Context context = mContext;
-
- // Tests the target Sdk version, as set in the Manifest. Could not be set using styles.xml
- // in a values-v? directory which targets the current platform Sdk version instead.
- if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
- // Donut apps get old color scheme
- if (mLeftStrip == null) {
- mLeftStrip = context.getDrawable(
- com.android.internal.R.drawable.tab_bottom_left_v4);
- }
- if (mRightStrip == null) {
- mRightStrip = context.getDrawable(
- com.android.internal.R.drawable.tab_bottom_right_v4);
- }
- } else {
- // Use modern color scheme for Eclair and beyond
- if (mLeftStrip == null) {
- mLeftStrip = context.getDrawable(
- com.android.internal.R.drawable.tab_bottom_left);
- }
- if (mRightStrip == null) {
- mRightStrip = context.getDrawable(
- com.android.internal.R.drawable.tab_bottom_right);
- }
- }
-
- // Deal with focus, as we don't want the focus to go by default
- // to a tab other than the current tab
- setFocusable(true);
- setOnFocusChangeListener(this);
- }
-
@Override
- void measureChildBeforeLayout(View child, int childIndex,
- int widthMeasureSpec, int totalWidth,
+ void measureChildBeforeLayout(View child, int childIndex, int widthMeasureSpec, int totalWidth,
int heightMeasureSpec, int totalHeight) {
if (!isMeasureWithLargestChildEnabled() && mImposedTabsHeight >= 0) {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -209,7 +206,8 @@
}
}
- // Measure again, this time with imposed tab widths and respecting initial spec request
+ // Measure again, this time with imposed tab widths and respecting
+ // initial spec request.
super.measureHorizontal(widthMeasureSpec, heightMeasureSpec);
}
@@ -225,7 +223,8 @@
/**
* Returns the number of tab indicator views.
- * @return the number of tab indicator views.
+ *
+ * @return the number of tab indicator views
*/
public int getTabCount() {
return getChildCount();
@@ -233,65 +232,104 @@
/**
* Sets the drawable to use as a divider between the tab indicators.
+ *
* @param drawable the divider drawable
+ * @attr ref android.R.styleable#TabWidget_divider
*/
@Override
- public void setDividerDrawable(Drawable drawable) {
+ public void setDividerDrawable(@Nullable Drawable drawable) {
super.setDividerDrawable(drawable);
}
/**
* Sets the drawable to use as a divider between the tab indicators.
- * @param resId the resource identifier of the drawable to use as a
- * divider.
+ *
+ * @param resId the resource identifier of the drawable to use as a divider
+ * @attr ref android.R.styleable#TabWidget_divider
*/
public void setDividerDrawable(@DrawableRes int resId) {
setDividerDrawable(mContext.getDrawable(resId));
}
-
+
/**
- * Sets the drawable to use as the left part of the strip below the
- * tab indicators.
+ * Sets the drawable to use as the left part of the strip below the tab
+ * indicators.
+ *
* @param drawable the left strip drawable
+ * @see #getLeftStripDrawable()
+ * @attr ref android.R.styleable#TabWidget_tabStripLeft
*/
- public void setLeftStripDrawable(Drawable drawable) {
+ public void setLeftStripDrawable(@Nullable Drawable drawable) {
mLeftStrip = drawable;
requestLayout();
invalidate();
}
/**
- * Sets the drawable to use as the left part of the strip below the
- * tab indicators.
- * @param resId the resource identifier of the drawable to use as the
- * left strip drawable
+ * Sets the drawable to use as the left part of the strip below the tab
+ * indicators.
+ *
+ * @param resId the resource identifier of the drawable to use as the left
+ * strip drawable
+ * @see #getLeftStripDrawable()
+ * @attr ref android.R.styleable#TabWidget_tabStripLeft
*/
public void setLeftStripDrawable(@DrawableRes int resId) {
setLeftStripDrawable(mContext.getDrawable(resId));
}
/**
- * Sets the drawable to use as the right part of the strip below the
- * tab indicators.
- * @param drawable the right strip drawable
+ * @return the drawable used as the left part of the strip below the tab
+ * indicators, may be {@code null}
+ * @see #setLeftStripDrawable(int)
+ * @see #setLeftStripDrawable(Drawable)
+ * @attr ref android.R.styleable#TabWidget_tabStripLeft
*/
- public void setRightStripDrawable(Drawable drawable) {
+ @Nullable
+ public Drawable getLeftStripDrawable() {
+ return mLeftStrip;
+ }
+
+ /**
+ * Sets the drawable to use as the right part of the strip below the tab
+ * indicators.
+ *
+ * @param drawable the right strip drawable
+ * @see #getRightStripDrawable()
+ * @attr ref android.R.styleable#TabWidget_tabStripRight
+ */
+ public void setRightStripDrawable(@Nullable Drawable drawable) {
mRightStrip = drawable;
requestLayout();
invalidate();
}
/**
- * Sets the drawable to use as the right part of the strip below the
- * tab indicators.
- * @param resId the resource identifier of the drawable to use as the
- * right strip drawable
+ * Sets the drawable to use as the right part of the strip below the tab
+ * indicators.
+ *
+ * @param resId the resource identifier of the drawable to use as the right
+ * strip drawable
+ * @see #getRightStripDrawable()
+ * @attr ref android.R.styleable#TabWidget_tabStripRight
*/
public void setRightStripDrawable(@DrawableRes int resId) {
setRightStripDrawable(mContext.getDrawable(resId));
}
/**
+ * @return the drawable used as the right part of the strip below the tab
+ * indicators, may be {@code null}
+ * @see #setRightStripDrawable(int)
+ * @see #setRightStripDrawable(Drawable)
+ * @attr ref android.R.styleable#TabWidget_tabStripRight
+ */
+ @Nullable
+ public Drawable getRightStripDrawable() {
+ return mRightStrip;
+ }
+
+ /**
* Controls whether the bottom strips on the tab indicators are drawn or
* not. The default is to draw them. If the user specifies a custom
* view for the tab indicators, then the TabHost class calls this method
@@ -360,13 +398,14 @@
/**
* Sets the current tab.
+ * <p>
* This method is used to bring a tab to the front of the Widget,
* and is used to post to the rest of the UI that a different tab
* has been brought to the foreground.
- *
+ * <p>
* Note, this is separate from the traditional "focus" that is
* employed from the view logic.
- *
+ * <p>
* For instance, if we have a list in a tabbed view, a user may be
* navigating up and down the list, moving the UI focus (orange
* highlighting) through the list items. The cursor movement does
@@ -374,16 +413,15 @@
* scrolled through is all on the same tab. The selected tab only
* changes when we navigate between tabs (moving from the list view
* to the next tabbed view, in this example).
- *
+ * <p>
* To move both the focus AND the selected tab at once, please use
* {@link #setCurrentTab}. Normally, the view logic takes care of
* adjusting the focus, so unless you're circumventing the UI,
* you'll probably just focus your interest here.
*
- * @param index The tab that you want to indicate as the selected
- * tab (tab brought to the front of the widget)
- *
- * @see #focusCurrentTab
+ * @param index the index of the tab that you want to indicate as the
+ * selected tab (tab brought to the front of the widget)
+ * @see #focusCurrentTab
*/
public void setCurrentTab(int index) {
if (index < 0 || index >= getTabCount() || index == mSelectedTab) {
@@ -473,7 +511,7 @@
final int count = getTabCount();
for (int i = 0; i < count; i++) {
- View child = getChildTabViewAt(i);
+ final View child = getChildTabViewAt(i);
child.setEnabled(enabled);
}
}
@@ -482,8 +520,7 @@
public void addView(View child) {
if (child.getLayoutParams() == null) {
final LinearLayout.LayoutParams lp = new LayoutParams(
- 0,
- ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
+ 0, ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
lp.setMargins(0, 0, 0, 0);
child.setLayoutParams(lp);
}
@@ -507,13 +544,13 @@
}
/**
- * Provides a way for {@link TabHost} to be notified that the user clicked on a tab indicator.
+ * Provides a way for {@link TabHost} to be notified that the user clicked
+ * on a tab indicator.
*/
void setTabSelectionListener(OnTabSelectionChanged listener) {
mSelectionChangedListener = listener;
}
- /** {@inheritDoc} */
public void onFocusChange(View v, boolean hasFocus) {
if (v == this && hasFocus && getTabCount() > 0) {
getChildTabViewAt(mSelectedTab).requestFocus();
@@ -540,7 +577,6 @@
// registered with each tab indicator so we can notify tab host
private class TabClickListener implements OnClickListener {
-
private final int mTabIndex;
private TabClickListener(int tabIndex) {
@@ -553,17 +589,18 @@
}
/**
- * Let {@link TabHost} know that the user clicked on a tab indicator.
+ * Lets {@link TabHost} know that the user clicked on a tab indicator.
*/
- static interface OnTabSelectionChanged {
+ interface OnTabSelectionChanged {
/**
* Informs the TabHost which tab was selected. It also indicates
* if the tab was clicked/pressed or just focused into.
*
* @param tabIndex index of the tab that was selected
- * @param clicked whether the selection changed due to a touch/click
- * or due to focus entering the tab through navigation. Pass true
- * if it was due to a press/click and false otherwise.
+ * @param clicked whether the selection changed due to a touch/click or
+ * due to focus entering the tab through navigation.
+ * {@code true} if it was due to a press/click and
+ * {@code false} otherwise.
*/
void onTabSelectionChanged(int tabIndex, boolean clicked);
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 33595f2..508cb01 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -4032,7 +4032,7 @@
// dark or the light button frame.
TypedValue value = new TypedValue();
getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
- if (Color.brightness(value.data) < 0.5) {
+ if (Color.luminance(value.data) < 0.5) {
nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
R.layout.non_client_decor_dark, null);
} else {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 9d0636a..f190d8c 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -294,6 +294,29 @@
}
/**
+ * Removes value from given array if present, providing set-like behavior.
+ */
+ public static @Nullable String[] removeString(@Nullable String[] cur, String val) {
+ if (cur == null) {
+ return null;
+ }
+ final int N = cur.length;
+ for (int i = 0; i < N; i++) {
+ if (Objects.equals(cur[i], val)) {
+ String[] ret = new String[N - 1];
+ if (i > 0) {
+ System.arraycopy(cur, 0, ret, 0, i);
+ }
+ if (i < (N - 1)) {
+ System.arraycopy(cur, i + 1, ret, i, N - i - 1);
+ }
+ return ret;
+ }
+ }
+ return cur;
+ }
+
+ /**
* Adds value to given array if not already present, providing set-like
* behavior.
*/
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 2e3eec5..c627297 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -113,89 +113,21 @@
}
/**
- * Returns the hue component of a color int.
- *
- * @return A value between 0.0f and 1.0f
- *
- * @hide Pending API council
- */
- public static float hue(@ColorInt int color) {
- int r = (color >> 16) & 0xFF;
- int g = (color >> 8) & 0xFF;
- int b = color & 0xFF;
-
- int V = Math.max(b, Math.max(r, g));
- int temp = Math.min(b, Math.min(r, g));
-
- float H;
-
- if (V == temp) {
- H = 0;
- } else {
- final float vtemp = (float) (V - temp);
- final float cr = (V - r) / vtemp;
- final float cg = (V - g) / vtemp;
- final float cb = (V - b) / vtemp;
-
- if (r == V) {
- H = cb - cg;
- } else if (g == V) {
- H = 2 + cr - cb;
- } else {
- H = 4 + cg - cr;
- }
-
- H /= 6.f;
- if (H < 0) {
- H++;
- }
- }
-
- return H;
- }
-
- /**
- * Returns the saturation component of a color int.
- *
- * @return A value between 0.0f and 1.0f
- *
- * @hide Pending API council
- */
- public static float saturation(@ColorInt int color) {
- int r = (color >> 16) & 0xFF;
- int g = (color >> 8) & 0xFF;
- int b = color & 0xFF;
-
-
- int V = Math.max(b, Math.max(r, g));
- int temp = Math.min(b, Math.min(r, g));
-
- float S;
-
- if (V == temp) {
- S = 0;
- } else {
- S = (V - temp) / (float) V;
- }
-
- return S;
- }
-
- /**
- * Returns the brightness component of a color int.
+ * Returns the relative luminance of a color.
+ * <p>
+ * Assumes sRGB encoding. Based on the formula for relative luminance
+ * defined in WCAG 2.0, W3C Recommendation 11 December 2008.
*
- * @return A value between 0.0f and 1.0f
- *
- * @hide Pending API council
+ * @return a value between 0 (darkest black) and 1 (lightest white)
*/
- public static float brightness(@ColorInt int color) {
- int r = (color >> 16) & 0xFF;
- int g = (color >> 8) & 0xFF;
- int b = color & 0xFF;
-
- int V = Math.max(b, Math.max(r, g));
-
- return (V / 255.f);
+ public static float luminance(@ColorInt int color) {
+ double red = Color.red(color) / 255.0;
+ red = red < 0.03928 ? red / 12.92 : Math.pow((red + 0.055) / 1.055, 2.4);
+ double green = Color.green(color) / 255.0;
+ green = green < 0.03928 ? green / 12.92 : Math.pow((green + 0.055) / 1.055, 2.4);
+ double blue = Color.blue(color) / 255.0;
+ blue = blue < 0.03928 ? blue / 12.92 : Math.pow((blue + 0.055) / 1.055, 2.4);
+ return (float) ((0.2126 * red) + (0.7152 * green) + (0.0722 * blue));
}
/**
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ba7974c..daf42fb 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -261,12 +261,6 @@
<!-- Doze: pulse parameter - how long does it take to fade in after a pickup? -->
<integer name="doze_pulse_duration_in_pickup">300</integer>
- <!-- Doze: pulse parameter - delay to wait for the screen to wake up -->
- <integer name="doze_pulse_delay_in">200</integer>
-
- <!-- Doze: pulse parameter - delay to wait for the screen to wake up after a pickup -->
- <integer name="doze_pulse_delay_in_pickup">200</integer>
-
<!-- Doze: pulse parameter - once faded in, how long does it stay visible? -->
<integer name="doze_pulse_duration_visible">3000</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index fe876d7..7f68e29 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -159,7 +159,9 @@
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Async playback only available from system UID.");
}
-
+ if (UserHandle.ALL.equals(user)) {
+ user = UserHandle.OWNER;
+ }
mAsyncPlayer.play(getContextForUser(user), uri, looping, aa);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a6cea62..a55256d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -171,13 +171,7 @@
// on-screen navigation buttons
protected NavigationBarView mNavigationBarView = null;
- protected Boolean mScreenOn;
-
- // The second field is a bit different from the first one because it only listens to screen on/
- // screen of events from Keyguard. We need this so we don't have a race condition with the
- // broadcast. In the future, we should remove the first field altogether and rename the second
- // field.
- protected boolean mScreenOnFromKeyguard;
+ protected boolean mDeviceInteractive;
protected boolean mVisible;
@@ -1722,7 +1716,7 @@
protected void updateVisibleToUser() {
boolean oldVisibleToUser = mVisibleToUser;
- mVisibleToUser = mVisible && mScreenOnFromKeyguard;
+ mVisibleToUser = mVisible && mDeviceInteractive;
if (oldVisibleToUser != mVisibleToUser) {
handleVisibleToUserChanged(mVisibleToUser);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 6b167b4..5a2fa3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -50,8 +50,6 @@
pw.print(" getPulseDuration(pickup=true): "); pw.println(getPulseDuration(true));
pw.print(" getPulseInDuration(pickup=false): "); pw.println(getPulseInDuration(false));
pw.print(" getPulseInDuration(pickup=true): "); pw.println(getPulseInDuration(true));
- pw.print(" getPulseInDelay(pickup=false): "); pw.println(getPulseInDelay(false));
- pw.print(" getPulseInDelay(pickup=true): "); pw.println(getPulseInDelay(true));
pw.print(" getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
pw.print(" getPulseOutDuration(): "); pw.println(getPulseOutDuration());
pw.print(" getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
@@ -80,12 +78,6 @@
: getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
}
- public int getPulseInDelay(boolean pickup) {
- return pickup
- ? getInt("doze.pulse.delay.in.pickup", R.integer.doze_pulse_delay_in_pickup)
- : getInt("doze.pulse.delay.in", R.integer.doze_pulse_delay_in);
- }
-
public int getPulseVisibleDuration() {
return getInt("doze.pulse.duration.visible", R.integer.doze_pulse_duration_visible);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 3e17328..86b8972 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -100,6 +100,16 @@
mHandler.post(mPulseIn);
}
+ public void onScreenTurnedOn() {
+ if (isPulsing()) {
+ final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
+ startScrimAnimation(true /* inFront */, 0f,
+ mDozeParameters.getPulseInDuration(pickup),
+ pickup ? mPulseInInterpolatorPickup : mPulseInInterpolator,
+ mPulseInFinished);
+ }
+ }
+
public boolean isPulsing() {
return mPulseCallback != null;
}
@@ -138,12 +148,11 @@
private void startScrimAnimation(final boolean inFront, float target, long duration,
Interpolator interpolator) {
- startScrimAnimation(inFront, target, duration, interpolator, 0 /* delay */,
- null /* endRunnable */);
+ startScrimAnimation(inFront, target, duration, interpolator, null /* endRunnable */);
}
private void startScrimAnimation(final boolean inFront, float target, long duration,
- Interpolator interpolator, long delay, final Runnable endRunnable) {
+ Interpolator interpolator, final Runnable endRunnable) {
Animator current = getCurrentAnimator(inFront);
if (current != null) {
float currentTarget = getCurrentTarget(inFront);
@@ -162,7 +171,6 @@
});
anim.setInterpolator(interpolator);
anim.setDuration(duration);
- anim.setStartDelay(delay);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -222,12 +230,6 @@
+ DozeLog.pulseReasonToString(mPulseReason));
if (!mDozing) return;
DozeLog.tracePulseStart(mPulseReason);
- final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
- startScrimAnimation(true /* inFront */, 0f,
- mDozeParameters.getPulseInDuration(pickup),
- pickup ? mPulseInInterpolatorPickup : mPulseInInterpolator,
- mDozeParameters.getPulseInDelay(pickup),
- mPulseInFinished);
// Signal that the pulse is ready to turn the screen on and draw.
pulseStarted();
@@ -249,7 +251,7 @@
if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
if (!mDozing) return;
startScrimAnimation(true /* inFront */, 1f, mDozeParameters.getPulseOutDuration(),
- mPulseOutInterpolator, 0 /* delay */, mPulseOutFinished);
+ mPulseOutInterpolator, mPulseOutFinished);
}
};
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 8c58fc5..710c335 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -918,7 +918,7 @@
}
private int getFalsingThreshold() {
- float factor = mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+ float factor = mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
return (int) (mQsFalsingThreshold * factor);
}
@@ -2075,7 +2075,7 @@
@Override
public float getAffordanceFalsingFactor() {
- return mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+ return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 5995fe1..9cd6ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -391,7 +391,7 @@
|| forceCancel;
DozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
mStatusBar.isFalsingThresholdNeeded(),
- mStatusBar.isScreenOnComingFromTouch());
+ mStatusBar.isWakeUpComingFromTouch());
// Log collapse gesture if on lock screen.
if (!expand && mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
float displayDensity = mStatusBar.getDisplayDensity();
@@ -420,7 +420,7 @@
}
private int getFalsingThreshold() {
- float factor = mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+ float factor = mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
return (int) (mUnlockFalsingThreshold * factor);
}
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 52acbf8..0635847 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -282,8 +282,8 @@
private StatusBarWindowManager mStatusBarWindowManager;
private UnlockMethodCache mUnlockMethodCache;
private DozeServiceHost mDozeServiceHost;
- private boolean mScreenOnComingFromTouch;
- private PointF mScreenOnTouchLocation;
+ private boolean mWakeUpComingFromTouch;
+ private PointF mWakeUpTouchLocation;
int mPixelFormat;
Object mQueueLock = new Object();
@@ -1933,8 +1933,8 @@
return mNotificationPanel.isQsExpanded();
}
- public boolean isScreenOnComingFromTouch() {
- return mScreenOnComingFromTouch;
+ public boolean isWakeUpComingFromTouch() {
+ return mWakeUpComingFromTouch;
}
public boolean isFalsingThresholdNeeded() {
@@ -2494,7 +2494,7 @@
private void checkBarMode(int mode, int windowState, BarTransitions transitions,
boolean noAnimation) {
final boolean powerSave = mBatteryController.isPowerSave();
- final boolean anim = !noAnimation && (mScreenOn == null || mScreenOn)
+ final boolean anim = !noAnimation && mDeviceInteractive
&& windowState != WINDOW_STATE_HIDDEN && !powerSave;
if (powerSave && getBarState() == StatusBarState.SHADE) {
mode = MODE_WARNING;
@@ -2902,14 +2902,12 @@
}
}
else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
- mScreenOn = false;
notifyNavigationBarScreenOn(false);
notifyHeadsUpScreenOff();
finishBarAnimations();
resetUserExpandedStates();
}
else if (Intent.ACTION_SCREEN_ON.equals(action)) {
- mScreenOn = true;
notifyNavigationBarScreenOn(true);
}
}
@@ -3363,7 +3361,7 @@
mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
setBarState(StatusBarState.KEYGUARD);
updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
- if (!mScreenOnFromKeyguard) {
+ if (!mDeviceInteractive) {
// If the screen is off already, we need to disable touch events because these might
// collapse the panel after we expanded it, and thus we would end up with a blank
@@ -3583,7 +3581,7 @@
private void updateDozingState() {
boolean animate = !mDozing && mDozeScrimController.isPulsing();
mNotificationPanel.setDozing(mDozing, animate);
- mStackScroller.setDark(mDozing, animate, mScreenOnTouchLocation);
+ mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
mScrimController.setDozing(mDozing);
mDozeScrimController.setDozing(mDozing, animate);
}
@@ -3636,7 +3634,7 @@
}
public boolean onSpacePressed() {
- if (mScreenOn != null && mScreenOn
+ if (mDeviceInteractive
&& (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
@@ -3846,16 +3844,16 @@
disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
}
- public void onScreenTurnedOff() {
- mScreenOnFromKeyguard = false;
- mScreenOnComingFromTouch = false;
- mScreenOnTouchLocation = null;
+ public void onFinishedGoingToSleep() {
+ mDeviceInteractive = false;
+ mWakeUpComingFromTouch = false;
+ mWakeUpTouchLocation = null;
mStackScroller.setAnimationsEnabled(false);
updateVisibleToUser();
}
- public void onScreenTurnedOn() {
- mScreenOnFromKeyguard = true;
+ public void onStartedWakingUp() {
+ mDeviceInteractive = true;
mStackScroller.setAnimationsEnabled(true);
mNotificationPanel.setTouchDisabled(false);
updateVisibleToUser();
@@ -3865,6 +3863,10 @@
mNotificationPanel.onScreenTurningOn();
}
+ public void onScreenTurnedOn() {
+ mDozeScrimController.onScreenTurnedOn();
+ }
+
/**
* This handles long-press of both back and recents. They are
* handled together to capture them both being long-pressed
@@ -3979,8 +3981,8 @@
if (mDozing && mDozeScrimController.isPulsing()) {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.wakeUp(time, "com.android.systemui:NODOZE");
- mScreenOnComingFromTouch = true;
- mScreenOnTouchLocation = new PointF(event.getX(), event.getY());
+ mWakeUpComingFromTouch = true;
+ mWakeUpTouchLocation = new PointF(event.getX(), event.getY());
mNotificationPanel.setTouchDisabled(false);
mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 9543f93..9d47713 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -162,14 +162,14 @@
public void onFinishedGoingToSleep() {
mDeviceInteractive = false;
- mPhoneStatusBar.onScreenTurnedOff();
+ mPhoneStatusBar.onFinishedGoingToSleep();
mBouncer.onScreenTurnedOff();
}
public void onStartedWakingUp() {
mDeviceInteractive = true;
mDeviceWillWakeUp = false;
- mPhoneStatusBar.onScreenTurnedOn();
+ mPhoneStatusBar.onStartedWakingUp();
}
public void onScreenTurningOn() {
@@ -184,6 +184,7 @@
animateScrimControllerKeyguardFadingOut(0, 200);
updateStates();
}
+ mPhoneStatusBar.onScreenTurnedOn();
}
public void onScreenTurnedOff() {
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 6b30183..82c1aa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -653,7 +653,7 @@
@Override
public float getFalsingThresholdFactor() {
- return mPhoneStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+ return mPhoneStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
public View getChildAtPosition(MotionEvent ev) {
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index c13401f..b766894 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -157,7 +157,7 @@
mFactoryTest = factoryTest;
// Let the package manager query for the sync adapters for a given authority
- // as we grant default permissions to sync adapters for specifix authorities.
+ // as we grant default permissions to sync adapters for specific authorities.
PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
packageManagerInternal.setSyncAdapterPackagesprovider(
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
index 18407c9..52d0928 100644
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ b/services/core/java/com/android/server/pm/BasePermission.java
@@ -88,4 +88,10 @@
return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS;
}
+
+ public boolean isDevelopment() {
+ return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ == PermissionInfo.PROTECTION_SIGNATURE
+ && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0;
+ }
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 71a2d59..d2a70df 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -296,7 +296,7 @@
PackageParser.Package storagePackage = getDefaultProviderAuthorityPackageLPr(
"com.android.externalstorage.documents", userId);
if (storagePackage != null) {
- grantRuntimePermissionsLPw(storagePackage, STORAGE_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(storagePackage, STORAGE_PERMISSIONS, true, userId);
}
// CertInstaller
@@ -360,7 +360,7 @@
PackageParser.Package cbrPackage =
getDefaultSystemHandlerActivityPackageLPr(cbrIntent, userId);
if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) {
- grantRuntimePermissionsLPw(cbrPackage, SMS_PERMISSIONS, false, userId);
+ grantRuntimePermissionsLPw(cbrPackage, SMS_PERMISSIONS, userId);
}
// Calendar
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c0a3097..e8ec8b9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -56,6 +56,7 @@
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
@@ -3451,14 +3452,14 @@
}
}
- private static void enforceDeclaredAsUsedAndRuntimePermission(PackageParser.Package pkg,
+ private static void enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(PackageParser.Package pkg,
BasePermission bp) {
int index = pkg.requestedPermissions.indexOf(bp.name);
if (index == -1) {
throw new SecurityException("Package " + pkg.packageName
+ " has not requested permission " + bp.name);
}
- if (!bp.isRuntime()) {
+ if (!bp.isRuntime() && !bp.isDevelopment()) {
throw new SecurityException("Permission " + bp.name
+ " is not a changeable permission type");
}
@@ -3492,7 +3493,7 @@
throw new IllegalArgumentException("Unknown permission: " + name);
}
- enforceDeclaredAsUsedAndRuntimePermission(pkg, bp);
+ enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
sb = (SettingBase) pkg.mExtras;
@@ -3508,6 +3509,16 @@
+ name + " for package: " + packageName);
}
+ if (bp.isDevelopment()) {
+ // Development permissions must be handled specially, since they are not
+ // normal runtime permissions. For now they apply to all users.
+ if (permissionsState.grantInstallPermission(bp) !=
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ scheduleWriteSettingsLocked();
+ }
+ return;
+ }
+
final int result = permissionsState.grantRuntimePermission(bp, userId);
switch (result) {
case PermissionsState.PERMISSION_OPERATION_FAILURE: {
@@ -3576,7 +3587,7 @@
throw new IllegalArgumentException("Unknown permission: " + name);
}
- enforceDeclaredAsUsedAndRuntimePermission(pkg, bp);
+ enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
SettingBase sb = (SettingBase) pkg.mExtras;
if (sb == null) {
@@ -3591,6 +3602,16 @@
+ name + " for package: " + packageName);
}
+ if (bp.isDevelopment()) {
+ // Development permissions must be handled specially, since they are not
+ // normal runtime permissions. For now they apply to all users.
+ if (permissionsState.revokeInstallPermission(bp) !=
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ scheduleWriteSettingsLocked();
+ }
+ return;
+ }
+
if (permissionsState.revokeRuntimePermission(bp, userId) ==
PermissionsState.PERMISSION_OPERATION_FAILURE) {
return;
@@ -3818,21 +3839,6 @@
return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
}
- void grantInstallPermissionLPw(String permission, PackageParser.Package pkg) {
- BasePermission bp = mSettings.mPermissions.get(permission);
- if (bp == null) {
- throw new SecurityException("Missing " + permission + " permission");
- }
-
- SettingBase sb = (SettingBase) pkg.mExtras;
- PermissionsState permissionsState = sb.getPermissionsState();
-
- if (permissionsState.grantInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- scheduleWriteSettingsLocked();
- }
- }
-
@Override
public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
mContext.enforceCallingOrSelfPermission(
@@ -4720,6 +4726,7 @@
ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>();
ArrayList<ResolveInfo> alwaysList = new ArrayList<ResolveInfo>();
ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>();
+ ArrayList<ResolveInfo> alwaysAskList = new ArrayList<ResolveInfo>();
ArrayList<ResolveInfo> neverList = new ArrayList<ResolveInfo>();
ArrayList<ResolveInfo> matchAllList = new ArrayList<ResolveInfo>();
@@ -4756,6 +4763,11 @@
Slog.i(TAG, " + never: " + info.activityInfo.packageName);
}
neverList.add(info);
+ } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.i(TAG, " + always-ask: " + info.activityInfo.packageName);
+ }
+ alwaysAskList.add(info);
} else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED ||
status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK) {
if (DEBUG_DOMAIN_VERIFICATION) {
@@ -4765,6 +4777,10 @@
}
}
}
+
+ // We'll want to include browser possibilities in a few cases
+ boolean includeBrowser = false;
+
// First try to add the "always" resolution(s) for the current user, if any
if (alwaysList.size() > 0) {
result.addAll(alwaysList);
@@ -4773,7 +4789,7 @@
== INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
result.add(xpDomainInfo.resolveInfo);
} else {
- // Add all undefined Apps as we want them to appear in the Disambiguation dialog.
+ // Add all undefined apps as we want them to appear in the disambiguation dialog.
result.addAll(undefinedList);
if (xpDomainInfo != null && (
xpDomainInfo.bestDomainVerificationStatus
@@ -4782,7 +4798,25 @@
== INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK)) {
result.add(xpDomainInfo.resolveInfo);
}
- // Also add Browsers (all of them or only the default one)
+ includeBrowser = true;
+ }
+
+ // The presence of any 'always ask' alternatives means we'll also offer browsers.
+ // If there were 'always' entries their preferred order has been set, so we also
+ // back that off to make the alternatives equivalent
+ if (alwaysAskList.size() > 0) {
+ for (ResolveInfo i : result) {
+ i.preferredOrder = 0;
+ }
+ result.addAll(alwaysAskList);
+ includeBrowser = true;
+ }
+
+ if (includeBrowser) {
+ // Also add browsers (all of them or only the default one)
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.v(TAG, " ...including browsers in candidate set");
+ }
if ((matchFlags & MATCH_ALL) != 0) {
result.addAll(matchAllList);
} else {
@@ -14876,6 +14910,7 @@
pw.println(" version: print database version info");
pw.println(" write: write current settings now");
pw.println(" installs: details about install sessions");
+ pw.println(" check-permission <permission> <package> [<user>]: does pkg hold perm?");
pw.println(" <package.name>: info about given package");
return;
} else if ("--checkin".equals(opt)) {
@@ -14897,6 +14932,31 @@
// When dumping a single package, we always dump all of its
// filter information since the amount of data will be reasonable.
dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
+ } else if ("check-permission".equals(cmd)) {
+ if (opti >= args.length) {
+ pw.println("Error: check-permission missing permission argument");
+ return;
+ }
+ String perm = args[opti];
+ opti++;
+ if (opti >= args.length) {
+ pw.println("Error: check-permission missing package argument");
+ return;
+ }
+ String pkg = args[opti];
+ opti++;
+ int user = UserHandle.getUserId(Binder.getCallingUid());
+ if (opti < args.length) {
+ try {
+ user = Integer.parseInt(args[opti]);
+ } catch (NumberFormatException e) {
+ pw.println("Error: check-permission user argument is not a number: "
+ + args[opti]);
+ return;
+ }
+ }
+ pw.println(checkPermission(perm, pkg, user));
+ return;
} else if ("l".equals(cmd) || "libraries".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_LIBS);
} else if ("f".equals(cmd) || "features".equals(cmd)) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index bd7ec31..943e649 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3952,7 +3952,7 @@
void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf,
- Date date, List<UserInfo> users) {
+ Date date, List<UserInfo> users, boolean dumpAll) {
if (checkinTag != null) {
pw.print(checkinTag);
pw.print(",");
@@ -4154,7 +4154,7 @@
pw.print(", COSTS_MONEY");
}
if ((perm.info.flags&PermissionInfo.FLAG_HIDDEN) != 0) {
- pw.print(", COSTS_HIDDEN");
+ pw.print(", HIDDEN");
}
if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
pw.print(", INSTALLED");
@@ -4163,7 +4163,21 @@
}
}
- if (ps.sharedUser == null || permissionNames != null) {
+ if ((permissionNames != null || dumpAll) && ps.pkg.requestedPermissions != null
+ && ps.pkg.requestedPermissions.size() > 0) {
+ final ArrayList<String> perms = ps.pkg.requestedPermissions;
+ pw.print(prefix); pw.println(" requested permissions:");
+ for (int i=0; i<perms.size(); i++) {
+ String perm = perms.get(i);
+ if (permissionNames != null
+ && !permissionNames.contains(perm)) {
+ continue;
+ }
+ pw.print(prefix); pw.print(" "); pw.println(perm);
+ }
+ }
+
+ if (ps.sharedUser == null || permissionNames != null || dumpAll) {
PermissionsState permissionsState = ps.getPermissionsState();
dumpInstallPermissionsLPr(pw, prefix + " ", permissionNames, permissionsState);
}
@@ -4190,7 +4204,7 @@
PermissionsState permissionsState = ps.getPermissionsState();
dumpGidsLPr(pw, prefix + " ", permissionsState.computeGids(user.id));
dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissionsState
- .getRuntimePermissionStates(user.id));
+ .getRuntimePermissionStates(user.id), dumpAll);
}
if (permissionNames == null) {
@@ -4238,11 +4252,12 @@
pw.println("Packages:");
printedSomething = true;
}
- dumpPackageLPr(pw, " ", checkin ? "pkg" : null, permissionNames, ps, sdf, date, users);
+ dumpPackageLPr(pw, " ", checkin ? "pkg" : null, permissionNames, ps, sdf, date, users,
+ packageName != null);
}
printedSomething = false;
- if (!checkin && mRenamedPackages.size() > 0 && permissionNames == null) {
+ if (mRenamedPackages.size() > 0 && permissionNames == null) {
for (final Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
if (packageName != null && !packageName.equals(e.getKey())
&& !packageName.equals(e.getValue())) {
@@ -4279,7 +4294,7 @@
printedSomething = true;
}
dumpPackageLPr(pw, " ", checkin ? "dis" : null, permissionNames, ps, sdf, date,
- users);
+ users, packageName != null);
}
}
}
@@ -4364,7 +4379,8 @@
if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": ");
dumpGidsLPr(pw, prefix + " ", gids);
- dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissions);
+ dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissions,
+ packageName != null);
}
}
} else {
@@ -4410,8 +4426,8 @@
}
void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
- List<PermissionState> permissionStates) {
- if (!permissionStates.isEmpty()) {
+ List<PermissionState> permissionStates, boolean dumpAll) {
+ if (!permissionStates.isEmpty() || dumpAll) {
pw.print(prefix); pw.println("runtime permissions:");
for (PermissionState permissionState : permissionStates) {
if (permissionNames != null
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 7bd0635..a2307f9 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -651,7 +652,7 @@
* when a thumbnail is specified with the activity options.
*/
Animation createThumbnailAspectScaleAnimationLocked(int appWidth, int appHeight,
- int deviceWidth, int transit) {
+ int deviceWidth) {
Animation a;
final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -659,7 +660,6 @@
final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
float scaleW = deviceWidth / thumbWidth;
- float unscaledWidth = deviceWidth;
float unscaledHeight = thumbHeight * scaleW;
float unscaledStartY = mNextAppTransitionStartY - (unscaledHeight - thumbHeight) / 2f;
if (mNextAppTransitionScaleUp) {
@@ -716,7 +716,7 @@
*/
Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
int appWidth, int appHeight, int orientation, int transit, Rect containingFrame,
- Rect contentInsets) {
+ Rect contentInsets, @Nullable Rect surfaceInsets, boolean resizedWindow) {
Animation a;
final int thumbWidthI = mNextAppTransitionStartWidth;
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -729,40 +729,45 @@
switch (thumbTransitState) {
case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
- // App window scaling up to become full screen
- if (orientation == Configuration.ORIENTATION_PORTRAIT) {
- // In portrait, we scale the width and clip to the top/left square
- scale = thumbWidth / appWidth;
- scaledTopDecor = (int) (scale * contentInsets.top);
- int unscaledThumbHeight = (int) (thumbHeight / scale);
- mTmpFromClipRect.set(containingFrame);
- mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
- mTmpToClipRect.set(containingFrame);
+ if (resizedWindow) {
+ a = createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
+ containingFrame, surfaceInsets);
} else {
- // In landscape, we scale the height and clip to the top/left square
- scale = thumbHeight / (appHeight - contentInsets.top);
- scaledTopDecor = (int) (scale * contentInsets.top);
- int unscaledThumbWidth = (int) (thumbWidth / scale);
- mTmpFromClipRect.set(containingFrame);
- mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth);
- mTmpToClipRect.set(containingFrame);
+ // App window scaling up to become full screen
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ // In portrait, we scale the width and clip to the top/left square
+ scale = thumbWidth / appWidth;
+ scaledTopDecor = (int) (scale * contentInsets.top);
+ int unscaledThumbHeight = (int) (thumbHeight / scale);
+ mTmpFromClipRect.set(containingFrame);
+ mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight);
+ mTmpToClipRect.set(containingFrame);
+ } else {
+ // In landscape, we scale the height and clip to the top/left square
+ scale = thumbHeight / (appHeight - contentInsets.top);
+ scaledTopDecor = (int) (scale * contentInsets.top);
+ int unscaledThumbWidth = (int) (thumbWidth / scale);
+ mTmpFromClipRect.set(containingFrame);
+ mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth);
+ mTmpToClipRect.set(containingFrame);
+ }
+ // exclude top screen decor (status bar) region from the source clip.
+ mTmpFromClipRect.top = contentInsets.top;
+
+ mNextAppTransitionInsets.set(contentInsets);
+
+ Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
+ computePivot(mNextAppTransitionStartX, scale),
+ computePivot(mNextAppTransitionStartY, scale));
+ Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+ Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
+
+ AnimationSet set = new AnimationSet(true);
+ set.addAnimation(clipAnim);
+ set.addAnimation(scaleAnim);
+ set.addAnimation(translateAnim);
+ a = set;
}
- // exclude top screen decor (status bar) region from the source clip.
- mTmpFromClipRect.top = contentInsets.top;
-
- mNextAppTransitionInsets.set(contentInsets);
-
- Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
- computePivot(mNextAppTransitionStartX, scale),
- computePivot(mNextAppTransitionStartY, scale));
- Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
- Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
-
- AnimationSet set = new AnimationSet(true);
- set.addAnimation(clipAnim);
- set.addAnimation(scaleAnim);
- set.addAnimation(translateAnim);
- a = set;
break;
}
case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
@@ -836,6 +841,31 @@
mTouchResponseInterpolator);
}
+ private Animation createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
+ Rect containingFrame, @Nullable Rect surfaceInsets) {
+ float width = containingFrame.width();
+ float height = containingFrame.height();
+ float scaleWidth = mNextAppTransitionStartWidth / width;
+ float scaleHeight = mNextAppTransitionStartHeight / height;
+ AnimationSet set = new AnimationSet(true);
+ int surfaceInsetsHorizontal = surfaceInsets == null
+ ? 0 : surfaceInsets.left + surfaceInsets.right;
+ int surfaceInsetsVertical = surfaceInsets == null
+ ? 0 : surfaceInsets.top + surfaceInsets.bottom;
+ // We want the scaling to happen from the center of the surface. In order to achieve that,
+ // we need to account for surface insets that will be used to enlarge the surface.
+ ScaleAnimation scale = new ScaleAnimation(scaleWidth, 1, scaleHeight, 1,
+ (width + surfaceInsetsHorizontal) / 2, (height + surfaceInsetsVertical) / 2);
+ int fromX = mNextAppTransitionStartX + mNextAppTransitionStartWidth / 2
+ - (containingFrame.left + containingFrame.width() / 2);
+ int fromY = mNextAppTransitionStartY + mNextAppTransitionStartHeight / 2
+ - (containingFrame.top + containingFrame.height() / 2);
+ TranslateAnimation translation = new TranslateAnimation(fromX, 0, fromY, 0);
+ set.addAnimation(scale);
+ set.addAnimation(translation);
+ return set;
+ }
+
/**
* This animation runs for the thumbnail that gets cross faded with the enter/exit activity
* when a thumbnail is specified with the activity options.
@@ -881,7 +911,7 @@
* leaving, and the activity that is entering.
*/
Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
- int appHeight, int transit) {
+ int appHeight, int transit) {
Animation a;
final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -954,7 +984,8 @@
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets,
- Rect appFrame, boolean isVoiceInteraction) {
+ @Nullable Rect surfaceInsets, Rect appFrame, boolean isVoiceInteraction,
+ boolean resizedWindow) {
Animation a;
if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
|| transit == TRANSIT_TASK_OPEN
@@ -1023,8 +1054,8 @@
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
a = createAspectScaledThumbnailEnterExitAnimationLocked(
- getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
- transit, containingFrame, contentInsets);
+ getThumbnailTransitionState(enter), appWidth, appHeight, orientation, transit,
+ containingFrame, contentInsets, surfaceInsets, resizedWindow);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
String animName = mNextAppTransitionScaleUp ?
"ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9af5e14..5ec2137 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3448,8 +3448,8 @@
}
}
- private boolean applyAnimationLocked(AppWindowToken atoken,
- WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction) {
+ private boolean applyAnimationLocked(AppWindowToken atoken, WindowManager.LayoutParams lp,
+ int transit, boolean enter, boolean isVoiceInteraction) {
// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
@@ -3466,24 +3466,36 @@
Rect containingFrame = new Rect(0, 0, width, height);
Rect contentInsets = new Rect();
Rect appFrame = new Rect(0, 0, width, height);
- if (win != null && win.isFullscreen(width, height)) {
- // For fullscreen windows use the window frames and insets to set the thumbnail
- // clip. For none-fullscreen windows we use the app display region so the clip
- // isn't affected by the window insets.
+ Rect surfaceInsets = null;
+ final boolean fullscreen = win != null && win.isFullscreen(width, height);
+ // Dialog activities have windows with containing frame being very large, but not
+ // exactly fullscreen and much smaller mFrame. We use this distinction to identify
+ // dialog activities.
+ final boolean dialogWindow = win != null && !win.mContainingFrame.equals(win.mFrame);
+ if (win != null) {
containingFrame.set(win.mContainingFrame);
- contentInsets.set(win.mContentInsets);
- appFrame.set(win.mFrame);
+ surfaceInsets = win.getAttrs().surfaceInsets;
+ if (fullscreen) {
+ // For fullscreen windows use the window frames and insets to set the thumbnail
+ // clip. For none-fullscreen windows we use the app display region so the clip
+ // isn't affected by the window insets.
+ contentInsets.set(win.mContentInsets);
+ appFrame.set(win.mFrame);
+ }
}
+ final int containingWidth = containingFrame.width();
+ final int containingHeight = containingFrame.height();
if (atoken.mLaunchTaskBehind) {
// Differentiate the two animations. This one which is briefly on the screen
// gets the !enter animation, and the other activity which remains on the
// screen gets the enter animation. Both appear in the mOpeningApps set.
enter = false;
}
- Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
- mCurConfiguration.orientation, containingFrame, contentInsets, appFrame,
- isVoiceInteraction);
+ final boolean resizedWindow = !fullscreen && !dialogWindow;
+ Animation a = mAppTransition.loadAnimation(lp, transit, enter, containingWidth,
+ containingHeight, mCurConfiguration.orientation, containingFrame, contentInsets,
+ surfaceInsets, appFrame, isVoiceInteraction, resizedWindow);
if (a != null) {
if (DEBUG_ANIM) {
RuntimeException e = null;
@@ -3493,7 +3505,7 @@
}
Slog.v(TAG, "Loaded animation " + a + " for " + atoken, e);
}
- atoken.mAppAnimator.setAnimation(a, width, height,
+ atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight,
mAppTransition.canSkipFirstFrame());
}
} else {
@@ -9533,7 +9545,7 @@
// open/close animation (only on the way down)
anim = mAppTransition.createThumbnailAspectScaleAnimationLocked(
displayInfo.appWidth, displayInfo.appHeight,
- displayInfo.logicalWidth, transit);
+ displayInfo.logicalWidth);
openingAppAnimator.thumbnailForceAboveLayer = Math.max(topOpeningLayer,
topClosingLayer);
openingAppAnimator.deferThumbnailDestruction =
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 48f2a9d..5d33cbd 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1090,7 +1090,6 @@
if (selfTransformation) {
tmpMatrix.postConcat(mTransformation.getMatrix());
}
- tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
if (attachedTransformation != null) {
tmpMatrix.postConcat(attachedTransformation.getMatrix());
}
@@ -1100,6 +1099,10 @@
if (screenAnimation) {
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
}
+ // The translation that applies the position of the window needs to be applied at the
+ // end in case that other translations include scaling. Otherwise the scaling will
+ // affect this translation.
+ tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
//TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 3d49308..5852b8e 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -97,7 +97,7 @@
* @hide
* */
public static String getDefaultDialerApplication(Context context) {
- return getDefaultDialerApplication(context, ActivityManager.getCurrentUser());
+ return getDefaultDialerApplication(context, context.getUserId());
}
/**
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index 36d5d98..fe17c6e 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -2,6 +2,7 @@
package="com.android.test.voiceinteraction">
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <uses-permission android:name="android.permission.READ_LOGS" />
<application>
<activity android:name="VoiceInteractionMain" android:label="Voice Interaction"