Merge "Incremental local builds for services"
diff --git a/api/current.txt b/api/current.txt
index daac1ba..537ae8a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2625,6 +2625,7 @@
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+ method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -2683,6 +2684,18 @@
method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.SoftKeyboardController {
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+ method public int getShowMode();
+ method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public boolean setShowMode(int);
+ }
+
+ public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+ method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+ }
+
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
method public static java.lang.String capabilityToString(int);
@@ -5824,6 +5837,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
@@ -5893,6 +5907,7 @@
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.String);
method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -22898,6 +22913,7 @@
method public void onInputAdded(java.lang.String);
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
+ method public void onInputUpdated(java.lang.String);
method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
@@ -51314,6 +51330,9 @@
public abstract class Inherited implements java.lang.annotation.Annotation {
}
+ public abstract class Repeatable implements java.lang.annotation.Annotation {
+ }
+
public abstract class Retention implements java.lang.annotation.Annotation {
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 06187504..1091ff1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2727,6 +2727,7 @@
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+ method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -2785,6 +2786,18 @@
method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.SoftKeyboardController {
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+ method public int getShowMode();
+ method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public boolean setShowMode(int);
+ }
+
+ public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+ method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+ }
+
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
method public static java.lang.String capabilityToString(int);
@@ -5964,6 +5977,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
@@ -6039,6 +6053,7 @@
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.String);
method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -54068,6 +54083,9 @@
public abstract class Inherited implements java.lang.annotation.Annotation {
}
+ public abstract class Repeatable implements java.lang.annotation.Annotation {
+ }
+
public abstract class Retention implements java.lang.annotation.Annotation {
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 684b385..09a9cca 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2625,6 +2625,7 @@
method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+ method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -2683,6 +2684,18 @@
method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
}
+ public static final class AccessibilityService.SoftKeyboardController {
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+ method public int getShowMode();
+ method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+ method public boolean setShowMode(int);
+ }
+
+ public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+ method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+ }
+
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
method public static java.lang.String capabilityToString(int);
@@ -5826,6 +5839,7 @@
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
+ method public java.lang.String getOrganizationName(android.content.ComponentName);
method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
@@ -5895,6 +5909,7 @@
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setOrganizationColor(android.content.ComponentName, int);
+ method public void setOrganizationName(android.content.ComponentName, java.lang.String);
method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -22907,6 +22922,7 @@
method public void onInputAdded(java.lang.String);
method public void onInputRemoved(java.lang.String);
method public void onInputStateChanged(java.lang.String, int);
+ method public void onInputUpdated(java.lang.String);
method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
}
@@ -51331,6 +51347,9 @@
public abstract class Inherited implements java.lang.annotation.Annotation {
}
+ public abstract class Repeatable implements java.lang.annotation.Annotation {
+ }
+
public abstract class Retention implements java.lang.annotation.Annotation {
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index be93926..c96cca2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -17,6 +17,7 @@
package android.accessibilityservice;
import android.accessibilityservice.GestureDescription.MotionEventGenerator;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
@@ -29,6 +30,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
@@ -46,6 +48,8 @@
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -363,9 +367,26 @@
public boolean onKeyEvent(KeyEvent event);
public void onMagnificationChanged(@NonNull Region region,
float scale, float centerX, float centerY);
+ public void onSoftKeyboardShowModeChanged(int showMode);
public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
}
+ /**
+ * Annotations for Soft Keyboard show modes so tools can catch invalid show modes.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SHOW_MODE_AUTO, SHOW_MODE_HIDDEN})
+ public @interface SoftKeyboardShowMode {};
+ /**
+ * @hide
+ */
+ public static final int SHOW_MODE_AUTO = 0;
+ /**
+ * @hide
+ */
+ public static final int SHOW_MODE_HIDDEN = 1;
+
private int mConnectionId;
private AccessibilityServiceInfo mInfo;
@@ -375,6 +396,7 @@
private WindowManager mWindowManager;
private MagnificationController mMagnificationController;
+ private SoftKeyboardController mSoftKeyboardController;
private int mGestureStatusCallbackSequence;
@@ -563,10 +585,12 @@
*/
@NonNull
public final MagnificationController getMagnificationController() {
- if (mMagnificationController == null) {
- mMagnificationController = new MagnificationController(this);
+ synchronized (mLock) {
+ if (mMagnificationController == null) {
+ mMagnificationController = new MagnificationController(this, mLock);
+ }
+ return mMagnificationController;
}
- return mMagnificationController;
}
/**
@@ -670,17 +694,21 @@
* first magnification listener.
*/
private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
+ private final Object mLock;
- MagnificationController(@NonNull AccessibilityService service) {
+ MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock) {
mService = service;
+ mLock = lock;
}
/**
* Called when the service is connected.
*/
void onServiceConnected() {
- if (mListeners != null && !mListeners.isEmpty()) {
- setMagnificationCallbackEnabled(true);
+ synchronized (mLock) {
+ if (mListeners != null && !mListeners.isEmpty()) {
+ setMagnificationCallbackEnabled(true);
+ }
}
}
@@ -707,17 +735,19 @@
*/
public void addListener(@NonNull OnMagnificationChangedListener listener,
@Nullable Handler handler) {
- if (mListeners == null) {
- mListeners = new ArrayMap<>();
- }
+ synchronized (mLock) {
+ if (mListeners == null) {
+ mListeners = new ArrayMap<>();
+ }
- final boolean shouldEnableCallback = mListeners.isEmpty();
- mListeners.put(listener, handler);
+ final boolean shouldEnableCallback = mListeners.isEmpty();
+ mListeners.put(listener, handler);
- if (shouldEnableCallback) {
- // This may fail if the service is not connected yet, but if we
- // still have listeners when it connects then we can try again.
- setMagnificationCallbackEnabled(true);
+ if (shouldEnableCallback) {
+ // This may fail if the service is not connected yet, but if we
+ // still have listeners when it connects then we can try again.
+ setMagnificationCallbackEnabled(true);
+ }
}
}
@@ -734,19 +764,21 @@
return false;
}
- final int keyIndex = mListeners.indexOfKey(listener);
- final boolean hasKey = keyIndex >= 0;
- if (hasKey) {
- mListeners.removeAt(keyIndex);
- }
+ synchronized (mLock) {
+ final int keyIndex = mListeners.indexOfKey(listener);
+ final boolean hasKey = keyIndex >= 0;
+ if (hasKey) {
+ mListeners.removeAt(keyIndex);
+ }
- if (hasKey && mListeners.isEmpty()) {
- // We just removed the last listener, so we don't need
- // callbacks from the service anymore.
- setMagnificationCallbackEnabled(false);
- }
+ if (hasKey && mListeners.isEmpty()) {
+ // We just removed the last listener, so we don't need
+ // callbacks from the service anymore.
+ setMagnificationCallbackEnabled(false);
+ }
- return hasKey;
+ return hasKey;
+ }
}
private void setMagnificationCallbackEnabled(boolean enabled) {
@@ -768,17 +800,19 @@
*/
void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
final float centerX, final float centerY) {
- if (mListeners == null || mListeners.isEmpty()) {
- Slog.d(LOG_TAG, "Received magnification changed "
- + "callback with no listeners registered!");
- setMagnificationCallbackEnabled(false);
- return;
- }
+ final ArrayMap<OnMagnificationChangedListener, Handler> entries;
+ synchronized (mLock) {
+ if (mListeners == null || mListeners.isEmpty()) {
+ Slog.d(LOG_TAG, "Received magnification changed "
+ + "callback with no listeners registered!");
+ setMagnificationCallbackEnabled(false);
+ return;
+ }
- // Listeners may remove themselves. Perform a shallow copy to avoid
- // concurrent modification.
- final ArrayMap<OnMagnificationChangedListener, Handler> entries =
- new ArrayMap<>(mListeners);
+ // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mListeners);
+ }
for (int i = 0, count = entries.size(); i < count; i++) {
final OnMagnificationChangedListener listener = entries.keyAt(i);
@@ -1011,6 +1045,243 @@
}
/**
+ * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard
+ * show mode.
+ *
+ * @return the soft keyboard controller
+ */
+ @NonNull
+ public final SoftKeyboardController getSoftKeyboardController() {
+ synchronized (mLock) {
+ if (mSoftKeyboardController == null) {
+ mSoftKeyboardController = new SoftKeyboardController(this, mLock);
+ }
+ return mSoftKeyboardController;
+ }
+ }
+
+ private void onSoftKeyboardShowModeChanged(int showMode) {
+ if (mSoftKeyboardController != null) {
+ mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
+ }
+ }
+
+ /**
+ * Used to control and query the soft keyboard show mode.
+ */
+ public static final class SoftKeyboardController {
+ private final AccessibilityService mService;
+
+ /**
+ * Map of listeners to their handlers. Lazily created when adding the first
+ * soft keyboard change listener.
+ */
+ private ArrayMap<OnShowModeChangedListener, Handler> mListeners;
+ private final Object mLock;
+
+ SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) {
+ mService = service;
+ mLock = lock;
+ }
+
+ /**
+ * Called when the service is connected.
+ */
+ void onServiceConnected() {
+ synchronized(mLock) {
+ if (mListeners != null && !mListeners.isEmpty()) {
+ setSoftKeyboardCallbackEnabled(true);
+ }
+ }
+ }
+
+ /**
+ * Adds the specified change listener to the list of show mode change listeners. The
+ * callback will occur on the service's main thread. Listener is not called on registration.
+ */
+ public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
+ addOnShowModeChangedListener(listener, null);
+ }
+
+ /**
+ * Adds the specified change listener to the list of soft keyboard show mode change
+ * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the
+ * services's main thread if the handler is {@code null}.
+ *
+ * @param listener the listener to add, must be non-null
+ * @param handler the handler on which to callback should execute, or {@code null} to
+ * execute on the service's main thread
+ */
+ public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener,
+ @Nullable Handler handler) {
+ synchronized (mLock) {
+ if (mListeners == null) {
+ mListeners = new ArrayMap<>();
+ }
+
+ final boolean shouldEnableCallback = mListeners.isEmpty();
+ mListeners.put(listener, handler);
+
+ if (shouldEnableCallback) {
+ // This may fail if the service is not connected yet, but if we still have
+ // listeners when it connects, we can try again.
+ setSoftKeyboardCallbackEnabled(true);
+ }
+ }
+ }
+
+ /**
+ * Removes all instances of the specified change listener from teh list of magnification
+ * change listeners.
+ *
+ * @param listener the listener to remove, must be non-null
+ * @return {@code true} if at least one instance of the listener was removed
+ */
+ public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
+ if (mListeners == null) {
+ return false;
+ }
+
+ synchronized (mLock) {
+ final int keyIndex = mListeners.indexOfKey(listener);
+ final boolean hasKey = keyIndex >= 0;
+ if (hasKey) {
+ mListeners.removeAt(keyIndex);
+ }
+
+ if (hasKey && mListeners.isEmpty()) {
+ // We just removed the last listener, so we don't need callbacks from the
+ // service anymore.
+ setSoftKeyboardCallbackEnabled(false);
+ }
+
+ return hasKey;
+ }
+ }
+
+ private void setSoftKeyboardCallbackEnabled(boolean enabled) {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(
+ mService.mConnectionId);
+ if (connection != null) {
+ try {
+ connection.setSoftKeyboardCallbackEnabled(enabled);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ /**
+ * Dispatches the soft keyboard show mode change to any registered listeners. This should
+ * be called on the service's main thread.
+ */
+ void dispatchSoftKeyboardShowModeChanged(final int showMode) {
+ final ArrayMap<OnShowModeChangedListener, Handler> entries;
+ synchronized (mLock) {
+ if (mListeners == null || mListeners.isEmpty()) {
+ Slog.d(LOG_TAG, "Received soft keyboard show mode changed callback"
+ + " with no listeners registered!");
+ setSoftKeyboardCallbackEnabled(false);
+ return;
+ }
+
+ // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+ // modification.
+ entries = new ArrayMap<>(mListeners);
+ }
+
+ for (int i = 0, count = entries.size(); i < count; i++) {
+ final OnShowModeChangedListener listener = entries.keyAt(i);
+ final Handler handler = entries.valueAt(i);
+ if (handler != null) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ listener.onShowModeChanged(SoftKeyboardController.this, showMode);
+ }
+ });
+ } else {
+ // We're already on the main thread, just run the listener.
+ listener.onShowModeChanged(this, showMode);
+ }
+ }
+ }
+
+ /**
+ * Returns the show mode of the soft keyboard. The default show mode is
+ * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+ * input field is focused. An AccessibilityService can also request the show mode
+ * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+ *
+ * @return the current soft keyboard show mode
+ *
+ * @see Settings#Secure#SHOW_MODE_AUTO
+ * @see Settings#Secure#SHOW_MODE_HIDDEN
+ */
+ @SoftKeyboardShowMode
+ public int getShowMode() {
+ try {
+ return Settings.Secure.getInt(mService.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+ } catch (Settings.SettingNotFoundException e) {
+ Log.v(LOG_TAG, "Failed to obtain the soft keyboard mode", e);
+ // The settings hasn't been changed yet, so it's value is null. Return the default.
+ return 0;
+ }
+ }
+
+ /**
+ * Sets the soft keyboard show mode. The default show mode is
+ * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+ * input field is focused. An AccessibilityService can also request the show mode
+ * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
+ * The lastto this method will be honored, regardless of any previous calls (including those
+ * made by other AccessibilityServices).
+ * <p>
+ * <strong>Note:</strong> If the service is not yet conected (e.g.
+ * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
+ * service has been disconnected, this method will hav no effect and return {@code false}.
+ *
+ * @param showMode the new show mode for the soft keyboard
+ * @return {@code true} on success
+ *
+ * @see Settings#Secure#SHOW_MODE_AUTO
+ * @see Settings#Secure#SHOW_MODE_HIDDEN
+ */
+ public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(
+ mService.mConnectionId);
+ if (connection != null) {
+ try {
+ return connection.setSoftKeyboardShowMode(showMode);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Falied to set soft keyboard behavior", re);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Listener for changes in the soft keyboard show mode.
+ */
+ public interface OnShowModeChangedListener {
+ /**
+ * Called when the soft keyboard behavior changes. The default show mode is
+ * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+ * input field is focused. An AccessibilityService can also request the show mode
+ * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+ *
+ * @param controller the soft keyboard controller
+ * @param showMode the current soft keyboard show mode
+ */
+ void onShowModeChanged(@NonNull SoftKeyboardController controller,
+ @SoftKeyboardShowMode int showMode);
+ }
+ }
+
+ /**
* Performs a global action. Such an action can be performed
* at any moment regardless of the current application or user
* location in that application. For example going back, going
@@ -1184,6 +1455,11 @@
}
@Override
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
+ }
+
+ @Override
public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
}
@@ -1205,7 +1481,8 @@
private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
private static final int DO_ON_KEY_EVENT = 6;
private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
- private static final int DO_GESTURE_COMPLETE = 8;
+ private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
+ private static final int DO_GESTURE_COMPLETE = 9;
private final HandlerCaller mCaller;
@@ -1264,6 +1541,12 @@
mCaller.sendMessage(message);
}
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ final Message message =
+ mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode);
+ mCaller.sendMessage(message);
+ }
+
public void onPerformGestureResult(int sequence, boolean successfully) {
Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
successfully ? 1 : 0);
@@ -1354,6 +1637,11 @@
mCallback.onMagnificationChanged(region, scale, centerX, centerY);
} return;
+ case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
+ final int showMode = (int) message.arg1;
+ mCallback.onSoftKeyboardShowModeChanged(showMode);
+ } return;
+
case DO_GESTURE_COMPLETE: {
final boolean successfully = message.arg2 == 1;
mCallback.onPerformGestureResult(message.arg1, successfully);
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 6280542..ef05d6f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -43,5 +43,7 @@
void onMagnificationChanged(in Region region, float scale, float centerX, float centerY);
+ void onSoftKeyboardShowModeChanged(int showMode);
+
void onPerformGestureResult(int sequence, boolean completedSuccessfully);
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index e58ef2f..d5e8a11 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -84,5 +84,9 @@
void setMagnificationCallbackEnabled(boolean enabled);
+ boolean setSoftKeyboardShowMode(int showMode);
+
+ void setSoftKeyboardCallbackEnabled(boolean enabled);
+
void sendMotionEvents(int sequence, in ParceledListSlice events);
}
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 79d383c..5ec59b4 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -1088,6 +1088,11 @@
}
@Override
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ /* do nothing */
+ }
+
+ @Override
public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
/* do nothing */
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e4e97a1..c79c407 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3346,6 +3346,10 @@
* <p>If the device owner information contains only whitespaces then the message on the lock
* screen will be blank and the user will not be allowed to change it.
*
+ * <p>If the device owner information needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @param admin The name of the admin component to check.
* @param info Device owner information which will be displayed instead of the user
* owner info.
@@ -5211,6 +5215,10 @@
* for support."
* If the message is longer than 200 characters it may be truncated.
*
+ * <p>If the short support message needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @see #setLongSupportMessage
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5250,6 +5258,10 @@
* Called by a device admin to set the long support message. This will
* be displayed to the user in the device administators settings screen.
*
+ * <p>If the long support message needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
* @see #setShortSupportMessage
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5414,6 +5426,58 @@
}
/**
+ * Called by a profile owner of a managed profile to set the name of the organization under
+ * management.
+ *
+ * <p>If the organization name needs to be localized, it is the responsibility of the
+ * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+ * and set a new version of this string accordingly.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param title The organization name or {@code null} to clear a previously set name.
+ */
+ public void setOrganizationName(@NonNull ComponentName admin, @Nullable String title) {
+ try {
+ mService.setOrganizationName(admin, title);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ }
+ }
+
+ /**
+ * Called by a profile owner of a managed profile to retrieve the name of the organization
+ * under management.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The organization name or {@code null} if none is set.
+ */
+ public String getOrganizationName(@NonNull ComponentName admin) {
+ try {
+ return mService.getOrganizationName(admin);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ return null;
+ }
+ }
+
+ /**
+ * Retrieve the default title message used in the confirm credentials screen for a given user.
+ *
+ * @param userHandle The user id of the user we're interested in.
+ * @return The organization name or {@code null} if none is set.
+ *
+ * @hide
+ */
+ public String getOrganizationNameForUser(int userHandle) {
+ try {
+ return mService.getOrganizationNameForUser(userHandle);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+ return null;
+ }
+ }
+
+ /**
* @return the {@link UserProvisioningState} for the current user - for unmanaged users will
* return {@link #STATE_USER_UNMANAGED}
* @hide
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6333013..37d13e5 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -276,6 +276,10 @@
int getOrganizationColor(in ComponentName admin);
int getOrganizationColorForUser(int userHandle);
+ void setOrganizationName(in ComponentName admin, in String title);
+ String getOrganizationName(in ComponentName admin);
+ String getOrganizationNameForUser(int userHandle);
+
int getUserProvisioningState();
void setUserProvisioningState(int state, int userHandle);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c9c0cde..6e92ec1 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4856,6 +4856,29 @@
"accessibility_display_magnification_auto_update";
/**
+ * Setting that specifies what mode the soft keyboard is in (default or hidden). Can be
+ * modified from an AccessibilityService using the SoftKeyboardController.
+ *
+ * @hide
+ */
+ public static final String ACCESSIBILITY_SOFT_KEYBOARD_MODE =
+ "accessibility_soft_keyboard_mode";
+
+ /**
+ * Default soft keyboard behavior.
+ *
+ * @hide
+ */
+ public static final int SHOW_MODE_AUTO = 0;
+
+ /**
+ * Soft keyboard is never shown.
+ *
+ * @hide
+ */
+ public static final int SHOW_MODE_HIDDEN = 1;
+
+ /**
* Setting that specifies whether timed text (captions) should be
* displayed in video content. Text display properties are controlled by
* the following settings:
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index df84970..7b6fa6d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -565,6 +565,12 @@
private Runnable mTouchModeReset;
/**
+ * Whether the most recent touch event stream resulted in a successful
+ * long-press action. This is reset on TOUCH_DOWN.
+ */
+ private boolean mHasPerformedLongPress;
+
+ /**
* This view is in transcript mode -- it shows the bottom of the list when the data
* changes
*/
@@ -3108,7 +3114,9 @@
handled = performLongPress(child, longPressPosition, longPressId);
}
}
+
if (handled) {
+ mHasPerformedLongPress = true;
mTouchMode = TOUCH_MODE_REST;
setPressed(false);
child.setPressed(false);
@@ -3811,6 +3819,7 @@
}
private void onTouchDown(MotionEvent ev) {
+ mHasPerformedLongPress = false;
mActivePointerId = ev.getPointerId(0);
if (mTouchMode == TOUCH_MODE_OVERFLING) {
@@ -3874,6 +3883,11 @@
}
private void onTouchMove(MotionEvent ev, MotionEvent vtev) {
+ if (mHasPerformedLongPress) {
+ // Consume all move events following a successful long press.
+ return;
+ }
+
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
pointerIndex = 0;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 617d3dd..3a61fcd 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2872,6 +2872,7 @@
protected PopupWindow mPopupWindow;
protected ViewGroup mContentView;
int mPositionX, mPositionY;
+ int mClippingLimitLeft, mClippingLimitRight;
protected abstract void createPopupWindow();
protected abstract void initContentView();
@@ -2939,8 +2940,9 @@
// Horizontal clipping
final DisplayMetrics displayMetrics = mTextView.getResources().getDisplayMetrics();
final int width = mContentView.getMeasuredWidth();
- positionX = Math.min(displayMetrics.widthPixels - width, positionX);
- positionX = Math.max(0, positionX);
+ positionX = Math.min(
+ displayMetrics.widthPixels - width + mClippingLimitRight, positionX);
+ positionX = Math.max(-mClippingLimitLeft, positionX);
if (isShowing()) {
mPopupWindow.update(positionX, positionY, -1, -1);
@@ -3118,6 +3120,8 @@
private TextView mAddToDictionaryButton;
private TextView mDeleteButton;
private SuggestionSpan mMisspelledSpan;
+ private int mContainerMarginWidth;
+ private int mContainerMarginTop;
private class CustomPopupWindow extends PopupWindow {
@Override
@@ -3155,10 +3159,20 @@
protected void initContentView() {
final LayoutInflater inflater = (LayoutInflater) mTextView.getContext().
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- final LinearLayout linearLayout = (LinearLayout) inflater.inflate(
+ final ViewGroup relativeLayout = (ViewGroup) inflater.inflate(
mTextView.mTextEditSuggestionContainerLayout, null);
- final ListView suggestionListView = (ListView) linearLayout.findViewById(
+ final LinearLayout suggestionWindowContainer =
+ (LinearLayout) relativeLayout.findViewById(
+ com.android.internal.R.id.suggestionWindowContainer);
+ ViewGroup.MarginLayoutParams lp =
+ (ViewGroup.MarginLayoutParams) suggestionWindowContainer.getLayoutParams();
+ mContainerMarginWidth = lp.leftMargin + lp.rightMargin;
+ mContainerMarginTop = lp.topMargin;
+ mClippingLimitLeft = lp.leftMargin;
+ mClippingLimitRight = lp.rightMargin;
+
+ final ListView suggestionListView = (ListView) relativeLayout.findViewById(
com.android.internal.R.id.suggestionContainer);
mSuggestionsAdapter = new SuggestionAdapter();
@@ -3171,9 +3185,9 @@
mSuggestionInfos[i] = new SuggestionInfo();
}
- mContentView = linearLayout;
+ mContentView = relativeLayout;
- mAddToDictionaryButton = (TextView) linearLayout.findViewById(
+ mAddToDictionaryButton = (TextView) relativeLayout.findViewById(
com.android.internal.R.id.addToDictionaryButton);
mAddToDictionaryButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
@@ -3197,7 +3211,7 @@
}
});
- mDeleteButton = (TextView) linearLayout.findViewById(
+ mDeleteButton = (TextView) relativeLayout.findViewById(
com.android.internal.R.id.deleteButton);
mDeleteButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
@@ -3306,6 +3320,8 @@
mDeleteButton.measure(horizontalMeasure, verticalMeasure);
width = Math.max(width, mDeleteButton.getMeasuredWidth());
+ width += mContainerMarginWidth;
+
// Enforce the width based on actual text widths
mContentView.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
@@ -3327,7 +3343,7 @@
@Override
protected int getVerticalLocalPosition(int line) {
- return mTextView.getLayout().getLineBottom(line);
+ return mTextView.getLayout().getLineBottom(line) - mContainerMarginTop;
}
@Override
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index 71c2c21..c7459d7 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -17,6 +17,7 @@
package com.android.internal.app;
import android.icu.util.ULocale;
+import android.icu.text.ListFormatter;
import android.util.LocaleList;
import java.text.Collator;
@@ -145,20 +146,16 @@
* @return the locale aware list of locale names
*/
public static String getDisplayLocaleList(LocaleList locales, Locale displayLocale) {
- final StringBuilder result = new StringBuilder();
-
final Locale dispLocale = displayLocale == null ? Locale.getDefault() : displayLocale;
+
int localeCount = locales.size();
+ final String[] localeNames = new String[localeCount];
for (int i = 0; i < localeCount; i++) {
- Locale locale = locales.get(i);
- result.append(LocaleHelper.getDisplayName(locale, dispLocale, false));
- // TODO: language aware list formatter. ICU has one.
- if (i < localeCount - 1) {
- result.append(", ");
- }
+ localeNames[i] = LocaleHelper.getDisplayName(locales.get(i), dispLocale, false);
}
- return result.toString();
+ ListFormatter lfn = ListFormatter.getInstance(dispLocale);
+ return lfn.format(localeNames);
}
/**
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index aada6e3..29190f9 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -32,6 +32,7 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -69,12 +70,11 @@
}
String dialogTitle;
- String dialogMessage;
+ String dialogMessage = null;
if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
dialogTitle = getResources().getString(R.string.work_mode_off_title);
dialogMessage = getResources().getString(R.string.work_mode_off_message);
} else if (mReason == UNLAUNCHABLE_REASON_SUSPENDED_PACKAGE) {
- PackageManager pm = getPackageManager();
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
Context.DEVICE_POLICY_SERVICE);
String packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
@@ -91,12 +91,19 @@
}
dialogTitle = String.format(getResources().getString(R.string.suspended_package_title),
packageLabel);
- dialogMessage = dpm.getShortSupportMessageForUser(dpm.getProfileOwnerAsUser(mUserId),
- mUserId);
- if (dialogMessage == null) {
- dialogMessage = String.format(
- getResources().getString(R.string.suspended_package_message),
- dpm.getProfileOwnerNameAsUser(mUserId));
+ ComponentName profileOwner = dpm.getProfileOwnerAsUser(mUserId);
+ String profileOwnerName = null;
+ if (profileOwner != null) {
+ dialogMessage = dpm.getShortSupportMessageForUser(profileOwner, mUserId);
+ profileOwnerName = dpm.getProfileOwnerNameAsUser(mUserId);
+ }
+ // Fall back to standard message if profile owner hasn't set something specific.
+ if (TextUtils.isEmpty(dialogMessage)) {
+ if (TextUtils.isEmpty(profileOwnerName)) {
+ profileOwnerName = getResources().getString(R.string.unknownName);
+ }
+ dialogMessage = getResources().getString(R.string.suspended_package_message,
+ profileOwnerName);
}
} else {
Log.wtf(TAG, "Invalid unlaunchable type: " + mReason);
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 976ef4b..480d806 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -920,14 +920,14 @@
mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
}
} else {
- if (hasOverflow()) {
- // overflow not open. Set closed state.
- final Size containerSize = mMainPanelSize;
- setSize(mContentContainer, containerSize);
- mMainPanel.setAlpha(1);
- mOverflowPanel.setAlpha(0);
- mOverflowButton.setImageDrawable(mOverflow);
+ // Overflow not open. Set closed state.
+ final Size containerSize = mMainPanelSize;
+ setSize(mContentContainer, containerSize);
+ mMainPanel.setAlpha(1);
+ mOverflowPanel.setAlpha(0);
+ mOverflowButton.setImageDrawable(mOverflow);
+ if (hasOverflow()) {
// Update x-coordinates depending on RTL state.
if (isRTL()) {
mContentContainer.setX(mMarginHorizontal); // align left
@@ -960,8 +960,11 @@
mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
}
} else {
- mContentContainer.setX(mMarginHorizontal);
- mContentContainer.setY(mMarginVertical);
+ // No overflow.
+ mContentContainer.setX(mMarginHorizontal); // align left
+ mContentContainer.setY(mMarginVertical); // align top
+ mMainPanel.setX(0); // align left
+ mMainPanel.setY(0); // align top
}
}
}
@@ -1092,6 +1095,7 @@
final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
mMainPanel.removeAllViews();
+ mMainPanel.setPaddingRelative(0, 0, 0, 0);
boolean isFirstItem = true;
while (!remainingMenuItems.isEmpty()) {
@@ -1302,7 +1306,6 @@
overflowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- final Drawable drawable = overflowButton.getDrawable();
if (mIsOverflowOpen) {
overflowButton.setImageDrawable(mToOverflow);
mToOverflow.start();
@@ -1599,6 +1602,8 @@
private static ViewGroup createContentContainer(Context context) {
ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context)
.inflate(R.layout.floating_popup_container, null);
+ contentContainer.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
contentContainer.setTag(FLOATING_TOOLBAR_TAG);
return contentContainer;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3f468ac..ba456f9 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -17,7 +17,6 @@
package com.android.internal.widget;
import android.annotation.IntDef;
-import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
@@ -503,10 +502,9 @@
if (userHandle == UserHandle.USER_SYSTEM) {
// Set the encryption password to default.
updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+ setCredentialRequiredToDecrypt(false);
}
- setCredentialRequiredToDecrypt(false);
-
getDevicePolicyManager().setActivePasswordState(
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
@@ -1340,9 +1338,9 @@
}
public void setCredentialRequiredToDecrypt(boolean required) {
- if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
- Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
- return;
+ if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
+ throw new IllegalStateException(
+ "Only the system or primary user may call setCredentialRequiredForDecrypt()");
}
if (isDeviceEncryptionEnabled()){
diff --git a/core/res/res/layout/text_edit_suggestion_container.xml b/core/res/res/layout/text_edit_suggestion_container.xml
index fe02d4e..17e93d0 100644
--- a/core/res/res/layout/text_edit_suggestion_container.xml
+++ b/core/res/res/layout/text_edit_suggestion_container.xml
@@ -14,32 +14,41 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:background="@drawable/text_edit_suggestions_window"
- android:dropDownSelector="@drawable/list_selector_background"
- android:divider="@null">
- <ListView
- android:id="@+id/suggestionContainer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:divider="?android:attr/dividerHorizontal">
- <!-- Suggestions will be added here. -->
- </ListView>
-
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
<LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/suggestionWindowContainer"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:divider="?android:attr/dividerHorizontal"
- android:showDividers="middle">
- <TextView
- style="@android:style/Widget.Holo.SuggestionButton"
- android:id="@+id/addToDictionaryButton"
- android:text="@string/addToDictionary" />
- <TextView
- style="@android:style/Widget.Holo.SuggestionButton"
- android:id="@+id/deleteButton"
- android:text="@string/deleteText" />
+ android:elevation="2dp"
+ android:layout_margin="20dp"
+ android:background="@drawable/text_edit_suggestions_window"
+ android:dropDownSelector="@drawable/list_selector_background"
+ android:divider="@null">
+ <ListView
+ android:id="@+id/suggestionContainer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:divider="?android:attr/dividerHorizontal">
+ <!-- Suggestions will be added here. -->
+ </ListView>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:divider="?android:attr/dividerHorizontal"
+ android:showDividers="middle">
+ <TextView
+ style="@android:style/Widget.Holo.SuggestionButton"
+ android:id="@+id/addToDictionaryButton"
+ android:text="@string/addToDictionary" />
+ <TextView
+ style="@android:style/Widget.Holo.SuggestionButton"
+ android:id="@+id/deleteButton"
+ android:text="@string/deleteText" />
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/layout/text_edit_suggestion_container_material.xml b/core/res/res/layout/text_edit_suggestion_container_material.xml
index 62e315b4..7826803 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -16,29 +16,38 @@
<!-- Background of the popup window is the same as the one of the floating toolbar.
Use floating toolbar background style. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
- android:divider="?android:attr/listDivider"
- android:showDividers="middle" >
- <ListView
- android:id="@+id/suggestionContainer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dip"
- android:paddingBottom="0dip"
- android:divider="@null" />
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
<LinearLayout
- android:layout_width="match_parent"
+ android:id="@+id/suggestionWindowContainer"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView
- style="@android:style/Widget.Material.SuggestionButton"
- android:id="@+id/addToDictionaryButton"
- android:text="@string/addToDictionary" />
- <TextView
- style="@android:style/Widget.Material.SuggestionButton"
- android:id="@+id/deleteButton"
- android:text="@string/deleteText" />
+ android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
+ android:elevation="2dp"
+ android:layout_margin="20dp"
+ android:orientation="vertical"
+ android:divider="?android:attr/listDivider"
+ android:showDividers="middle">
+ <ListView
+ android:id="@+id/suggestionContainer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:paddingBottom="0dp"
+ android:divider="@null" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ style="@android:style/Widget.Material.SuggestionButton"
+ android:id="@+id/addToDictionaryButton"
+ android:text="@string/addToDictionary" />
+ <TextView
+ style="@android:style/Widget.Material.SuggestionButton"
+ android:id="@+id/deleteButton"
+ android:text="@string/deleteText" />
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1af5059..74ca8a5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2388,6 +2388,7 @@
<java-symbol type="color" name="system_bar_background_semi_transparent" />
<!-- EditText suggestion popup. -->
+ <java-symbol type="id" name="suggestionWindowContainer" />
<java-symbol type="id" name="suggestionContainer" />
<java-symbol type="id" name="addToDictionaryButton" />
<java-symbol type="id" name="deleteButton" />
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 869512d..93e6dac 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -473,8 +473,9 @@
// the service will be told when we connect.
if (mState == CONNECT_STATE_CONNECTED) {
try {
- // NOTE: In order not to break the behavior of the support library, call
- // addSubscription instead of addSubscriptionWithOptions when the options are null.
+ // NOTE: Do not call addSubscriptionWithOptions when options are null. Otherwise,
+ // it will break the action of support library which expects addSubscription will
+ // be called when options are null.
if (options == null) {
mServiceBinder.addSubscription(parentId, mServiceCallbacks);
} else {
@@ -500,9 +501,9 @@
// Tell the service if necessary.
if (sub != null && sub.remove(options) && mState == CONNECT_STATE_CONNECTED) {
try {
- // NOTE: In order not to break the behavior of the support library, call
- // removeSubscription instead of removeSubscriptionWithOptions when the options
- // are null.
+ // NOTE: Do not call removeSubscriptionWithOptions when options are null. Otherwise,
+ // it will break the action of support library which expects removeSubscription will
+ // be called when options are null.
if (options == null) {
mServiceBinder.removeSubscription(parentId, mServiceCallbacks);
} else {
@@ -572,9 +573,9 @@
Subscription sub = subscriptionEntry.getValue();
for (Bundle options : sub.getOptionsList()) {
try {
- // NOTE: In order not to break the behavior of the support library,
- // call addSubscription instead of addSubscriptionWithOptions when
- // the options are null.
+ // NOTE: Do not call addSubscriptionWithOptions when options are null.
+ // Otherwise, it will break the action of support library which expects
+ // addSubscription will be called when options are null.
if (options == null) {
mServiceBinder.addSubscription(id, mServiceCallbacks);
} else {
@@ -1034,7 +1035,7 @@
* are the initial data as requested.
*/
@Override
- public void onConnect(final String root, final MediaSession.Token session,
+ public void onConnect(String root, MediaSession.Token session,
final Bundle extras) {
MediaBrowser mediaBrowser = mMediaBrowser.get();
if (mediaBrowser != null) {
@@ -1054,7 +1055,12 @@
}
@Override
- public void onLoadChildren(final String parentId, final ParceledListSlice list,
+ public void onLoadChildren(String parentId, ParceledListSlice list) {
+ onLoadChildrenWithOptions(parentId, list, null);
+ }
+
+ @Override
+ public void onLoadChildrenWithOptions(String parentId, ParceledListSlice list,
final Bundle options) {
MediaBrowser mediaBrowser = mMediaBrowser.get();
if (mediaBrowser != null) {
diff --git a/media/java/android/media/tv/ITvInputServiceCallback.aidl b/media/java/android/media/tv/ITvInputServiceCallback.aidl
index 74ab562..4fdc102 100644
--- a/media/java/android/media/tv/ITvInputServiceCallback.aidl
+++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl
@@ -24,7 +24,7 @@
* @hide
*/
oneway interface ITvInputServiceCallback {
- void addHardwareTvInput(in int deviceId, in TvInputInfo inputInfo);
- void addHdmiTvInput(in int id, in TvInputInfo inputInfo);
- void removeTvInput(in String inputId);
+ void addHardwareInput(in int deviceId, in TvInputInfo inputInfo);
+ void addHdmiInput(in int id, in TvInputInfo inputInfo);
+ void removeHardwareInput(in String inputId);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 86bded9..1cd1958 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -719,9 +719,7 @@
* the media on which a newer version of the package exists becomes available/unavailable.
*
* @param inputId The ID of the TV input.
- * @hide
*/
- @SystemApi
public void onInputUpdated(String inputId) {
}
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index a2b6346..d48b2c8 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -150,25 +150,25 @@
@Override
public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_INPUT,
hardwareInfo).sendToTarget();
}
@Override
public void notifyHardwareRemoved(TvInputHardwareInfo hardwareInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_INPUT,
hardwareInfo).sendToTarget();
}
@Override
public void notifyHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_INPUT,
deviceInfo).sendToTarget();
}
@Override
public void notifyHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_TV_INPUT,
+ mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_INPUT,
deviceInfo).sendToTarget();
}
};
@@ -525,7 +525,7 @@
public void notifyVideoUnavailable(final int reason) {
if (reason < TvInputManager.VIDEO_UNAVAILABLE_REASON_START
|| reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) {
- throw new IllegalArgumentException("Unknown reason: " + reason);
+ Log.e(TAG, "notifyVideoUnavailable - unknown reason: " + reason);
}
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -1934,42 +1934,42 @@
private static final int DO_CREATE_SESSION = 1;
private static final int DO_NOTIFY_SESSION_CREATED = 2;
private static final int DO_CREATE_RECORDING_SESSION = 3;
- private static final int DO_ADD_HARDWARE_TV_INPUT = 4;
- private static final int DO_REMOVE_HARDWARE_TV_INPUT = 5;
- private static final int DO_ADD_HDMI_TV_INPUT = 6;
- private static final int DO_REMOVE_HDMI_TV_INPUT = 7;
+ private static final int DO_ADD_HARDWARE_INPUT = 4;
+ private static final int DO_REMOVE_HARDWARE_INPUT = 5;
+ private static final int DO_ADD_HDMI_INPUT = 6;
+ private static final int DO_REMOVE_HDMI_INPUT = 7;
- private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
+ private void broadcastAddHardwareInput(int deviceId, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).addHardwareTvInput(deviceId, inputInfo);
+ mCallbacks.getBroadcastItem(i).addHardwareInput(deviceId, inputInfo);
} catch (RemoteException e) {
- Log.e(TAG, "error in broadcastAddHardwareTvInput", e);
+ Log.e(TAG, "error in broadcastAddHardwareInput", e);
}
}
mCallbacks.finishBroadcast();
}
- private void broadcastAddHdmiTvInput(int id, TvInputInfo inputInfo) {
+ private void broadcastAddHdmiInput(int id, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).addHdmiTvInput(id, inputInfo);
+ mCallbacks.getBroadcastItem(i).addHdmiInput(id, inputInfo);
} catch (RemoteException e) {
- Log.e(TAG, "error in broadcastAddHdmiTvInput", e);
+ Log.e(TAG, "error in broadcastAddHdmiInput", e);
}
}
mCallbacks.finishBroadcast();
}
- private void broadcastRemoveTvInput(String inputId) {
+ private void broadcastRemoveHardwareInput(String inputId) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).removeTvInput(inputId);
+ mCallbacks.getBroadcastItem(i).removeHardwareInput(inputId);
} catch (RemoteException e) {
- Log.e(TAG, "error in broadcastRemoveTvInput", e);
+ Log.e(TAG, "error in broadcastRemoveHardwareInput", e);
}
}
mCallbacks.finishBroadcast();
@@ -2075,35 +2075,35 @@
recordingSessionImpl.initialize(cb);
return;
}
- case DO_ADD_HARDWARE_TV_INPUT: {
+ case DO_ADD_HARDWARE_INPUT: {
TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
TvInputInfo inputInfo = onHardwareAdded(hardwareInfo);
if (inputInfo != null) {
- broadcastAddHardwareTvInput(hardwareInfo.getDeviceId(), inputInfo);
+ broadcastAddHardwareInput(hardwareInfo.getDeviceId(), inputInfo);
}
return;
}
- case DO_REMOVE_HARDWARE_TV_INPUT: {
+ case DO_REMOVE_HARDWARE_INPUT: {
TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
String inputId = onHardwareRemoved(hardwareInfo);
if (inputId != null) {
- broadcastRemoveTvInput(inputId);
+ broadcastRemoveHardwareInput(inputId);
}
return;
}
- case DO_ADD_HDMI_TV_INPUT: {
+ case DO_ADD_HDMI_INPUT: {
HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
TvInputInfo inputInfo = onHdmiDeviceAdded(deviceInfo);
if (inputInfo != null) {
- broadcastAddHdmiTvInput(deviceInfo.getId(), inputInfo);
+ broadcastAddHdmiInput(deviceInfo.getId(), inputInfo);
}
return;
}
- case DO_REMOVE_HDMI_TV_INPUT: {
+ case DO_REMOVE_HDMI_INPUT: {
HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
String inputId = onHdmiDeviceRemoved(deviceInfo);
if (inputId != null) {
- broadcastRemoveTvInput(inputId);
+ broadcastRemoveHardwareInput(inputId);
}
return;
}
diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
index fe7ebfa..6ca5ac5 100644
--- a/media/java/android/service/media/IMediaBrowserService.aidl
+++ b/media/java/android/service/media/IMediaBrowserService.aidl
@@ -16,7 +16,7 @@
oneway interface IMediaBrowserService {
// Warning: DO NOT CHANGE the methods signature and order of methods.
- // The change of the order or the method signatures could break the support library.
+ // A change of the order or the method signatures could break the support library.
void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
void disconnect(IMediaBrowserServiceCallbacks callbacks);
diff --git a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
index dadb025..e6b0e8c 100644
--- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
@@ -13,6 +13,10 @@
* @hide
*/
oneway interface IMediaBrowserServiceCallbacks {
+
+ // Warning: DO NOT CHANGE the methods signature and order of methods.
+ // A change of the order or the method signatures could break the support library.
+
/**
* Invoked when the connected has been established.
* @param root The root media id for browsing.
@@ -22,5 +26,6 @@
*/
void onConnect(String root, in MediaSession.Token session, in Bundle extras);
void onConnectFailed();
- void onLoadChildren(String mediaId, in ParceledListSlice list, in Bundle options);
+ void onLoadChildren(String mediaId, in ParceledListSlice list);
+ void onLoadChildrenWithOptions(String mediaId, in ParceledListSlice list, in Bundle options);
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 6cf90d5..299b770 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -589,7 +589,14 @@
final ParceledListSlice<MediaBrowser.MediaItem> pls =
filteredList == null ? null : new ParceledListSlice<>(filteredList);
try {
- connection.callbacks.onLoadChildren(parentId, pls, options);
+ // NOTE: Do not call onLoadChildrenWithOptions when options are null. Otherwise,
+ // it will break the action of support library which expects onLoadChildren will
+ // be called when options are null.
+ if (options == null) {
+ connection.callbacks.onLoadChildren(parentId, pls);
+ } else {
+ connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
+ }
} catch (RemoteException ex) {
// The other side is in the process of crashing.
Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 112914e..959fac6 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -165,22 +165,27 @@
cursor.close();
}
- long capacityBytes = 0;
- long availableBytes = 0;
- int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
- int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
- while (storageCursor.moveToNext()) {
- // If requested columnNames does not include COLUMN_XXX_BYTES, we don't
- // calculate corresponding values.
- if (capacityIndex != -1) {
- capacityBytes += cursor.getLong(capacityIndex);
+ if (storageCursor.getCount() != 0) {
+ long capacityBytes = 0;
+ long availableBytes = 0;
+ int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
+ int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
+ while (storageCursor.moveToNext()) {
+ // If requested columnNames does not include COLUMN_XXX_BYTES, we
+ // don't calculate corresponding values.
+ if (capacityIndex != -1) {
+ capacityBytes += cursor.getLong(capacityIndex);
+ }
+ if (availableIndex != -1) {
+ availableBytes += cursor.getLong(availableIndex);
+ }
}
- if (availableIndex != -1) {
- availableBytes += cursor.getLong(availableIndex);
- }
+ values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
+ values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
+ } else {
+ values.putNull(Root.COLUMN_CAPACITY_BYTES);
+ values.putNull(Root.COLUMN_AVAILABLE_BYTES);
}
- values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
- values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
}
} finally {
storageCursor.close();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 97ea717..8075999 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -899,4 +899,24 @@
mDatabase.getMapper().stopAddingDocuments(null);
assertEquals("1", mDatabase.getDocumentIdForDevice(100));
}
+
+ public void testGetClosedDevice() {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", /* opened is */ false , new MtpRoot[0], null, null));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ final String[] columns = new String [] {
+ DocumentsContract.Root.COLUMN_ROOT_ID,
+ DocumentsContract.Root.COLUMN_TITLE,
+ DocumentsContract.Root.COLUMN_AVAILABLE_BYTES
+ };
+ try (final Cursor cursor = mDatabase.queryRoots(columns)) {
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals(1, cursor.getLong(0));
+ assertEquals("Device", cursor.getString(1));
+ assertTrue(cursor.isNull(2));
+ }
+ }
}
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6df31ff..ebe0d97 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -103,7 +103,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast
+ wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast,work
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 8717a15..03dd25e3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -66,6 +66,9 @@
}
public boolean hasMultipleUsers() {
+ if (mUserListener == null) {
+ return false;
+ }
return mUserListener.getCount() != 0;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 2a8672d..53504cc 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -958,7 +958,15 @@
final UserState state = getCurrentUserStateLocked();
for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
final Service service = state.mBoundServices.get(i);
- service.notifyMagnificationChanged(region, scale, centerX, centerY);
+ service.notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+ }
+ }
+
+ private void notifySoftKeyboardShowModeChangedLocked(int showMode) {
+ final UserState state = getCurrentUserStateLocked();
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ final Service service = state.mBoundServices.get(i);
+ service.notifySoftKeyboardShowModeChangedLocked(showMode);
}
}
@@ -1407,6 +1415,7 @@
updateEnhancedWebAccessibilityLocked(userState);
updateDisplayColorAdjustmentSettingsLocked(userState);
updateMagnificationLocked(userState);
+ updateSoftKeyboardShowModeLocked(userState);
scheduleUpdateInputFilter(userState);
scheduleUpdateClientsIfNeededLocked(userState);
}
@@ -1623,6 +1632,18 @@
return false;
}
+ private boolean readSoftKeyboardShowModeChangedLocked(UserState userState) {
+ final int softKeyboardShowMode = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0,
+ userState.mUserId);
+ if (softKeyboardShowMode != userState.mSoftKeyboardShowMode) {
+ userState.mSoftKeyboardShowMode = softKeyboardShowMode;
+ return true;
+ }
+ return false;
+ }
+
private void updateTouchExplorationLocked(UserState userState) {
boolean enabled = false;
final int serviceCount = userState.mBoundServices.size();
@@ -1757,6 +1778,25 @@
return false;
}
+ private void updateSoftKeyboardShowModeLocked(UserState userState) {
+ final int userId = userState.mUserId;
+ if (userId == mCurrentUserId) {
+ // Check whether any Accessibility Services are still enabled and, if not, remove flag
+ // requesting no soft keyboard
+ final boolean accessibilityRequestingNoIme = userState.mSoftKeyboardShowMode == 1;
+ if (accessibilityRequestingNoIme && !userState.mIsAccessibilityEnabled) {
+ // No active Accessibility Services can be requesting the soft keyboard to be hidden
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+ 0,
+ userState.mUserId);
+ userState.mSoftKeyboardShowMode = 0;
+ }
+
+ notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode);
+ }
+ }
+
private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
IBinder windowToken = mGlobalWindowTokens.get(windowId);
if (windowToken == null) {
@@ -2102,7 +2142,7 @@
};
// Handler for scheduling method invocations on the main thread.
- public InvocationHandler mInvocationHandler = new InvocationHandler(
+ public final InvocationHandler mInvocationHandler = new InvocationHandler(
mMainHandler.getLooper());
public Service(int userId, ComponentName componentName,
@@ -2297,17 +2337,20 @@
}
}
+ private boolean isCalledForCurrentUserLocked() {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
+ final int resolvedUserId = mSecurityPolicy
+ .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.USER_CURRENT);
+ return resolvedUserId == mCurrentUserId;
+ }
+
@Override
public List<AccessibilityWindowInfo> getWindows() {
ensureWindowsAvailableTimed();
synchronized (mLock) {
- // We treat calls from a profile as if made by its perent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return null;
}
final boolean permissionGranted =
@@ -2335,13 +2378,7 @@
public AccessibilityWindowInfo getWindow(int windowId) {
ensureWindowsAvailableTimed();
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return null;
}
final boolean permissionGranted =
@@ -2368,13 +2405,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2425,13 +2456,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2482,13 +2507,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2539,13 +2558,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
@@ -2597,13 +2610,7 @@
IAccessibilityInteractionConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2670,13 +2677,7 @@
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2709,13 +2710,7 @@
@Override
public boolean performGlobalAction(int action) {
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
}
@@ -2750,13 +2745,7 @@
@Override
public float getMagnificationScale() {
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return 1.0f;
}
}
@@ -2771,13 +2760,7 @@
@Override
public Region getMagnifiedRegion() {
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return Region.obtain();
}
}
@@ -2794,13 +2777,7 @@
@Override
public float getMagnificationCenterX() {
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return 0.0f;
}
}
@@ -2815,13 +2792,7 @@
@Override
public float getMagnificationCenterY() {
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return 0.0f;
}
}
@@ -2836,13 +2807,7 @@
@Override
public boolean resetMagnification(boolean animate) {
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this);
@@ -2862,13 +2827,7 @@
public boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY,
boolean animate) {
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
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
+ if (!isCalledForCurrentUserLocked()) {
return false;
}
final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this);
@@ -2891,6 +2850,33 @@
}
@Override
+ public boolean setSoftKeyboardShowMode(int showMode) {
+ final UserState userState;
+ synchronized (mLock) {
+ if (!isCalledForCurrentUserLocked()) {
+ return false;
+ }
+
+ userState = getCurrentUserStateLocked();
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, showMode,
+ userState.mUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return true;
+ }
+
+ @Override
+ public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+ mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
+ }
+
+ @Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
synchronized (mLock) {
@@ -3080,9 +3066,14 @@
InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
}
- public void notifyMagnificationChanged(@NonNull Region region,
+ public void notifyMagnificationChangedLocked(@NonNull Region region,
float scale, float centerX, float centerY) {
- mInvocationHandler.notifyMagnificationChanged(region, scale, centerX, centerY);
+ mInvocationHandler
+ .notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+ }
+
+ public void notifySoftKeyboardShowModeChangedLocked(int showState) {
+ mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState);
}
/**
@@ -3104,6 +3095,25 @@
}
}
+ /**
+ * Called by the invocation handler to notify the service that the state of the soft
+ * keyboard show mode has changed.
+ */
+ private void notifySoftKeyboardShowModeChangedInternal(int showState) {
+ final IAccessibilityServiceClient listener;
+ synchronized (mLock) {
+ listener = mServiceInterface;
+ }
+ if (listener != null) {
+ try {
+ listener.onSoftKeyboardShowModeChanged(showState);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
+ re);
+ }
+ }
+ }
+
private void notifyGestureInternal(int gestureId) {
final IAccessibilityServiceClient listener;
synchronized (mLock) {
@@ -3239,8 +3249,10 @@
public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2;
private static final int MSG_ON_MAGNIFICATION_CHANGED = 5;
+ private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
private boolean mIsMagnificationCallbackEnabled = false;
+ private boolean mIsSoftKeyboardCallbackEnabled = false;
public InvocationHandler(Looper looper) {
super(looper, null, true);
@@ -3268,13 +3280,18 @@
notifyMagnificationChangedInternal(region, scale, centerX, centerY);
} break;
+ case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: {
+ final int showState = (int) message.arg1;
+ notifySoftKeyboardShowModeChangedInternal(showState);
+ } break;
+
default: {
throw new IllegalArgumentException("Unknown message: " + type);
}
}
}
- public void notifyMagnificationChanged(@NonNull Region region, float scale,
+ public void notifyMagnificationChangedLocked(@NonNull Region region, float scale,
float centerX, float centerY) {
if (!mIsMagnificationCallbackEnabled) {
// Callback is disabled, don't bother packing args.
@@ -3294,8 +3311,20 @@
public void setMagnificationCallbackEnabled(boolean enabled) {
mIsMagnificationCallbackEnabled = enabled;
}
- }
+ public void notifySoftKeyboardShowModeChangedLocked(int showState) {
+ if (!mIsSoftKeyboardCallbackEnabled) {
+ return;
+ }
+
+ final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0);
+ msg.sendToTarget();
+ }
+
+ public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+ mIsSoftKeyboardCallbackEnabled = enabled;
+ }
+ }
}
final class WindowsForAccessibilityCallback implements
@@ -3976,6 +4005,8 @@
public int mLastSentClientState = -1;
+ public int mSoftKeyboardShowMode = 0;
+
public boolean mIsAccessibilityEnabled;
public boolean mIsTouchExplorationEnabled;
public boolean mIsTextHighContrastEnabled;
@@ -4048,6 +4079,7 @@
mIsEnhancedWebAccessibilityEnabled = false;
mIsDisplayMagnificationEnabled = false;
mIsAutoclickEnabled = false;
+ mSoftKeyboardShowMode = 0;
}
public void destroyUiAutomationService() {
@@ -4105,6 +4137,9 @@
private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
+ private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+
public AccessibilityContentObserver(Handler handler) {
super(handler);
}
@@ -4135,6 +4170,8 @@
mDisplayColorMatrixUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mHighTextContrastUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
}
@Override
@@ -4189,6 +4226,10 @@
if (readHighTextContrastEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
}
+ } else if (mAccessibilitySoftKeyboardModeUri.equals(uri)) {
+ if (readSoftKeyboardShowModeChangedLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2d1f96b..3fd8b40 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -33,7 +33,6 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import android.annotation.Nullable;
-import android.app.AlarmManager;
import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.NotificationManager;
@@ -88,7 +87,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -115,7 +113,6 @@
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
-import com.android.internal.telephony.DctConstants;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
@@ -155,11 +152,9 @@
import java.util.HashSet;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* @hide
@@ -2186,7 +2181,7 @@
if (wasDefault) {
mDefaultInetConditionPublished = 0;
}
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
// TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
// by other networks that are already connected. Perhaps that can be done by
// sending all CALLBACK_LOST messages (for requests, not listens) at the end
@@ -4095,7 +4090,7 @@
}
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
@@ -4719,7 +4714,11 @@
notifyLockdownVpn(networkAgent);
if (oldInfo != null && oldInfo.getState() == state) {
- if (VDBG) log("ignoring duplicate network state non-change");
+ if (oldInfo.isRoaming() != newInfo.isRoaming()) {
+ if (VDBG) log("roaming status changed, notifying NetworkStatsService");
+ notifyIfacesChangedForNetworkStats();
+ } else if (VDBG) log("ignoring duplicate network state non-change");
+ // In either case, no further work should be needed.
return;
}
if (DBG) {
@@ -4749,7 +4748,7 @@
}
networkAgent.created = true;
updateLinkProperties(networkAgent, null);
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
scheduleUnvalidatedPrompt(networkAgent);
@@ -4913,9 +4912,10 @@
}
/**
- * Notify other system services that set of active ifaces has changed.
+ * Notify NetworkStatsService that the set of active ifaces has changed, or that one of the
+ * properties tracked by NetworkStatsService on an active iface has changed.
*/
- private void notifyIfacesChanged() {
+ private void notifyIfacesChangedForNetworkStats() {
try {
mStatsService.forceUpdateIfaces();
} catch (Exception ignored) {
@@ -4949,7 +4949,7 @@
success = mVpns.get(user).setUnderlyingNetworks(networks);
}
if (success) {
- notifyIfacesChanged();
+ notifyIfacesChangedForNetworkStats();
}
return success;
}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 4a123df..d77def6 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -448,6 +448,7 @@
private int[] mSubtypeIds;
private Locale mLastSystemLocale;
private boolean mShowImeWithHardKeyboard;
+ private boolean mAccessibilityRequestingNoSoftKeyboard;
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
private final IPackageManager mIPackageManager;
private final String mSlotIme;
@@ -485,15 +486,31 @@
Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
mRegistered = true;
}
@Override public void onChange(boolean selfChange, Uri uri) {
- final Uri showImeUri =
- Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+ final Uri showImeUri = Settings.Secure.getUriFor(
+ Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+ final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
synchronized (mMethodMap) {
if (showImeUri.equals(uri)) {
updateKeyboardFromSettingsLocked();
+ } else if (accessibilityRequestingNoImeUri.equals(uri)) {
+ mAccessibilityRequestingNoSoftKeyboard = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+ 0, mUserId) == 1;
+ if (mAccessibilityRequestingNoSoftKeyboard) {
+ final boolean showRequested = mShowRequested;
+ hideCurrentInputLocked(0, null);
+ mShowRequested = showRequested;
+ } else if (mShowRequested) {
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
+ }
} else {
boolean enabledChanged = false;
String newEnabled = mSettings.getEnabledInputMethodsStr();
@@ -655,7 +672,7 @@
boolean changed = false;
if (curIm != null) {
- int change = isPackageDisappearing(curIm.getPackageName());
+ int change = isPackageDisappearing(curIm.getPackageName());
if (change == PACKAGE_TEMPORARY_CHANGE
|| change == PACKAGE_PERMANENT_CHANGE) {
ServiceInfo si = null;
@@ -2073,12 +2090,15 @@
boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
mShowRequested = true;
- if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
- mShowExplicitlyRequested = true;
+ if (mAccessibilityRequestingNoSoftKeyboard) {
+ return false;
}
+
if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
mShowExplicitlyRequested = true;
mShowForced = true;
+ } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
+ mShowExplicitlyRequested = true;
}
if (!mSystemReady) {
@@ -3265,7 +3285,7 @@
"Requires permission "
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
-
+
long ident = Binder.clearCallingIdentity();
try {
return setInputMethodEnabledLocked(id, enabled);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index cf876ee..5d97afa 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -189,10 +189,6 @@
mInstaller.execute("freecache", uuid, freeStorageSize);
}
- public void moveFiles() throws InstallerException {
- mInstaller.execute("movefiles");
- }
-
/**
* Links the 32 bit native library directory in an application's data
* directory to the real location for backward compatibility. Note that no
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4d66e10..bce7223 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -70,7 +70,8 @@
}
static boolean canOptimizePackage(PackageParser.Package pkg) {
- return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
+ return pkg.canHaveOatDir() &&
+ ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0);
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c3f20eb..1c4176a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2175,13 +2175,6 @@
scanDirTracedLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
- if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
- try {
- mInstaller.moveFiles();
- } catch (InstallerException e) {
- logCriticalInfo(Log.WARN, "Update commands failed: " + e);
- }
-
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
if (!mOnlyCore) {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 578428b..4e96d71 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -266,7 +266,7 @@
return (configs.length > 0) ? INPUT_STATE_CONNECTED_STANDBY : INPUT_STATE_DISCONNECTED;
}
- public void addHardwareTvInput(int deviceId, TvInputInfo info) {
+ public void addHardwareInput(int deviceId, TvInputInfo info) {
synchronized (mLock) {
String oldInputId = mHardwareInputIdMap.get(deviceId);
if (oldInputId != null) {
@@ -325,7 +325,7 @@
return false;
}
- public void addHdmiTvInput(int id, TvInputInfo info) {
+ public void addHdmiInput(int id, TvInputInfo info) {
if (info.getType() != TvInputInfo.TYPE_HDMI) {
throw new IllegalArgumentException("info (" + info + ") has non-HDMI type.");
}
@@ -346,7 +346,7 @@
}
}
- public void removeTvInput(String inputId) {
+ public void removeHardwareInput(String inputId) {
synchronized (mLock) {
mInputMap.remove(inputId);
int hardwareIndex = indexOfEqualValue(mHardwareInputIdMap, inputId);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 318f966..b065e85 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -311,7 +311,7 @@
userState.serviceStateMap.put(component, serviceState);
updateServiceConnectionLocked(component, userId);
} else {
- inputList.addAll(serviceState.inputList);
+ inputList.addAll(serviceState.hardwareInputList);
}
} else {
try {
@@ -2018,7 +2018,7 @@
private final ServiceConnection connection;
private final ComponentName component;
private final boolean isHardware;
- private final List<TvInputInfo> inputList = new ArrayList<>();
+ private final List<TvInputInfo> hardwareInputList = new ArrayList<>();
private ITvInputService service;
private ServiceCallback callback;
@@ -2215,39 +2215,36 @@
}
}
- private void addTvInputLocked(TvInputInfo inputInfo) {
+ private void addHardwareInputLocked(TvInputInfo inputInfo) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
- serviceState.inputList.add(inputInfo);
+ serviceState.hardwareInputList.add(inputInfo);
buildTvInputListLocked(mUserId, null);
}
- @Override
- public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
+ public void addHardwareInput(int deviceId, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
- mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
- addTvInputLocked(inputInfo);
+ mTvInputHardwareManager.addHardwareInput(deviceId, inputInfo);
+ addHardwareInputLocked(inputInfo);
}
}
- @Override
- public void addHdmiTvInput(int id, TvInputInfo inputInfo) {
+ public void addHdmiInput(int id, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
- mTvInputHardwareManager.addHdmiTvInput(id, inputInfo);
- addTvInputLocked(inputInfo);
+ mTvInputHardwareManager.addHdmiInput(id, inputInfo);
+ addHardwareInputLocked(inputInfo);
}
}
- @Override
- public void removeTvInput(String inputId) {
+ public void removeHardwareInput(String inputId) {
ensureHardwarePermission();
synchronized (mLock) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
boolean removed = false;
- for (Iterator<TvInputInfo> it = serviceState.inputList.iterator();
+ for (Iterator<TvInputInfo> it = serviceState.hardwareInputList.iterator();
it.hasNext(); ) {
if (it.next().getId().equals(inputId)) {
it.remove();
@@ -2257,7 +2254,7 @@
}
if (removed) {
buildTvInputListLocked(mUserId, null);
- mTvInputHardwareManager.removeTvInput(inputId);
+ mTvInputHardwareManager.removeHardwareInput(inputId);
} else {
Slog.e(TAG, "failed to remove input " + inputId);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1b0660d..ca0b43a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -509,6 +509,7 @@
private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message";
private static final String TAG_PARENT_ADMIN = "parent-admin";
private static final String TAG_ORGANIZATION_COLOR = "organization-color";
+ private static final String TAG_ORGANIZATION_NAME = "organization-name";
final DeviceAdminInfo info;
@@ -607,6 +608,9 @@
static final int DEF_ORGANIZATION_COLOR = Color.GRAY;
int organizationColor = DEF_ORGANIZATION_COLOR;
+ // Default title of confirm credentials screen
+ String organizationName = null;
+
ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
info = _info;
isParent = parent;
@@ -830,6 +834,11 @@
out.attribute(null, ATTR_VALUE, Integer.toString(organizationColor));
out.endTag(null, TAG_ORGANIZATION_COLOR);
}
+ if (organizationName != null) {
+ out.startTag(null, TAG_ORGANIZATION_NAME);
+ out.text(organizationName);
+ out.endTag(null, TAG_ORGANIZATION_NAME);
+ }
}
void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -971,6 +980,13 @@
} else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
organizationColor = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_ORGANIZATION_NAME.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ organizationName = parser.getText();
+ } else {
+ Log.w(LOG_TAG, "Missing text when loading organization name");
+ }
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1179,6 +1195,12 @@
pw.print(prefix); pw.print("keepUninstalledPackages=");
pw.println(keepUninstalledPackages);
}
+ pw.print(prefix); pw.print("organizationColor=");
+ pw.println(organizationColor);
+ if (organizationName != null) {
+ pw.print(prefix); pw.print("organizationName=");
+ pw.println(organizationName);
+ }
pw.print(prefix); pw.println("userRestrictions:");
UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", userRestrictions);
pw.print(prefix); pw.print("isParent=");
@@ -8096,11 +8118,12 @@
@Override
public void setOrganizationColor(@NonNull ComponentName who, int color) {
- final int userHandle = mInjector.userHandleGetCallingUserId();
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ enforceManagedProfile(userHandle, "set organization color");
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8111,11 +8134,11 @@
@Override
public int getOrganizationColor(@NonNull ComponentName who) {
- final int userHandle = mInjector.userHandleGetCallingUserId();
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization color");
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8125,10 +8148,11 @@
@Override
public int getOrganizationColorForUser(int userHandle) {
- if (!mHasFeature || !isManagedProfile(userHandle)) {
+ if (!mHasFeature) {
return ActiveAdmin.DEF_ORGANIZATION_COLOR;
}
- enforceCrossUsersPermission(userHandle);
+ enforceFullCrossUsersPermission(userHandle);
+ enforceManagedProfile(userHandle, "get organization color");
synchronized (this) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
return (profileOwner != null)
@@ -8138,6 +8162,53 @@
}
@Override
+ public void setOrganizationName(@NonNull ComponentName who, String text) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ enforceManagedProfile(userHandle, "set organization name");
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!TextUtils.equals(admin.organizationName, text)) {
+ admin.organizationName = TextUtils.nullIfEmpty(text);
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
+
+ @Override
+ public String getOrganizationName(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization name");
+ synchronized(this) {
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ return admin.organizationName;
+ }
+ }
+
+ @Override
+ public String getOrganizationNameForUser(int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ enforceFullCrossUsersPermission(userHandle);
+ enforceManagedProfile(userHandle, "get organization name");
+ synchronized (this) {
+ ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
+ return (profileOwner != null)
+ ? profileOwner.organizationName
+ : null;
+ }
+ }
+
+ @Override
public void setAffiliationIds(ComponentName admin, List<String> ids) {
final Set<String> affiliationIds = new ArraySet<String>(ids);
final int callingUserId = mInjector.userHandleGetCallingUserId();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index bfdac7e..77740387 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -145,6 +145,8 @@
private boolean mScreenOn;
private long mLastAppIdleParoledTime;
+ private volatile boolean mPendingOneTimeCheckIdleStates;
+
long mScreenOnTime;
long mLastScreenOnEventRealtime;
@@ -221,6 +223,10 @@
synchronized (mLock) {
updateDisplayLocked();
}
+
+ if (mPendingOneTimeCheckIdleStates) {
+ postOneTimeCheckIdleStates();
+ }
} else if (phase == PHASE_BOOT_COMPLETED) {
setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
}
@@ -368,7 +374,13 @@
* scheduling a series of repeating checkIdleStates each time we fired off one.
*/
void postOneTimeCheckIdleStates() {
- mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ if (mDeviceIdleController == null) {
+ // Not booted yet; wait for it!
+ mPendingOneTimeCheckIdleStates = true;
+ } else {
+ mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ mPendingOneTimeCheckIdleStates = false;
+ }
}
/** Check all running users' or specified user's apps to see if they enter an idle state. */