Merge "Associate rotation watchers with displays"
diff --git a/api/current.txt b/api/current.txt
index 7e1dec3..2dbc4e4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -34646,6 +34646,7 @@
field public static final java.lang.String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS";
field public static final java.lang.String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
field public static final java.lang.String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
+ field public static final java.lang.String ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS";
field public static final java.lang.String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
@@ -47497,15 +47498,16 @@
}
public final class AutofillManager {
+ method public void cancel();
+ method public void commit();
+ method public void notifyValueChanged(android.view.View);
+ method public void notifyViewEntered(android.view.View);
+ method public void notifyViewExited(android.view.View);
+ method public void notifyVirtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
+ method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect);
+ method public void notifyVirtualViewExited(android.view.View, int);
method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback);
- method public void reset();
- method public void startAutofillRequest(android.view.View);
- method public void startAutofillRequestOnVirtualView(android.view.View, int, android.graphics.Rect);
- method public void stopAutofillRequest(android.view.View);
- method public void stopAutofillRequestOnVirtualView(android.view.View, int);
method public void unregisterCallback(android.view.autofill.AutofillManager.AutofillCallback);
- method public void valueChanged(android.view.View);
- method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
}
diff --git a/api/system-current.txt b/api/system-current.txt
index bb2678c..094cb1d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -27720,7 +27720,6 @@
method public boolean clearScores() throws java.lang.SecurityException;
method public void disableScoring() throws java.lang.SecurityException;
method public java.lang.String getActiveScorerPackage();
- method public android.net.RecommendationResult requestRecommendation(android.net.RecommendationRequest) throws java.lang.SecurityException;
method public boolean setActiveScorer(java.lang.String) throws java.lang.SecurityException;
method public boolean updateScores(android.net.ScoredNetwork[]) throws java.lang.SecurityException;
field public static final java.lang.String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
@@ -37655,6 +37654,7 @@
field public static final java.lang.String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS";
field public static final java.lang.String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
field public static final java.lang.String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
+ field public static final java.lang.String ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS";
field public static final java.lang.String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
@@ -50960,15 +50960,16 @@
}
public final class AutofillManager {
+ method public void cancel();
+ method public void commit();
+ method public void notifyValueChanged(android.view.View);
+ method public void notifyViewEntered(android.view.View);
+ method public void notifyViewExited(android.view.View);
+ method public void notifyVirtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
+ method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect);
+ method public void notifyVirtualViewExited(android.view.View, int);
method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback);
- method public void reset();
- method public void startAutofillRequest(android.view.View);
- method public void startAutofillRequestOnVirtualView(android.view.View, int, android.graphics.Rect);
- method public void stopAutofillRequest(android.view.View);
- method public void stopAutofillRequestOnVirtualView(android.view.View, int);
method public void unregisterCallback(android.view.autofill.AutofillManager.AutofillCallback);
- method public void valueChanged(android.view.View);
- method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
}
diff --git a/api/test-current.txt b/api/test-current.txt
index bf9fc82..f35f321 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -34774,6 +34774,7 @@
field public static final java.lang.String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS";
field public static final java.lang.String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
field public static final java.lang.String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
+ field public static final java.lang.String ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS";
field public static final java.lang.String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
@@ -47866,15 +47867,16 @@
}
public final class AutofillManager {
+ method public void cancel();
+ method public void commit();
+ method public void notifyValueChanged(android.view.View);
+ method public void notifyViewEntered(android.view.View);
+ method public void notifyViewExited(android.view.View);
+ method public void notifyVirtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
+ method public void notifyVirtualViewEntered(android.view.View, int, android.graphics.Rect);
+ method public void notifyVirtualViewExited(android.view.View, int);
method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback);
- method public void reset();
- method public void startAutofillRequest(android.view.View);
- method public void startAutofillRequestOnVirtualView(android.view.View, int, android.graphics.Rect);
- method public void stopAutofillRequest(android.view.View);
- method public void stopAutofillRequestOnVirtualView(android.view.View, int);
method public void unregisterCallback(android.view.autofill.AutofillManager.AutofillCallback);
- method public void valueChanged(android.view.View);
- method public void virtualValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 1969f8b..78c29e8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1783,7 +1783,7 @@
mTranslucentCallback = null;
mCalled = true;
if (isFinishing() && mAutoFillResetNeeded) {
- getSystemService(AutofillManager.class).reset();
+ getSystemService(AutofillManager.class).commit();
}
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index e6fe0d0..70ecf89 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -419,6 +419,7 @@
* to connect to
* @throws SecurityException if the caller does not hold the
* {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
+ * @hide
*/
public RecommendationResult requestRecommendation(RecommendationRequest request)
throws SecurityException {
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 9db58ee..6656b00 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -18,6 +18,8 @@
import android.util.ArrayMap;
+import java.util.function.Consumer;
+
/**
* Takes care of the grunt work of maintaining a list of remote interfaces,
* typically for the use of performing callbacks from a
@@ -308,6 +310,23 @@
}
/**
+ * Performs {@code action} on each callback, calling
+ * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping
+ *
+ * @hide
+ */
+ public void broadcast(Consumer<E> action) {
+ int itemCount = beginBroadcast();
+ try {
+ for (int i = 0; i < itemCount; i++) {
+ action.accept(getBroadcastItem(i));
+ }
+ } finally {
+ finishBroadcast();
+ }
+ }
+
+ /**
* Returns the number of registered callbacks. Note that the number of registered
* callbacks may differ from the value returned by {@link #beginBroadcast()} since
* the former returns the number of callbacks registered at the time of the call
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4482662..8a2a14c 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -506,8 +506,6 @@
* Input: Nothing.
* <p>
* Output: Nothing.
- *
- * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_NIGHT_DISPLAY_SETTINGS =
@@ -7668,12 +7666,14 @@
public static final String HDMI_CONTROL_ENABLED = "hdmi_control_enabled";
/**
- * Whether HDMI system audio is enabled. If enabled, TV internal speaker is muted,
- * and the output is redirected to AV Receiver connected via
- * {@Global#HDMI_SYSTEM_AUDIO_OUTPUT}.
+ * Whether HDMI System Audio Control feature is enabled. If enabled, TV will try to turn on
+ * system audio mode if there's a connected CEC-enabled AV Receiver. Then audio stream will
+ * be played on AVR instead of TV spaeker. If disabled, the system audio mode will never be
+ * activated.
* @hide
*/
- public static final String HDMI_SYSTEM_AUDIO_ENABLED = "hdmi_system_audio_enabled";
+ public static final String HDMI_SYSTEM_AUDIO_CONTROL_ENABLED =
+ "hdmi_system_audio_control_enabled";
/**
* Whether TV will automatically turn on upon reception of the CEC command
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 61b1247..6d320ef 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -500,7 +500,12 @@
// While creating the surface, we will set it's initial
// geometry. Outside of that though, we should generally
// leave it to the RenderThread.
- if (creating || !mRtHandlingPositionUpdates) {
+ //
+ // There is one more case when the buffer size changes we aren't yet
+ // prepared to sync (as even following the transaction applying
+ // we still need to latch a buffer).
+ // b/28866173
+ if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
0.0f, 0.0f,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index aa1cbf2..029caf9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6132,6 +6132,9 @@
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+
+ notifyEnterOrExitForAutoFillIfNeeded(true);
+
return result;
}
@@ -6791,14 +6794,18 @@
mAttachInfo.mKeyDispatchState.reset(this);
}
+ notifyEnterOrExitForAutoFillIfNeeded(gainFocus);
+ }
+
+ private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) {
if (isAutofillable() && isAttachedToWindow()
&& getResolvedAutofillMode() == AUTOFILL_MODE_AUTO) {
AutofillManager afm = getAutofillManager();
if (afm != null) {
- if (gainFocus) {
- afm.startAutofillRequest(this);
- } else {
- afm.stopAutofillRequest(this);
+ if (enter && hasWindowFocus() && isFocused()) {
+ afm.notifyViewEntered(this);
+ } else if (!hasWindowFocus() || !isFocused()) {
+ afm.notifyViewExited(this);
}
}
}
@@ -7368,13 +7375,17 @@
* <li>Also implement {@link #autofillVirtual(int, AutofillValue)} to autofill the virtual
* children.
* <li>Call
- * {@link android.view.autofill.AutofillManager#startAutofillRequestOnVirtualView} and
- * {@link android.view.autofill.AutofillManager#stopAutofillRequestOnVirtualView(View, int)}
+ * {@link android.view.autofill.AutofillManager#notifyVirtualViewEntered} and
+ * {@link android.view.autofill.AutofillManager#notifyVirtualViewExited(View, int)}
* when the focus inside the view changed.
- * <li>Call {@link android.view.autofill.AutofillManager#virtualValueChanged(View, int,
+ * <li>Call {@link android.view.autofill.AutofillManager#notifyVirtualValueChanged(View, int,
* AutofillValue)} when the value of a child changed.
- * <li>Call {@link android.view.autofill.AutofillManager#reset()} when the autofill context
- * of the view structure changed.
+ * <li>Call {@link AutofillManager#commit()} when the autofill context
+ * of the view structure changed and you want the current autofill interaction if such
+ * to be commited.
+ * <li>Call {@link AutofillManager#cancel()} ()} when the autofill context
+ * of the view structure changed and you want the current autofill interaction if such
+ * to be cancelled.
* </ol>
*
* @param structure Fill in with structured view data.
@@ -11085,6 +11096,7 @@
@CallSuper
public void dispatchStartTemporaryDetach() {
mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH;
+ notifyEnterOrExitForAutoFillIfNeeded(false);
onStartTemporaryDetach();
}
@@ -11110,6 +11122,7 @@
if (hasWindowFocus() && hasFocus()) {
InputMethodManager.getInstance().focusIn(this);
}
+ notifyEnterOrExitForAutoFillIfNeeded(true);
}
/**
@@ -11512,6 +11525,9 @@
} else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) {
imm.focusIn(this);
}
+
+ notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus);
+
refreshDrawableState();
}
@@ -16879,12 +16895,7 @@
}
needGlobalAttributesUpdate(false);
- if (isAutofillable() && isFocused() && getResolvedAutofillMode() == AUTOFILL_MODE_AUTO) {
- AutofillManager afm = getAutofillManager();
- if (afm != null) {
- afm.startAutofillRequest(this);
- }
- }
+ notifyEnterOrExitForAutoFillIfNeeded(true);
}
void dispatchDetachedFromWindow() {
@@ -16932,12 +16943,7 @@
mOverlay.getOverlayView().dispatchDetachedFromWindow();
}
- if (isAutofillable() && isFocused() && getResolvedAutofillMode() == AUTOFILL_MODE_AUTO) {
- AutofillManager afm = getAutofillManager();
- if (afm != null) {
- afm.stopAutofillRequest(this);
- }
- }
+ notifyEnterOrExitForAutoFillIfNeeded(false);
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9fa9985e..de0ec40 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -46,6 +46,7 @@
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pools;
import android.util.Pools.SynchronizedPool;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -3327,7 +3328,74 @@
@Override
public void dispatchProvideStructure(ViewStructure structure) {
super.dispatchProvideStructure(structure);
- dispatchProvideStructureForAssistOrAutoFill(structure, false);
+ if (isAssistBlocked() || structure.getChildCount() != 0) {
+ return;
+ }
+ final int childrenCount = mChildrenCount;
+ if (childrenCount <= 0) {
+ return;
+ }
+ structure.setChildCount(childrenCount);
+ ArrayList<View> preorderedList = buildOrderedChildList();
+ boolean customOrder = preorderedList == null
+ && isChildrenDrawingOrderEnabled();
+ for (int i = 0; i < childrenCount; i++) {
+ int childIndex;
+ try {
+ childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+ } catch (IndexOutOfBoundsException e) {
+ childIndex = i;
+ if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.M) {
+ Log.w(TAG, "Bad getChildDrawingOrder while collecting assist @ "
+ + i + " of " + childrenCount, e);
+ // At least one app is failing when we call getChildDrawingOrder
+ // at this point, so deal semi-gracefully with it by falling back
+ // on the basic order.
+ customOrder = false;
+ if (i > 0) {
+ // If we failed at the first index, there really isn't
+ // anything to do -- we will just proceed with the simple
+ // sequence order.
+ // Otherwise, we failed in the middle, so need to come up
+ // with an order for the remaining indices and use that.
+ // Failed at the first one, easy peasy.
+ int[] permutation = new int[childrenCount];
+ SparseBooleanArray usedIndices = new SparseBooleanArray();
+ // Go back and collected the indices we have done so far.
+ for (int j = 0; j < i; j++) {
+ permutation[j] = getChildDrawingOrder(childrenCount, j);
+ usedIndices.put(permutation[j], true);
+ }
+ // Fill in the remaining indices with indices that have not
+ // yet been used.
+ int nextIndex = 0;
+ for (int j = i; j < childrenCount; j++) {
+ while (usedIndices.get(nextIndex, false)) {
+ nextIndex++;
+ }
+ permutation[j] = nextIndex;
+ nextIndex++;
+ }
+ // Build the final view list.
+ preorderedList = new ArrayList<>(childrenCount);
+ for (int j = 0; j < childrenCount; j++) {
+ final int index = permutation[j];
+ final View child = mChildren[index];
+ preorderedList.add(child);
+ }
+ }
+ } else {
+ throw e;
+ }
+ }
+ final View child = getAndVerifyPreorderedView(preorderedList, mChildren,
+ childIndex);
+ final ViewStructure cstructure = structure.newChild(i);
+ child.dispatchProvideStructure(cstructure);
+ }
+ if (preorderedList != null) {
+ preorderedList.clear();
+ }
}
/**
@@ -3339,21 +3407,44 @@
@Override
public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
super.dispatchProvideAutofillStructure(structure, flags);
- dispatchProvideStructureForAssistOrAutoFill(structure, true);
+ if (isAutofillBlocked() || structure.getChildCount() != 0) {
+ return;
+ }
+ final ChildListForAutoFill children = getChildrenForAutofill();
+ final int childrenCount = children.size();
+ structure.setChildCount(childrenCount);
+ for (int i = 0; i < childrenCount; i++) {
+ final View child = children.get(i);
+ final ViewStructure cstructure = structure.newChild(i);
+ child.dispatchProvideAutofillStructure(cstructure, flags);
+ }
+ children.recycle();
}
- /** @hide */
- private ArrayList<View> getChildrenForAutofill() {
- final ArrayList<View> list = new ArrayList<>();
- populateChildrenForAutofill(list);
- return list;
+ /**
+ * Gets the children for autofill. Children for autofill are the first
+ * level descendants that are important for autofill. The returned
+ * child list object is pooled and the caller must recycle it once done.
+ * @hide */
+ private @NonNull ChildListForAutoFill getChildrenForAutofill() {
+ final ChildListForAutoFill children = ChildListForAutoFill.obtain();
+ populateChildrenForAutofill(children);
+ return children;
}
/** @hide */
private void populateChildrenForAutofill(ArrayList<View> list) {
- final int count = mChildrenCount;
- for (int i = 0; i < count; i++) {
- final View child = mChildren[i];
+ final int childrenCount = mChildrenCount;
+ if (childrenCount <= 0) {
+ return;
+ }
+ final ArrayList<View> preorderedList = buildOrderedChildList();
+ final boolean customOrder = preorderedList == null
+ && isChildrenDrawingOrderEnabled();
+ for (int i = 0; i < childrenCount; i++) {
+ final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+ final View child = (preorderedList == null)
+ ? mChildren[childIndex] : preorderedList.get(childIndex);
if (child.isImportantForAutofill()) {
list.add(child);
} else if (child instanceof ViewGroup) {
@@ -3362,106 +3453,6 @@
}
}
- private void dispatchProvideStructureForAssistOrAutoFill(ViewStructure structure,
- boolean forAutofill) {
- boolean blocked = forAutofill ? isAutofillBlocked() : isAssistBlocked();
- if (blocked || structure.getChildCount() != 0) {
- return;
- }
- final View[] childrenArray;
- final ArrayList<View> childrenList;
- final int childrenCount;
-
- if (forAutofill) {
- childrenArray = null;
- // TODO(b/33197203): the current algorithm allocates a new list for each children that
- // is a view group; ideally, we should use mAttachInfo.mTempArrayList instead, but that
- // would complicated the algorithm a lot...
- childrenList = getChildrenForAutofill();
-
- childrenCount = childrenList.size();
- } else {
- childrenArray = mChildren;
- childrenList = null;
- childrenCount = getChildCount();
- }
-
- if (childrenCount > 0) {
- structure.setChildCount(childrenCount);
- ArrayList<View> preorderedList = buildOrderedChildList();
- boolean customOrder = preorderedList == null
- && isChildrenDrawingOrderEnabled();
- for (int i = 0; i < childrenCount; i++) {
- int childIndex;
- try {
- childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
- } catch (IndexOutOfBoundsException e) {
- childIndex = i;
- if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.M) {
- Log.w(TAG, "Bad getChildDrawingOrder while collecting assist @ "
- + i + " of " + childrenCount, e);
- // At least one app is failing when we call getChildDrawingOrder
- // at this point, so deal semi-gracefully with it by falling back
- // on the basic order.
- customOrder = false;
- if (i > 0) {
- // If we failed at the first index, there really isn't
- // anything to do -- we will just proceed with the simple
- // sequence order.
- // Otherwise, we failed in the middle, so need to come up
- // with an order for the remaining indices and use that.
- // Failed at the first one, easy peasy.
- int[] permutation = new int[childrenCount];
- SparseBooleanArray usedIndices = new SparseBooleanArray();
- // Go back and collected the indices we have done so far.
- for (int j = 0; j < i; j++) {
- permutation[j] = getChildDrawingOrder(childrenCount, j);
- usedIndices.put(permutation[j], true);
- }
- // Fill in the remaining indices with indices that have not
- // yet been used.
- int nextIndex = 0;
- for (int j = i; j < childrenCount; j++) {
- while (usedIndices.get(nextIndex, false)) {
- nextIndex++;
- }
- permutation[j] = nextIndex;
- nextIndex++;
- }
- // Build the final view list.
- preorderedList = new ArrayList<>(childrenCount);
- for (int j = 0; j < childrenCount; j++) {
- final int index = permutation[j];
- final View child = forAutofill
- ? childrenList.get(index)
- : childrenArray[index];
- preorderedList.add(child);
- }
- }
- } else {
- throw e;
- }
- }
-
- final View child = forAutofill
- ? getAndVerifyPreorderedView(preorderedList, childrenList, childIndex)
- : getAndVerifyPreorderedView(preorderedList, childrenArray, childIndex);
- final ViewStructure cstructure = structure.newChild(i);
-
- // Must explicitly check which recursive method to call.
- if (forAutofill) {
- // NOTE: flags are not currently supported, hence 0
- child.dispatchProvideAutofillStructure(cstructure, 0);
- } else {
- child.dispatchProvideStructure(cstructure);
- }
- }
- if (preorderedList != null) {
- preorderedList.clear();
- }
- }
- }
-
private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children,
int childIndex) {
final View child;
@@ -3477,21 +3468,6 @@
return child;
}
- private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList,
- ArrayList<View> children, int childIndex) {
- final View child;
- if (preorderedList != null) {
- child = preorderedList.get(childIndex);
- if (child == null) {
- throw new RuntimeException("Invalid preorderedList contained null child at index "
- + childIndex);
- }
- } else {
- child = children.get(childIndex);
- }
- return child;
- }
-
/** @hide */
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
@@ -8192,6 +8168,29 @@
}
/**
+ * Pooled class that to hold the children for autifill.
+ */
+ static class ChildListForAutoFill extends ArrayList<View> {
+ private static final int MAX_POOL_SIZE = 32;
+
+ private static final Pools.SimplePool<ChildListForAutoFill> sPool =
+ new Pools.SimplePool<>(MAX_POOL_SIZE);
+
+ public static ChildListForAutoFill obtain() {
+ ChildListForAutoFill list = sPool.acquire();
+ if (list == null) {
+ list = new ChildListForAutoFill();
+ }
+ return list;
+ }
+
+ public void recycle() {
+ clear();
+ sPool.release(this);
+ }
+ }
+
+ /**
* Pooled class that orderes the children of a ViewGroup from start
* to end based on how they are laid out and the layout direction.
*/
@@ -8228,10 +8227,6 @@
return mChildren.get(index);
}
- public int getChildIndex(View child) {
- return mChildren.indexOf(child);
- }
-
private void init(ViewGroup parent, boolean sort) {
ArrayList<View> children = mChildren;
final int childCount = parent.getChildCount();
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index fe888ec..c9f9f31 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -40,6 +40,8 @@
import android.view.IWindow;
import android.view.View;
+import com.android.internal.util.IntPair;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -109,6 +111,8 @@
boolean mIsEnabled;
+ int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
+
boolean mIsTouchExplorationEnabled;
boolean mIsHighTextContrastEnabled;
@@ -203,6 +207,11 @@
public void notifyServicesStateChanged() {
mHandler.obtainMessage(MyHandler.MSG_NOTIFY_SERVICES_STATE_CHANGED).sendToTarget();
}
+
+ @Override
+ public void setRelevantEventTypes(int eventTypes) {
+ mRelevantEventTypes = eventTypes;
+ }
};
/**
@@ -362,6 +371,14 @@
return;
}
}
+ if ((event.getEventType() & mRelevantEventTypes) == 0) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Not dispatching irrelevant event: " + event
+ + " that is not among "
+ + AccessibilityEvent.eventTypeToString(mRelevantEventTypes));
+ }
+ return;
+ }
userId = mUserId;
}
try {
@@ -865,8 +882,9 @@
}
try {
- final int stateFlags = service.addClient(mClient, mUserId);
- setStateLocked(stateFlags);
+ final long userStateAndRelevantEvents = service.addClient(mClient, mUserId);
+ setStateLocked(IntPair.first(userStateAndRelevantEvents));
+ mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
mService = service;
} catch (RemoteException re) {
Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 157980f..06cb5dc 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -38,7 +38,7 @@
oneway void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
- int addClient(IAccessibilityManagerClient client, int userId);
+ long addClient(IAccessibilityManagerClient client, int userId);
List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 045ac91..9cc0315 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -25,5 +25,8 @@
oneway interface IAccessibilityManagerClient {
void setState(int stateFlags);
+
void notifyServicesStateChanged();
+
+ void setRelevantEventTypes(int eventTypes);
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 2a12e4b..c4f90dc 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -72,8 +72,8 @@
"android.view.autofill.extra.AUTHENTICATION_RESULT";
/** @hide */ public static final int FLAG_START_SESSION = 0x1;
- /** @hide */ public static final int FLAG_FOCUS_GAINED = 0x2;
- /** @hide */ public static final int FLAG_FOCUS_LOST = 0x4;
+ /** @hide */ public static final int FLAG_VIEW_ENTERED = 0x2;
+ /** @hide */ public static final int FLAG_VIEW_EXITED = 0x4;
/** @hide */ public static final int FLAG_VALUE_CHANGED = 0x8;
private final Rect mTempRect = new Rect();
@@ -121,11 +121,11 @@
}
/**
- * Called when an autofill operation on a {@link View} should start.
+ * Called when a {@link View} that supports autofill is entered.
*
- * @param view {@link View} that triggered the autofill request.
+ * @param view {@link View} that was entered.
*/
- public void startAutofillRequest(@NonNull View view) {
+ public void notifyViewEntered(@NonNull View view) {
ensureServiceClientAddedIfNeeded();
if (!mEnabled) {
@@ -142,35 +142,34 @@
startSession(id, view.getWindowToken(), bounds, value);
} else {
// Update focus on existing session.
- updateSession(id, bounds, value, FLAG_FOCUS_GAINED);
+ updateSession(id, bounds, value, FLAG_VIEW_ENTERED);
}
}
/**
- * Called when an autofill operation on a {@link View} should stop.
+ * Called when a {@link View} that supports autofill is exited.
*
- * @param view {@link View} that triggered the autofill request in
- * {@link #startAutofillRequest(View)}.
+ * @param view {@link View} that was exited.
*/
- public void stopAutofillRequest(@NonNull View view) {
+ public void notifyViewExited(@NonNull View view) {
ensureServiceClientAddedIfNeeded();
if (mEnabled && mHasSession) {
final AutofillId id = getAutofillId(view);
// Update focus on existing session.
- updateSession(id, null, null, FLAG_FOCUS_LOST);
+ updateSession(id, null, null, FLAG_VIEW_EXITED);
}
}
/**
- * Called when an autofill operation on a virtual {@link View} should start.
+ * Called when a virtual view that supports autofill is entered.
*
- * @param parent parent of the {@link View} that triggered the autofill request.
- * @param childId id identifying the virtual child inside the parent view.
+ * @param view the {@link View} whose descendant is the virtual view.
+ * @param childId id identifying the virtual child inside the view.
* @param bounds child boundaries, relative to the top window.
*/
- public void startAutofillRequestOnVirtualView(@NonNull View parent, int childId,
+ public void notifyVirtualViewEntered(@NonNull View view, int childId,
@NonNull Rect bounds) {
ensureServiceClientAddedIfNeeded();
@@ -178,32 +177,31 @@
return;
}
- final AutofillId id = getAutofillId(parent, childId);
+ final AutofillId id = getAutofillId(view, childId);
if (!mHasSession) {
// Starts new session.
- startSession(id, parent.getWindowToken(), bounds, null);
+ startSession(id, view.getWindowToken(), bounds, null);
} else {
// Update focus on existing session.
- updateSession(id, bounds, null, FLAG_FOCUS_GAINED);
+ updateSession(id, bounds, null, FLAG_VIEW_ENTERED);
}
}
/**
- * Called when an autofill operation on a virtual {@link View} should stop.
+ * Called when a virtual view that supports autofill is exited.
*
- * @param parent parent of the {@link View} that triggered the autofill request in
- * {@link #startAutofillRequestOnVirtualView(View, int, Rect)}.
- * @param childId id identifying the virtual child inside the parent view.
+ * @param view the {@link View} whose descendant is the virtual view.
+ * @param childId id identifying the virtual child inside the view.
*/
- public void stopAutofillRequestOnVirtualView(@NonNull View parent, int childId) {
+ public void notifyVirtualViewExited(@NonNull View view, int childId) {
ensureServiceClientAddedIfNeeded();
if (mEnabled && mHasSession) {
- final AutofillId id = getAutofillId(parent, childId);
+ final AutofillId id = getAutofillId(view, childId);
// Update focus on existing session.
- updateSession(id, null, null, FLAG_FOCUS_LOST);
+ updateSession(id, null, null, FLAG_VIEW_EXITED);
}
}
@@ -212,7 +210,7 @@
*
* @param view view whose value changed.
*/
- public void valueChanged(View view) {
+ public void notifyValueChanged(View view) {
if (!mEnabled || !mHasSession) {
return;
}
@@ -230,7 +228,7 @@
* @param childId id identifying the virtual child inside the parent view.
* @param value new value of the child.
*/
- public void virtualValueChanged(View parent, int childId, AutofillValue value) {
+ public void notifyVirtualValueChanged(View parent, int childId, AutofillValue value) {
if (!mEnabled || !mHasSession) {
return;
}
@@ -240,12 +238,12 @@
}
/**
- * Called to indicate the current autofill context should be reset.
+ * Called to indicate the current autofill context should be commited.
*
* <p>For example, when a virtual view is rendering an {@code HTML} page with a form, it should
* call this method after the form is submitted and another page is rendered.
*/
- public void reset() {
+ public void commit() {
if (!mEnabled && !mHasSession) {
return;
}
@@ -253,6 +251,20 @@
finishSession();
}
+ /**
+ * Called to indicate the current autofill context should be cancelled.
+ *
+ * <p>For example, when a virtual view is rendering an {@code HTML} page with a form, it should
+ * call this method if the user does not post the form but moves to another form in this page.
+ */
+ public void cancel() {
+ if (!mEnabled && !mHasSession) {
+ return;
+ }
+
+ cancelSession();
+ }
+
private AutofillClient getClient() {
if (mContext instanceof AutofillClient) {
return (AutofillClient) mContext;
@@ -324,9 +336,21 @@
}
}
+ private void cancelSession() {
+ if (DEBUG) {
+ Log.d(TAG, "cancelSession()");
+ }
+ mHasSession = false;
+ try {
+ mService.cancelSession(mContext.getActivityToken(), mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private void updateSession(AutofillId id, Rect bounds, AutofillValue value, int flags) {
if (DEBUG) {
- if (VERBOSE || (flags & FLAG_FOCUS_LOST) != 0) {
+ if (VERBOSE || (flags & FLAG_VIEW_EXITED) != 0) {
Log.d(TAG, "updateSession(): id=" + id + ", bounds=" + bounds + ", value=" + value
+ ", flags=" + flags);
}
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 07d8cab..86a4965 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -36,6 +36,7 @@
oneway void updateSession(in IBinder activityToken, in AutofillId id, in Rect bounds,
in AutofillValue value, int flags, int userId);
oneway void finishSession(in IBinder activityToken, int userId);
+ oneway void cancelSession(in IBinder activityToken, int userId);
oneway void setAuthenticationResult(in Bundle data,
in IBinder activityToken, int userId);
oneway void setHasCallback(in IBinder activityToken, int userId, boolean hasIt);
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index e5505a6..5725b49 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -918,7 +918,7 @@
// Always notify AutoFillManager - it will return right away if autofill is disabled.
final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
if (afm != null) {
- afm.valueChanged(this);
+ afm.notifyValueChanged(this);
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 81aec9c..d246405 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -173,7 +173,7 @@
}
final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
if (afm != null) {
- afm.valueChanged(this);
+ afm.notifyValueChanged(this);
}
mBroadcasting = false;
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index fa8316c..31a88d4 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -182,7 +182,7 @@
mDelegate.setAutoFillChangeListener((v, y, m, d) -> {
final AutofillManager afm = context.getSystemService(AutofillManager.class);
if (afm != null) {
- afm.valueChanged(this);
+ afm.notifyValueChanged(this);
}
});
}
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index bd62d6c..dc9976d 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -188,7 +188,7 @@
}
final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
if (afm != null) {
- afm.valueChanged(this);
+ afm.notifyValueChanged(this);
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index ee70acc..d591316f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9136,7 +9136,7 @@
if (DEBUG_AUTOFILL) {
Log.v(LOG_TAG, "sendAfterTextChanged(): notify AFM for text=" + mText);
}
- afm.valueChanged(TextView.this);
+ afm.notifyValueChanged(TextView.this);
}
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 1435983..9825f1e 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -144,7 +144,7 @@
mDelegate.setAutoFillChangeListener((v, h, m) -> {
final AutofillManager afm = context.getSystemService(AutofillManager.class);
if (afm != null) {
- afm.valueChanged(this);
+ afm.notifyValueChanged(this);
}
});
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 2aeddb3..6aa7766 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -6027,7 +6027,8 @@
* Clear all stats for this uid. Returns true if the uid is completely
* inactive so can be dropped.
*/
- boolean reset() {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public boolean reset() {
boolean active = false;
if (mWifiRunningTimer != null) {
@@ -6968,7 +6969,10 @@
boolean reset() {
if (mBgCounter != null) {
- mBgCounter.reset(true);
+ mBgCounter.reset(true /*detachIfReset*/);
+ // If we detach, we must null the mBgCounter reference so that it
+ // can be recreated and attached.
+ mBgCounter = null;
}
if (mTimer.reset(true)) {
mTimer = null;
diff --git a/core/java/com/android/internal/util/IntPair.java b/core/java/com/android/internal/util/IntPair.java
new file mode 100644
index 0000000..7992507
--- /dev/null
+++ b/core/java/com/android/internal/util/IntPair.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+/**
+ * Utilities for treating a {@code long} as a pair of {@code int}s
+ *
+ * @hide
+ */
+public class IntPair {
+ private IntPair() {}
+
+ public static long of(int first, int second) {
+ return (((long)first) << 32) | ((long)second & 0xffffffffL);
+ }
+
+ public static int first(long intPair) {
+ return (int)(intPair >> 32);
+ }
+
+ public static int second(long intPair) {
+ return (int)intPair;
+ }
+}
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 7eb0582..98c9e78 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -97,7 +97,7 @@
SettingProto download_max_bytes_over_mobile = 52;
SettingProto download_recommended_max_bytes_over_mobile = 53;
SettingProto hdmi_control_enabled = 54;
- SettingProto hdmi_system_audio_enabled = 55;
+ SettingProto hdmi_system_audio_control_enabled = 55;
SettingProto hdmi_control_auto_wakeup_enabled = 56;
SettingProto hdmi_control_auto_device_off_enabled = 57;
SettingProto mhl_input_switching_enabled = 58;
diff --git a/core/res/res/layout/autofill_dataset_picker.xml b/core/res/res/layout/autofill_dataset_picker.xml
index 9b90de6..133265b 100644
--- a/core/res/res/layout/autofill_dataset_picker.xml
+++ b/core/res/res/layout/autofill_dataset_picker.xml
@@ -18,6 +18,7 @@
android:id="@+id/autofill_dataset_picker"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
- android:divider="?android:attr/listDivider"
- android:background="#ffffffff">
+ android:divider="@null"
+ android:background="#ffffffff"
+ android:elevation="@dimen/floating_window_z">
</ListView>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 903ef84..0cfdaf5 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -198,7 +198,7 @@
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
- Settings.Global.HDMI_SYSTEM_AUDIO_ENABLED,
+ Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
Settings.Global.HTTP_PROXY,
Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
index e152163..4ec78ff 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -65,4 +65,49 @@
assertEquals(1, sensorBgCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
}
+
+ @SmallTest
+ public void testNestedSensorReset() throws Exception {
+ final MockClocks clocks = new MockClocks();
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ bi.mForceOnBattery = true;
+ clocks.realtime = 100;
+ clocks.uptime = 100;
+ bi.getOnBatteryTimeBase().setRunning(true, 100, 100);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_RECEIVER);
+
+ clocks.realtime += 100;
+ clocks.uptime += 100;
+
+ bi.noteStartSensorLocked(UID, SENSOR_ID);
+
+ clocks.realtime += 100;
+ clocks.uptime += 100;
+
+ // The sensor is started and the background counter has been created.
+ final BatteryStats.Uid uid = bi.getUidStats().get(UID);
+ assertNotNull(uid);
+
+ BatteryStats.Uid.Sensor sensor = uid.getSensorStats().get(SENSOR_ID);
+ assertNotNull(sensor);
+ assertNotNull(sensor.getSensorTime());
+ assertNotNull(sensor.getSensorBgCount());
+
+ // Reset the stats. Since the sensor is still running, we should still see the sensor
+ // timer. Background counter should be gone though.
+ bi.getUidStatsLocked(UID).reset();
+
+ sensor = uid.getSensorStats().get(SENSOR_ID);
+ assertNotNull(sensor);
+ assertNotNull(sensor.getSensorTime());
+ assertNull(sensor.getSensorBgCount());
+
+ bi.noteStopSensorLocked(UID, SENSOR_ID);
+
+ // Now the sensor timer has stopped so this reset should also take out the sensor.
+ bi.getUidStatsLocked(UID).reset();
+
+ sensor = uid.getSensorStats().get(SENSOR_ID);
+ assertNull(sensor);
+ }
}
diff --git a/libs/common_time/Android.mk b/libs/common_time/Android.mk
index 636f057..1fec504 100644
--- a/libs/common_time/Android.mk
+++ b/libs/common_time/Android.mk
@@ -15,8 +15,7 @@
clock_recovery.cpp \
common_clock.cpp \
main.cpp \
- utils.cpp \
- LinearTransform.cpp
+ utils.cpp
# Uncomment to enable vesbose logging and debug service.
#TIME_SERVICE_DEBUG=true
diff --git a/libs/common_time/LinearTransform.cpp b/libs/common_time/LinearTransform.cpp
deleted file mode 100644
index 6730855..0000000
--- a/libs/common_time/LinearTransform.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#define __STDC_LIMIT_MACROS
-
-#include "LinearTransform.h"
-#include <assert.h>
-
-
-// disable sanitize as these functions may intentionally overflow (see comments below).
-// the ifdef can be removed when host builds use clang.
-#if defined(__clang__)
-#define ATTRIBUTE_NO_SANITIZE_INTEGER __attribute__((no_sanitize("integer")))
-#else
-#define ATTRIBUTE_NO_SANITIZE_INTEGER
-#endif
-
-namespace android {
-
-// sanitize failure with T = int32_t and x = 0x80000000
-template<class T>
-ATTRIBUTE_NO_SANITIZE_INTEGER
-static inline T ABS(T x) { return (x < 0) ? -x : x; }
-
-// Static math methods involving linear transformations
-// remote sanitize failure on overflow case.
-ATTRIBUTE_NO_SANITIZE_INTEGER
-static bool scale_u64_to_u64(
- uint64_t val,
- uint32_t N,
- uint32_t D,
- uint64_t* res,
- bool round_up_not_down) {
- uint64_t tmp1, tmp2;
- uint32_t r;
-
- assert(res);
- assert(D);
-
- // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit
- // integer X.
- // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit
- // integer X.
- // Let X[A, B] with A <= B denote bits A through B of the integer X.
- // Let (A | B) denote the concatination of two 32 bit ints, A and B.
- // IOW X = (A | B) => U32(X) == A && L32(X) == B
- //
- // compute M = val * N (a 96 bit int)
- // ---------------------------------
- // tmp2 = U32(val) * N (a 64 bit int)
- // tmp1 = L32(val) * N (a 64 bit int)
- // which means
- // M = val * N = (tmp2 << 32) + tmp1
- tmp2 = (val >> 32) * N;
- tmp1 = (val & UINT32_MAX) * N;
-
- // compute M[32, 95]
- // tmp2 = tmp2 + U32(tmp1)
- // = (U32(val) * N) + U32(L32(val) * N)
- // = M[32, 95]
- tmp2 += tmp1 >> 32;
-
- // if M[64, 95] >= D, then M/D has bits > 63 set and we have
- // an overflow.
- if ((tmp2 >> 32) >= D) {
- *res = UINT64_MAX;
- return false;
- }
-
- // Divide. Going in we know
- // tmp2 = M[32, 95]
- // U32(tmp2) < D
- r = tmp2 % D;
- tmp2 /= D;
-
- // At this point
- // tmp1 = L32(val) * N
- // tmp2 = M[32, 95] / D
- // = (M / D)[32, 95]
- // r = M[32, 95] % D
- // U32(tmp2) = 0
- //
- // compute tmp1 = (r | M[0, 31])
- tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32);
-
- // Divide again. Keep the remainder around in order to round properly.
- r = tmp1 % D;
- tmp1 /= D;
-
- // At this point
- // tmp2 = (M / D)[32, 95]
- // tmp1 = (M / D)[ 0, 31]
- // r = M % D
- // U32(tmp1) = 0
- // U32(tmp2) = 0
-
- // Pack the result and deal with the round-up case (As well as the
- // remote possiblility over overflow in such a case).
- *res = (tmp2 << 32) | tmp1;
- if (r && round_up_not_down) {
- ++(*res);
- if (!(*res)) {
- *res = UINT64_MAX;
- return false;
- }
- }
-
- return true;
-}
-
-// at least one known sanitize failure (see comment below)
-ATTRIBUTE_NO_SANITIZE_INTEGER
-static bool linear_transform_s64_to_s64(
- int64_t val,
- int64_t basis1,
- int32_t N,
- uint32_t D,
- bool invert_frac,
- int64_t basis2,
- int64_t* out) {
- uint64_t scaled, res;
- uint64_t abs_val;
- bool is_neg;
-
- if (!out)
- return false;
-
- // Compute abs(val - basis_64). Keep track of whether or not this delta
- // will be negative after the scale opertaion.
- if (val < basis1) {
- is_neg = true;
- abs_val = basis1 - val;
- } else {
- is_neg = false;
- abs_val = val - basis1;
- }
-
- if (N < 0)
- is_neg = !is_neg;
-
- if (!scale_u64_to_u64(abs_val,
- invert_frac ? D : ABS(N),
- invert_frac ? ABS(N) : D,
- &scaled,
- is_neg))
- return false; // overflow/undeflow
-
- // if scaled is >= 0x8000<etc>, then we are going to overflow or
- // underflow unless ABS(basis2) is large enough to pull us back into the
- // non-overflow/underflow region.
- if (scaled & INT64_MIN) {
- if (is_neg && (basis2 < 0))
- return false; // certain underflow
-
- if (!is_neg && (basis2 >= 0))
- return false; // certain overflow
-
- if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX))
- return false; // not enough
-
- // Looks like we are OK
- *out = (is_neg ? (-scaled) : scaled) + basis2;
- } else {
- // Scaled fits within signed bounds, so we just need to check for
- // over/underflow for two signed integers. Basically, if both scaled
- // and basis2 have the same sign bit, and the result has a different
- // sign bit, then we have under/overflow. An easy way to compute this
- // is
- // (scaled_signbit XNOR basis_signbit) &&
- // (scaled_signbit XOR res_signbit)
- // ==
- // (scaled_signbit XOR basis_signbit XOR 1) &&
- // (scaled_signbit XOR res_signbit)
-
- if (is_neg)
- scaled = -scaled; // known sanitize failure
- res = scaled + basis2;
-
- if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN)
- return false;
-
- *out = res;
- }
-
- return true;
-}
-
-bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const {
- if (0 == a_to_b_denom)
- return false;
-
- return linear_transform_s64_to_s64(a_in,
- a_zero,
- a_to_b_numer,
- a_to_b_denom,
- false,
- b_zero,
- b_out);
-}
-
-bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const {
- if (0 == a_to_b_numer)
- return false;
-
- return linear_transform_s64_to_s64(b_in,
- b_zero,
- a_to_b_numer,
- a_to_b_denom,
- true,
- a_zero,
- a_out);
-}
-
-template <class T> void LinearTransform::reduce(T* N, T* D) {
- T a, b;
- if (!N || !D || !(*D)) {
- assert(false);
- return;
- }
-
- a = *N;
- b = *D;
-
- if (a == 0) {
- *D = 1;
- return;
- }
-
- // This implements Euclid's method to find GCD.
- if (a < b) {
- T tmp = a;
- a = b;
- b = tmp;
- }
-
- while (1) {
- // a is now the greater of the two.
- const T remainder = a % b;
- if (remainder == 0) {
- *N /= b;
- *D /= b;
- return;
- }
- // by swapping remainder and b, we are guaranteeing that a is
- // still the greater of the two upon entrance to the loop.
- a = b;
- b = remainder;
- }
-};
-
-template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D);
-template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D);
-
-// sanitize failure if *N = 0x80000000
-ATTRIBUTE_NO_SANITIZE_INTEGER
-void LinearTransform::reduce(int32_t* N, uint32_t* D) {
- if (N && D && *D) {
- if (*N < 0) {
- *N = -(*N);
- reduce(reinterpret_cast<uint32_t*>(N), D);
- *N = -(*N);
- } else {
- reduce(reinterpret_cast<uint32_t*>(N), D);
- }
- }
-}
-
-} // namespace android
diff --git a/libs/common_time/LinearTransform.h b/libs/common_time/LinearTransform.h
deleted file mode 100644
index bf6ab8e..0000000
--- a/libs/common_time/LinearTransform.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef _LINEAR_TRANSFORM_H
-#define _LINEAR_TRANSFORM_H
-
-#include <stdint.h>
-
-namespace android {
-
-// LinearTransform defines a structure which hold the definition of a
-// transformation from single dimensional coordinate system A into coordinate
-// system B (and back again). Values in A and in B are 64 bit, the linear
-// scale factor is expressed as a rational number using two 32 bit values.
-//
-// Specifically, let
-// f(a) = b
-// F(b) = f^-1(b) = a
-// then
-//
-// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero;
-//
-// and
-//
-// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero;
-//
-struct LinearTransform {
- int64_t a_zero;
- int64_t b_zero;
- int32_t a_to_b_numer;
- uint32_t a_to_b_denom;
-
- // Transform from A->B
- // Returns true on success, or false in the case of a singularity or an
- // overflow.
- bool doForwardTransform(int64_t a_in, int64_t* b_out) const;
-
- // Transform from B->A
- // Returns true on success, or false in the case of a singularity or an
- // overflow.
- bool doReverseTransform(int64_t b_in, int64_t* a_out) const;
-
- // Helpers which will reduce the fraction N/D using Euclid's method.
- template <class T> static void reduce(T* N, T* D);
- static void reduce(int32_t* N, uint32_t* D);
-};
-
-
-}
-
-#endif // _LINEAR_TRANSFORM_H
diff --git a/libs/common_time/clock_recovery.h b/libs/common_time/clock_recovery.h
index 8066a39..278a75e 100644
--- a/libs/common_time/clock_recovery.h
+++ b/libs/common_time/clock_recovery.h
@@ -19,10 +19,9 @@
#include <stdint.h>
#include <common_time/ICommonClock.h>
+#include <utils/LinearTransform.h>
#include <utils/threads.h>
-#include "LinearTransform.h"
-
#ifdef TIME_SERVICE_DEBUG
#include "diag_thread.h"
#endif
diff --git a/libs/common_time/common_clock.cpp b/libs/common_time/common_clock.cpp
index aed52f1..ee326e1 100644
--- a/libs/common_time/common_clock.cpp
+++ b/libs/common_time/common_clock.cpp
@@ -23,6 +23,7 @@
#include <stdint.h>
#include <utils/Errors.h>
+#include <utils/LinearTransform.h>
#include "common_clock.h"
diff --git a/libs/common_time/common_clock.h b/libs/common_time/common_clock.h
index 5e4e5f5..b786fdc 100644
--- a/libs/common_time/common_clock.h
+++ b/libs/common_time/common_clock.h
@@ -20,10 +20,9 @@
#include <stdint.h>
#include <utils/Errors.h>
+#include <utils/LinearTransform.h>
#include <utils/threads.h>
-#include "LinearTransform.h"
-
namespace android {
class CommonClock {
diff --git a/packages/CarrierDefaultApp/res/values/strings.xml b/packages/CarrierDefaultApp/res/values/strings.xml
index fe5669d..f904600 100644
--- a/packages/CarrierDefaultApp/res/values/strings.xml
+++ b/packages/CarrierDefaultApp/res/values/strings.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">CarrierDefaultApp</string>
- <string name="android_system_label">Android System</string>
+ <string name="android_system_label">Mobile Carrier</string>
<string name="portal_notification_id">Mobile data has run out</string>
- <string name="no_data_notification_id">No Mobile data service</string>
- <string name="portal_notification_detail">Tap to add funds to your %s SIM</string>
+ <string name="no_data_notification_id">Your mobile data has been deactivated</string>
+ <string name="portal_notification_detail">Tap to visit the %s website</string>
<string name="no_data_notification_detail">Please contact your service provider %s</string>
<string name="progress_dialogue_network_connection">Connecting to captive portal...</string>
<string name="alert_dialogue_network_timeout">Network timeout, would you like to retry?</string>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1fe3c48..4a54c0e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -240,8 +240,8 @@
Settings.Global.HDMI_CONTROL_ENABLED,
GlobalSettingsProto.HDMI_CONTROL_ENABLED);
dumpSetting(s, p,
- Settings.Global.HDMI_SYSTEM_AUDIO_ENABLED,
- GlobalSettingsProto.HDMI_SYSTEM_AUDIO_ENABLED);
+ Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
+ GlobalSettingsProto.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED);
dumpSetting(s, p,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
GlobalSettingsProto.HDMI_CONTROL_AUTO_WAKEUP_ENABLED);
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 6a66fca7..8882cab 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,7 @@
package com.android.systemui.recents.views;
+import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
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;
@@ -303,7 +304,7 @@
// TODO: Sometimes targetStackId is not initialized after reboot, so we also have to
// check for INVALID_STACK_ID
if (targetStackId == FULLSCREEN_WORKSPACE_STACK_ID || targetStackId == DOCKED_STACK_ID
- || targetStackId == INVALID_STACK_ID) {
+ || targetStackId == ASSISTANT_STACK_ID || targetStackId == INVALID_STACK_ID) {
if (taskView == null) {
specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
} else {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e0d7806..b56035f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -50,6 +50,7 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
+import android.hardware.fingerprint.IFingerprintService;
import android.hardware.input.InputManager;
import android.net.Uri;
import android.os.Binder;
@@ -69,7 +70,6 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
-import android.hardware.fingerprint.IFingerprintService;
import android.provider.SettingsStringUtil.ComponentNameSet;
import android.provider.SettingsStringUtil.SettingStringHelper;
import android.text.TextUtils;
@@ -100,7 +100,9 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.IntPair;
import com.android.server.LocalServices;
import com.android.server.policy.AccessibilityShortcutController;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -120,6 +122,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Consumer;
/**
* This class is instantiated by the system as a system level service and can be
@@ -434,7 +437,7 @@
}
@Override
- public int addClient(IAccessibilityManagerClient client, int userId) {
+ public long addClient(IAccessibilityManagerClient client, int userId) {
synchronized (mLock) {
// We treat calls from a profile as if made by its parent as profiles
// share the accessibility state of the parent. The call below
@@ -450,7 +453,8 @@
if (DEBUG) {
Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
}
- return userState.getClientState();
+ return IntPair.of(
+ userState.getClientState(), userState.mLastSentRelevantEventTypes);
} else {
userState.mUserClients.register(client);
// If this client is not for the current user we do not
@@ -460,7 +464,9 @@
Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
+ " and userId:" + mCurrentUserId);
}
- return (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0;
+ return IntPair.of(
+ (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0,
+ userState.mLastSentRelevantEventTypes);
}
}
}
@@ -1323,6 +1329,35 @@
scheduleNotifyClientsOfServicesStateChange(userState);
}
+ private void updateRelevantEventsLocked(UserState userState) {
+ int relevantEventTypes = AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK;
+ for (Service service : userState.mBoundServices) {
+ relevantEventTypes |= service.mEventTypes;
+ }
+ int finalRelevantEventTypes = relevantEventTypes;
+
+ if (userState.mLastSentRelevantEventTypes != finalRelevantEventTypes) {
+ userState.mLastSentRelevantEventTypes = finalRelevantEventTypes;
+ mMainHandler.obtainMessage(MainHandler.MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS,
+ userState.mUserId, finalRelevantEventTypes);
+ mMainHandler.post(() -> {
+ broadcastToClients(userState, (client) -> {
+ try {
+ client.setRelevantEventTypes(finalRelevantEventTypes);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ });
+ });
+ }
+ }
+
+ private void broadcastToClients(
+ UserState userState, Consumer<IAccessibilityManagerClient> clientAction) {
+ mGlobalClients.broadcast(clientAction);
+ userState.mUserClients.broadcast(clientAction);
+ }
+
/**
* Determines if given event can be dispatched to a service based on the package of the
* event source. Specifically, a service is notified if it is interested in events from the
@@ -1633,6 +1668,7 @@
scheduleUpdateFingerprintGestureHandling(userState);
scheduleUpdateInputFilter(userState);
scheduleUpdateClientsIfNeededLocked(userState);
+ updateRelevantEventsLocked(userState);
}
private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
@@ -2281,6 +2317,7 @@
public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
public static final int MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS = 10;
public static final int MSG_UPDATE_FINGERPRINT = 11;
+ public static final int MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS = 12;
public MainHandler(Looper looper) {
super(looper);
@@ -2351,6 +2388,22 @@
case MSG_UPDATE_FINGERPRINT: {
updateFingerprintGestureHandling((UserState) msg.obj);
} break;
+
+ case MSG_SEND_RELEVANT_EVENTS_CHANGED_TO_CLIENTS: {
+ final int userId = msg.arg1;
+ final int relevantEventTypes = msg.arg2;
+ final UserState userState;
+ synchronized (mLock) {
+ userState = getUserStateLocked(userId);
+ }
+ broadcastToClients(userState, (client) -> {
+ try {
+ client.setRelevantEventTypes(relevantEventTypes);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ });
+ } break;
}
}
@@ -2380,19 +2433,13 @@
private void sendStateToClients(int clientState,
RemoteCallbackList<IAccessibilityManagerClient> clients) {
- try {
- final int userClientCount = clients.beginBroadcast();
- for (int i = 0; i < userClientCount; i++) {
- IAccessibilityManagerClient client = clients.getBroadcastItem(i);
- try {
- client.setState(clientState);
- } catch (RemoteException re) {
- /* ignore */
- }
+ clients.broadcast((client) -> {
+ try {
+ client.setState(clientState);
+ } catch (RemoteException re) {
+ /* ignore */
}
- } finally {
- clients.finishBroadcast();
- }
+ });
}
private void notifyClientsOfServicesStateChange(
@@ -4710,6 +4757,8 @@
public final CopyOnWriteArrayList<Service> mBoundServices =
new CopyOnWriteArrayList<>();
+ public int mLastSentRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
+
public final Map<ComponentName, Service> mComponentNameToServiceMap =
new HashMap<>();
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
similarity index 88%
rename from services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
rename to services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index b90a2a2..a372f95 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -67,13 +67,13 @@
* Entry point service for autofill management.
*
* <p>This service provides the {@link IAutoFillManager} implementation and keeps a list of
- * {@link AutoFillManagerServiceImpl} per user; the real work is done by
- * {@link AutoFillManagerServiceImpl} itself.
+ * {@link AutofillManagerServiceImpl} per user; the real work is done by
+ * {@link AutofillManagerServiceImpl} itself.
*/
// TODO(b/33197203): Handle removing of packages
-public final class AutoFillManagerService extends SystemService {
+public final class AutofillManagerService extends SystemService {
- private static final String TAG = "AutoFillManagerService";
+ private static final String TAG = "AutofillManagerService";
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
@@ -83,7 +83,7 @@
private final Object mLock = new Object();
/**
- * Cache of {@link AutoFillManagerServiceImpl} per user id.
+ * Cache of {@link AutofillManagerServiceImpl} per user id.
* <p>
* It has to be mapped by user id because the same current user could have simultaneous sessions
* associated to different user profiles (for example, in a multi-window environment or when
@@ -97,7 +97,7 @@
*/
// TODO(b/33197203): Update the above comment
@GuardedBy("mLock")
- private SparseArray<AutoFillManagerServiceImpl> mServicesCache = new SparseArray<>();
+ private SparseArray<AutofillManagerServiceImpl> mServicesCache = new SparseArray<>();
// TODO(b/33197203): set a different max (or disable it) on low-memory devices.
private final LocalLog mRequestsHistory = new LocalLog(20);
@@ -115,7 +115,7 @@
}
};
- public AutoFillManagerService(Context context) {
+ public AutofillManagerService(Context context) {
super(context);
mContext = context;
mUi = new AutoFillUI(mContext);
@@ -157,10 +157,11 @@
*
* @return service instance.
*/
- @NonNull AutoFillManagerServiceImpl getServiceForUserLocked(int userId) {
- AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ @NonNull
+ AutofillManagerServiceImpl getServiceForUserLocked(int userId) {
+ AutofillManagerServiceImpl service = mServicesCache.get(userId);
if (service == null) {
- service = new AutoFillManagerServiceImpl(mContext, mLock,
+ service = new AutofillManagerServiceImpl(mContext, mLock,
mRequestsHistory, userId, mUi);
mServicesCache.put(userId, service);
}
@@ -174,7 +175,7 @@
final IBinder activityToken = getTopActivityForUser();
if (activityToken != null) {
synchronized (mLock) {
- final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ final AutofillManagerServiceImpl service = mServicesCache.get(userId);
if (service == null) {
Log.w(TAG, "handleSaveForUser(): no cached service for userId " + userId);
return;
@@ -258,7 +259,7 @@
* Removes a cached service for a given user.
*/
private void removeCachedServiceLocked(int userId) {
- final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ final AutofillManagerServiceImpl service = mServicesCache.get(userId);
if (service != null) {
mServicesCache.delete(userId);
service.destroyLocked();
@@ -269,7 +270,7 @@
* Updates a cached service for a given user.
*/
private void updateCachedServiceLocked(int userId) {
- AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ AutofillManagerServiceImpl service = mServicesCache.get(userId);
if (service != null) {
service.updateLocked();
}
@@ -299,7 +300,7 @@
@Override
public void setAuthenticationResult(Bundle data, IBinder activityToken, int userId) {
synchronized (mLock) {
- final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
service.setAuthenticationResultLocked(data, activityToken);
}
}
@@ -307,7 +308,7 @@
@Override
public void setHasCallback(IBinder activityToken, int userId, boolean hasIt) {
synchronized (mLock) {
- final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
service.setHasCallback(activityToken, hasIt);
}
}
@@ -319,7 +320,7 @@
// TODO(b/33197203): make sure it's called by resumed / focused activity
synchronized (mLock) {
- final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
+ final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
service.startSessionLocked(activityToken, windowToken, appCallback,
autofillId, bounds, value, hasCallback);
}
@@ -329,7 +330,7 @@
public void updateSession(IBinder activityToken, AutofillId id, Rect bounds,
AutofillValue value, int flags, int userId) {
synchronized (mLock) {
- final AutoFillManagerServiceImpl service = mServicesCache.get(
+ final AutofillManagerServiceImpl service = mServicesCache.get(
UserHandle.getCallingUserId());
if (service != null) {
service.updateSessionLocked(activityToken, id, bounds, value, flags);
@@ -340,7 +341,7 @@
@Override
public void finishSession(IBinder activityToken, int userId) {
synchronized (mLock) {
- final AutoFillManagerServiceImpl service = mServicesCache.get(
+ final AutofillManagerServiceImpl service = mServicesCache.get(
UserHandle.getCallingUserId());
if (service != null) {
service.finishSessionLocked(activityToken);
@@ -349,6 +350,17 @@
}
@Override
+ public void cancelSession(IBinder activityToken, int userId) {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = mServicesCache.get(
+ UserHandle.getCallingUserId());
+ if (service != null) {
+ service.cancelSessionLocked(activityToken);
+ }
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingPermission(
Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
@@ -366,7 +378,7 @@
pw.println(size);
for (int i = 0; i < size; i++) {
pw.print("\nService at index "); pw.println(i);
- final AutoFillManagerServiceImpl impl = mServicesCache.valueAt(i);
+ final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i);
impl.dumpLocked(" ", pw);
}
}
@@ -379,7 +391,7 @@
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
- (new AutoFillManagerServiceShellCommand(AutoFillManagerService.this)).exec(
+ (new AutofillManagerServiceShellCommand(AutofillManagerService.this)).exec(
this, in, out, err, args, callback, resultReceiver);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
similarity index 97%
rename from services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
rename to services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index e691623..b6c60d0 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -19,8 +19,8 @@
import static android.service.autofill.AutofillService.EXTRA_ACTIVITY_TOKEN;
import static android.service.voice.VoiceInteractionSession.KEY_RECEIVER_EXTRAS;
import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
-import static android.view.autofill.AutofillManager.FLAG_FOCUS_GAINED;
-import static android.view.autofill.AutofillManager.FLAG_FOCUS_LOST;
+import static android.view.autofill.AutofillManager.FLAG_VIEW_ENTERED;
+import static android.view.autofill.AutofillManager.FLAG_VIEW_EXITED;
import static android.view.autofill.AutofillManager.FLAG_START_SESSION;
import static android.view.autofill.AutofillManager.FLAG_VALUE_CHANGED;
@@ -77,13 +77,13 @@
import java.util.Map.Entry;
/**
- * Bridge between the {@code system_server}'s {@link AutoFillManagerService} and the
+ * Bridge between the {@code system_server}'s {@link AutofillManagerService} and the
* app's {@link IAutoFillService} implementation.
*
*/
-final class AutoFillManagerServiceImpl {
+final class AutofillManagerServiceImpl {
- private static final String TAG = "AutoFillManagerServiceImpl";
+ private static final String TAG = "AutofillManagerServiceImpl";
private static final int MSG_SERVICE_SAVE = 1;
@@ -173,7 +173,7 @@
}
};
- AutoFillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
+ AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
int userId, AutoFillUI ui) {
mContext = context;
mLock = lock;
@@ -240,7 +240,7 @@
}
/**
- * Used by {@link AutoFillManagerServiceShellCommand} to request save for the current top app.
+ * Used by {@link AutofillManagerServiceShellCommand} to request save for the current top app.
*/
void requestSaveForUserLocked(IBinder activityToken) {
if (!hasService()) {
@@ -321,6 +321,20 @@
session.showSaveLocked();
}
+ void cancelSessionLocked(IBinder activityToken) {
+ if (!hasService()) {
+ return;
+ }
+
+ final Session session = mSessions.get(activityToken);
+ if (session == null) {
+ Slog.w(TAG, "cancelSessionLocked(): no session for " + activityToken);
+ return;
+ }
+
+ session.destroyLocked();
+ }
+
private Session createSessionByTokenLocked(IBinder activityToken, IBinder windowToken,
IBinder appCallbackToken, boolean hasCallback) {
final Session newSession = new Session(mContext, activityToken,
@@ -457,7 +471,7 @@
@Override
public String toString() {
- return "AutoFillManagerServiceImpl: [userId=" + mUserId
+ return "AutofillManagerServiceImpl: [userId=" + mUserId
+ ", component=" + (mInfo != null
? mInfo.getServiceInfo().getComponentName() : null) + "]";
}
@@ -610,7 +624,7 @@
private AssistStructure mStructure;
/**
- * Whether the client has an {@link android.view.autofill.AutoFillManager.AutofillCallback}.
+ * Whether the client has an {@link android.view.autofill.AutofillManager.AutofillCallback}.
*/
private boolean mHasCallback;
@@ -905,7 +919,7 @@
return;
}
- if ((flags & FLAG_FOCUS_GAINED) != 0) {
+ if ((flags & FLAG_VIEW_ENTERED) != 0) {
// Remove the UI if the ViewState has changed.
if (mCurrentViewState != viewState) {
mUi.hideFillUi(mCurrentViewState != null ? mCurrentViewState.mId : null);
@@ -923,7 +937,7 @@
return;
}
- if ((flags & FLAG_FOCUS_LOST) != 0) {
+ if ((flags & FLAG_VIEW_EXITED) != 0) {
if (mCurrentViewState == viewState) {
mUi.hideFillUi(viewState.mId);
mCurrentViewState = null;
@@ -1001,7 +1015,7 @@
}
CharSequence getServiceName() {
- return AutoFillManagerServiceImpl.this.getServiceName();
+ return AutofillManagerServiceImpl.this.getServiceName();
}
private Intent createAuthFillInIntent(AssistStructure structure) {
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
similarity index 96%
rename from services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
rename to services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 76d9aea..80560f1 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -16,7 +16,7 @@
package com.android.server.autofill;
-import static com.android.server.autofill.AutoFillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS;
+import static com.android.server.autofill.AutofillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS;
import android.app.ActivityManager;
import android.os.Bundle;
@@ -30,11 +30,11 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-public final class AutoFillManagerServiceShellCommand extends ShellCommand {
+public final class AutofillManagerServiceShellCommand extends ShellCommand {
- private final AutoFillManagerService mService;
+ private final AutofillManagerService mService;
- public AutoFillManagerServiceShellCommand(AutoFillManagerService service) {
+ public AutofillManagerServiceShellCommand(AutofillManagerService service) {
mService = service;
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 76385b1..eeff37c 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -182,7 +182,7 @@
return;
}
if (!isBound()) {
- if (mPendingRequest != null && mPendingRequest != pendingRequest) {
+ if (mPendingRequest != null) {
mPendingRequest.cancel();
}
mPendingRequest = pendingRequest;
@@ -337,9 +337,10 @@
Slog.w(LOG_TAG, "Exception calling onConnected(): " + e);
}
-
if (mPendingRequest != null) {
- handlePendingRequest(mPendingRequest);
+ PendingRequest pendingRequest = mPendingRequest;
+ mPendingRequest = null;
+ handlePendingRequest(pendingRequest);
}
mServiceDied = false;
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 4a380c5..3fdcd9e 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -44,6 +44,8 @@
final class FillUi {
private static final String TAG = "FillUi";
+ private static final int VISIBLE_OPTIONS_MAX_COUNT = 3;
+
interface Callback {
void onResponsePicked(@NonNull FillResponse response);
void onDatasetPicked(@NonNull Dataset dataset);
@@ -56,6 +58,8 @@
private final @NonNull Callback mCallback;
+ private final @NonNull ListView mListView;
+
private final @Nullable ArrayAdapter<ViewItem> mAdapter;
private @Nullable String mFilterText;
@@ -73,6 +77,9 @@
mCallback = callback;
if (response.getAuthentication() != null) {
+ mListView = null;
+ mAdapter = null;
+
final View content;
try {
content = response.getPresentation().apply(context, null);
@@ -80,7 +87,6 @@
callback.onCanceled();
Slog.e(TAG, "Error inflating remote views", e);
mWindow = null;
- mAdapter = null;
return;
}
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
@@ -89,10 +95,9 @@
content.setOnClickListener(v -> mCallback.onResponsePicked(response));
mContentWidth = content.getMeasuredWidth();
mContentHeight = content.getMeasuredHeight();
- mAdapter = null;
mWindow = new AnchoredWindow(windowToken, content);
- mWindow.update(mContentWidth, mContentHeight, mAnchorBounds);
+ mWindow.show(mContentWidth, mContentHeight, mAnchorBounds);
} else {
final int datasetCount = response.getDatasets().size();
final ArrayList<ViewItem> items = new ArrayList<>(datasetCount);
@@ -121,16 +126,16 @@
};
final LayoutInflater inflater = LayoutInflater.from(context);
- final ListView listView = (ListView) inflater.inflate(
+ mListView = (ListView) inflater.inflate(
com.android.internal.R.layout.autofill_dataset_picker, null);
- listView.setAdapter(mAdapter);
- listView.setOnItemClickListener((adapter, view, position, id) -> {
+ mListView.setAdapter(mAdapter);
+ mListView.setOnItemClickListener((adapter, view, position, id) -> {
final ViewItem vi = mAdapter.getItem(position);
mCallback.onDatasetPicked(vi.getDataset());
});
filter(filterText);
- mWindow = new AnchoredWindow(windowToken, listView);
+ mWindow = new AnchoredWindow(windowToken, mListView);
}
}
@@ -138,7 +143,7 @@
throwIfDestroyed();
if (!mAnchorBounds.equals(anchorBounds)) {
mAnchorBounds.set(anchorBounds);
- mWindow.update(mContentWidth, mContentHeight, anchorBounds);
+ mWindow.show(mContentWidth, mContentHeight, anchorBounds);
}
}
@@ -156,10 +161,16 @@
return;
}
if (count <= 0) {
- mCallback.onCanceled();
+ mWindow.hide();
} else {
if (updateContentSize()) {
- mWindow.update(mContentWidth, mContentHeight, mAnchorBounds);
+ mWindow.show(mContentWidth, mContentHeight, mAnchorBounds);
+ }
+ if (mAdapter.getCount() > VISIBLE_OPTIONS_MAX_COUNT) {
+ mListView.setVerticalScrollBarEnabled(true);
+ mListView.onVisibilityAggregated(true);
+ } else {
+ mListView.setVerticalScrollBarEnabled(false);
}
}
});
@@ -167,7 +178,7 @@
public void destroy() {
throwIfDestroyed();
- mWindow.destroy();
+ mWindow.hide();
mDestroyed = true;
}
@@ -193,7 +204,7 @@
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
- final int itemCount = mAdapter.getCount();
+ final int itemCount = Math.min(mAdapter.getCount(), VISIBLE_OPTIONS_MAX_COUNT);
for (int i = 0; i < itemCount; i++) {
View view = mAdapter.getItem(i).getView();
view.measure(widthMeasureSpec, heightMeasureSpec);
@@ -266,7 +277,7 @@
/**
* Hides the window.
*/
- void destroy() {
+ void hide() {
if (mContentView.isAttachedToWindow()) {
mContentView.setOnTouchListener(null);
mWm.removeView(mContentView);
@@ -283,7 +294,7 @@
return false;
}
- public void update(int desiredWidth, int desiredHeight, Rect anchorBounds) {
+ public void show(int desiredWidth, int desiredHeight, Rect anchorBounds) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.setTitle("FillUi");
params.token = mActivityToken;
@@ -293,7 +304,6 @@
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
- params.format = PixelFormat.TRANSLUCENT;
mWm.getDefaultDisplay().getRealSize(mTempPoint);
final int screenWidth = mTempPoint.x;
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index de11f36..a5e357c 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -235,6 +235,7 @@
}
public AppOpsService(File storagePath, Handler handler) {
+ LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
mFile = new AtomicFile(storagePath);
mHandler = handler;
readState();
diff --git a/services/core/java/com/android/server/LockGuard.java b/services/core/java/com/android/server/LockGuard.java
index 3a381ae..b744917 100644
--- a/services/core/java/com/android/server/LockGuard.java
+++ b/services/core/java/com/android/server/LockGuard.java
@@ -53,10 +53,29 @@
* <li>A guarded synchronized block takes 50ns when disabled.
* <li>A guarded synchronized block takes 460ns per lock checked when enabled.
* </ul>
+ * <p>
+ * This class also supports a second simpler mode of operation where well-known
+ * locks are explicitly registered and checked via indexes.
*/
public class LockGuard {
private static final String TAG = "LockGuard";
+ public static final boolean ENABLED = false;
+
+ /**
+ * Well-known locks ordered by fixed index. Locks with a specific index
+ * should never be acquired while holding a lock of a lower index.
+ */
+ public static final int INDEX_APP_OPS = 0;
+ public static final int INDEX_POWER = 1;
+ public static final int INDEX_USER = 2;
+ public static final int INDEX_PACKAGES = 3;
+ public static final int INDEX_STORAGE = 4;
+ public static final int INDEX_WINDOW = 5;
+ public static final int INDEX_ACTIVITY = 6;
+
+ private static Object[] sKnownFixed = new Object[INDEX_ACTIVITY + 1];
+
private static ArrayMap<Object, LockInfo> sKnown = new ArrayMap<>(0, true);
private static class LockInfo {
@@ -119,11 +138,41 @@
}
/**
+ * Yell if any lower-level locks are being held by the calling thread that
+ * is about to acquire the given lock.
+ */
+ public static void guard(int index) {
+ for (int i = 0; i < index; i++) {
+ final Object lock = sKnownFixed[i];
+ if (lock != null && Thread.holdsLock(lock)) {
+ Slog.w(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding "
+ + lockToString(i) + " while trying to acquire "
+ + lockToString(index), new Throwable());
+ }
+ }
+ }
+
+ /**
* Report the given lock with a well-known label.
*/
- public static void installLock(Object lock, String label) {
+ public static Object installLock(Object lock, String label) {
final LockInfo info = findOrCreateLockInfo(lock);
info.label = label;
+ return lock;
+ }
+
+ /**
+ * Report the given lock with a well-known index.
+ */
+ public static Object installLock(Object lock, int index) {
+ sKnownFixed[index] = lock;
+ return lock;
+ }
+
+ public static Object installNewLock(int index) {
+ final Object lock = new Object();
+ installLock(lock, index);
+ return lock;
}
private static String lockToString(Object lock) {
@@ -135,6 +184,19 @@
}
}
+ private static String lockToString(int index) {
+ switch (index) {
+ case INDEX_APP_OPS: return "APP_OPS";
+ case INDEX_POWER: return "POWER";
+ case INDEX_USER: return "USER";
+ case INDEX_PACKAGES: return "PACKAGES";
+ case INDEX_STORAGE: return "STORAGE";
+ case INDEX_WINDOW: return "WINDOW";
+ case INDEX_ACTIVITY: return "ACTIVITY";
+ default: return Integer.toString(index);
+ }
+ }
+
public static void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
for (int i = 0; i < sKnown.size(); i++) {
final Object lock = sKnown.keyAt(i);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1f544a0..3667ecd 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -308,7 +308,7 @@
* <em>Never</em> hold the lock while performing downcalls into vold, since
* unsolicited events can suddenly appear to update data structures.
*/
- private final Object mLock = new Object();
+ private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_STORAGE);
/** Set of users that we know are unlocked. */
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5a6d9aa..9dc59cb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -691,6 +691,9 @@
Process.setThreadPriority(tid, -2);
}
state.regionCounter++;
+ if (LockGuard.ENABLED) {
+ LockGuard.guard(LockGuard.INDEX_ACTIVITY);
+ }
}
static void resetPriorityAfterLockedSection() {
@@ -2657,6 +2660,7 @@
// Note: This method is invoked on the main thread but may need to attach various
// handlers to other threads. So take care to be explicit about the looper.
public ActivityManagerService(Context systemContext) {
+ LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY);
mContext = systemContext;
mFactoryTest = FactoryTest.getMode();
mSystemThread = ActivityThread.currentActivityThread();
@@ -8533,13 +8537,21 @@
// Third... does the caller itself have permission to access
// this uri?
- if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
- if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
- // Require they hold a strong enough Uri permission
- if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) {
- throw new SecurityException("Uid " + callingUid
- + " does not have permission to uri " + grantUri);
- }
+ final int callingAppId = UserHandle.getAppId(callingUid);
+ if ((callingAppId == Process.SYSTEM_UID) || (callingAppId == Process.ROOT_UID)) {
+ if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) {
+ // Exempted authority for cropping user photos in Settings app
+ } else {
+ Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
+ + " grant to " + grantUri + "; use startActivityAsCaller() instead");
+ return -1;
+ }
+ }
+ if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
+ // Require they hold a strong enough Uri permission
+ if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) {
+ throw new SecurityException("Uid " + callingUid
+ + " does not have permission to uri " + grantUri);
}
}
return targetUid;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index d81e092..a50ec49f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -72,7 +72,8 @@
@ServiceThreadOnly
private boolean mArcEstablished = false;
- // Stores whether ARC feature is enabled per port. True by default for all the ARC-enabled ports.
+ // Stores whether ARC feature is enabled per port.
+ // True by default for all the ARC-enabled ports.
private final SparseBooleanArray mArcFeatureEnabled = new SparseBooleanArray();
// Whether System audio mode is activated or not.
@@ -80,6 +81,10 @@
@GuardedBy("mLock")
private boolean mSystemAudioActivated = false;
+ // Whether the System Audio Control feature is enabled or not. True by default.
+ @GuardedBy("mLock")
+ private boolean mSystemAudioControlFeatureEnabled;
+
// The previous port id (input) before switching to the new one. This is remembered in order to
// be able to switch to it upon receiving <Inactive Source> from currently active source.
// This remains valid only when the active source was switched via one touch play operation
@@ -186,6 +191,8 @@
mAutoDeviceOff = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
true);
mAutoWakeup = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, true);
+ mSystemAudioControlFeatureEnabled =
+ mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
mStandbyHandler = new HdmiCecStandbyModeHandler(service, this);
}
@@ -778,14 +785,11 @@
addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
addAndStartAction(new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this));
- // If there is AVR, initiate System Audio Auto initiation action,
- // which turns on and off system audio according to last system
- // audio setting.
HdmiDeviceInfo avr = getAvrDeviceInfo();
if (avr != null) {
onNewAvrAdded(avr);
} else {
- setSystemAudioMode(false, true);
+ setSystemAudioMode(false);
}
}
});
@@ -818,13 +822,13 @@
void changeSystemAudioMode(boolean enabled, IHdmiControlCallback callback) {
assertRunOnServiceThread();
if (!mService.isControlEnabled() || hasAction(DeviceDiscoveryAction.class)) {
- setSystemAudioMode(false, true);
+ setSystemAudioMode(false);
invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
return;
}
HdmiDeviceInfo avr = getAvrDeviceInfo();
if (avr == null) {
- setSystemAudioMode(false, true);
+ setSystemAudioMode(false);
invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
return;
}
@@ -834,12 +838,13 @@
}
// # Seq 25
- void setSystemAudioMode(boolean on, boolean updateSetting) {
- HdmiLogger.debug("System Audio Mode change[old:%b new:%b]", mSystemAudioActivated, on);
-
- if (updateSetting) {
- mService.writeBooleanSetting(Global.HDMI_SYSTEM_AUDIO_ENABLED, on);
+ void setSystemAudioMode(boolean on) {
+ if (!isSystemAudioControlFeatureEnabled() && on) {
+ HdmiLogger.debug("Cannot turn on system audio mode "
+ + "because the System Audio Control feature is disabled.");
+ return;
}
+ HdmiLogger.debug("System Audio Mode change[old:%b new:%b]", mSystemAudioActivated, on);
updateAudioManagerForSystemAudio(on);
synchronized (mLock) {
if (mSystemAudioActivated != on) {
@@ -863,8 +868,21 @@
}
}
- boolean getSystemAudioModeSetting() {
- return mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_ENABLED, false);
+ @ServiceThreadOnly
+ void setSystemAudioControlFeatureEnabled(boolean enabled) {
+ assertRunOnServiceThread();
+ synchronized (mLock) {
+ mSystemAudioControlFeatureEnabled = enabled;
+ }
+ if (hasSystemAudioDevice()) {
+ changeSystemAudioMode(enabled, null);
+ }
+ }
+
+ boolean isSystemAudioControlFeatureEnabled() {
+ synchronized (mLock) {
+ return mSystemAudioControlFeatureEnabled;
+ }
}
/**
@@ -1112,6 +1130,7 @@
@ServiceThreadOnly
protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
assertRunOnServiceThread();
+ boolean systemAudioStatus = HdmiUtils.parseCommandParamSystemAudioStatus(message);
if (!isMessageForSystemAudio(message)) {
if (getAvrDeviceInfo() == null) {
// AVR may not have been discovered yet. Delay the message processing.
@@ -1121,10 +1140,15 @@
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
}
return true;
+ } else if (systemAudioStatus && !isSystemAudioControlFeatureEnabled()) {
+ HdmiLogger.debug("Ignoring <Set System Audio Mode> message "
+ + "because the System Audio Control feature is disabled: %s", message);
+ mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+ return true;
}
removeAction(SystemAudioAutoInitiationAction.class);
SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this,
- message.getSource(), HdmiUtils.parseCommandParamSystemAudioStatus(message), null);
+ message.getSource(), systemAudioStatus, null);
addAndStartAction(action);
return true;
}
@@ -1138,7 +1162,7 @@
// Ignore this message.
return true;
}
- setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message), true);
+ setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message));
return true;
}
@@ -1882,6 +1906,7 @@
pw.println("mArcFeatureEnabled: " + mArcFeatureEnabled);
pw.println("mSystemAudioActivated: " + mSystemAudioActivated);
pw.println("mSystemAudioMute: " + mSystemAudioMute);
+ pw.println("mSystemAudioControlFeatureEnabled: " + mSystemAudioControlFeatureEnabled);
pw.println("mAutoDeviceOff: " + mAutoDeviceOff);
pw.println("mAutoWakeup: " + mAutoWakeup);
pw.println("mSkipRoutingControl: " + mSkipRoutingControl);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 89b10ac..6864e1e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -486,7 +486,7 @@
Global.HDMI_CONTROL_ENABLED,
Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
- Global.HDMI_SYSTEM_AUDIO_ENABLED,
+ Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Global.MHL_INPUT_SWITCHING_ENABLED,
Global.MHL_POWER_CHARGE_ENABLED
};
@@ -525,9 +525,9 @@
}
// No need to propagate to HAL.
break;
- case Global.HDMI_SYSTEM_AUDIO_ENABLED:
- if (isTvDeviceEnabled() && tv().isSystemAudioActivated() != enabled) {
- tv().changeSystemAudioMode(enabled, null);
+ case Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED:
+ if (isTvDeviceEnabled()) {
+ tv().setSystemAudioControlFeatureEnabled(enabled);
}
break;
case Global.MHL_INPUT_SWITCHING_ENABLED:
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index e1bcd99..7670dcc 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -262,8 +262,7 @@
return;
}
- // Turn off system audio mode and update settings.
- tv().setSystemAudioMode(false, true);
+ tv().setSystemAudioMode(false);
if (tv().isArcEstablished()) {
tv().enableAudioReturnChannel(false);
addAndStartAction(new RequestArcTerminationAction(localDevice(), address));
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index af1a85d..449b208 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -133,7 +133,7 @@
}
protected void setSystemAudioMode(boolean mode) {
- tv().setSystemAudioMode(mode, true);
+ tv().setSystemAudioMode(mode);
}
@Override
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index 01063b7..d347a91 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -50,7 +50,7 @@
@Override
public void onSendCompleted(int error) {
if (error != SendMessageResult.SUCCESS) {
- tv().setSystemAudioMode(false, true);
+ tv().setSystemAudioMode(false);
finish();
}
}
@@ -71,18 +71,24 @@
return false;
}
- private void handleSystemAudioModeStatusMessage(boolean isSystemAudioModeOn) {
+ private void handleSystemAudioModeStatusMessage(boolean currentSystemAudioMode) {
if (!canChangeSystemAudio()) {
HdmiLogger.debug("Cannot change system audio mode in auto initiation action.");
finish();
return;
}
- boolean systemAudioModeSetting = tv().getSystemAudioModeSetting();
- if (systemAudioModeSetting && !isSystemAudioModeOn) {
- addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, systemAudioModeSetting, null));
+ // If System Audio Control feature is enabled, turn on system audio mode when new AVR is
+ // detected. Otherwise, turn off system audio mode.
+ boolean targetSystemAudioMode = tv().isSystemAudioControlFeatureEnabled();
+ if (currentSystemAudioMode != targetSystemAudioMode) {
+ // Start System Audio Control feature actions only if necessary.
+ addAndStartAction(
+ new SystemAudioActionFromTv(tv(), mAvrAddress, targetSystemAudioMode, null));
} else {
- tv().setSystemAudioMode(isSystemAudioModeOn, true);
+ // If AVR already has correct system audio mode, update target system audio mode
+ // immediately rather than starting feature action.
+ tv().setSystemAudioMode(targetSystemAudioMode);
}
finish();
}
@@ -101,13 +107,15 @@
}
private void handleSystemAudioModeStatusTimeout() {
- if (tv().getSystemAudioModeSetting()) {
- if (canChangeSystemAudio()) {
- addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress, true, null));
- }
- } else {
- tv().setSystemAudioMode(false, true);
+ if (!canChangeSystemAudio()) {
+ HdmiLogger.debug("Cannot change system audio mode in auto initiation action.");
+ finish();
+ return;
}
+ // If we can't get the current system audio mode status, just try to turn on/off system
+ // audio mode according to the system audio control setting.
+ addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress,
+ tv().isSystemAudioControlFeatureEnabled(), null));
finish();
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 6365d15..bb7ffda 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -207,9 +207,35 @@
}
public void grantDefaultPermissions(int userId) {
- grantPermissionsToSysComponentsAndPrivApps(userId);
- grantDefaultSystemHandlerPermissions(userId);
- grantDefaultPermissionExceptions(userId);
+ if (mService.hasSystemFeature(PackageManager.FEATURE_EMBEDDED, 0)) {
+ grantAllRuntimePermissions(userId);
+ } else {
+ grantPermissionsToSysComponentsAndPrivApps(userId);
+ grantDefaultSystemHandlerPermissions(userId);
+ grantDefaultPermissionExceptions(userId);
+ }
+ }
+
+ private void grantRuntimePermissionsForPackageLocked(int userId, PackageParser.Package pkg) {
+ Set<String> permissions = new ArraySet<>();
+ for (String permission : pkg.requestedPermissions) {
+ BasePermission bp = mService.mSettings.mPermissions.get(permission);
+ if (bp != null && bp.isRuntime()) {
+ permissions.add(permission);
+ }
+ }
+ if (!permissions.isEmpty()) {
+ grantRuntimePermissionsLPw(pkg, permissions, true, userId);
+ }
+ }
+
+ private void grantAllRuntimePermissions(int userId) {
+ Log.i(TAG, "Granting all runtime permissions for user " + userId);
+ synchronized (mService.mPackages) {
+ for (PackageParser.Package pkg : mService.mPackages.values()) {
+ grantRuntimePermissionsForPackageLocked(userId, pkg);
+ }
+ }
}
public void scheduleReadDefaultPermissionExceptions() {
@@ -226,18 +252,7 @@
|| pkg.requestedPermissions.isEmpty()) {
continue;
}
- Set<String> permissions = new ArraySet<>();
- final int permissionCount = pkg.requestedPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- String permission = pkg.requestedPermissions.get(i);
- BasePermission bp = mService.mSettings.mPermissions.get(permission);
- if (bp != null && bp.isRuntime()) {
- permissions.add(permission);
- }
- }
- if (!permissions.isEmpty()) {
- grantRuntimePermissionsLPw(pkg, permissions, true, userId);
- }
+ grantRuntimePermissionsForPackageLocked(userId, pkg);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e8af310..c27806d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -266,6 +266,7 @@
import com.android.server.FgThread;
import com.android.server.IntentResolver;
import com.android.server.LocalServices;
+import com.android.server.LockGuard;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.SystemServerInitThreadPool;
@@ -2212,6 +2213,7 @@
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
+ LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 627fa54..b9fcf4e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -94,6 +94,7 @@
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
+import com.android.server.LockGuard;
import com.android.server.SystemService;
import com.android.server.am.UserState;
import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -227,7 +228,7 @@
private final Object mPackagesLock;
private final UserDataPreparer mUserDataPreparer;
// Short-term lock for internal state, when interaction/sync with PM is not required
- private final Object mUsersLock = new Object();
+ private final Object mUsersLock = LockGuard.installNewLock(LockGuard.INDEX_USER);
private final Object mRestrictionsLock = new Object();
private final Handler mHandler;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 24f6f89..4f67e8c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -76,6 +76,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.server.EventLogTags;
+import com.android.server.LockGuard;
import com.android.server.RescueParty;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
@@ -210,7 +211,7 @@
private DreamManagerInternal mDreamManager;
private Light mAttentionLight;
- private final Object mLock = new Object();
+ private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_POWER);
// A bitfield that indicates what parts of the power state have
// changed and need to be recalculated.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3e9f2a8..f9c4efd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -213,6 +213,7 @@
import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.LockGuard;
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.input.InputManagerService;
@@ -940,6 +941,7 @@
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
+ LockGuard.installLock(this, LockGuard.INDEX_WINDOW);
mRoot = new RootWindowContainer(this);
mContext = context;
mHaveInputMethods = haveInputMethods;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1a0aff7..a8423e2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -195,7 +195,7 @@
private static final String WALLPAPER_SERVICE_CLASS =
"com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
private static final String AUTO_FILL_MANAGER_SERVICE_CLASS =
- "com.android.server.autofill.AutoFillManagerService";
+ "com.android.server.autofill.AutofillManagerService";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
index 60842a6..340c624 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
@@ -34,6 +34,8 @@
import android.view.accessibility.IAccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
+import com.android.internal.util.IntPair;
+
/**
* This test exercises the
* {@link com.android.server.accessibility.AccessibilityManagerService} by mocking the
@@ -109,7 +111,7 @@
// invoke the method under test
final int stateFlagsDisabled =
- mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
+ IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
boolean enabledAccessibilityDisabled =
(stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
@@ -122,7 +124,7 @@
// invoke the method under test
final int stateFlagsEnabled =
- mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
+ IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
boolean enabledAccessibilityEnabled =
(stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
@@ -144,7 +146,7 @@
// invoke the method under test
final int stateFlagsEnabled =
- mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
+ IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
boolean enabledAccessibilityEnabled =
(stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
@@ -157,7 +159,7 @@
// invoke the method under test
final int stateFlagsDisabled =
- mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
+ IntPair.first(mManagerService.addClient(mockClient, UserHandle.USER_CURRENT));
boolean enabledAccessibilityDisabled =
(stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
@@ -572,8 +574,9 @@
public void notifyServicesStateChanged() {}
- public void setTouchExplorationEnabled(boolean enabled) {
- }
+ public void setRelevantEventTypes(int eventTypes) {}
+
+ public void setTouchExplorationEnabled(boolean enabled) {}
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
index 6e3e6c6..9261771 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
@@ -18,7 +18,6 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,6 +31,8 @@
import android.view.accessibility.IAccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
+import com.android.internal.util.IntPair;
+
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -60,10 +61,12 @@
private AccessibilityManager createManager(boolean enabled) throws Exception {
if (enabled) {
when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
- .thenReturn(AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
+ .thenReturn(
+ IntPair.of(AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
+ AccessibilityEvent.TYPES_ALL_MASK));
} else {
when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
- .thenReturn(0);
+ .thenReturn(IntPair.of(0, AccessibilityEvent.TYPES_ALL_MASK));
}
AccessibilityManager manager =
diff --git a/tests/net/java/android/net/ip/IpManagerTest.java b/tests/net/java/android/net/ip/IpManagerTest.java
new file mode 100644
index 0000000..025b017
--- /dev/null
+++ b/tests/net/java/android/net/ip/IpManagerTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.INetworkManagementService;
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.mock.MockContentResolver;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.R;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for IpManager.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpManagerTest {
+ private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
+
+ @Mock private Context mContext;
+ @Mock private INetworkManagementService mNMService;
+ @Mock private Resources mResources;
+ private MockContentResolver mContentResolver;
+
+ @Before public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
+ .thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
+
+ mContentResolver = new MockContentResolver();
+ mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ }
+
+ @Test
+ public void testNullCallbackDoesNotThrow() throws Exception {
+ final IpManager ipm = new IpManager(mContext, "lo", null, mNMService);
+ }
+
+ @Test
+ public void testInvalidInterfaceDoesNotThrow() throws Exception {
+ final IpManager.Callback cb = new IpManager.Callback();
+ final IpManager ipm = new IpManager(mContext, "test_wlan0", cb, mNMService);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/accessibility/AccessibilityManager.java b/tools/layoutlib/bridge/src/android/view/accessibility/AccessibilityManager.java
index 3ce7cab..672ff6d 100644
--- a/tools/layoutlib/bridge/src/android/view/accessibility/AccessibilityManager.java
+++ b/tools/layoutlib/bridge/src/android/view/accessibility/AccessibilityManager.java
@@ -95,6 +95,9 @@
public void notifyServicesStateChanged() {
}
+
+ public void setRelevantEventTypes(int eventTypes) {
+ }
};
/**