diff options
Diffstat (limited to 'core/java')
89 files changed, 2146 insertions, 996 deletions
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java index 435d5ab..d8d2737 100644 --- a/core/java/android/animation/AnimatorInflater.java +++ b/core/java/android/animation/AnimatorInflater.java @@ -441,8 +441,12 @@ public class AnimatorInflater { long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0); - int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, VALUE_TYPE_FLOAT); + int valueType = arrayAnimator.getInt(R.styleable.Animator_valueType, VALUE_TYPE_UNDEFINED); + if (valueType == VALUE_TYPE_UNDEFINED) { + valueType = inferValueTypeFromValues(arrayAnimator, R.styleable.Animator_valueFrom, + R.styleable.Animator_valueTo); + } PropertyValuesHolder pvh = getPVH(arrayAnimator, valueType, R.styleable.Animator_valueFrom, R.styleable.Animator_valueTo, ""); if (pvh != null) { @@ -520,8 +524,14 @@ public class AnimatorInflater { ObjectAnimator oa = (ObjectAnimator) anim; String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData); - // Note that if there is a pathData defined in the Object Animator, - // valueFrom / valueTo will be ignored. + // Path can be involved in an ObjectAnimator in the following 3 ways: + // 1) Path morphing: the property to be animated is pathData, and valueFrom and valueTo + // are both of pathType. valueType = pathType needs to be explicitly defined. + // 2) A property in X or Y dimension can be animated along a path: the property needs to be + // defined in propertyXName or propertyYName attribute, the path will be defined in the + // pathData attribute. valueFrom and valueTo will not be necessary for this animation. + // 3) PathInterpolator can also define a path (in pathData) for its interpolation curve. + // Here we are dealing with case 2: if (pathData != null) { String propertyXName = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_propertyXName); @@ -805,6 +815,25 @@ public class AnimatorInflater { return valueType; } + private static int inferValueTypeFromValues(TypedArray styledAttributes, int valueFromId, + int valueToId) { + TypedValue tvFrom = styledAttributes.peekValue(valueFromId); + boolean hasFrom = (tvFrom != null); + int fromType = hasFrom ? tvFrom.type : 0; + TypedValue tvTo = styledAttributes.peekValue(valueToId); + boolean hasTo = (tvTo != null); + int toType = hasTo ? tvTo.type : 0; + + int valueType; + // Check whether it's color type. If not, fall back to default type (i.e. float type) + if ((hasFrom && isColorType(fromType)) || (hasTo && isColorType(toType))) { + valueType = VALUE_TYPE_COLOR; + } else { + valueType = VALUE_TYPE_FLOAT; + } + return valueType; + } + private static void dumpKeyframes(Object[] keyframes, String header) { if (keyframes == null || keyframes.length == 0) { return; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index edebc28..3892dd9 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -462,7 +462,7 @@ public class ActivityManager { public int getMemoryClass() { return staticGetMemoryClass(); } - + /** @hide */ static public int staticGetMemoryClass() { // Really brain dead right now -- just take this from the configured @@ -473,7 +473,7 @@ public class ActivityManager { } return staticGetLargeMemoryClass(); } - + /** * Return the approximate per-application memory class of the current * device when an application is running with a large heap. This is the @@ -490,7 +490,7 @@ public class ActivityManager { public int getLargeMemoryClass() { return staticGetLargeMemoryClass(); } - + /** @hide */ static public int staticGetLargeMemoryClass() { // Really brain dead right now -- just take this from the configured @@ -809,7 +809,7 @@ public class ActivityManager { * The true identifier of this task, valid even if it is not running. */ public int persistentId; - + /** * The original Intent used to launch the task. You can use this * Intent to re-launch the task (if it is no longer running) or bring @@ -1014,7 +1014,7 @@ public class ActivityManager { * user has started and the maximum number the system can remember. * @param flags Information about what to return. May be any combination * of {@link #RECENT_WITH_EXCLUDED} and {@link #RECENT_IGNORE_UNAVAILABLE}. - * + * * @return Returns a list of RecentTaskInfo records describing each of * the recent tasks. */ @@ -1146,7 +1146,7 @@ public class ActivityManager { numActivities = source.readInt(); numRunning = source.readInt(); } - + public static final Creator<RunningTaskInfo> CREATOR = new Creator<RunningTaskInfo>() { public RunningTaskInfo createFromParcel(Parcel source) { return new RunningTaskInfo(source); @@ -1469,100 +1469,100 @@ public class ActivityManager { * If non-zero, this is the process the service is running in. */ public int pid; - + /** * The UID that owns this service. */ public int uid; - + /** * The name of the process this service runs in. */ public String process; - + /** * Set to true if the service has asked to run as a foreground process. */ public boolean foreground; - + /** * The time when the service was first made active, either by someone * starting or binding to it. This * is in units of {@link android.os.SystemClock#elapsedRealtime()}. */ public long activeSince; - + /** * Set to true if this service has been explicitly started. */ public boolean started; - + /** * Number of clients connected to the service. */ public int clientCount; - + /** * Number of times the service's process has crashed while the service * is running. */ public int crashCount; - + /** * The time when there was last activity in the service (either * explicit requests to start it or clients binding to it). This * is in units of {@link android.os.SystemClock#uptimeMillis()}. */ public long lastActivityTime; - + /** * If non-zero, this service is not currently running, but scheduled to * restart at the given time. */ public long restarting; - + /** * Bit for {@link #flags}: set if this service has been * explicitly started. */ public static final int FLAG_STARTED = 1<<0; - + /** * Bit for {@link #flags}: set if the service has asked to * run as a foreground process. */ public static final int FLAG_FOREGROUND = 1<<1; - + /** * Bit for {@link #flags): set if the service is running in a * core system process. */ public static final int FLAG_SYSTEM_PROCESS = 1<<2; - + /** * Bit for {@link #flags): set if the service is running in a * persistent process. */ public static final int FLAG_PERSISTENT_PROCESS = 1<<3; - + /** * Running flags. */ public int flags; - + /** * For special services that are bound to by system code, this is * the package that holds the binding. */ public String clientPackage; - + /** * For special services that are bound to by system code, this is * a string resource providing a user-visible label for who the * client is. */ public int clientLabel; - + public RunningServiceInfo() { } @@ -1603,7 +1603,7 @@ public class ActivityManager { clientPackage = source.readString(); clientLabel = source.readInt(); } - + public static final Creator<RunningServiceInfo> CREATOR = new Creator<RunningServiceInfo>() { public RunningServiceInfo createFromParcel(Parcel source) { return new RunningServiceInfo(source); @@ -1627,7 +1627,7 @@ public class ActivityManager { * @param maxNum The maximum number of entries to return in the list. The * actual number returned may be smaller, depending on how many services * are running. - * + * * @return Returns a list of RunningServiceInfo records describing each of * the running tasks. */ @@ -1641,7 +1641,7 @@ public class ActivityManager { return null; } } - + /** * Returns a PendingIntent you can start to show a control panel for the * given running service. If the service does not have a control panel, @@ -1657,7 +1657,7 @@ public class ActivityManager { return null; } } - + /** * Information you can retrieve about the available memory through * {@link ActivityManager#getMemoryInfo}. @@ -1684,7 +1684,7 @@ public class ActivityManager { * processes. */ public long threshold; - + /** * Set to true if the system considers itself to currently be in a low * memory situation. @@ -1717,7 +1717,7 @@ public class ActivityManager { dest.writeLong(visibleAppThreshold); dest.writeLong(foregroundAppThreshold); } - + public void readFromParcel(Parcel source) { availMem = source.readLong(); totalMem = source.readLong(); @@ -1841,7 +1841,7 @@ public class ActivityManager { */ public boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) { try { - return ActivityManagerNative.getDefault().clearApplicationUserData(packageName, + return ActivityManagerNative.getDefault().clearApplicationUserData(packageName, observer, UserHandle.myUserId()); } catch (RemoteException e) { return false; @@ -1882,7 +1882,7 @@ public class ActivityManager { * The process name in which the crash or error occurred. */ public String processName; - + /** * The pid of this process; 0 if none */ @@ -1894,7 +1894,7 @@ public class ActivityManager { * the same uid). */ public int uid; - + /** * The activity name associated with the error, if known. May be null. */ @@ -1950,8 +1950,8 @@ public class ActivityManager { longMsg = source.readString(); stackTrace = source.readString(); } - - public static final Creator<ProcessErrorStateInfo> CREATOR = + + public static final Creator<ProcessErrorStateInfo> CREATOR = new Creator<ProcessErrorStateInfo>() { public ProcessErrorStateInfo createFromParcel(Parcel source) { return new ProcessErrorStateInfo(source); @@ -1965,11 +1965,11 @@ public class ActivityManager { readFromParcel(source); } } - + /** - * Returns a list of any processes that are currently in an error condition. The result + * Returns a list of any processes that are currently in an error condition. The result * will be null if all processes are running properly at this time. - * + * * @return Returns a list of ProcessErrorStateInfo records, or null if there are no * current error conditions (it will not return an empty list). This list ordering is not * specified. @@ -1985,7 +1985,7 @@ public class ActivityManager { /** * Information you can retrieve about a running process. */ - public static class RunningAppProcessInfo implements Parcelable { + public static class RunningAppProcessInfo implements Parcelable { /** * The name of the process that this object is associated with */ @@ -1995,17 +1995,17 @@ public class ActivityManager { * The pid of this process; 0 if none */ public int pid; - + /** * The user id of this process. */ public int uid; - + /** * All packages that have been loaded into the process. */ public String pkgList[]; - + /** * Constant for {@link #flags}: this is an app that is unable to * correctly save its state when going to the background, @@ -2013,7 +2013,7 @@ public class ActivityManager { * @hide */ public static final int FLAG_CANT_SAVE_STATE = 1<<0; - + /** * Constant for {@link #flags}: this process is associated with a * persistent system app. @@ -2048,7 +2048,7 @@ public class ActivityManager { * that the user is interacting with. */ public static final int IMPORTANCE_FOREGROUND = 100; - + /** * Constant for {@link #importance}: This process is running a foreground * service, for example to perform music playback even while the user is @@ -2075,13 +2075,13 @@ public class ActivityManager { * other services under the system's control that it inconsiders important. */ public static final int IMPORTANCE_VISIBLE = 200; - + /** * Constant for {@link #importance}: This process is not something the user * is directly aware of, but is otherwise perceptable to them to some degree. */ public static final int IMPORTANCE_PERCEPTIBLE = 130; - + /** * Constant for {@link #importance}: This process is running an * application that can not save its state, and thus can't be killed @@ -2089,7 +2089,7 @@ public class ActivityManager { * @hide */ public static final int IMPORTANCE_CANT_SAVE_STATE = 170; - + /** * Constant for {@link #importance}: This process is contains services * that should remain running. These are background services apps have @@ -2098,13 +2098,13 @@ public class ActivityManager { * stay running as long as they want to). */ public static final int IMPORTANCE_SERVICE = 300; - + /** * Constant for {@link #importance}: This process process contains * background code that is expendable. */ public static final int IMPORTANCE_BACKGROUND = 400; - + /** * Constant for {@link #importance}: This process is empty of any * actively running code. @@ -2148,7 +2148,7 @@ public class ActivityManager { * smaller than "less important" values. */ public int importance; - + /** * An additional ordering within a particular {@link #importance} * category, providing finer-grained information about the relative @@ -2165,7 +2165,7 @@ public class ActivityManager { * been specified for the reason for this level. */ public static final int REASON_UNKNOWN = 0; - + /** * Constant for {@link #importanceReasonCode}: one of the application's * content providers is being used by another process. The pid of @@ -2174,7 +2174,7 @@ public class ActivityManager { * {@link #importanceReasonComponent}. */ public static final int REASON_PROVIDER_IN_USE = 1; - + /** * Constant for {@link #importanceReasonCode}: one of the application's * content providers is being used by another process. The pid of @@ -2183,25 +2183,25 @@ public class ActivityManager { * {@link #importanceReasonComponent}. */ public static final int REASON_SERVICE_IN_USE = 2; - + /** * The reason for {@link #importance}, if any. */ public int importanceReasonCode; - + /** * For the specified values of {@link #importanceReasonCode}, this * is the process ID of the other process that is a client of this * process. This will be 0 if no other process is using this one. */ public int importanceReasonPid; - + /** * For the specified values of {@link #importanceReasonCode}, this * is the name of the component that is being used in this process. */ public ComponentName importanceReasonComponent; - + /** * When {@link #importanceReasonPid} is non-0, this is the importance * of the other pid. @hide @@ -2219,7 +2219,7 @@ public class ActivityManager { importanceReasonCode = REASON_UNKNOWN; processState = PROCESS_STATE_IMPORTANT_FOREGROUND; } - + public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) { processName = pProcessName; pid = pPid; @@ -2262,7 +2262,7 @@ public class ActivityManager { processState = source.readInt(); } - public static final Creator<RunningAppProcessInfo> CREATOR = + public static final Creator<RunningAppProcessInfo> CREATOR = new Creator<RunningAppProcessInfo>() { public RunningAppProcessInfo createFromParcel(Parcel source) { return new RunningAppProcessInfo(source); @@ -2276,7 +2276,7 @@ public class ActivityManager { readFromParcel(source); } } - + /** * Returns a list of application processes installed on external media * that are running on the device. @@ -2297,6 +2297,23 @@ public class ActivityManager { } /** + * Sets the memory trim mode for a process and schedules a memory trim operation. + * + * <p><b>Note: this method is only intended for testing framework.</b></p> + * + * @return Returns true if successful. + * @hide + */ + public boolean setProcessMemoryTrimLevel(String process, int userId, int level) { + try { + return ActivityManagerNative.getDefault().setProcessMemoryTrimLevel(process, userId, + level); + } catch (RemoteException e) { + return false; + } + } + + /** * Returns a list of application processes that are running on the device. * * <p><b>Note: this method is only intended for debugging or building @@ -2368,7 +2385,7 @@ public class ActivityManager { return null; } } - + /** * @deprecated This is now just a wrapper for * {@link #killBackgroundProcesses(String)}; the previous behavior here @@ -2380,17 +2397,17 @@ public class ActivityManager { public void restartPackage(String packageName) { killBackgroundProcesses(packageName); } - + /** * Have the system immediately kill all background processes associated * with the given package. This is the same as the kernel killing those * processes to reclaim memory; the system will take care of restarting * these processes in the future as needed. - * + * * <p>You must hold the permission * {@link android.Manifest.permission#KILL_BACKGROUND_PROCESSES} to be able to * call this method. - * + * * @param packageName The name of the package whose processes are to * be killed. */ @@ -2426,14 +2443,14 @@ public class ActivityManager { * removed, etc. In addition, a {@link Intent#ACTION_PACKAGE_RESTARTED} * broadcast will be sent, so that any of its registered alarms can * be stopped, notifications removed, etc. - * + * * <p>You must hold the permission * {@link android.Manifest.permission#FORCE_STOP_PACKAGES} to be able to * call this method. - * + * * @param packageName The name of the package to be stopped. * @param userId The user for which the running package is to be stopped. - * + * * @hide This is not available to third party applications due to * it allowing them to break other applications by stopping their * services, removing their alarms, etc. @@ -2697,7 +2714,7 @@ public class ActivityManager { } /** - * @param userid the user's id. Zero indicates the default user + * @param userid the user's id. Zero indicates the default user. * @hide */ public boolean switchUser(int userid) { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index b6cec60..dabcc50c 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1548,21 +1548,21 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeInt(res ? 1 : 0); return true; } - + case STOP_APP_SWITCHES_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); stopAppSwitches(); reply.writeNoException(); return true; } - + case RESUME_APP_SWITCHES_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); resumeAppSwitches(); reply.writeNoException(); return true; } - + case PEEK_SERVICE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); Intent service = Intent.CREATOR.createFromParcel(data); @@ -1572,7 +1572,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeStrongBinder(binder); return true; } - + case START_BACKUP_AGENT_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data); @@ -1625,7 +1625,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } - + case GET_PROCESS_MEMORY_INFO_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int[] pids = data.createIntArray(); @@ -1643,7 +1643,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } - + case OVERRIDE_PENDING_TRANSITION_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); @@ -1654,7 +1654,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } - + case IS_USER_A_MONKEY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); boolean areThey = isUserAMonkey(); @@ -1662,7 +1662,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeInt(areThey ? 1 : 0); return true; } - + case SET_USER_IS_MONKEY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); final boolean monkey = (data.readInt() == 1); @@ -1738,7 +1738,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } - + case IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); boolean isit = isTopActivityImmersive(); @@ -1890,7 +1890,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } - + case SWITCH_USER_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int userid = data.readInt(); @@ -2208,7 +2208,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM int requestType = data.readInt(); String hint = data.readString(); int userHandle = data.readInt(); - boolean res = launchAssistIntent(intent, requestType, hint, userHandle); + Bundle args = data.readBundle(); + boolean res = launchAssistIntent(intent, requestType, hint, userHandle, args); reply.writeNoException(); reply.writeInt(res ? 1 : 0); return true; @@ -2533,21 +2534,23 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case UPDATE_PREFERRED_SETUP_ACTIVITY_TRANSACTION: { + case GET_PACKAGE_PROCESS_STATE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - ComponentName preferredActivity = ComponentName.readFromParcel(data); - int userId = data.readInt(); - updatePreferredSetupActivity(preferredActivity, userId); + String pkg = data.readString(); + int res = getPackageProcessState(pkg); reply.writeNoException(); + reply.writeInt(res); return true; } - case GET_PACKAGE_PROCESS_STATE_TRANSACTION: { + case SET_PROCESS_MEMORY_TRIM_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - String pkg = data.readString(); - int res = getPackageProcessState(pkg); + String process = data.readString(); + int userId = data.readInt(); + int level = data.readInt(); + boolean res = setProcessMemoryTrimLevel(process, userId, level); reply.writeNoException(); - reply.writeInt(res); + reply.writeInt(res ? 1 : 0); return true; } } @@ -3621,7 +3624,7 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return res; } - + public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, int userId) throws RemoteException { @@ -3724,7 +3727,7 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return res; } - + public void publishService(IBinder token, Intent intent, IBinder service) throws RemoteException { Parcel data = Parcel.obtain(); @@ -3767,7 +3770,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - + public IBinder peekService(Intent service, String resolvedType) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -4457,7 +4460,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - + public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo) throws RemoteException { @@ -4521,7 +4524,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); return res; } - + public void stopAppSwitches() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -4531,7 +4534,7 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); data.recycle(); } - + public void resumeAppSwitches() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -4566,7 +4569,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - + public void closeSystemDialogs(String reason) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -4577,7 +4580,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - + public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids) throws RemoteException { Parcel data = Parcel.obtain(); @@ -4603,7 +4606,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - + public void overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim) throws RemoteException { Parcel data = Parcel.obtain(); @@ -4618,7 +4621,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - + public boolean isUserAMonkey() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -4874,7 +4877,7 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); return res; } - + public int startActivities(IApplicationThread caller, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle options, int userId) throws RemoteException { @@ -5378,8 +5381,8 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } - public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) - throws RemoteException { + public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle, + Bundle args) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -5387,6 +5390,7 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(requestType); data.writeString(hint); data.writeInt(userHandle); + data.writeBundle(args); mRemote.transact(LAUNCH_ASSIST_INTENT_TRANSACTION, data, reply, 0); reply.readException(); boolean res = reply.readInt() != 0; @@ -5855,31 +5859,34 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void updatePreferredSetupActivity(ComponentName preferredActivity, int userId) - throws RemoteException { + public int getPackageProcessState(String packageName) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - ComponentName.writeToParcel(preferredActivity, data); - data.writeInt(userId); - mRemote.transact(UPDATE_PREFERRED_SETUP_ACTIVITY_TRANSACTION, data, reply, 0); + data.writeString(packageName); + mRemote.transact(GET_PACKAGE_PROCESS_STATE_TRANSACTION, data, reply, 0); reply.readException(); + int res = reply.readInt(); data.recycle(); reply.recycle(); + return res; } @Override - public int getPackageProcessState(String packageName) throws RemoteException { + public boolean setProcessMemoryTrimLevel(String process, int userId, int level) + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - data.writeString(packageName); - mRemote.transact(GET_PACKAGE_PROCESS_STATE_TRANSACTION, data, reply, 0); + data.writeString(process); + data.writeInt(userId); + data.writeInt(level); + mRemote.transact(SET_PROCESS_MEMORY_TRIM_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); data.recycle(); reply.recycle(); - return res; + return res != 0; } private IBinder mRemote; diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 9f23b43..6fb997e 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -41,16 +41,16 @@ public class ActivityOptions { /** * A long in the extras delivered by {@link #requestUsageTimeReport} that contains - * the total time (in ms) the user spent in the app. + * the total time (in ms) the user spent in the app flow. */ - public static final String EXTRA_USAGE_REPORT_TIME = "android.time"; + public static final String EXTRA_USAGE_TIME_REPORT = "android.usage_time"; /** * A Bundle in the extras delivered by {@link #requestUsageTimeReport} that contains * detailed information about the time spent in each package associated with the app; * each key is a package name, whose value is a long containing the time (in ms). */ - public static final String EXTRA_USAGE_REPORT_PACKAGES = "android.package"; + public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages"; /** * The package name that created the options. @@ -915,7 +915,7 @@ public class ActivityOptions { /** * Ask the the system track that time the user spends in the app being launched, and * report it back once done. The report will be sent to the given receiver, with - * the extras {@link #EXTRA_USAGE_REPORT_TIME} and {@link #EXTRA_USAGE_REPORT_PACKAGES} + * the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES} * filled in. * * <p>The time interval tracked is from launching this activity until the user leaves diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3224d41..ffb3fb8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1640,6 +1640,10 @@ public final class ActivityThread { return sCurrentActivityThread; } + public static boolean isSystem() { + return (sCurrentActivityThread != null) ? sCurrentActivityThread.mSystemThread : false; + } + public static String currentOpPackageName() { ActivityThread am = currentActivityThread(); return (am != null && am.getApplication() != null) @@ -2440,7 +2444,8 @@ public final class ActivityThread { && r.packageInfo.mPackageName.contains(pkgName)) { for (int id : dm.getDisplayIds()) { if (id != Display.DEFAULT_DISPLAY) { - Display display = dm.getRealDisplay(id, r.overrideConfig); + Display display = + dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id)); baseContext = appContext.createDisplayContext(display); break; } @@ -2580,9 +2585,9 @@ public final class ActivityThread { intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)); intent.removeUnsafeExtras(); - content.setIntent(intent); + content.setDefaultIntent(intent); } else { - content.setIntent(new Intent()); + content.setDefaultIntent(new Intent()); } r.activity.onProvideAssistContent(content); } diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index eafcdb2..9c0d931 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -24,7 +24,10 @@ import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; import android.graphics.SurfaceTexture; +import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; +import android.os.Message; import android.os.OperationCanceledException; import android.os.RemoteException; import android.util.AttributeSet; @@ -48,7 +51,9 @@ public class ActivityView extends ViewGroup { private static final String TAG = "ActivityView"; private static final boolean DEBUG = false; - DisplayMetrics mMetrics; + private static final int MSG_SET_SURFACE = 1; + + DisplayMetrics mMetrics = new DisplayMetrics(); private final TextureView mTextureView; private ActivityContainerWrapper mActivityContainer; private Activity mActivity; @@ -58,6 +63,9 @@ public class ActivityView extends ViewGroup { private int mLastVisibility; private ActivityViewCallback mActivityViewCallback; + private HandlerThread mThread = new HandlerThread("ActivityViewThread"); + private Handler mHandler; + public ActivityView(Context context) { this(context, null); } @@ -89,12 +97,27 @@ public class ActivityView extends ViewGroup { + e); } + mThread.start(); + mHandler = new Handler(mThread.getLooper()) { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == MSG_SET_SURFACE) { + try { + mActivityContainer.setSurface((Surface) msg.obj, msg.arg1, msg.arg2, + mMetrics.densityDpi); + } catch (RemoteException e) { + throw new RuntimeException( + "ActivityView: Unable to set surface of ActivityContainer. " + e); + } + } + } + }; mTextureView = new TextureView(context); mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener()); addView(mTextureView); WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE); - mMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(mMetrics); mLastVisibility = getVisibility(); @@ -111,18 +134,12 @@ public class ActivityView extends ViewGroup { protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); - if (mSurface != null) { - try { - if (visibility == View.GONE) { - mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi); - } else if (mLastVisibility == View.GONE) { - // Don't change surface when going between View.VISIBLE and View.INVISIBLE. - mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi); - } - } catch (RemoteException e) { - throw new RuntimeException( - "ActivityView: Unable to set surface of ActivityContainer. " + e); - } + if (mSurface != null && (visibility == View.GONE || mLastVisibility == View.GONE)) { + Message msg = Message.obtain(mHandler, MSG_SET_SURFACE); + msg.obj = (visibility == View.GONE) ? null : mSurface; + msg.arg1 = mWidth; + msg.arg2 = mHeight; + mHandler.sendMessage(msg); } mLastVisibility = visibility; } diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java index 4cb89a8..d23e73d 100644 --- a/core/java/android/app/AssistContent.java +++ b/core/java/android/app/AssistContent.java @@ -31,6 +31,7 @@ import android.os.Parcelable; */ @Deprecated public class AssistContent { + private boolean mIsAppProvidedIntent = false; private Intent mIntent; private ClipData mClipData; private Uri mUri; @@ -55,12 +56,14 @@ public class AssistContent { } /** - * Sets the Intent associated with the content, describing the current top-level context of - * the activity. If this contains a reference to a piece of data related to the activity, - * be sure to set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} so the accessibility - * service can access it. + * @hide + * Called by {@link android.app.ActivityThread} to set the default Intent based on + * {@link android.app.Activity#getIntent Activity.getIntent}. + * + * <p>Automatically populates {@link #mUri} if that Intent is an {@link Intent#ACTION_VIEW} + * of a web (http or https scheme) URI.</p> */ - public void setIntent(Intent intent) { + public void setDefaultIntent(Intent intent) { mIntent = intent; setWebUri(null); if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { @@ -72,7 +75,19 @@ public class AssistContent { } /** - * Return the current {@link #setIntent}, which you can modify in-place. + * Sets the Intent associated with the content, describing the current top-level context of + * the activity. If this contains a reference to a piece of data related to the activity, + * be sure to set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} so the accessibility + * service can access it. + */ + public void setIntent(Intent intent) { + mIsAppProvidedIntent = true; + mIntent = intent; + } + + /** + * Returns the current {@link #setIntent} if one is set, else the default Intent obtained from + * {@link android.app.Activity#getIntent Activity.getIntent}. Can be modified in-place. * @hide */ public Intent getIntent() { @@ -80,6 +95,16 @@ public class AssistContent { } /** + * Returns whether or not the current Intent was explicitly provided in + * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. If not, + * the Intent was automatically set based on + * {@link android.app.Activity#getIntent Activity.getIntent}. + */ + public boolean isAppProvidedIntent() { + return mIsAppProvidedIntent; + } + + /** * Optional additional content items that are involved with * the current UI. Access to this content will be granted to the assistant as if you * are sending it through an Intent with {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}. @@ -103,9 +128,6 @@ public class AssistContent { * off the device into other environments to acesss the same data as is currently * being shown in the app; if the app does not have such a representation, it should * leave the null and only report the local intent and clip data. - * - * <p>This will be automatically populated for you from {@link #setIntent} if that Intent - * is an {@link Intent#ACTION_VIEW} of a web (http or https scheme) URI.</p> */ public void setWebUri(Uri uri) { mUri = uri; @@ -130,6 +152,7 @@ public class AssistContent { if (in.readInt() != 0) { mUri = Uri.CREATOR.createFromParcel(in); } + mIsAppProvidedIntent = in.readInt() == 1; } /** @hide */ @@ -152,5 +175,6 @@ public class AssistContent { } else { dest.writeInt(0); } + dest.writeInt(mIsAppProvidedIntent ? 1 : 0); } } diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java index ef7fde4..0f69817 100644 --- a/core/java/android/app/AssistStructure.java +++ b/core/java/android/app/AssistStructure.java @@ -235,7 +235,7 @@ public class AssistStructure { static final int FLAGS_CHECKED = 0x00000200; static final int FLAGS_CLICKABLE = 0x00004000; static final int FLAGS_LONG_CLICKABLE = 0x00200000; - static final int FLAGS_STYLUS_BUTTON_PRESSABLE = 0x00400000; + static final int FLAGS_CONTEXT_CLICKABLE = 0x00400000; int mFlags; @@ -413,8 +413,8 @@ public class AssistStructure { return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0; } - public boolean isStylusButtonPressable() { - return (mFlags&ViewNode.FLAGS_STYLUS_BUTTON_PRESSABLE) != 0; + public boolean isContextClickable() { + return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0; } public String getClassName() { @@ -529,9 +529,9 @@ public class AssistStructure { } @Override - public void setStylusButtonPressable(boolean state) { - mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_STYLUS_BUTTON_PRESSABLE) - | (state ? ViewNode.FLAGS_STYLUS_BUTTON_PRESSABLE : 0); + public void setContextClickable(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CONTEXT_CLICKABLE) + | (state ? ViewNode.FLAGS_CONTEXT_CLICKABLE : 0); } @Override diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 3b1ccd2..829b098 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1597,7 +1597,7 @@ class ContextImpl extends Context { final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, new UserHandle(UserHandle.getUserId(application.uid)), restricted, - mDisplay, null); + mDisplay, null, Display.INVALID_DISPLAY); if (c.mResources != null) { return c; } @@ -1620,14 +1620,14 @@ class ContextImpl extends Context { final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; if (packageName.equals("system") || packageName.equals("android")) { return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, - user, restricted, mDisplay, null); + user, restricted, mDisplay, null, Display.INVALID_DISPLAY); } LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier()); if (pi != null) { ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, - user, restricted, mDisplay, null); + user, restricted, mDisplay, null, Display.INVALID_DISPLAY); if (c.mResources != null) { return c; } @@ -1645,7 +1645,7 @@ class ContextImpl extends Context { } return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, - mUser, mRestricted, mDisplay, overrideConfiguration); + mUser, mRestricted, mDisplay, overrideConfiguration, Display.INVALID_DISPLAY); } @Override @@ -1655,15 +1655,15 @@ class ContextImpl extends Context { } return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, - mUser, mRestricted, display, null); + mUser, mRestricted, display, null, Display.INVALID_DISPLAY); } Display getDisplay() { if (mDisplay != null) { return mDisplay; } - DisplayManager dm = getSystemService(DisplayManager.class); - return dm.getDisplay(Display.DEFAULT_DISPLAY); + return ResourcesManager.getInstance().getAdjustedDisplay( + Display.DEFAULT_DISPLAY, mDisplayAdjustments); } private int getDisplayId() { @@ -1708,7 +1708,7 @@ class ContextImpl extends Context { static ContextImpl createSystemContext(ActivityThread mainThread) { LoadedApk packageInfo = new LoadedApk(mainThread); ContextImpl context = new ContextImpl(null, mainThread, - packageInfo, null, null, false, null, null); + packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY); context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), context.mResourcesManager.getDisplayMetricsLocked()); return context; @@ -1717,21 +1717,19 @@ class ContextImpl extends Context { static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); return new ContextImpl(null, mainThread, - packageInfo, null, null, false, null, null); + packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY); } static ContextImpl createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); - final Display display = ResourcesManager.getInstance().getAdjustedDisplay( - displayId, overrideConfiguration); - return new ContextImpl(null, mainThread, packageInfo, null, null, false, display, - overrideConfiguration); + return new ContextImpl(null, mainThread, packageInfo, null, null, false, + null, overrideConfiguration, displayId); } private ContextImpl(ContextImpl container, ActivityThread mainThread, LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted, - Display display, Configuration overrideConfiguration) { + Display display, Configuration overrideConfiguration, int createDisplayWithId) { mOuterContext = this; mMainThread = mainThread; @@ -1745,9 +1743,10 @@ class ContextImpl extends Context { mPackageInfo = packageInfo; mResourcesManager = ResourcesManager.getInstance(); - mDisplay = display; - final int displayId = getDisplayId(); + final int displayId = (createDisplayWithId != Display.INVALID_DISPLAY) + ? createDisplayWithId : getDisplayId(); + CompatibilityInfo compatInfo = null; if (container != null) { compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo(); @@ -1760,6 +1759,9 @@ class ContextImpl extends Context { mDisplayAdjustments.setCompatibilityInfo(compatInfo); mDisplayAdjustments.setConfiguration(overrideConfiguration); + mDisplay = (createDisplayWithId == Display.INVALID_DISPLAY) ? display + : ResourcesManager.getInstance().getAdjustedDisplay(displayId, mDisplayAdjustments); + Resources resources = packageInfo.getResources(mainThread); if (resources != null) { if (displayId != Display.DEFAULT_DISPLAY diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 249cdb2..0d5e1c7 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -242,14 +242,14 @@ public interface IActivityManager extends IInterface { public void showWaitingForDebugger(IApplicationThread who, boolean waiting) throws RemoteException; - + public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException; - + public void killBackgroundProcesses(final String packageName, int userId) throws RemoteException; public void killAllBackgroundProcesses() throws RemoteException; public void forceStopPackage(final String packageName, int userId) throws RemoteException; - + // Note: probably don't want to allow applications access to these. public void setLockScreenShown(boolean shown) throws RemoteException; @@ -263,7 +263,7 @@ public interface IActivityManager extends IInterface { throws RemoteException; public void enterSafeMode() throws RemoteException; - + public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag) throws RemoteException; public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag) @@ -318,9 +318,9 @@ public interface IActivityManager extends IInterface { public void killApplicationWithAppId(String pkg, int appid, String reason) throws RemoteException; - + public void closeSystemDialogs(String reason) throws RemoteException; - + public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids) throws RemoteException; @@ -438,8 +438,8 @@ public interface IActivityManager extends IInterface { public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure, AssistContent content) throws RemoteException; - public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) - throws RemoteException; + public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle, + Bundle args) throws RemoteException; public void killUid(int uid, String reason) throws RemoteException; @@ -502,11 +502,12 @@ public interface IActivityManager extends IInterface { throws RemoteException; public void updateLockTaskPackages(int userId, String[] packages) throws RemoteException; public void updateDeviceOwner(String packageName) throws RemoteException; - public void updatePreferredSetupActivity(ComponentName preferredActivity, int userId) - throws RemoteException; public int getPackageProcessState(String packageName) throws RemoteException; + public boolean setProcessMemoryTrimLevel(String process, int uid, int level) + throws RemoteException; + /* * Private non-Binder interfaces */ @@ -792,6 +793,7 @@ public interface IActivityManager extends IInterface { // Available int GET_ACTIVITY_DISPLAY_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184; int DELETE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+185; + int SET_PROCESS_MEMORY_TRIM_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+186; // Start of L transactions @@ -846,8 +848,7 @@ public interface IActivityManager extends IInterface { int GET_PACKAGE_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+293; int SHOW_LOCK_TASK_ESCAPE_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+294; int UPDATE_DEVICE_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+295; - int UPDATE_PREFERRED_SETUP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+296; - int KEYGUARD_GOING_AWAY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+297; - int REGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298; - int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+299; + int KEYGUARD_GOING_AWAY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+296; + int REGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+297; + int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298; } diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 63ff005..f78fb47 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -17,7 +17,6 @@ package android.app; -import android.app.INotificationManagerCallback; import android.app.ITransientNotification; import android.app.Notification; import android.app.NotificationManager; @@ -87,7 +86,6 @@ interface INotificationManager oneway void setZenMode(int mode, in Uri conditionId, String reason); oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions); oneway void requestZenModeConditions(in IConditionListener callback, int relevance); - oneway void requestNotificationPolicyAccess(String pkg, in INotificationManagerCallback callback); boolean isNotificationPolicyAccessGranted(String pkg); NotificationManager.Policy getNotificationPolicy(String pkg); void setNotificationPolicy(String pkg, in NotificationManager.Policy policy); diff --git a/core/java/android/app/INotificationManagerCallback.aidl b/core/java/android/app/INotificationManagerCallback.aidl deleted file mode 100644 index 9929745..0000000 --- a/core/java/android/app/INotificationManagerCallback.aidl +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2015, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app; - -import android.app.NotificationManager; - -/** @hide */ -oneway interface INotificationManagerCallback { - void onPolicyRequestResult(boolean granted); -} diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl index 6d27910..6094012 100644 --- a/core/java/android/app/ISearchManager.aidl +++ b/core/java/android/app/ISearchManager.aidl @@ -31,5 +31,5 @@ interface ISearchManager { ComponentName getGlobalSearchActivity(); ComponentName getWebSearchActivity(); ComponentName getAssistIntent(int userHandle); - boolean launchAssistAction(String hint, int userHandle); + boolean launchAssistAction(String hint, int userHandle, in Bundle args); } diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 557964b..0904e21 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -101,6 +101,16 @@ public class NotificationManager = "android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED"; /** + * Intent that is broadcast when the state of {@link #isNotificationPolicyAccessGranted()} + * changes. + * + * This broadcast is only sent to registered receivers, and only to the apps that have changed. + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED + = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED"; + + /** * Intent that is broadcast when the state of getNotificationPolicy() changes. * This broadcast is only sent to registered receivers. */ @@ -403,55 +413,18 @@ public class NotificationManager } /** - * Requests the ability to read/modify notification policy for the calling package. - * - * @param callback required, used to receive the granted or the denied signal. - * @param handler The handler used when receiving the result. - * If null, the current thread is used. - */ - public void requestPolicyAccess(@NonNull final NotificationPolicyAccessRequestCallback callback, - @Nullable Handler handler) { - checkRequired("callback", callback); - final Handler h = handler != null ? handler : new Handler(); - INotificationManager service = getService(); - try { - service.requestNotificationPolicyAccess(mContext.getOpPackageName(), - new INotificationManagerCallback.Stub() { - @Override - public void onPolicyRequestResult(final boolean granted) throws RemoteException { - h.post(new Runnable() { - @Override - public void run() { - if (granted) { - callback.onAccessGranted(); - } else { - callback.onAccessDenied(); - } - } - }); - } - }); - } catch (RemoteException e) { - } - } - - /** Callback for receiving the result of a policy access request. */ - public static abstract class NotificationPolicyAccessRequestCallback { - /** - * Received if the request was granted for this package. - */ - public abstract void onAccessGranted(); - - /** - * Received if the request was denied for this package. - */ - public abstract void onAccessDenied(); - } - - /** * Checks the ability to read/modify notification policy for the calling package. * + * <p> * Returns true if the calling package can read/modify notification policy. + * + * <p> + * Request policy access by sending the user to the activity that matches the system intent + * action {@link android.provider.Settings#ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS}. + * + * <p> + * Use {@link #ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED} to listen for + * user grant or denial of this access. */ public boolean isNotificationPolicyAccessGranted() { INotificationManager service = getService(); @@ -476,7 +449,8 @@ public class NotificationManager * Gets the current notification policy. * * <p> - * Only available if policy access is granted. + * Only available if policy access is granted to this package. + * See {@link #isNotificationPolicyAccessGranted}. */ public Policy getNotificationPolicy() { INotificationManager service = getService(); @@ -491,7 +465,8 @@ public class NotificationManager * Sets the current notification policy. * * <p> - * Only available if policy access is granted. + * Only available if policy access is granted to this package. + * See {@link #isNotificationPolicyAccessGranted}. * * @param policy The new desired policy. */ @@ -716,7 +691,8 @@ public class NotificationManager * unavailable. * * <p> - * Only available if policy access is granted. + * Only available if policy access is granted to this package. + * See {@link #isNotificationPolicyAccessGranted}. */ public final int getCurrentInterruptionFilter() { final INotificationManager service = getService(); @@ -738,7 +714,8 @@ public class NotificationManager * unavailable. * * <p> - * Only available if policy access is granted. + * Only available if policy access is granted to this package. + * See {@link #isNotificationPolicyAccessGranted}. */ public final void setInterruptionFilter(int interruptionFilter) { final INotificationManager service = getService(); diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 2cfc1fa4..031854a 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -25,11 +25,13 @@ import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.IntentSender; import android.os.Bundle; +import android.os.Looper; import android.os.RemoteException; import android.os.Handler; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.os.UserHandle; import android.util.AndroidException; @@ -206,10 +208,20 @@ public final class PendingIntent implements Parcelable { private int mResultCode; private String mResultData; private Bundle mResultExtras; + private static Handler sDefaultSystemHandler; FinishedDispatcher(PendingIntent pi, OnFinished who, Handler handler) { mPendingIntent = pi; mWho = who; - mHandler = handler; + if (handler == null && ActivityThread.isSystem()) { + // We assign a default handler for the system process to avoid deadlocks when + // processing receivers in various components that hold global service locks. + if (sDefaultSystemHandler == null) { + sDefaultSystemHandler = new Handler(Looper.getMainLooper()); + } + mHandler = sDefaultSystemHandler; + } else { + mHandler = handler; + } } public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean serialized, boolean sticky, int sendingUser) { diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 79797c9..2117597 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -31,6 +31,8 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; import android.view.Display; +import android.view.DisplayAdjustments; + import java.lang.ref.WeakReference; import java.util.Locale; @@ -42,7 +44,7 @@ public class ResourcesManager { private static ResourcesManager sResourcesManager; private final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources = new ArrayMap<>(); - private final ArrayMap<Pair<Integer, Configuration>, WeakReference<Display>> mDisplays = + private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>> mDisplays = new ArrayMap<>(); CompatibilityInfo mResCompatibilityInfo; @@ -68,7 +70,8 @@ public class ResourcesManager { DisplayMetrics getDisplayMetricsLocked(int displayId) { DisplayMetrics dm = new DisplayMetrics(); - final Display display = getAdjustedDisplay(displayId, Configuration.EMPTY); + final Display display = + getAdjustedDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); if (display != null) { display.getMetrics(dm); } else { @@ -113,12 +116,13 @@ public class ResourcesManager { * available. * * @param displayId display Id. - * @param overrideConfiguration override configurations. + * @param displayAdjustments display adjustments. */ - public Display getAdjustedDisplay(final int displayId, Configuration overrideConfiguration) { - final Configuration configCopy = (overrideConfiguration != null) - ? new Configuration(overrideConfiguration) : new Configuration(); - final Pair<Integer, Configuration> key = Pair.create(displayId, configCopy); + public Display getAdjustedDisplay(final int displayId, DisplayAdjustments displayAdjustments) { + final DisplayAdjustments displayAdjustmentsCopy = (displayAdjustments != null) + ? new DisplayAdjustments(displayAdjustments) : new DisplayAdjustments(); + final Pair<Integer, DisplayAdjustments> key = + Pair.create(displayId, displayAdjustmentsCopy); synchronized (this) { WeakReference<Display> wd = mDisplays.get(key); if (wd != null) { @@ -132,7 +136,7 @@ public class ResourcesManager { // may be null early in system startup return null; } - final Display display = dm.getRealDisplay(displayId, key.second); + final Display display = dm.getCompatibleDisplay(displayId, key.second); if (display != null) { mDisplays.put(key, new WeakReference<>(display)); } diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index fa27631..45799a1 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -985,12 +985,12 @@ public class SearchManager * Launch an assist action for the current top activity. * @hide */ - public boolean launchAssistAction(String hint, int userHandle) { + public boolean launchAssistAction(String hint, int userHandle, Bundle args) { try { if (mService == null) { return false; } - return mService.launchAssistAction(hint, userHandle); + return mService.launchAssistAction(hint, userHandle, args); } catch (RemoteException re) { Log.e(TAG, "launchAssistAction() failed: " + re); return false; diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 0d00908..10e8a53 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -691,7 +691,7 @@ final class SystemServiceRegistry { @Override public MidiManager createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(Context.MIDI_SERVICE); - return new MidiManager(ctx, IMidiManager.Stub.asInterface(b)); + return new MidiManager(IMidiManager.Stub.asInterface(b)); }}); registerService(Context.RADIO_SERVICE, RadioManager.class, diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index 9ba6a8e..39cd3bc 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -239,9 +239,10 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { public void run() { InputStream in = null; OutputStream out = null; + java.lang.Process process = null; try { - java.lang.Process process = Runtime.getRuntime().exec(command); + process = Runtime.getRuntime().exec(command); in = process.getInputStream(); out = new FileOutputStream(sink.getFileDescriptor()); @@ -257,7 +258,9 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } catch (IOException ioe) { throw new RuntimeException("Error running shell command", ioe); } finally { - IoUtils.closeQuietly(in); + if (process != null) { + process.destroy(); + } IoUtils.closeQuietly(out); IoUtils.closeQuietly(sink); } diff --git a/core/java/android/app/VoiceInteractor.aidl b/core/java/android/app/VoiceInteractor.aidl index 40a4a0e..949605c 100644 --- a/core/java/android/app/VoiceInteractor.aidl +++ b/core/java/android/app/VoiceInteractor.aidl @@ -17,3 +17,4 @@ package android.app; parcelable VoiceInteractor.PickOptionRequest.Option; +parcelable VoiceInteractor.Prompt; diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java index ba27c54..eccd9dc 100644 --- a/core/java/android/app/VoiceInteractor.java +++ b/core/java/android/app/VoiceInteractor.java @@ -16,6 +16,8 @@ package android.app; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.os.Bundle; import android.os.IBinder; @@ -257,7 +259,7 @@ public class VoiceInteractor { * so the user can give a confirmation. */ public static class ConfirmationRequest extends Request { - final CharSequence mPrompt; + final Prompt mPrompt; final Bundle mExtras; /** @@ -266,11 +268,23 @@ public class VoiceInteractor { * should be spoken. * @param extras Additional optional information or null. */ - public ConfirmationRequest(CharSequence prompt, Bundle extras) { + public ConfirmationRequest(@Nullable Prompt prompt, @Nullable Bundle extras) { mPrompt = prompt; mExtras = extras; } + /** + * Create a new confirmation request. + * @param prompt Optional confirmation to speak to the user or null if nothing + * should be spoken. + * @param extras Additional optional information or null. + * @deprecated Prefer the version that takes a {@link Prompt}. + */ + public ConfirmationRequest(CharSequence prompt, Bundle extras) { + mPrompt = (prompt != null ? new Prompt(prompt) : null); + mExtras = extras; + } + public void onConfirmationResult(boolean confirmed, Bundle result) { } @@ -288,7 +302,7 @@ public class VoiceInteractor { * either {@link #onPickOptionResult} or {@link #onCancel()}. */ public static class PickOptionRequest extends Request { - final CharSequence mPrompt; + final Prompt mPrompt; final Option[] mOptions; final Bundle mExtras; @@ -417,13 +431,28 @@ public class VoiceInteractor { * @param options The set of {@link Option}s the user is selecting from. * @param extras Additional optional information or null. */ - public PickOptionRequest(CharSequence prompt, Option[] options, Bundle extras) { + public PickOptionRequest(@Nullable Prompt prompt, Option[] options, + @Nullable Bundle extras) { mPrompt = prompt; mOptions = options; mExtras = extras; } /** + * Create a new pick option request. + * @param prompt Optional question to be asked of the user when the options are + * presented or null if nothing should be asked. + * @param options The set of {@link Option}s the user is selecting from. + * @param extras Additional optional information or null. + * @deprecated Prefer the version that takes a {@link Prompt}. + */ + public PickOptionRequest(CharSequence prompt, Option[] options, Bundle extras) { + mPrompt = (prompt != null ? new Prompt(prompt) : null); + mOptions = options; + mExtras = extras; + } + + /** * Called when a single option is confirmed or narrowed to one of several options. * @param finished True if the voice interaction has finished making a selection, in * which case {@code selections} contains the final result. If false, this request is @@ -451,17 +480,29 @@ public class VoiceInteractor { * interaction task. */ public static class CompleteVoiceRequest extends Request { - final CharSequence mMessage; + final Prompt mPrompt; final Bundle mExtras; /** * Create a new completed voice interaction request. + * @param prompt Optional message to speak to the user about the completion status of + * the task or null if nothing should be spoken. + * @param extras Additional optional information or null. + */ + public CompleteVoiceRequest(@Nullable Prompt prompt, @Nullable Bundle extras) { + mPrompt = prompt; + mExtras = extras; + } + + /** + * Create a new completed voice interaction request. * @param message Optional message to speak to the user about the completion status of * the task or null if nothing should be spoken. * @param extras Additional optional information or null. + * @deprecated Prefer the version that takes a {@link Prompt}. */ public CompleteVoiceRequest(CharSequence message, Bundle extras) { - mMessage = message; + mPrompt = (message != null ? new Prompt(message) : null); mExtras = extras; } @@ -470,7 +511,7 @@ public class VoiceInteractor { IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, IVoiceInteractorCallback callback) throws RemoteException { - return interactor.startCompleteVoice(packageName, callback, mMessage, mExtras); + return interactor.startCompleteVoice(packageName, callback, mPrompt, mExtras); } } @@ -486,17 +527,29 @@ public class VoiceInteractor { * interaction task. */ public static class AbortVoiceRequest extends Request { - final CharSequence mMessage; + final Prompt mPrompt; final Bundle mExtras; /** * Create a new voice abort request. + * @param prompt Optional message to speak to the user indicating why the task could + * not be completed by voice or null if nothing should be spoken. + * @param extras Additional optional information or null. + */ + public AbortVoiceRequest(@Nullable Prompt prompt, @Nullable Bundle extras) { + mPrompt = prompt; + mExtras = extras; + } + + /** + * Create a new voice abort request. * @param message Optional message to speak to the user indicating why the task could * not be completed by voice or null if nothing should be spoken. * @param extras Additional optional information or null. + * @deprecated Prefer the version that takes a {@link Prompt}. */ public AbortVoiceRequest(CharSequence message, Bundle extras) { - mMessage = message; + mPrompt = (message != null ? new Prompt(message) : null); mExtras = extras; } @@ -505,7 +558,7 @@ public class VoiceInteractor { IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, IVoiceInteractorCallback callback) throws RemoteException { - return interactor.startAbortVoice(packageName, callback, mMessage, mExtras); + return interactor.startAbortVoice(packageName, callback, mPrompt, mExtras); } } @@ -550,7 +603,101 @@ public class VoiceInteractor { IVoiceInteractorCallback callback) throws RemoteException { return interactor.startCommand(packageName, callback, mCommand, mArgs); } - } + } + + /** + * A set of voice prompts to use with the voice interaction system to confirm an action, select + * an option, or do similar operations. Multiple voice prompts may be provided for variety. A + * visual prompt must be provided, which might not match the spoken version. For example, the + * confirmation "Are you sure you want to purchase this item?" might use a visual label like + * "Purchase item". + */ + public static class Prompt implements Parcelable { + // Mandatory voice prompt. Must contain at least one item, which must not be null. + private final CharSequence[] mVoicePrompts; + + // Mandatory visual prompt. + private final CharSequence mVisualPrompt; + + /** + * Constructs a prompt set. + * @param voicePrompts An array of one or more voice prompts. Must not be empty or null. + * @param visualPrompt A prompt to display on the screen. Must not be null. + */ + public Prompt(@NonNull CharSequence[] voicePrompts, @NonNull CharSequence visualPrompt) { + if (voicePrompts == null) { + throw new NullPointerException("voicePrompts must not be null"); + } + if (voicePrompts.length == 0) { + throw new IllegalArgumentException("voicePrompts must not be empty"); + } + if (visualPrompt == null) { + throw new NullPointerException("visualPrompt must not be null"); + } + this.mVoicePrompts = voicePrompts; + this.mVisualPrompt = visualPrompt; + } + + /** + * Constructs a prompt set with single prompt used for all interactions. This is most useful + * in test apps. Non-trivial apps should prefer the detailed constructor. + */ + public Prompt(@NonNull CharSequence prompt) { + this.mVoicePrompts = new CharSequence[] { prompt }; + this.mVisualPrompt = prompt; + } + + /** + * Returns a prompt to use for voice interactions. + */ + @NonNull + public CharSequence getVoicePromptAt(int index) { + return mVoicePrompts[index]; + } + + /** + * Returns the number of different voice prompts. + */ + public int countVoicePrompts() { + return mVoicePrompts.length; + } + + /** + * Returns the prompt to use for visual display. + */ + @NonNull + public CharSequence getVisualPrompt() { + return mVisualPrompt; + } + + /** Constructor to support Parcelable behavior. */ + Prompt(Parcel in) { + mVoicePrompts = in.readCharSequenceArray(); + mVisualPrompt = in.readCharSequence(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeCharSequenceArray(mVoicePrompts); + dest.writeCharSequence(mVisualPrompt); + } + + public static final Creator<Prompt> CREATOR + = new Creator<Prompt>() { + public Prompt createFromParcel(Parcel in) { + return new Prompt(in); + } + + public Prompt[] newArray(int size) { + return new Prompt[size]; + } + }; + } VoiceInteractor(IVoiceInteractor interactor, Context context, Activity activity, Looper looper) { @@ -631,7 +778,7 @@ public class VoiceInteractor { } /** - * Queries the supported commands available from the VoiceinteractionService. + * Queries the supported commands available from the VoiceInteractionService. * The command is a string that describes the generic operation to be performed. * An example might be "org.example.commands.PICK_DATE" to ask the user to pick * a date. (Note: This is not an actual working example.) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 55eaf27..3ab0e01 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4404,24 +4404,6 @@ public class DevicePolicyManager { } /** - * Called by a device initializer to set the activity to be launched on device boot or after a - * user switch during user setup. This activity will be started regardless of the priority of - * other 'home' activities. Once user setup is complete, the preferred setup activity will be - * ignored. - * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. - * @param activity The Activity to be started by default during user setup. - */ - public void setPreferredSetupActivity(@NonNull ComponentName admin, - @NonNull ComponentName activity) { - try { - mService.setPreferredSetupActivity(admin, activity); - } catch (RemoteException re) { - Log.w(TAG, "Failed talking with device policy service", re); - } - } - - /** * Called by profile or device owners to set the default response for future runtime permission * requests by applications. The policy can allow for normal operation which prompts the * user to grant a permission, or can allow automatic granting or denying of runtime diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 477a338..8c7b20a 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -218,8 +218,6 @@ interface IDevicePolicyManager { String getDeviceInitializer(); ComponentName getDeviceInitializerComponent(); - void setPreferredSetupActivity(in ComponentName admin, in ComponentName activity); - void setUserIcon(in ComponentName admin, in Bitmap icon); void sendDeviceInitializerStatus(int statusCode, String description); diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 5193563..1079f1a 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -29,11 +29,11 @@ import android.util.Log; import dalvik.system.CloseGuard; /** - * Class providing enumeration over buckets of network usage statistics. NetworkUsageStats objects + * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects * are returned as results to various queries in {@link NetworkStatsManager}. */ public final class NetworkStats implements AutoCloseable { - private final static String TAG = "NetworkUsageStats"; + private final static String TAG = "NetworkStats"; private final CloseGuard mCloseGuard = CloseGuard.get(); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c01ce4f..5c23204 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1274,6 +1274,13 @@ public class Intent implements Parcelable, Cloneable { "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD"; /** + * An optional field on {@link #ACTION_ASSIST} containing the InputDevice id + * that was used to invoke the assist. + */ + public static final String EXTRA_ASSIST_INPUT_DEVICE_ID = + "android.intent.extra.ASSIST_INPUT_DEVICE_ID"; + + /** * Activity Action: List all available applications * <p>Input: Nothing. * <p>Output: nothing. diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 45245e4..c016ac3 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3274,10 +3274,11 @@ public abstract class PackageManager { throws NameNotFoundException; /** - * If the target user is a managed profile of the calling user or the caller - * is itself a managed profile, then this returns a badged copy of the given - * icon to be able to distinguish it from the original icon. For badging an - * arbitrary drawable use {@link #getUserBadgedDrawableForDensity( + * If the target user is a managed profile of the calling user or if the + * target user is the caller and is itself a managed profile, then this + * returns a badged copy of the given icon to be able to distinguish it from + * the original icon. For badging an arbitrary drawable use + * {@link #getUserBadgedDrawableForDensity( * android.graphics.drawable.Drawable, UserHandle, android.graphics.Rect, int)}. * <p> * If the original drawable is a BitmapDrawable and the backing bitmap is diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index a572590..9a99a46 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -2486,7 +2486,8 @@ public class Resources { return true; } - /*package*/ Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException { + @Nullable + Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException { if (TRACE_FOR_PRELOAD) { // Log only framework resources if ((id >>> 24) == 0x1) { @@ -2541,7 +2542,7 @@ public class Resources { // Determine if the drawable has unresolved theme attributes. If it // does, we'll need to apply a theme and store it in a theme-specific // cache. - final boolean canApplyTheme = dr.canApplyTheme(); + final boolean canApplyTheme = dr != null && dr.canApplyTheme(); if (canApplyTheme && theme != null) { dr = dr.mutate(); dr.applyTheme(theme); diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index b2c1c71..bc625dd 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -169,6 +169,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> private final HashSet<Surface> mSurfaceSet; private final CameraMetadataNative mSettings; private boolean mIsReprocess; + // If this request is part of constrained high speed request list that was created by + // {@link CameraDevice#createConstrainedHighSpeedRequestList}. + private boolean mIsPartOfCHSRequestList = false; // Each reprocess request must be tied to a reprocessable session ID. // Valid only for reprocess requests (mIsReprocess == true). private int mReprocessableSessionId; @@ -197,6 +200,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> mSettings = new CameraMetadataNative(source.mSettings); mSurfaceSet = (HashSet<Surface>) source.mSurfaceSet.clone(); mIsReprocess = source.mIsReprocess; + mIsPartOfCHSRequestList = source.mIsPartOfCHSRequestList; mReprocessableSessionId = source.mReprocessableSessionId; mUserTag = source.mUserTag; } @@ -321,6 +325,35 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> } /** + * <p>Determine if this request is part of a constrained high speed request list that was + * created by {@link CameraDevice#createConstrainedHighSpeedRequestList}. A constrained high + * speed request list contains some constrained high speed capture requests with certain + * interleaved pattern that is suitable for high speed preview/video streaming. An active + * constrained high speed capture session only accepts constrained high speed request lists. + * This method can be used to do the sanity check when a constrained high speed capture session + * receives a request list via {@link CameraCaptureSession#setRepeatingBurst} or + * {@link CameraCaptureSession#captureBurst}. + * </p> + * + * + * @return {@code true} if this request is part of a constrained high speed request list, + * {@code false} otherwise. + * + * @hide + */ + public boolean isPartOfCRequestList() { + return mIsPartOfCHSRequestList; + } + + /** + * Returns a copy of the underlying {@link CameraMetadataNative}. + * @hide + */ + public CameraMetadataNative getNativeCopy() { + return new CameraMetadataNative(mSettings); + } + + /** * Get the reprocessable session ID this reprocess capture request is associated with. * * @return the reprocessable session ID this reprocess capture request is associated with @@ -547,6 +580,18 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> } /** + * <p>Mark this request as part of a constrained high speed request list created by + * {@link CameraDevice#createConstrainedHighSpeedRequestList}. A constrained high speed + * request list contains some constrained high speed capture requests with certain + * interleaved pattern that is suitable for high speed preview/video streaming.</p> + * + * @hide + */ + public void setPartOfCHSRequestList(boolean partOfCHSList) { + mRequest.mIsPartOfCHSRequestList = partOfCHSList; + } + + /** * Build a request using the current target Surfaces and settings. * <p>Note that, although it is possible to create a {@code CaptureRequest} with no target * {@link Surface}s, passing such a request into {@link CameraCaptureSession#capture}, @@ -563,7 +608,6 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> return new CaptureRequest(mRequest); } - /** * @hide */ diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl index 375b310..1574f93 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl @@ -61,7 +61,7 @@ interface ICameraDeviceUser * must be called before any requests can be submitted. * <p> */ - int endConfigure(); + int endConfigure(boolean isConstrainedHighSpeed); int deleteStream(int streamId); diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index ab0f607..3d261dd 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -60,6 +60,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { private final android.hardware.camera2.impl.CameraDeviceImpl mDeviceImpl; /** Internal handler; used for all incoming events to preserve total order */ private final Handler mDeviceHandler; + private final boolean mIsConstrainedHighSpeedSession; /** Drain Sequence IDs which have been queued but not yet finished with aborted/completed */ private final TaskDrainer<Integer> mSequenceDrainer; @@ -88,13 +89,14 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { CameraCaptureSessionImpl(int id, Surface input, List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler stateHandler, android.hardware.camera2.impl.CameraDeviceImpl deviceImpl, - Handler deviceStateHandler, boolean configureSuccess) { + Handler deviceStateHandler, boolean configureSuccess, boolean isConstrainedHighSpeed) { if (outputs == null || outputs.isEmpty()) { throw new IllegalArgumentException("outputs must be a non-null, non-empty list"); } else if (callback == null) { throw new IllegalArgumentException("callback must not be null"); } + mIsConstrainedHighSpeedSession = isConstrainedHighSpeed; mId = id; mIdString = String.format("Session %d: ", mId); @@ -134,6 +136,30 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { } } + + private boolean isConstrainedHighSpeedRequestList(List<CaptureRequest> requestList) { + checkCollectionNotEmpty(requestList, "High speed request list"); + for (CaptureRequest request : requestList) { + if (!request.isPartOfCRequestList()) { + return false; + } + } + return true; + } + + /** + * If the session is constrained high speed session, it only accept constrained high speed + * request list. + */ + private void checkConstrainedHighSpeedRequestSanity(List<CaptureRequest> requestList) { + if (mIsConstrainedHighSpeedSession) { + if (!isConstrainedHighSpeedRequestList(requestList)) { + throw new IllegalArgumentException("It is only allowed to submit a constrained " + + "high speed request list to a constrained high speed session!!!"); + } + } + } + @Override public CameraDevice getDevice() { return mDeviceImpl; @@ -155,6 +181,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { } else if (request.isReprocess() && request.getReprocessableSessionId() != mId) { throw new IllegalArgumentException("capture request was created for another session"); } + if (mIsConstrainedHighSpeedSession) { + throw new UnsupportedOperationException("Constrained high speed session doesn't support" + + " this method"); + } checkNotClosed(); @@ -178,6 +208,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { throw new IllegalArgumentException("Requests must have at least one element"); } + checkConstrainedHighSpeedRequestSanity(requests); + for (CaptureRequest request : requests) { if (request.isReprocess()) { if (!isReprocessable()) { @@ -212,7 +244,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { } else if (request.isReprocess()) { throw new IllegalArgumentException("repeating reprocess requests are not supported"); } - + if (mIsConstrainedHighSpeedSession) { + throw new UnsupportedOperationException("Constrained high speed session doesn't support" + + " this method"); + } checkNotClosed(); @@ -236,6 +271,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { throw new IllegalArgumentException("requests must have at least one element"); } + checkConstrainedHighSpeedRequestSanity(requests); + for (CaptureRequest r : requests) { if (r.isReprocess()) { throw new IllegalArgumentException("repeating reprocess burst requests are not " + @@ -704,7 +741,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { // everything is idle. try { // begin transition to unconfigured - mDeviceImpl.configureStreamsChecked(null, null); + mDeviceImpl.configureStreamsChecked(/*inputConfig*/null, /*outputs*/null, + /*isConstrainedHighSpeed*/false); } catch (CameraAccessException e) { // OK: do not throw checked exceptions. Log.e(TAG, mIdString + "Exception while unconfiguring outputs: ", e); @@ -723,8 +761,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession { @Override public boolean isConstrainedHighSpeed() { - // TODO: to be implemented - return false; + return mIsConstrainedHighSpeedSession; } } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index ad0cd0f..c073ba5 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -18,6 +18,7 @@ package android.hardware.camera2.impl; import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE; +import android.graphics.ImageFormat; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; @@ -35,17 +36,22 @@ import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.CameraBinderDecorator; import android.hardware.camera2.utils.CameraRuntimeException; import android.hardware.camera2.utils.LongParcelable; +import android.hardware.camera2.utils.SurfaceUtils; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import android.util.Range; import android.util.Size; import android.util.SparseArray; import android.view.Surface; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -326,7 +332,8 @@ public class CameraDeviceImpl extends CameraDevice { for (Surface s : outputs) { outputConfigs.add(new OutputConfiguration(s)); } - configureStreamsChecked(/*inputConfig*/null, outputConfigs); + configureStreamsChecked(/*inputConfig*/null, outputConfigs, + /*isConstrainedHighSpeed*/false); } @@ -344,12 +351,14 @@ public class CameraDeviceImpl extends CameraDevice { * * @param inputConfig input configuration or {@code null} for no input * @param outputs a list of one or more surfaces, or {@code null} to unconfigure + * @param isConstrainedHighSpeed If the streams configuration is for constrained high speed output. * @return whether or not the configuration was successful * * @throws CameraAccessException if there were any unexpected problems during configuration */ public boolean configureStreamsChecked(InputConfiguration inputConfig, - List<OutputConfiguration> outputs) throws CameraAccessException { + List<OutputConfiguration> outputs, boolean isConstrainedHighSpeed) + throws CameraAccessException { // Treat a null input the same an empty list if (outputs == null) { outputs = new ArrayList<OutputConfiguration>(); @@ -422,7 +431,7 @@ public class CameraDeviceImpl extends CameraDevice { } try { - mRemoteDevice.endConfigure(); + mRemoteDevice.endConfigure(isConstrainedHighSpeed); } catch (IllegalArgumentException e) { // OK. camera service can reject stream config if it's not supported by HAL @@ -463,7 +472,8 @@ public class CameraDeviceImpl extends CameraDevice { for (Surface surface : outputs) { outConfigurations.add(new OutputConfiguration(surface)); } - createCaptureSessionInternal(null, outConfigurations, callback, handler); + createCaptureSessionInternal(null, outConfigurations, callback, handler, + /*isConstrainedHighSpeed*/false); } @Override @@ -475,7 +485,8 @@ public class CameraDeviceImpl extends CameraDevice { Log.d(TAG, "createCaptureSessionByOutputConfiguration"); } - createCaptureSessionInternal(null, outputConfigurations, callback, handler); + createCaptureSessionInternal(null, outputConfigurations, callback, handler, + /*isConstrainedHighSpeed*/false); } @Override @@ -494,13 +505,14 @@ public class CameraDeviceImpl extends CameraDevice { for (Surface surface : outputs) { outConfigurations.add(new OutputConfiguration(surface)); } - createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler); + createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler, + /*isConstrainedHighSpeed*/false); } private void createCaptureSessionInternal(InputConfiguration inputConfig, List<OutputConfiguration> outputConfigurations, - CameraCaptureSession.StateCallback callback, Handler handler) - throws CameraAccessException { + CameraCaptureSession.StateCallback callback, Handler handler, + boolean isConstrainedHighSpeed) throws CameraAccessException { synchronized(mInterfaceLock) { if (DEBUG) { Log.d(TAG, "createCaptureSessionInternal"); @@ -508,6 +520,11 @@ public class CameraDeviceImpl extends CameraDevice { checkIfCameraClosedOrInError(); + if (isConstrainedHighSpeed && inputConfig != null) { + throw new IllegalArgumentException("Constrained high speed session doesn't support" + + " input configuration yet."); + } + // Notify current session that it's going away, before starting camera operations // After this call completes, the session is not allowed to call into CameraDeviceImpl if (mCurrentSession != null) { @@ -520,7 +537,8 @@ public class CameraDeviceImpl extends CameraDevice { Surface input = null; try { // configure streams and then block until IDLE - configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations); + configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations, + isConstrainedHighSpeed); if (inputConfig != null) { input = new Surface(); mRemoteDevice.getInputSurface(/*out*/input); @@ -545,7 +563,7 @@ public class CameraDeviceImpl extends CameraDevice { CameraCaptureSessionImpl newSession = new CameraCaptureSessionImpl(mNextSessionId++, input, outSurfaces, callback, handler, this, mDeviceHandler, - configureSuccess); + configureSuccess, isConstrainedHighSpeed); // TODO: wait until current session closes, then create the new session mCurrentSession = newSession; @@ -1906,17 +1924,156 @@ public class CameraDeviceImpl extends CameraDevice { return mCharacteristics; } + private void checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces, + Range<Integer> fpsRange) { + if (surfaces == null || surfaces.size() == 0 || surfaces.size() > 2) { + throw new IllegalArgumentException("Output target surface list must not be null and" + + " the size must be 1 or 2"); + } + + StreamConfigurationMap config = + getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + List<Size> highSpeedSizes = null; + if (fpsRange == null) { + highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes()); + } else { + // Check the FPS range first if provided + Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRanges(); + if(!Arrays.asList(highSpeedFpsRanges).contains(fpsRange)) { + throw new IllegalArgumentException("Fps range " + fpsRange.toString() + " in the" + + " request is not a supported high speed fps range " + + Arrays.toString(highSpeedFpsRanges)); + } + highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizesFor(fpsRange)); + } + + for (Surface surface : surfaces) { + // Surface size must be supported high speed sizes. + Size surfaceSize = SurfaceUtils.getSurfaceSize(surface); + int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface); + + if (surfaceFormat != ImageFormat.PRIVATE) { + throw new IllegalArgumentException("Surface format is not for preview or" + + " hardware video encoding" + surfaceFormat); + } + + if (!highSpeedSizes.contains(surfaceSize)) { + throw new IllegalArgumentException("Surface size " + surfaceSize.toString() + " is" + + " not part of the high speed supported size list " + + Arrays.toString(highSpeedSizes.toArray())); + } + // Each output surface must be either preview surface or recording surface. + if (!SurfaceUtils.isSurfaceForPreview(surface) && + !SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) { + throw new IllegalArgumentException("This output surface is neither preview nor " + + "hardware video encoding surface"); + } + if (SurfaceUtils.isSurfaceForPreview(surface) && + SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) { + throw new IllegalArgumentException("This output surface can not be both preview" + + " and hardware video encoding surface"); + } + } + + // For 2 output surface case, they shouldn't be same type. + if (surfaces.size() == 2) { + // Up to here, each surface can only be either preview or recording. + Iterator<Surface> iterator = surfaces.iterator(); + boolean isFirstSurfacePreview = + SurfaceUtils.isSurfaceForPreview(iterator.next()); + boolean isSecondSurfacePreview = + SurfaceUtils.isSurfaceForPreview(iterator.next()); + if (isFirstSurfacePreview == isSecondSurfacePreview) { + throw new IllegalArgumentException("The 2 output surfaces must have different" + + " type"); + } + } + } + @Override public void createConstrainedHighSpeedCaptureSession(List<Surface> outputs, android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler) throws CameraAccessException { - // TODO: to be implemented - throw new UnsupportedOperationException("To be implemented!!!!"); + if (outputs == null || outputs.size() == 0 || outputs.size() > 2) { + throw new IllegalArgumentException( + "Output surface list must not be null and the size must be no more than 2"); + } + checkConstrainedHighSpeedSurfaces(outputs, /*fpsRange*/null); + + List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size()); + for (Surface surface : outputs) { + outConfigurations.add(new OutputConfiguration(surface)); + } + createCaptureSessionInternal(null, outConfigurations, callback, handler, + /*isConstrainedHighSpeed*/true); } @Override public List<CaptureRequest> createConstrainedHighSpeedRequestList(CaptureRequest request) throws CameraAccessException { - throw new UnsupportedOperationException("To be implemented!!!!"); + if (request == null) { + throw new IllegalArgumentException("Input capture request must not be null"); + } + Collection<Surface> outputSurfaces = request.getTargets(); + Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE); + checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange); + + // Request list size: to limit the preview to 30fps, need use maxFps/30; to maximize + // the preview frame rate, should use maxBatch size for that high speed stream + // configuration. We choose the former for now. + int requestListSize = fpsRange.getUpper() / 30; + List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); + + // Prepare the Request builders: need carry over the request controls. + // First, create a request builder that will only include preview or recording target. + CameraMetadataNative requestMetadata = new CameraMetadataNative(request.getNativeCopy()); + CaptureRequest.Builder singleTargetRequestBuilder = new CaptureRequest.Builder( + requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); + + // Overwrite the capture intent to make sure a good value is set. + Surface[] surfaces = (Surface[])outputSurfaces.toArray(); + if (outputSurfaces.size() == 1 && SurfaceUtils.isSurfaceForHwVideoEncoder(surfaces[0])) { + singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, + CaptureRequest.CONTROL_CAPTURE_INTENT_PREVIEW); + } else { + // Video only, or preview + video + singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, + CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD); + } + singleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true); + + // Second, Create a request builder that will include both preview and recording targets. + CaptureRequest.Builder doubleTargetRequestBuilder = null; + if (outputSurfaces.size() == 2) { + doubleTargetRequestBuilder = new CaptureRequest.Builder( + requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); + doubleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, + CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD); + doubleTargetRequestBuilder.addTarget(surfaces[0]); + doubleTargetRequestBuilder.addTarget(surfaces[1]); + doubleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true); + // Make sure singleTargetRequestBuilder contains only recording surface for + // preview + recording case. + Surface recordingSurface = surfaces[0]; + if (!SurfaceUtils.isSurfaceForHwVideoEncoder(recordingSurface)) { + recordingSurface = surfaces[1]; + } + singleTargetRequestBuilder.addTarget(recordingSurface); + } else { + // Single output case: either recording or preview. + singleTargetRequestBuilder.addTarget(surfaces[0]); + } + + // Generate the final request list. + for (int i = 0; i < requestListSize; i++) { + if (i == 0 && doubleTargetRequestBuilder != null) { + // First request should be recording + preview request + requestList.add(doubleTargetRequestBuilder.build()); + } else { + requestList.add(singleTargetRequestBuilder.build()); + } + } + + return Collections.unmodifiableList(requestList); } } diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java index bc0a3a8..f5314da 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java @@ -88,15 +88,6 @@ public class CameraDeviceUserShim implements ICameraDeviceUser { mSurfaceIdCounter = 0; } - private static int translateErrorsFromCamera1(int errorCode) { - switch (errorCode) { - case CameraBinderDecorator.EACCES: - return CameraBinderDecorator.PERMISSION_DENIED; - default: - return errorCode; - } - } - /** * Create a separate looper/thread for the camera to run on; open the camera. * @@ -140,7 +131,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser { // Save the looper so that we can terminate this thread // after we are done with it. mLooper = Looper.myLooper(); - mInitErrors = translateErrorsFromCamera1(mCamera.cameraInitUnspecified(mCameraId)); + mInitErrors = mCamera.cameraInitUnspecified(mCameraId); mStartDone.open(); Looper.loop(); // Blocks forever until #close is called. } @@ -465,7 +456,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser { } @Override - public int endConfigure() { + public int endConfigure(boolean isConstrainedHighSpeed) { if (DEBUG) { Log.d(TAG, "endConfigure called."); } diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index 098c2d8..cc9d496 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -82,6 +82,7 @@ public class LegacyCameraDevice implements AutoCloseable { private static final int GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003; private static final int GRALLOC_USAGE_HW_TEXTURE = 0x00000100; private static final int GRALLOC_USAGE_HW_COMPOSER = 0x00000800; + private static final int GRALLOC_USAGE_HW_RENDER = 0x00000200; private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000; public static final int MAX_DIMEN_FOR_ROUNDING = 1080; // maximum allowed width for rounding @@ -549,6 +550,42 @@ public class LegacyCameraDevice implements AutoCloseable { return flexibleConsumer; } + public static boolean isPreviewConsumer(Surface output) { + int usageFlags = detectSurfaceUsageFlags(output); + int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT | + GRALLOC_USAGE_SW_READ_OFTEN; + int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER | + GRALLOC_USAGE_HW_RENDER; + boolean previewConsumer = ((usageFlags & disallowedFlags) == 0 && + (usageFlags & allowedFlags) != 0); + int surfaceFormat = ImageFormat.UNKNOWN; + try { + surfaceFormat = detectSurfaceType(output); + } catch(BufferQueueAbandonedException e) { + throw new IllegalArgumentException("Surface was abandoned", e); + } + + return previewConsumer && (surfaceFormat == ImageFormat.PRIVATE); + } + + public static boolean isVideoEncoderConsumer(Surface output) { + int usageFlags = detectSurfaceUsageFlags(output); + int disallowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER | + GRALLOC_USAGE_RENDERSCRIPT | GRALLOC_USAGE_SW_READ_OFTEN; + int allowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER; + boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0 && + (usageFlags & allowedFlags) != 0); + + int surfaceFormat = ImageFormat.UNKNOWN; + try { + surfaceFormat = detectSurfaceType(output); + } catch(BufferQueueAbandonedException e) { + throw new IllegalArgumentException("Surface was abandoned", e); + } + + return videoEncoderConsumer && (surfaceFormat == ImageFormat.PRIVATE); + } + /** * Query the surface for its currently configured usage flags */ diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java new file mode 100644 index 0000000..32e74e2 --- /dev/null +++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java @@ -0,0 +1,80 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2.utils; + +import android.hardware.camera2.legacy.LegacyCameraDevice; +import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException; +import android.util.Size; +import android.view.Surface; + +/** + * Various Surface utilities. + */ +public class SurfaceUtils { + + /** + * Check if a surface is for preview consumer. + * + * @param surface The surface to be checked. + * @return true if the surface is for preview consumer, false otherwise. + */ + public static boolean isSurfaceForPreview(Surface surface) { + return LegacyCameraDevice.isPreviewConsumer(surface); + } + + /** + * Check if the surface is for hardware video encoder consumer. + * + * @param surface The surface to be checked. + * @return true if the surface is for hardware video encoder consumer, false otherwise. + */ + public static boolean isSurfaceForHwVideoEncoder(Surface surface) { + return LegacyCameraDevice.isVideoEncoderConsumer(surface); + } + + /** + * Get the Surface size. + * + * @param surface The surface to be queried for size. + * @return Size of the surface. + * + * @throws IllegalArgumentException if the surface is already abandoned. + */ + public static Size getSurfaceSize(Surface surface) { + try { + return LegacyCameraDevice.getSurfaceSize(surface); + } catch (BufferQueueAbandonedException e) { + throw new IllegalArgumentException("Surface was abandoned", e); + } + } + + /** + * Get the Surface format. + * + * @param surface The surface to be queried for format. + * @return format of the surface. + * + * @throws IllegalArgumentException if the surface is already abandoned. + */ + public static int getSurfaceFormat(Surface surface) { + try { + return LegacyCameraDevice.detectSurfaceType(surface); + } catch (BufferQueueAbandonedException e) { + throw new IllegalArgumentException("Surface was abandoned", e); + } + } +} diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index d9f9c1e..21ba7bd 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -192,17 +192,6 @@ public final class DisplayManagerGlobal { return getCompatibleDisplay(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); } - /** - * Gets information about a logical display without applying any compatibility metrics. - * - * @param displayId The logical display id. - * @param configuration the configuration. - * @return The display object, or null if there is no display with the given id. - */ - public Display getRealDisplay(int displayId, Configuration configuration) { - return getCompatibleDisplay(displayId, new DisplayAdjustments(configuration)); - } - public void registerDisplayListener(DisplayListener listener, Handler handler) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index caf21d5..e61813c 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -18,32 +18,30 @@ package android.hardware.fingerprint; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.app.ActivityManagerNative; -import android.content.ContentResolver; import android.content.Context; import android.os.Binder; import android.os.CancellationSignal; import android.os.CancellationSignal.OnCancelListener; import android.os.Handler; import android.os.IBinder; -import android.os.Parcel; -import android.os.Parcelable; +import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; -import android.provider.Settings; -import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback; import android.security.keystore.AndroidKeyStoreProvider; import android.util.Log; import android.util.Slog; import java.security.Signature; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import javax.crypto.Cipher; import javax.crypto.Mac; +import static android.Manifest.permission.USE_FINGERPRINT; +import static android.Manifest.permission.MANAGE_FINGERPRINT; + /** * A class that coordinates access to the fingerprint hardware. * <p> @@ -57,9 +55,10 @@ public class FingerprintManager { private static final boolean DEBUG = true; private static final int MSG_ENROLL_RESULT = 100; private static final int MSG_ACQUIRED = 101; - private static final int MSG_AUTHENTICATED = 102; - private static final int MSG_ERROR = 103; - private static final int MSG_REMOVED = 104; + private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; + private static final int MSG_AUTHENTICATION_FAILED = 103; + private static final int MSG_ERROR = 104; + private static final int MSG_REMOVED = 105; // // Error messages from fingerprint hardware during initilization, enrollment, authentication or @@ -112,6 +111,7 @@ public class FingerprintManager { /** * Hardware vendors may extend this list if there are conditions that do not fall under one of * the above categories. Vendors are responsible for providing error strings for these errors. + * @hide */ public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000; @@ -162,6 +162,7 @@ public class FingerprintManager { /** * Hardware vendors may extend this list if there are conditions that do not fall under one of * the above categories. Vendors are responsible for providing error strings for these errors. + * @hide */ public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000; @@ -173,6 +174,7 @@ public class FingerprintManager { private RemovalCallback mRemovalCallback; private CryptoObject mCryptoObject; private Fingerprint mRemovalFingerprint; + private Handler mHandler; private class OnEnrollCancelListener implements OnCancelListener { @Override @@ -198,72 +200,71 @@ public class FingerprintManager { * A wrapper class for the crypto objects supported by FingerprintManager. Currently the * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. */ - public static class CryptoObject { + public static final class CryptoObject { public CryptoObject(@NonNull Signature signature) { - mSignature = signature; - mCipher = null; - mMac = null; + mCrypto = signature; } public CryptoObject(@NonNull Cipher cipher) { - mCipher = cipher; - mSignature = null; - mMac = null; + mCrypto = cipher; } public CryptoObject(@NonNull Mac mac) { - mMac = mac; - mCipher = null; - mSignature = null; + mCrypto = mac; } /** * Get {@link Signature} object. * @return {@link Signature} object or null if this doesn't contain one. */ - public Signature getSignature() { return mSignature; } + public Signature getSignature() { + return mCrypto instanceof Signature ? (Signature) mCrypto : null; + } /** * Get {@link Cipher} object. * @return {@link Cipher} object or null if this doesn't contain one. */ - public Cipher getCipher() { return mCipher; } + public Cipher getCipher() { + return mCrypto instanceof Cipher ? (Cipher) mCrypto : null; + } /** * Get {@link Mac} object. * @return {@link Mac} object or null if this doesn't contain one. */ - public Mac getMac() { return mMac; } + public Mac getMac() { + return mCrypto instanceof Mac ? (Mac) mCrypto : null; + } /** * @hide * @return the opId associated with this object or 0 if none */ public long getOpId() { - if (mSignature != null) { - return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mSignature); - } else if (mCipher != null) { - return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCipher); - } else if (mMac != null) { - return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mMac); - } - return 0; + return mCrypto != null ? + AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0; } - private final Signature mSignature; - private final Cipher mCipher; - private final Mac mMac; + private final Object mCrypto; }; /** * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject, - * CancellationSignal, AuthenticationCallback, int)}. + * CancellationSignal, int, AuthenticationCallback, Handler)}. */ public static final class AuthenticationResult { private Fingerprint mFingerprint; private CryptoObject mCryptoObject; + /** + * Authentication result + * + * @param crypto the crypto object + * @param fingerprint the recognized fingerprint data, if allowed. + * @hide + */ public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) { mCryptoObject = crypto; mFingerprint = fingerprint; @@ -272,7 +273,7 @@ public class FingerprintManager { /** * Obtain the crypto object associated with this transaction * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject, - * CancellationSignal, AuthenticationCallback, int)}. + * CancellationSignal, int, AuthenticationCallback, Handler)}. */ public CryptoObject getCryptoObject() { return mCryptoObject; } @@ -287,28 +288,28 @@ public class FingerprintManager { /** * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject, - * CancellationSignal, AuthenticationCallback, int)}. Users of {@link + * CancellationSignal, int, AuthenticationCallback, Handler)}. Users of {@link * FingerprintManager#authenticate(CryptoObject, CancellationSignal, - * AuthenticationCallback, int) } must provide an implementation of this for listening to + * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to * fingerprint events. */ public static abstract class AuthenticationCallback { /** * Called when an unrecoverable error has been encountered and the operation is complete. * No further callbacks will be made on this object. - * @param errMsgId An integer identifying the error message + * @param errorCode An integer identifying the error message * @param errString A human-readable error string that can be shown in UI */ - public void onAuthenticationError(int errMsgId, CharSequence errString) { } + public void onAuthenticationError(int errorCode, CharSequence errString) { } /** * Called when a recoverable error has been encountered during authentication. The help * string is provided to give the user guidance for what went wrong, such as * "Sensor dirty, please clean it." - * @param helpMsgId An integer identifying the error message + * @param helpCode An integer identifying the error message * @param helpString A human-readable string that can be shown in UI */ - public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { } + public void onAuthenticationHelp(int helpCode, CharSequence helpString) { } /** * Called when a fingerprint is recognized. @@ -326,7 +327,7 @@ public class FingerprintManager { * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback, * CancellationSignal, int). Users of {@link #FingerprintManager()} * must provide an implementation of this to {@link FingerprintManager#enroll(long, - * CancellationSignal, EnrollmentCallback, int) for listening to fingerprint events. + * CancellationSignal, int, EnrollmentCallback) for listening to fingerprint events. * * @hide */ @@ -392,31 +393,35 @@ public class FingerprintManager { * * @param crypto object associated with the call or null if none required. * @param cancel an object that can be used to cancel authentication - * @param callback an object to receive authentication events * @param flags optional flags; should be 0 + * @param callback an object to receive authentication events + * @param handler an optional handler to handle callback events */ + @RequiresPermission(USE_FINGERPRINT) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, - @NonNull AuthenticationCallback callback, int flags) { - authenticate(crypto, cancel, callback, flags, UserHandle.myUserId()); + int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) { + authenticate(crypto, cancel, flags, callback, handler, UserHandle.myUserId()); } /** - * Request authentication of a crypto object. This call warms up the fingerprint hardware - * and starts scanning for a fingerprint. It terminates when - * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or - * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult) is called, at - * which point the object is no longer valid. The operation can be canceled by using the - * provided cancel object. - * - * @param crypto object associated with the call or null if none required. - * @param cancel an object that can be used to cancel authentication - * @param callback an object to receive authentication events - * @param flags optional flags; should be 0 - * @param userId the userId the fingerprint belongs to + * Use the provided handler thread for events. + * @param handler + */ + private void useHandler(Handler handler) { + if (handler != null) { + mHandler = new MyHandler(handler.getLooper()); + } else if (mHandler.getLooper() != mContext.getMainLooper()){ + mHandler = new MyHandler(mContext.getMainLooper()); + } + } + + /** + * Per-user version * @hide */ + @RequiresPermission(USE_FINGERPRINT) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, - @NonNull AuthenticationCallback callback, int flags, int userId) { + int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) { if (callback == null) { throw new IllegalArgumentException("Must supply an authentication callback"); } @@ -431,6 +436,7 @@ public class FingerprintManager { } if (mService != null) try { + useHandler(handler); mAuthenticationCallback = callback; mCryptoObject = crypto; long sessionId = crypto != null ? crypto.getOpId() : 0; @@ -458,12 +464,13 @@ public class FingerprintManager { * @param token a unique token provided by a recent creation or verification of device * credentials (e.g. pin, pattern or password). * @param cancel an object that can be used to cancel enrollment - * @param callback an object to receive enrollment events * @param flags optional flags + * @param callback an object to receive enrollment events * @hide */ - public void enroll(byte [] token, CancellationSignal cancel, EnrollmentCallback callback, - int flags) { + @RequiresPermission(MANAGE_FINGERPRINT) + public void enroll(byte [] token, CancellationSignal cancel, int flags, + EnrollmentCallback callback) { if (callback == null) { throw new IllegalArgumentException("Must supply an enrollment callback"); } @@ -496,6 +503,7 @@ public class FingerprintManager { * existing device credentials (e.g. pin/pattern/password). * @hide */ + @RequiresPermission(MANAGE_FINGERPRINT) public long preEnroll() { long result = 0; if (mService != null) try { @@ -514,6 +522,7 @@ public class FingerprintManager { * * @hide */ + @RequiresPermission(MANAGE_FINGERPRINT) public void remove(Fingerprint fp, RemovalCallback callback) { if (mService != null) try { mRemovalCallback = callback; @@ -535,6 +544,7 @@ public class FingerprintManager { * * @hide */ + @RequiresPermission(MANAGE_FINGERPRINT) public void rename(int fpId, String newName) { // Renames the given fpId if (mService != null) { @@ -554,6 +564,7 @@ public class FingerprintManager { * * @hide */ + @RequiresPermission(USE_FINGERPRINT) public List<Fingerprint> getEnrolledFingerprints(int userId) { if (mService != null) try { return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName()); @@ -569,6 +580,7 @@ public class FingerprintManager { * * @hide */ + @RequiresPermission(USE_FINGERPRINT) public List<Fingerprint> getEnrolledFingerprints() { return getEnrolledFingerprints(UserHandle.myUserId()); } @@ -578,6 +590,7 @@ public class FingerprintManager { * * @return true if at least one fingerprint is enrolled, false otherwise */ + @RequiresPermission(USE_FINGERPRINT) public boolean hasEnrolledFingerprints() { if (mService != null) try { return mService.hasEnrolledFingerprints(UserHandle.myUserId(), @@ -593,6 +606,7 @@ public class FingerprintManager { * * @return true if hardware is present and functional, false otherwise. */ + @RequiresPermission(USE_FINGERPRINT) public boolean isHardwareDetected() { if (mService != null) { try { @@ -626,13 +640,15 @@ public class FingerprintManager { return 0; } - private Handler mHandler; - private class MyHandler extends Handler { private MyHandler(Context context) { super(context.getMainLooper()); } + private MyHandler(Looper looper) { + super(looper); + } + public void handleMessage(android.os.Message msg) { switch(msg.what) { case MSG_ENROLL_RESULT: @@ -641,8 +657,11 @@ public class FingerprintManager { case MSG_ACQUIRED: sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */); break; - case MSG_AUTHENTICATED: - sendAuthenticatedResult((Fingerprint) msg.obj); + case MSG_AUTHENTICATION_SUCCEEDED: + sendAuthenticatedSucceeded((Fingerprint) msg.obj); + break; + case MSG_AUTHENTICATION_FAILED: + sendAuthenticatedFailed(); break; case MSG_ERROR: sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */); @@ -684,15 +703,16 @@ public class FingerprintManager { } } - private void sendAuthenticatedResult(Fingerprint fp) { + private void sendAuthenticatedSucceeded(Fingerprint fp) { if (mAuthenticationCallback != null) { - if (fp.getFingerId() == 0) { - // Fingerprint template valid but doesn't match one in database - mAuthenticationCallback.onAuthenticationFailed(); - } else { - final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp); - mAuthenticationCallback.onAuthenticationSucceeded(result); - } + final AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp); + mAuthenticationCallback.onAuthenticationSucceeded(result); + } + } + + private void sendAuthenticatedFailed() { + if (mAuthenticationCallback != null) { + mAuthenticationCallback.onAuthenticationFailed(); } } @@ -809,24 +829,33 @@ public class FingerprintManager { private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() { + @Override // binder call public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0, new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); } + @Override // binder call public void onAcquired(long deviceId, int acquireInfo) { mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget(); } - public void onAuthenticated(long deviceId, int fingerId, int groupId) { - mHandler.obtainMessage(MSG_AUTHENTICATED, - new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget(); + @Override // binder call + public void onAuthenticationSucceeded(long deviceId, Fingerprint fp) { + mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, fp).sendToTarget(); + } + + @Override // binder call + public void onAuthenticationFailed(long deviceId) { + mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();; } + @Override // binder call public void onError(long deviceId, int error) { mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget(); } + @Override // binder call public void onRemoved(long deviceId, int fingerId, int groupId) { mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget(); } diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl index a2d74b8..57a429f 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl @@ -15,6 +15,7 @@ */ package android.hardware.fingerprint; +import android.hardware.fingerprint.Fingerprint; import android.os.Bundle; import android.os.UserHandle; @@ -25,7 +26,8 @@ import android.os.UserHandle; oneway interface IFingerprintServiceReceiver { void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining); void onAcquired(long deviceId, int acquiredInfo); - void onAuthenticated(long deviceId, int fingerId, int groupId); + void onAuthenticationSucceeded(long deviceId, in Fingerprint fp); + void onAuthenticationFailed(long deviceId); void onError(long deviceId, int error); void onRemoved(long deviceId, int fingerId, int groupId); } diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java index 48b604c..f965f54 100644 --- a/core/java/android/inputmethodservice/ExtractEditText.java +++ b/core/java/android/inputmethodservice/ExtractEditText.java @@ -106,7 +106,7 @@ public class ExtractEditText extends EditText { if (mIME != null && mIME.onExtractTextContextMenuItem(id)) { // Mode was started on Extracted, needs to be stopped here. // Cut and paste will change the text, which stops selection mode. - if (id == android.R.id.copy) stopSelectionActionMode(); + if (id == android.R.id.copy) stopTextActionMode(); return true; } return super.onTextContextMenuItem(id); diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 81a65f8..a7afa91 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1565,11 +1565,17 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme() " + " mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme); if (!mShouldClearInsetOfPreviousIme || mWindow == null) return; - // We do not call onWindowShown() and onWindowHidden() so as not to make the IME author - // confused. - // TODO: Find out a better way which has less side-effect. - mWindow.show(); - mWindow.hide(); + try { + // We do not call onWindowShown() and onWindowHidden() so as not to make the IME author + // confused. + // TODO: Find out a better way which has less side-effect. + mWindow.show(); + mWindow.hide(); + } catch (WindowManager.BadTokenException e) { + if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme: BadTokenException: IME is done."); + mWindowVisible = false; + mWindowAdded = false; + } mShouldClearInsetOfPreviousIme = false; } diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 754c6b3..9628bae 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -19,6 +19,8 @@ package android.net; import android.os.Parcelable; import android.os.Parcel; import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; import java.io.FileDescriptor; import java.io.IOException; @@ -64,7 +66,7 @@ public class Network implements Parcelable { // maybeInitHttpClient() must be called prior to reading either variable. private volatile ConnectionPool mConnectionPool = null; private volatile com.android.okhttp.internal.Network mNetwork = null; - private Object mLock = new Object(); + private final Object mLock = new Object(); // Default connection pool values. These are evaluated at startup, just // like the OkHttp code. Also like the OkHttp code, we will throw parse @@ -300,14 +302,10 @@ public class Network implements Parcelable { * connected. */ public void bindSocket(DatagramSocket socket) throws IOException { - // Apparently, the kernel doesn't update a connected UDP socket's routing upon mark changes. - if (socket.isConnected()) { - throw new SocketException("Socket is connected"); - } // Query a property of the underlying socket to ensure that the socket's file descriptor // exists, is available to bind to a network and is not closed. socket.getReuseAddress(); - bindSocketFd(socket.getFileDescriptor$()); + bindSocket(socket.getFileDescriptor$()); } /** @@ -316,18 +314,38 @@ public class Network implements Parcelable { * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected. */ public void bindSocket(Socket socket) throws IOException { - // Apparently, the kernel doesn't update a connected TCP socket's routing upon mark changes. - if (socket.isConnected()) { - throw new SocketException("Socket is connected"); - } // Query a property of the underlying socket to ensure that the socket's file descriptor // exists, is available to bind to a network and is not closed. socket.getReuseAddress(); - bindSocketFd(socket.getFileDescriptor$()); + bindSocket(socket.getFileDescriptor$()); } - private void bindSocketFd(FileDescriptor fd) throws IOException { - int err = NetworkUtils.bindSocketToNetwork(fd.getInt$(), netId); + /** + * Binds the specified {@link FileDescriptor} to this {@code Network}. All data traffic on the + * socket represented by this file descriptor will be sent on this {@code Network}, + * irrespective of any process-wide network binding set by + * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected. + */ + public void bindSocket(FileDescriptor fd) throws IOException { + try { + final SocketAddress peer = Os.getpeername(fd); + final InetAddress inetPeer = ((InetSocketAddress) peer).getAddress(); + if (!inetPeer.isAnyLocalAddress()) { + // Apparently, the kernel doesn't update a connected UDP socket's + // routing upon mark changes. + throw new SocketException("Socket is connected"); + } + } catch (ErrnoException e) { + // getpeername() failed. + if (e.errno != OsConstants.ENOTCONN) { + throw e.rethrowAsSocketException(); + } + } catch (ClassCastException e) { + // Wasn't an InetSocketAddress. + throw new SocketException("Only AF_INET/AF_INET6 sockets supported"); + } + + final int err = NetworkUtils.bindSocketToNetwork(fd.getInt$(), netId); if (err != 0) { // bindSocketToNetwork returns negative errno. throw new ErrnoException("Binding socket to network " + netId, -err) diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java index 3d065e3..7678678 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -92,11 +92,6 @@ public final class ApduServiceInfo implements Parcelable { final int mUid; /** - * Whether this service has dynamic resources - */ - final boolean mHasDynamicResources; - - /** * Settings Activity for this service */ final String mSettingsActivityName; @@ -106,7 +101,7 @@ public final class ApduServiceInfo implements Parcelable { */ public ApduServiceInfo(ResolveInfo info, boolean onHost, String description, ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups, - boolean requiresUnlock, int bannerResource, int uid, boolean hasDynamicResources, + boolean requiresUnlock, int bannerResource, int uid, String settingsActivityName) { this.mService = info; this.mDescription = description; @@ -122,7 +117,6 @@ public final class ApduServiceInfo implements Parcelable { } this.mBannerResourceId = bannerResource; this.mUid = uid; - this.mHasDynamicResources = hasDynamicResources; this.mSettingsActivityName = settingsActivityName; } @@ -172,8 +166,6 @@ public final class ApduServiceInfo implements Parcelable { false); mBannerResourceId = sa.getResourceId( com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1); - mHasDynamicResources = sa.getBoolean( - com.android.internal.R.styleable.HostApduService_dynamicResources, false); mSettingsActivityName = sa.getString( com.android.internal.R.styleable.HostApduService_settingsActivity); sa.recycle(); @@ -186,8 +178,6 @@ public final class ApduServiceInfo implements Parcelable { mRequiresDeviceUnlock = false; mBannerResourceId = sa.getResourceId( com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1); - mHasDynamicResources = sa.getBoolean( - com.android.internal.R.styleable.OffHostApduService_dynamicResources, false); mSettingsActivityName = sa.getString( com.android.internal.R.styleable.HostApduService_settingsActivity); sa.recycle(); @@ -410,9 +400,6 @@ public final class ApduServiceInfo implements Parcelable { return null; } } - public boolean hasDynamicResources() { - return mHasDynamicResources; - } public String getSettingsActivityName() { return mSettingsActivityName; } @@ -468,7 +455,6 @@ public final class ApduServiceInfo implements Parcelable { dest.writeInt(mRequiresDeviceUnlock ? 1 : 0); dest.writeInt(mBannerResourceId); dest.writeInt(mUid); - dest.writeInt(mHasDynamicResources ? 1 : 0); dest.writeString(mSettingsActivityName); }; @@ -492,10 +478,9 @@ public final class ApduServiceInfo implements Parcelable { boolean requiresUnlock = source.readInt() != 0; int bannerResource = source.readInt(); int uid = source.readInt(); - boolean dynamicResources = source.readInt() != 0; String settingsActivityName = source.readString(); return new ApduServiceInfo(info, onHost, description, staticAidGroups, - dynamicAidGroups, requiresUnlock, bannerResource, uid, dynamicResources, + dynamicAidGroups, requiresUnlock, bannerResource, uid, settingsActivityName); } diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index b94d4a6..64c2bc2 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -90,37 +90,6 @@ public final class CardEmulation { public static final String CATEGORY_OTHER = "other"; /** - * Ordered broadcast that can be sent to your app to - * request a description and banner to be shown in - * Android Settings UI. - * When sent to you, this broadcast will contain the - * {@link #EXTRA_SERVICE_COMPONENT} extra to identify - * the service. - * - * Note that this broadcast will only be sent to your - * app, if a card emulation service in your app has requested - * its resources to be loaded dynamically. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_REQUEST_SERVICE_RESOURCES = - "android.nfc.cardemulation.action.REQUEST_SERVICE_RESOURCES"; - - /** - * The description of the service. Note that this must - * be localized by your app, as the String will be shown - * as is. - */ - public static final String EXTRA_DESCRIPTION = - "android.nfc.cardemulation.extra.DESCRIPTION"; - - /** - * The resource ID of the service banner to be shown - * for this service. - */ - public static final String EXTRA_BANNER_RES_ID = - "android.nfc.cardemulation.extra.BANNER_RES_ID"; - - /** * Return value for {@link #getSelectionModeForCategory(String)}. * * <p>In this mode, the user has set a default service for this diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 0a45b8b..c9609e5 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -1940,6 +1940,15 @@ public abstract class BatteryStats implements Parcelable { */ public abstract long getFlashlightOnCount(int which); + /** + * Returns the time in microseconds that the camera has been on while the device was + * running on battery. + * + * {@hide} + */ + public abstract long getCameraOnTime(long elapsedRealtimeUs, int which); + + public static final int NETWORK_MOBILE_RX_DATA = 0; public static final int NETWORK_MOBILE_TX_DATA = 1; public static final int NETWORK_WIFI_RX_DATA = 2; @@ -2735,6 +2744,9 @@ public abstract class BatteryStats implements Parcelable { case OVERCOUNTED: label = "over"; break; + case CAMERA: + label = "camera"; + break; default: label = "???"; } @@ -3523,6 +3535,10 @@ public abstract class BatteryStats implements Parcelable { pw.print(prefix); pw.print(" Over-counted: "); printmAh(pw, bs.totalPowerMah); pw.println(); break; + case CAMERA: + pw.print(prefix); pw.print(" Camera: "); printmAh(pw, bs.totalPowerMah); + pw.println(); + break; } } pw.println(); diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 19c8fa9..87e8c5e 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -34,6 +34,7 @@ import java.lang.annotation.Target; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.HashMap; import java.util.Map; import org.apache.harmony.dalvik.ddmc.Chunk; @@ -389,6 +390,132 @@ public final class Debug } } + /** + * Returns the value of a particular memory statistic or {@code null} if no + * such memory statistic exists. + * + * <p>The following table lists the memory statistics that are supported. + * Note that memory statistics may be added or removed in a future API level.</p> + * + * <table> + * <thead> + * <tr> + * <th>Memory statistic name</th> + * <th>Meaning</th> + * <th>Example</th> + * <th>Supported (API Levels)</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td>summary.java-heap</td> + * <td>The private Java Heap usage in kB. This corresponds to the Java Heap field + * in the App Summary section output by dumpsys meminfo.</td> + * <td>{@code 1442}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>summary.native-heap</td> + * <td>The private Native Heap usage in kB. This corresponds to the Native Heap + * field in the App Summary section output by dumpsys meminfo.</td> + * <td>{@code 1442}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>summary.code</td> + * <td>The memory usage for static code and resources in kB. This corresponds to + * the Code field in the App Summary section output by dumpsys meminfo.</td> + * <td>{@code 1442}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>summary.stack</td> + * <td>The stack usage in kB. This corresponds to the Stack field in the + * App Summary section output by dumpsys meminfo.</td> + * <td>{@code 1442}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>summary.graphics</td> + * <td>The graphics usage in kB. This corresponds to the Graphics field in the + * App Summary section output by dumpsys meminfo.</td> + * <td>{@code 1442}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>summary.private-other</td> + * <td>Other private memory usage in kB. This corresponds to the Private Other + * field output in the App Summary section by dumpsys meminfo.</td> + * <td>{@code 1442}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>summary.system</td> + * <td>Shared and system memory usage in kB. This corresponds to the System + * field output in the App Summary section by dumpsys meminfo.</td> + * <td>{@code 1442}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>summary.total-pss</td> + * <td>Total PPS memory usage in kB.</td> + * <td>{@code 1442}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>summary.total-swap</td> + * <td>Total swap usage in kB.</td> + * <td>{@code 1442}</td> + * <td>23</td> + * </tr> + * </tbody> + * </table> + */ + public String getMemoryStat(String statName) { + switch(statName) { + case "summary.java-heap": + return Integer.toString(getSummaryJavaHeap()); + case "summary.native-heap": + return Integer.toString(getSummaryNativeHeap()); + case "summary.code": + return Integer.toString(getSummaryCode()); + case "summary.stack": + return Integer.toString(getSummaryStack()); + case "summary.graphics": + return Integer.toString(getSummaryGraphics()); + case "summary.private-other": + return Integer.toString(getSummaryPrivateOther()); + case "summary.system": + return Integer.toString(getSummarySystem()); + case "summary.total-pss": + return Integer.toString(getSummaryTotalPss()); + case "summary.total-swap": + return Integer.toString(getSummaryTotalSwap()); + default: + return null; + } + } + + /** + * Returns a map of the names/values of the memory statistics + * that {@link #getMemoryStat(String)} supports. + * + * @return a map of the names/values of the supported memory statistics. + */ + public Map<String, String> getMemoryStats() { + Map<String, String> stats = new HashMap<String, String>(); + stats.put("summary.java-heap", Integer.toString(getSummaryJavaHeap())); + stats.put("summary.native-heap", Integer.toString(getSummaryNativeHeap())); + stats.put("summary.code", Integer.toString(getSummaryCode())); + stats.put("summary.stack", Integer.toString(getSummaryStack())); + stats.put("summary.graphics", Integer.toString(getSummaryGraphics())); + stats.put("summary.private-other", Integer.toString(getSummaryPrivateOther())); + stats.put("summary.system", Integer.toString(getSummarySystem())); + stats.put("summary.total-pss", Integer.toString(getSummaryTotalPss())); + stats.put("summary.total-swap", Integer.toString(getSummaryTotalSwap())); + return stats; + } + /** * Pss of Java Heap bytes in KB due to the application. * Notes: diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 009649f..dbb5146 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -21,6 +21,7 @@ import android.net.LocalSocketAddress; import android.system.Os; import android.util.Log; import com.android.internal.os.Zygote; +import dalvik.system.VMRuntime; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.IOException; @@ -744,7 +745,14 @@ public class Process { * @return Returns the number of milliseconds this process has return. */ public static final native long getElapsedCpuTime(); - + + /** + * Returns true if the current process is a 64-bit runtime. + */ + public static final boolean is64Bit() { + return VMRuntime.getRuntime().is64Bit(); + } + /** * Returns the identifier of this process, which can be used with * {@link #killProcess} and {@link #sendSignal}. diff --git a/core/java/android/provider/AlarmClock.java b/core/java/android/provider/AlarmClock.java index be37293..63ae9a9 100644 --- a/core/java/android/provider/AlarmClock.java +++ b/core/java/android/provider/AlarmClock.java @@ -86,7 +86,7 @@ public final class AlarmClock { * If the extra {@link #EXTRA_ALARM_SEARCH_MODE} is used, and the search results contain two or * more matching alarms, then the implementation should show an UI with the results and allow * the user to select the alarm to dismiss. If the implementation supports - * {@link android.content.Intent.CATEGORY_VOICE} and the activity is started in Voice + * {@link android.content.Intent#CATEGORY_VOICE} and the activity is started in Voice * Interaction mode (i.e. check {@link android.app.Activity#isVoiceInteraction}), then the * implementation should additionally use {@link android.app.VoiceInteractor.PickOptionRequest} * to start a voice interaction follow-on flow to help the user disambiguate the alarm by voice. diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index df2e5f9..d9c412b 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -4079,9 +4079,8 @@ public final class ContactsContract { public static final String CARRIER_PRESENCE = "carrier_presence"; /** - * Bitmask flags for CARRIER_PRESENCE column. Each value represents - * a bit (or a set of bits) which may be set independently of each - * other. + * Indicates that the entry is Video Telephony (VT) capable on the + * current carrier. An allowed bitmask of {@link #CARRIER_PRESENCE}. */ public static final int CARRIER_PRESENCE_VT_CAPABLE = 0x01; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 37645b5..cac4a53 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -811,14 +811,17 @@ public final class Settings { /** * Activity Action: Show Do Not Disturb access settings. * <p> - * In some cases, a matching Activity may not exist, so ensure you safeguard against this. + * Users can grant and deny access to Do Not Disturb configuration from here. + * See {@link android.app.NotificationManager#isNotificationPolicyAccessGranted()} for more + * details. * <p> * Input: Nothing. * <p> * Output: Nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_ZEN_ACCESS_SETTINGS = "android.settings.ZEN_ACCESS_SETTINGS"; + public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS + = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS"; /** * @hide @@ -5425,7 +5428,7 @@ public final class Settings { public static final String ASSIST_STRUCTURE_ENABLED = "assist_structure_enabled"; /** - * Names of the packages that the current user has explicitly allowed to + * Names of the service components that the current user has explicitly allowed to * see all of the user's notifications, separated by ':'. * * @hide @@ -5433,6 +5436,15 @@ public final class Settings { public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners"; /** + * Names of the packages that the current user has explicitly allowed to + * manage notification policy configuration, separated by ':'. + * + * @hide + */ + public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = + "enabled_notification_policy_access_packages"; + + /** * @hide */ public static final String ENABLED_CONDITION_PROVIDERS = "enabled_condition_providers"; diff --git a/core/java/android/service/carrier/CarrierService.java b/core/java/android/service/carrier/CarrierService.java index 4a4a375..5f83452 100644 --- a/core/java/android/service/carrier/CarrierService.java +++ b/core/java/android/service/carrier/CarrierService.java @@ -59,16 +59,16 @@ public abstract class CarrierService extends Service { * <ol> * <li>The carrier app package is updated, or</li> * <li>The carrier app requests a reload with - * {@link android.telephony.CarrierConfigManager#reloadCarrierConfigForSubId - * reloadCarrierConfigForSubId}.</li> + * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId + * notifyConfigChangedForSubId}.</li> * </ol> * This method can be called after a SIM card loads, which may be before or after boot. * </p> * <p> * This method should not block for a long time. If expensive operations (e.g. network access) * are required, this method can schedule the work and return null. Then, use - * {@link android.telephony.CarrierConfigManager#reloadCarrierConfigForSubId - * reloadCarrierConfigForSubId} to trigger a reload when the config is ready. + * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId + * notifyConfigChangedForSubId} to trigger a reload when the config is ready. * </p> * <p> * Implementations should use the keys defined in {@link android.telephony.CarrierConfigManager diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 33fef62..d5ee7e7 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -16,6 +16,7 @@ package android.service.voice; +import android.annotation.Nullable; import android.app.Dialog; import android.app.Instrumentation; import android.app.VoiceInteractor; @@ -122,7 +123,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() { @Override public IVoiceInteractorRequest startConfirmation(String callingPackage, - IVoiceInteractorCallback callback, CharSequence prompt, Bundle extras) { + IVoiceInteractorCallback callback, VoiceInteractor.Prompt prompt, Bundle extras) { ConfirmationRequest request = new ConfirmationRequest(callingPackage, Binder.getCallingUid(), callback, VoiceInteractionSession.this, prompt, extras); @@ -134,7 +135,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall @Override public IVoiceInteractorRequest startPickOption(String callingPackage, - IVoiceInteractorCallback callback, CharSequence prompt, + IVoiceInteractorCallback callback, VoiceInteractor.Prompt prompt, VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) { PickOptionRequest request = new PickOptionRequest(callingPackage, Binder.getCallingUid(), callback, VoiceInteractionSession.this, @@ -147,7 +148,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall @Override public IVoiceInteractorRequest startCompleteVoice(String callingPackage, - IVoiceInteractorCallback callback, CharSequence message, Bundle extras) { + IVoiceInteractorCallback callback, VoiceInteractor.Prompt message, Bundle extras) { CompleteVoiceRequest request = new CompleteVoiceRequest(callingPackage, Binder.getCallingUid(), callback, VoiceInteractionSession.this, message, extras); @@ -159,7 +160,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall @Override public IVoiceInteractorRequest startAbortVoice(String callingPackage, - IVoiceInteractorCallback callback, CharSequence message, Bundle extras) { + IVoiceInteractorCallback callback, VoiceInteractor.Prompt message, Bundle extras) { AbortVoiceRequest request = new AbortVoiceRequest(callingPackage, Binder.getCallingUid(), callback, VoiceInteractionSession.this, message, extras); @@ -404,10 +405,10 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * VoiceInteractor.ConfirmationRequest}. */ public static final class ConfirmationRequest extends Request { - final CharSequence mPrompt; + final VoiceInteractor.Prompt mPrompt; ConfirmationRequest(String packageName, int uid, IVoiceInteractorCallback callback, - VoiceInteractionSession session, CharSequence prompt, Bundle extras) { + VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) { super(packageName, uid, callback, session, extras); mPrompt = prompt; } @@ -417,11 +418,23 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * {@link android.app.VoiceInteractor.ConfirmationRequest * VoiceInteractor.ConfirmationRequest}. */ - public CharSequence getPrompt() { + @Nullable + public VoiceInteractor.Prompt getVoicePrompt() { return mPrompt; } /** + * Return the prompt informing the user of what will happen, as per + * {@link android.app.VoiceInteractor.ConfirmationRequest + * VoiceInteractor.ConfirmationRequest}. + * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts. + */ + @Nullable + public CharSequence getPrompt() { + return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null); + } + + /** * Report that the voice interactor has confirmed the operation with the user, resulting * in a call to * {@link android.app.VoiceInteractor.ConfirmationRequest#onConfirmationResult @@ -437,11 +450,11 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. */ public static final class PickOptionRequest extends Request { - final CharSequence mPrompt; + final VoiceInteractor.Prompt mPrompt; final VoiceInteractor.PickOptionRequest.Option[] mOptions; PickOptionRequest(String packageName, int uid, IVoiceInteractorCallback callback, - VoiceInteractionSession session, CharSequence prompt, + VoiceInteractionSession session, VoiceInteractor.Prompt prompt, VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) { super(packageName, uid, callback, session, extras); mPrompt = prompt; @@ -452,11 +465,22 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * Return the prompt informing the user of what they are picking, as per * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. */ - public CharSequence getPrompt() { + @Nullable + public VoiceInteractor.Prompt getVoicePrompt() { return mPrompt; } /** + * Return the prompt informing the user of what they are picking, as per + * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. + * @deprecated Prefer {@link #getVoicePrompt()} which allows multiple voice prompts. + */ + @Nullable + public CharSequence getPrompt() { + return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null); + } + + /** * Return the set of options the user is picking from, as per * {@link android.app.VoiceInteractor.PickOptionRequest VoiceInteractor.PickOptionRequest}. */ @@ -494,12 +518,12 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * VoiceInteractor.CompleteVoiceRequest}. */ public static final class CompleteVoiceRequest extends Request { - final CharSequence mMessage; + final VoiceInteractor.Prompt mPrompt; CompleteVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback, - VoiceInteractionSession session, CharSequence message, Bundle extras) { + VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) { super(packageName, uid, callback, session, extras); - mMessage = message; + mPrompt = prompt; } /** @@ -507,8 +531,20 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * {@link android.app.VoiceInteractor.CompleteVoiceRequest * VoiceInteractor.CompleteVoiceRequest}. */ + @Nullable + public VoiceInteractor.Prompt getVoicePrompt() { + return mPrompt; + } + + /** + * Return the message informing the user of the completion, as per + * {@link android.app.VoiceInteractor.CompleteVoiceRequest + * VoiceInteractor.CompleteVoiceRequest}. + * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message. + */ + @Nullable public CharSequence getMessage() { - return mMessage; + return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null); } /** @@ -527,20 +563,31 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. */ public static final class AbortVoiceRequest extends Request { - final CharSequence mMessage; + final VoiceInteractor.Prompt mPrompt; AbortVoiceRequest(String packageName, int uid, IVoiceInteractorCallback callback, - VoiceInteractionSession session, CharSequence message, Bundle extras) { + VoiceInteractionSession session, VoiceInteractor.Prompt prompt, Bundle extras) { super(packageName, uid, callback, session, extras); - mMessage = message; + mPrompt = prompt; } /** * Return the message informing the user of the problem, as per * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. */ + @Nullable + public VoiceInteractor.Prompt getVoicePrompt() { + return mPrompt; + } + + /** + * Return the message informing the user of the problem, as per + * {@link android.app.VoiceInteractor.AbortVoiceRequest VoiceInteractor.AbortVoiceRequest}. + * @deprecated Prefer {@link #getVoicePrompt()} which allows a separate visual message. + */ + @Nullable public CharSequence getMessage() { - return mMessage; + return (mPrompt != null ? mPrompt.getVoicePromptAt(0) : null); } /** @@ -1035,7 +1082,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall public void onCreate(Bundle args) { doOnCreate(); } - + /** @hide */ public void onCreate(Bundle args, int showFlags) { doOnCreate(); diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 1b25505..c61ca4e 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -19,6 +19,7 @@ package android.transition; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TimeInterpolator; +import android.annotation.Nullable; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Path; @@ -700,7 +701,7 @@ public abstract class Transition implements Cloneable { continue; } // Only bother trying to animate with values that differ between start/end - boolean isChanged = start == null || end == null || areValuesChanged(start, end); + boolean isChanged = start == null || end == null || isTransitionRequired(start, end); if (isChanged) { if (DBG) { View view = (end != null) ? end.view : start.view; @@ -1747,7 +1748,7 @@ public abstract class Transition implements Cloneable { endValues = mEndValues.viewValues.get(oldView); } boolean cancel = (startValues != null || endValues != null) && - oldInfo.transition.areValuesChanged(oldValues, endValues); + oldInfo.transition.isTransitionRequired(oldValues, endValues); if (cancel) { if (anim.isRunning() || anim.isStarted()) { if (DBG) { @@ -1770,32 +1771,36 @@ public abstract class Transition implements Cloneable { } /** - * Returns whether transition values have changed between the start scene and the end scene - * (thus determining whether animation is required). The default implementation compares the + * Returns whether or not the transition should create an Animator, based on the values + * captured during {@link #captureStartValues(TransitionValues)} and + * {@link #captureEndValues(TransitionValues)}. The default implementation compares the * property values returned from {@link #getTransitionProperties()}, or all property values if * {@code getTransitionProperties()} returns null. Subclasses may override this method to - * provide logic more specific to their transition implementation. + * provide logic more specific to the transition implementation. * - * @param oldValues the first set of values, may be {@code null} - * @param newValues the second set of values, may be {@code null} + * @param startValues the values from captureStartValues, This may be {@code null} if the + * View did not exist in the start state. + * @param endValues the values from captureEndValues. This may be {@code null} if the View + * did not exist in the end state. */ - protected boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) { + public boolean isTransitionRequired(@Nullable TransitionValues startValues, + @Nullable TransitionValues endValues) { boolean valuesChanged = false; - // if oldValues null, then transition didn't care to stash values, + // if startValues null, then transition didn't care to stash values, // and won't get canceled - if (oldValues != null && newValues != null) { + if (startValues != null && endValues != null) { String[] properties = getTransitionProperties(); if (properties != null) { int count = properties.length; for (int i = 0; i < count; i++) { - if (isValueChanged(oldValues, newValues, properties[i])) { + if (isValueChanged(startValues, endValues, properties[i])) { valuesChanged = true; break; } } } else { - for (String key : oldValues.values.keySet()) { - if (isValueChanged(oldValues, newValues, key)) { + for (String key : startValues.values.keySet()) { + if (isValueChanged(startValues, endValues, key)) { valuesChanged = true; break; } diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java index ed7fd86..bac668a 100644 --- a/core/java/android/transition/Visibility.java +++ b/core/java/android/transition/Visibility.java @@ -445,7 +445,7 @@ public abstract class Visibility extends Transition { mForcedEndVisibility != -1; if (!isForcedVisibility) { originalVisibility = viewToKeep.getVisibility(); - viewToKeep.setVisibility(View.VISIBLE); + viewToKeep.setTransitionVisibility(View.VISIBLE); } Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues); if (animator != null) { @@ -454,7 +454,7 @@ public abstract class Visibility extends Transition { animator.addListener(disappearListener); addListener(disappearListener); } else if (!isForcedVisibility) { - viewToKeep.setVisibility(originalVisibility); + viewToKeep.setTransitionVisibility(originalVisibility); } return animator; } @@ -462,18 +462,18 @@ public abstract class Visibility extends Transition { } @Override - protected boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) { - if (oldValues == null && newValues == null) { + public boolean isTransitionRequired(TransitionValues startValues, TransitionValues newValues) { + if (startValues == null && newValues == null) { return false; } - if (oldValues != null && newValues != null && + if (startValues != null && newValues != null && newValues.values.containsKey(PROPNAME_VISIBILITY) != - oldValues.values.containsKey(PROPNAME_VISIBILITY)) { + startValues.values.containsKey(PROPNAME_VISIBILITY)) { // The transition wasn't targeted in either the start or end, so it couldn't // have changed. return false; } - VisibilityInfo changeInfo = getVisibilityChangeInfo(oldValues, newValues); + VisibilityInfo changeInfo = getVisibilityChangeInfo(startValues, newValues); return changeInfo.visibilityChange && (changeInfo.startVisibility == View.VISIBLE || changeInfo.endVisibility == View.VISIBLE); } @@ -516,14 +516,14 @@ public abstract class Visibility extends Transition { @Override public void onAnimationPause(Animator animation) { if (!mCanceled && !mIsForcedVisibility) { - mView.setVisibility(mFinalVisibility); + mView.setTransitionVisibility(mFinalVisibility); } } @Override public void onAnimationResume(Animator animation) { if (!mCanceled && !mIsForcedVisibility) { - mView.setVisibility(View.VISIBLE); + mView.setTransitionVisibility(View.VISIBLE); } } @@ -557,7 +557,7 @@ public abstract class Visibility extends Transition { if (mIsForcedVisibility) { mView.setTransitionAlpha(0); } else { - mView.setVisibility(mFinalVisibility); + mView.setTransitionVisibility(mFinalVisibility); } } } diff --git a/core/java/android/util/LayoutDirection.java b/core/java/android/util/LayoutDirection.java index 20af20b..03077e4 100644 --- a/core/java/android/util/LayoutDirection.java +++ b/core/java/android/util/LayoutDirection.java @@ -27,6 +27,12 @@ public final class LayoutDirection { private LayoutDirection() {} /** + * An undefined layout direction. + * @hide + */ + public static final int UNDEFINED = -1; + + /** * Horizontal layout direction is from Left to Right. */ public static final int LTR = 0; diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java index 4b9b590..80dcecc 100644 --- a/core/java/android/view/ActionMode.java +++ b/core/java/android/view/ActionMode.java @@ -45,10 +45,10 @@ public abstract class ActionMode { public static final int TYPE_FLOATING = 1; /** - * Default snooze time. + * Default value to hide the action mode for + * {@link ViewConfiguration#getDefaultActionModeHideDuration()}. */ - public static final int SNOOZE_TIME_DEFAULT = - ViewConfiguration.getDefaultActionModeSnoozeTime(); + public static final int DEFAULT_HIDE_DURATION = -1; private Object mTag; private boolean mTitleOptionalHint; @@ -213,17 +213,17 @@ public abstract class ActionMode { public void invalidateContentRect() {} /** - * Hide the action mode view from obstructing the content below for a short period. + * Hide the action mode view from obstructing the content below for a short duration. * This only makes sense for action modes that support dynamic positioning on the screen. - * If this method is called again before the snooze time expires, the later snooze will + * If this method is called again before the hide duration expires, the later hide call will * cancel the former and then take effect. - * NOTE that there is an internal limit to how long the mode can be snoozed for. It's typically + * NOTE that there is an internal limit to how long the mode can be hidden for. It's typically * about a few seconds. * - * @param snoozeTime The number of milliseconds to snooze for. - * @see #SNOOZE_TIME_DEFAULT + * @param duration The number of milliseconds to hide for. + * @see #DEFAULT_HIDE_DURATION */ - public void snooze(int snoozeTime) {} + public void hide(long duration) {} /** * Finish and close this action mode. The action mode's {@link ActionMode.Callback} will diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 5a587fe..35c4192 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -89,6 +89,11 @@ public final class Display { public static final int DEFAULT_DISPLAY = 0; /** + * Invalid display id. + */ + public static final int INVALID_DISPLAY = -1; + + /** * Display flag: Indicates that the display supports compositing content * that is stored in protected graphics buffers. * <p> diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java index ff0af6b..b705cf1 100644 --- a/core/java/android/view/GestureDetector.java +++ b/core/java/android/view/GestureDetector.java @@ -32,7 +32,7 @@ import android.os.Message; * <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call * {@link #onTouchEvent(MotionEvent)}. The methods defined in your callback * will be executed when the events occur. - * <li>If listening for {@link OnStylusButtonPressListener#onStylusButtonPress(MotionEvent)} + * <li>If listening for {@link OnContextClickListener#onContextClick(MotionEvent)} * you must call {@link #onGenericMotionEvent(MotionEvent)} * in {@link View#onGenericMotionEvent(MotionEvent)}. * </ul> @@ -152,31 +152,28 @@ public class GestureDetector { } /** - * The listener that is used to notify when a stylus button press occurs. When listening for a - * stylus button press ensure that you call {@link #onGenericMotionEvent(MotionEvent)} in + * The listener that is used to notify when a context click occurs. When listening for a + * context click ensure that you call {@link #onGenericMotionEvent(MotionEvent)} in * {@link View#onGenericMotionEvent(MotionEvent)}. */ - public interface OnStylusButtonPressListener { + public interface OnContextClickListener { /** - * Notified when a stylus button press occurs. This is when the stylus - * is touching the screen and the {@value MotionEvent#BUTTON_STYLUS_PRIMARY} - * is pressed. + * Notified when a context click occurs. * - * @param e The motion event that occurred during the stylus button - * press. + * @param e The motion event that occurred during the context click. * @return true if the event is consumed, else false */ - boolean onStylusButtonPress(MotionEvent e); + boolean onContextClick(MotionEvent e); } /** * A convenience class to extend when you only want to listen for a subset * of all the gestures. This implements all methods in the - * {@link OnGestureListener}, {@link OnDoubleTapListener}, and {@link OnStylusButtonPressListener} + * {@link OnGestureListener}, {@link OnDoubleTapListener}, and {@link OnContextClickListener} * but does nothing and return {@code false} for all applicable methods. */ public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener, - OnStylusButtonPressListener { + OnContextClickListener { public boolean onSingleTapUp(MotionEvent e) { return false; @@ -214,7 +211,7 @@ public class GestureDetector { return false; } - public boolean onStylusButtonPress(MotionEvent e) { + public boolean onContextClick(MotionEvent e) { return false; } } @@ -238,12 +235,12 @@ public class GestureDetector { private final Handler mHandler; private final OnGestureListener mListener; private OnDoubleTapListener mDoubleTapListener; - private OnStylusButtonPressListener mStylusButtonListener; + private OnContextClickListener mContextClickListener; private boolean mStillDown; private boolean mDeferConfirmSingleTap; private boolean mInLongPress; - private boolean mInStylusButtonPress; + private boolean mInContextClick; private boolean mAlwaysInTapRegion; private boolean mAlwaysInBiggerTapRegion; private boolean mIgnoreNextUpEvent; @@ -388,8 +385,8 @@ public class GestureDetector { if (listener instanceof OnDoubleTapListener) { setOnDoubleTapListener((OnDoubleTapListener) listener); } - if (listener instanceof OnStylusButtonPressListener) { - setOnStylusButtonPressListener((OnStylusButtonPressListener) listener); + if (listener instanceof OnContextClickListener) { + setContextClickListener((OnContextClickListener) listener); } init(context); } @@ -453,16 +450,13 @@ public class GestureDetector { } /** - * Sets the listener which will be called for stylus button related - * gestures. + * Sets the listener which will be called for context clicks. * - * @param onStylusButtonPressListener the listener invoked for all the - * callbacks, or null to stop listening for stylus button - * gestures. + * @param onContextClickListener the listener invoked for all the callbacks, or null to stop + * listening for context clicks. */ - public void setOnStylusButtonPressListener( - OnStylusButtonPressListener onStylusButtonPressListener) { - mStylusButtonListener = onStylusButtonPressListener; + public void setContextClickListener(OnContextClickListener onContextClickListener) { + mContextClickListener = onContextClickListener; } /** @@ -597,7 +591,7 @@ public class GestureDetector { break; case MotionEvent.ACTION_MOVE: - if (mInLongPress || mInStylusButtonPress) { + if (mInLongPress || mInContextClick) { break; } final float scrollX = mLastFocusX - focusX; @@ -698,12 +692,14 @@ public class GestureDetector { mInputEventConsistencyVerifier.onGenericMotionEvent(ev, 0); } + final int actionButton = ev.getActionButton(); switch (ev.getActionMasked()) { case MotionEvent.ACTION_BUTTON_PRESS: - if (mStylusButtonListener != null && !mInStylusButtonPress && !mInLongPress - && ev.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { - if (mStylusButtonListener.onStylusButtonPress(ev)) { - mInStylusButtonPress = true; + if (mContextClickListener != null && !mInContextClick && !mInLongPress + && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY + || actionButton == MotionEvent.BUTTON_SECONDARY)) { + if (mContextClickListener.onContextClick(ev)) { + mInContextClick = true; mHandler.removeMessages(LONG_PRESS); mHandler.removeMessages(TAP); return true; @@ -712,9 +708,9 @@ public class GestureDetector { break; case MotionEvent.ACTION_BUTTON_RELEASE: - if (mInStylusButtonPress - && ev.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { - mInStylusButtonPress = false; + if (mInContextClick && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY + || actionButton == MotionEvent.BUTTON_SECONDARY)) { + mInContextClick = false; mIgnoreNextUpEvent = true; } break; @@ -734,7 +730,7 @@ public class GestureDetector { mAlwaysInBiggerTapRegion = false; mDeferConfirmSingleTap = false; mInLongPress = false; - mInStylusButtonPress = false; + mInContextClick = false; mIgnoreNextUpEvent = false; } @@ -747,7 +743,7 @@ public class GestureDetector { mAlwaysInBiggerTapRegion = false; mDeferConfirmSingleTap = false; mInLongPress = false; - mInStylusButtonPress = false; + mInContextClick = false; mIgnoreNextUpEvent = false; } diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java index 41502b6..d1b96ba 100644 --- a/core/java/android/view/GhostView.java +++ b/core/java/android/view/GhostView.java @@ -39,7 +39,7 @@ public class GhostView extends View { mView = view; mView.mGhostView = this; final ViewGroup parent = (ViewGroup) mView.getParent(); - setGhostedVisibility(View.INVISIBLE); + mView.setTransitionVisibility(View.INVISIBLE); parent.invalidate(); } @@ -66,19 +66,15 @@ public class GhostView extends View { super.setVisibility(visibility); if (mView.mGhostView == this) { int inverseVisibility = (visibility == View.VISIBLE) ? View.INVISIBLE : View.VISIBLE; - setGhostedVisibility(inverseVisibility); + mView.setTransitionVisibility(inverseVisibility); } } - private void setGhostedVisibility(int visibility) { - mView.mViewFlags = (mView.mViewFlags & ~View.VISIBILITY_MASK) | visibility; - } - @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (!mBeingMoved) { - setGhostedVisibility(View.VISIBLE); + mView.setTransitionVisibility(View.VISIBLE); mView.mGhostView = null; final ViewGroup parent = (ViewGroup) mView.getParent(); if (parent != null) { diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java index 6651b83..2f87d2e 100644 --- a/core/java/android/view/HapticFeedbackConstants.java +++ b/core/java/android/view/HapticFeedbackConstants.java @@ -52,9 +52,9 @@ public class HapticFeedbackConstants { public static final int CALENDAR_DATE = 5; /** - * The user has touched the screen with a stylus and pressed the stylus button. + * The user has performed a context click on an object. */ - public static final int STYLUS_BUTTON_PRESS = 6; + public static final int CONTEXT_CLICK = 6; /** * This is a private constant. Feel free to renumber as desired. diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 1ee4780..f39d1f5 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -56,7 +56,7 @@ public final class InputDevice implements Parcelable { private final int mKeyboardType; private final KeyCharacterMap mKeyCharacterMap; private final boolean mHasVibrator; - private final boolean mHasMic; + private final boolean mHasMicrophone; private final boolean mHasButtonUnderPad; private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>(); @@ -358,7 +358,7 @@ public final class InputDevice implements Parcelable { // Called by native code. private InputDevice(int id, int generation, int controllerNumber, String name, int vendorId, int productId, String descriptor, boolean isExternal, int sources, int keyboardType, - KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasMic, + KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasMicrophone, boolean hasButtonUnderPad) { mId = id; mGeneration = generation; @@ -372,7 +372,7 @@ public final class InputDevice implements Parcelable { mKeyboardType = keyboardType; mKeyCharacterMap = keyCharacterMap; mHasVibrator = hasVibrator; - mHasMic = hasMic; + mHasMicrophone = hasMicrophone; mHasButtonUnderPad = hasButtonUnderPad; mIdentifier = new InputDeviceIdentifier(descriptor, vendorId, productId); } @@ -390,7 +390,7 @@ public final class InputDevice implements Parcelable { mKeyboardType = in.readInt(); mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in); mHasVibrator = in.readInt() != 0; - mHasMic = in.readInt() != 0; + mHasMicrophone = in.readInt() != 0; mHasButtonUnderPad = in.readInt() != 0; mIdentifier = new InputDeviceIdentifier(mDescriptor, mVendorId, mProductId); @@ -723,8 +723,8 @@ public final class InputDevice implements Parcelable { * Reports whether the device has a built-in microphone. * @return Whether the device has a built-in microphone. */ - public boolean hasMic() { - return mHasMic; + public boolean hasMicrophone() { + return mHasMicrophone; } /** @@ -861,7 +861,7 @@ public final class InputDevice implements Parcelable { out.writeInt(mKeyboardType); mKeyCharacterMap.writeToParcel(out, flags); out.writeInt(mHasVibrator ? 1 : 0); - out.writeInt(mHasMic ? 1 : 0); + out.writeInt(mHasMicrophone ? 1 : 0); out.writeInt(mHasButtonUnderPad ? 1 : 0); final int numRanges = mMotionRanges.size(); @@ -907,7 +907,7 @@ public final class InputDevice implements Parcelable { description.append(" Has Vibrator: ").append(mHasVibrator).append("\n"); - description.append(" Has mic: ").append(mHasMic).append("\n"); + description.append(" Has mic: ").append(mHasMicrophone).append("\n"); description.append(" Sources: 0x").append(Integer.toHexString(mSources)).append(" ("); appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard"); diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 7b0f1fb..37e4000 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -516,8 +516,8 @@ public class ScaleGestureDetector { } /** - * Return whether the stylus scale gesture, in which the user uses a stylus - * and presses the button, should preform scaling. {@see #setButtonScaleEnabled(boolean)}. + * Return whether the stylus scale gesture, in which the user uses a stylus and presses the + * button, should perform scaling. {@see #setStylusScaleEnabled(boolean)} */ public boolean isStylusScaleEnabled() { return mStylusScaleEnabled; diff --git a/core/java/android/view/SearchEvent.java b/core/java/android/view/SearchEvent.java index ef51e7d..643cc3e 100644 --- a/core/java/android/view/SearchEvent.java +++ b/core/java/android/view/SearchEvent.java @@ -25,7 +25,7 @@ public class SearchEvent { private InputDevice mInputDevice; - /** @hide */ + /** Create a new search event. */ public SearchEvent(InputDevice inputDevice) { mInputDevice = inputDevice; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 126540f..5dd5ab8 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -990,13 +990,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * <p> - * Indicates this view can be stylus button pressed. When stylus button - * pressable, a View reacts to stylus button presses by notifiying - * the OnStylusButtonPressListener. + * Indicates this view can be context clicked. When context clickable, a View reacts to a + * context click (e.g. a primary stylus button press or right mouse click) by notifying the + * OnContextClickListener. * </p> * {@hide} */ - static final int STYLUS_BUTTON_PRESSABLE = 0x00800000; + static final int CONTEXT_CLICKABLE = 0x00800000; /** @hide */ @@ -1872,6 +1872,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public @interface ResolvedLayoutDir {} /** + * A flag to indicate that the layout direction of this view has not been defined yet. + * @hide + */ + public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; + + /** * Horizontal layout direction of this view is from Left to Right. * Use with {@link #setLayoutDirection}. */ @@ -3418,11 +3424,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, protected OnLongClickListener mOnLongClickListener; /** - * Listener used to dispatch stylus touch and button press events. This field should be made - * private, so it is hidden from the SDK. + * Listener used to dispatch context click events. This field should be made private, so it + * is hidden from the SDK. * {@hide} */ - protected OnStylusButtonPressListener mOnStylusButtonPressListener; + protected OnContextClickListener mOnContextClickListener; /** * Listener used to build the context menu. @@ -3515,11 +3521,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private boolean mHasPerformedLongPress; /** - * Whether the stylus button is currently pressed down. This is true when - * the stylus is touching the screen and the button has been pressed, this - * is false once the stylus has been lifted. + * Whether a context click button is currently pressed down. This is true when the stylus is + * touching the screen and the primary button has been pressed, or if a mouse's right button is + * pressed. This is false once the button is released or if the stylus has been lifted. */ - private boolean mInStylusButtonPress; + private boolean mInContextButtonPress; /** * Whether the next up event should be ignored for the purposes of gesture recognition. This is @@ -4045,10 +4051,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, viewFlagMasks |= LONG_CLICKABLE; } break; - case com.android.internal.R.styleable.View_stylusButtonPressable: + case com.android.internal.R.styleable.View_contextClickable: if (a.getBoolean(attr, false)) { - viewFlagValues |= STYLUS_BUTTON_PRESSABLE; - viewFlagMasks |= STYLUS_BUTTON_PRESSABLE; + viewFlagValues |= CONTEXT_CLICKABLE; + viewFlagMasks |= CONTEXT_CLICKABLE; } break; case com.android.internal.R.styleable.View_saveEnabled: @@ -4537,7 +4543,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); - out.append((mViewFlags & STYLUS_BUTTON_PRESSABLE) != 0 ? 'S' : '.'); + out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); out.append(' '); out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); @@ -5125,17 +5131,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Register a callback to be invoked when this view is touched with a stylus and the button is - * pressed. + * Register a callback to be invoked when this view is context clicked. If the view is not + * context clickable, it becomes context clickable. * * @param l The callback that will run - * @see #setStylusButtonPressable(boolean) + * @see #setContextClickable(boolean) */ - public void setOnStylusButtonPressListener(@Nullable OnStylusButtonPressListener l) { - if (!isStylusButtonPressable()) { - setStylusButtonPressable(true); + public void setOnContextClickListener(@Nullable OnContextClickListener l) { + if (!isContextClickable()) { + setContextClickable(true); } - getListenerInfo().mOnStylusButtonPressListener = l; + getListenerInfo().mOnContextClickListener = l; } /** @@ -5216,21 +5222,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Call this view's OnStylusButtonPressListener, if it is defined. + * Call this view's OnContextClickListener, if it is defined. * - * @return True if there was an assigned OnStylusButtonPressListener that consumed the event, - * false otherwise. + * @return True if there was an assigned OnContextClickListener that consumed the event, false + * otherwise. */ - public boolean performStylusButtonPress() { - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_STYLUS_BUTTON_PRESSED); + public boolean performContextClick() { + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); boolean handled = false; ListenerInfo li = mListenerInfo; - if (li != null && li.mOnStylusButtonPressListener != null) { - handled = li.mOnStylusButtonPressListener.onStylusButtonPress(View.this); + if (li != null && li.mOnContextClickListener != null) { + handled = li.mOnContextClickListener.onContextClick(View.this); } if (handled) { - performHapticFeedback(HapticFeedbackConstants.STYLUS_BUTTON_PRESS); + performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); } return handled; } @@ -6025,7 +6031,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> - * <li>{@link AccessibilityNodeInfo#setStylusButtonPressable(boolean)}</li> + * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> * </ul> * <p> * Subclasses should override this method, call the super implementation, @@ -6177,8 +6183,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setChecked(true); } } - if (isStylusButtonPressable()) { - structure.setStylusButtonPressable(true); + if (isContextClickable()) { + structure.setContextClickable(true); } structure.setClassName(getAccessibilityClassName().toString()); structure.setContentDescription(getContentDescription()); @@ -6247,8 +6253,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setChecked(true); } } - if (info.isStylusButtonPressable()) { - structure.setStylusButtonPressable(true); + if (info.isContextClickable()) { + structure.setContextClickable(true); } CharSequence cname = info.getClassName(); structure.setClassName(cname != null ? cname.toString() : null); @@ -6379,7 +6385,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, info.setAccessibilityFocused(isAccessibilityFocused()); info.setSelected(isSelected()); info.setLongClickable(isLongClickable()); - info.setStylusButtonPressable(isStylusButtonPressable()); + info.setContextClickable(isContextClickable()); info.setLiveRegion(getAccessibilityLiveRegion()); // TODO: These make sense only if we are in an AdapterView but all @@ -6410,8 +6416,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); } - if (isStylusButtonPressable() && isEnabled()) { - info.addAction(AccessibilityAction.ACTION_STYLUS_BUTTON_PRESS); + if (isContextClickable() && isEnabled()) { + info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); } CharSequence text = getIterableTextForAccessibility(); @@ -7801,28 +7807,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Indicates whether this view reacts to stylus button press events or not. + * Indicates whether this view reacts to context clicks or not. * - * @return true if the view is stylus button pressable, false otherwise - * @see #setStylusButtonPressable(boolean) - * @attr ref android.R.styleable#View_stylusButtonPressable + * @return true if the view is context clickable, false otherwise + * @see #setContextClickable(boolean) + * @attr ref android.R.styleable#View_contextClickable */ - public boolean isStylusButtonPressable() { - return (mViewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE; + public boolean isContextClickable() { + return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; } /** - * Enables or disables stylus button press events for this view. When a view is stylus button - * pressable it reacts to the user touching the screen with a stylus and pressing the first - * stylus button. This event can launch the listener. + * Enables or disables context clicking for this view. This event can launch the listener. * - * @param stylusButtonPressable true to make the view react to a stylus button press, false - * otherwise - * @see #isStylusButtonPressable() - * @attr ref android.R.styleable#View_stylusButtonPressable + * @param contextClickable true to make the view react to a context click, false otherwise + * @see #isContextClickable() + * @attr ref android.R.styleable#View_contextClickable */ - public void setStylusButtonPressable(boolean stylusButtonPressable) { - setFlags(stylusButtonPressable ? STYLUS_BUTTON_PRESSABLE : 0, STYLUS_BUTTON_PRESSABLE); + public void setContextClickable(boolean contextClickable) { + setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); } /** @@ -8243,7 +8246,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final int viewFlags = mViewFlags; if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE - || (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE) + || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) && (viewFlags & ENABLED_MASK) == ENABLED) { views.add(this); } @@ -8786,6 +8789,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Change the visibility of the View without triggering any other changes. This is + * important for transitions, where visibility changes should not adjust focus or + * trigger a new layout. This is only used when the visibility has already been changed + * and we need a transient value during an animation. When the animation completes, + * the original visibility value is always restored. + * + * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. + * @hide + */ + public void setTransitionVisibility(@Visibility int visibility) { + mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; + } + + /** * Reset the flag indicating the accessibility state of the subtree rooted * at this view changed. */ @@ -8962,9 +8979,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return requestRectangleOnScreen(r, true); } } break; - case R.id.accessibilityActionStylusButtonPress: { - if (isStylusButtonPressable()) { - performStylusButtonPress(); + case R.id.accessibilityActionContextClick: { + if (isContextClickable()) { + performContextClick(); return true; } } break; @@ -9369,12 +9386,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return true; } + final int actionButton = event.getActionButton(); switch (event.getActionMasked()) { case MotionEvent.ACTION_BUTTON_PRESS: - if (isStylusButtonPressable() && !mInStylusButtonPress && !mHasPerformedLongPress - && event.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { - if (performStylusButtonPress()) { - mInStylusButtonPress = true; + if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress + && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY + || actionButton == MotionEvent.BUTTON_SECONDARY)) { + if (performContextClick()) { + mInContextButtonPress = true; setPressed(true, event.getX(), event.getY()); removeTapCallback(); removeLongPressCallback(); @@ -9384,9 +9403,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, break; case MotionEvent.ACTION_BUTTON_RELEASE: - if (mInStylusButtonPress - && event.getActionButton() == MotionEvent.BUTTON_STYLUS_PRIMARY) { - mInStylusButtonPress = false; + if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY + || actionButton == MotionEvent.BUTTON_SECONDARY)) { + mInContextButtonPress = false; mIgnoreNextUpEvent = true; } break; @@ -10145,7 +10164,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return (viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE - || (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE; + || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; } /** @@ -10238,7 +10257,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // events, it just doesn't respond to them. return (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) - || (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE); + || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE); } if (mTouchDelegate != null) { @@ -10249,7 +10268,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || - (viewFlags & STYLUS_BUTTON_PRESSABLE) == STYLUS_BUTTON_PRESSABLE) { + (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) { switch (action) { case MotionEvent.ACTION_UP: boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; @@ -10335,7 +10354,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setPressed(false); removeTapCallback(); removeLongPressCallback(); - mInStylusButtonPress = false; + mInContextButtonPress = false; mHasPerformedLongPress = false; mIgnoreNextUpEvent = false; break; @@ -10643,7 +10662,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (accessibilityEnabled) { if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 - || (changed & STYLUS_BUTTON_PRESSABLE) != 0) { + || (changed & CONTEXT_CLICKABLE) != 0) { if (oldIncludeForAccessibility != includeForAccessibility()) { notifySubtreeAccessibilityStateChangedIfNeeded(); } else { @@ -17148,6 +17167,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * drawable. * * @return The color of the ColorDrawable background, if set, otherwise 0. + * @hide */ @ColorInt public int getBackgroundColor() { @@ -21301,17 +21321,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Interface definition for a callback to be invoked when a view is touched with a stylus while - * the stylus button is pressed. + * Interface definition for a callback to be invoked when a view is context clicked. */ - public interface OnStylusButtonPressListener { + public interface OnContextClickListener { /** - * Called when a view is touched with a stylus while the stylus button is pressed. + * Called when a view is context clicked. * - * @param v The view that was touched. - * @return true if the callback consumed the stylus button press, false otherwise. + * @param v The view that has been context clicked. + * @return true if the callback consumed the context click, false otherwise. */ - boolean onStylusButtonPress(View v); + boolean onContextClick(View v); } /** diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 8c6fa3f..4d584a3 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -213,9 +213,9 @@ public class ViewConfiguration { private static final int OVERFLING_DISTANCE = 6; /** - * Default time to snooze an action mode for. + * Default duration to hide an action mode for. */ - private static final int ACTION_MODE_SNOOZE_TIME_DEFAULT = 2000; + private static final long ACTION_MODE_HIDE_DURATION_DEFAULT = 2000; /** * Configuration values for overriding {@link #hasPermanentMenuKey()} behavior. @@ -737,10 +737,10 @@ public class ViewConfiguration { } /** - * @return the default duration in milliseconds for {@link ActionMode#snooze(int)}. + * @return the default duration in milliseconds for {@link ActionMode#hide(long)}. */ - public static int getDefaultActionModeSnoozeTime() { - return ACTION_MODE_SNOOZE_TIME_DEFAULT; + public static long getDefaultActionModeHideDuration() { + return ACTION_MODE_HIDE_DURATION_DEFAULT; } /** diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index e525474..8ceb166 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -75,10 +75,10 @@ public abstract class ViewStructure { public abstract void setLongClickable(boolean state); /** - * Set the stylus button pressable state of this view, as per - * {@link View#isStylusButtonPressable View.isStylusButtonPressable()}. + * Set the context clickable state of this view, as per + * {@link View#isContextClickable View.isContextClickable()}. */ - public abstract void setStylusButtonPressable(boolean state); + public abstract void setContextClickable(boolean state); /** * Set the focusable state of this view, as per {@link View#isFocusable View.isFocusable()}. diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index b0dbeca..ab793e0 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -684,9 +684,9 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par public static final int TYPE_WINDOWS_CHANGED = 0x00400000; /** - * Represents the event of a stylus button press on a {@link android.view.View}. + * Represents the event of a context click on a {@link android.view.View}. */ - public static final int TYPE_VIEW_STYLUS_BUTTON_PRESSED = 0x00800000; + public static final int TYPE_VIEW_CONTEXT_CLICKED = 0x00800000; /** * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: @@ -736,7 +736,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par * @see #TYPE_TOUCH_INTERACTION_START * @see #TYPE_TOUCH_INTERACTION_END * @see #TYPE_WINDOWS_CHANGED - * @see #TYPE_VIEW_STYLUS_BUTTON_PRESSED + * @see #TYPE_VIEW_CONTEXT_CLICKED */ public static final int TYPES_ALL_MASK = 0xFFFFFFFF; @@ -1402,11 +1402,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par builder.append("TYPE_WINDOWS_CHANGED"); eventTypeCount++; } break; - case TYPE_VIEW_STYLUS_BUTTON_PRESSED: { + case TYPE_VIEW_CONTEXT_CLICKED: { if (eventTypeCount > 0) { builder.append(", "); } - builder.append("TYPE_VIEW_STYLUS_BUTTON_PRESSED"); + builder.append("TYPE_VIEW_CONTEXT_CLICKED"); eventTypeCount++; } break; diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index b454d1c..36de8f3 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -520,7 +520,7 @@ public class AccessibilityNodeInfo implements Parcelable { private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000; - private static final int BOOLEAN_PROPERTY_STYLUS_BUTTON_PRESSABLE = 0x00020000; + private static final int BOOLEAN_PROPERTY_CONTEXT_CLICKABLE = 0x00020000; /** * Bits that provide the id of a virtual descendant of a view. @@ -1945,27 +1945,27 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Gets whether this node is stylus button pressable. + * Gets whether this node is context clickable. * - * @return True if the node is stylus button pressable. + * @return True if the node is context clickable. */ - public boolean isStylusButtonPressable() { - return getBooleanProperty(BOOLEAN_PROPERTY_STYLUS_BUTTON_PRESSABLE); + public boolean isContextClickable() { + return getBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE); } /** - * Sets whether this node is stylus button pressable. + * Sets whether this node is context clickable. * <p> * <strong>Note:</strong> Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable * before being delivered to an AccessibilityService. * </p> * - * @param stylusButtonPressable True if the node is stylus button pressable. + * @param contextClickable True if the node is context clickable. * @throws IllegalStateException If called from an AccessibilityService. */ - public void setStylusButtonPressable(boolean stylusButtonPressable) { - setBooleanProperty(BOOLEAN_PROPERTY_STYLUS_BUTTON_PRESSABLE, stylusButtonPressable); + public void setContextClickable(boolean contextClickable) { + setBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE, contextClickable); } /** @@ -3156,7 +3156,7 @@ public class AccessibilityNodeInfo implements Parcelable { builder.append("; selected: ").append(isSelected()); builder.append("; clickable: ").append(isClickable()); builder.append("; longClickable: ").append(isLongClickable()); - builder.append("; stylusButtonPressable: ").append(isStylusButtonPressable()); + builder.append("; contextClickable: ").append(isContextClickable()); builder.append("; enabled: ").append(isEnabled()); builder.append("; password: ").append(isPassword()); builder.append("; scrollable: ").append(isScrollable()); @@ -3537,10 +3537,10 @@ public class AccessibilityNodeInfo implements Parcelable { new AccessibilityAction(R.id.accessibilityActionScrollRight, null); /** - * Action that stylus button presses the node. + * Action that context clicks the node. */ - public static final AccessibilityAction ACTION_STYLUS_BUTTON_PRESS = - new AccessibilityAction(R.id.accessibilityActionStylusButtonPress, null); + public static final AccessibilityAction ACTION_CONTEXT_CLICK = + new AccessibilityAction(R.id.accessibilityActionContextClick, null); private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>(); static { @@ -3572,7 +3572,7 @@ public class AccessibilityNodeInfo implements Parcelable { sStandardActions.add(ACTION_SCROLL_LEFT); sStandardActions.add(ACTION_SCROLL_DOWN); sStandardActions.add(ACTION_SCROLL_RIGHT); - sStandardActions.add(ACTION_STYLUS_BUTTON_PRESS); + sStandardActions.add(ACTION_CONTEXT_CLICK); } private final int mActionId; diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index c0395cf..76c8fbd 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -298,6 +298,17 @@ public class EditorInfo implements InputType, Parcelable { /** * Name of the package that owns this editor. + * + * <p><strong>IME authors:</strong> In API level 22 + * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and prior, do not trust this package + * name. The system had not verified the consistency between the package name here and + * application's uid. Consider to use {@link InputBinding#getUid()}, which is trustworthy. + * Starting from Android MNC, the system verifies the consistency between this package name + * and application uid before {@link EditorInfo} is passed to the input method.</p> + * + * <p><strong>Editor authors:</strong> Starting from Android MNC, the application is no longer + * able to establish input connections if the package name provided here is inconsistent with + * application's uid.</p> */ public String packageName; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index a0d1930..0001860 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -694,9 +694,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te */ private boolean mForceTranscriptScroll; - private int mGlowPaddingLeft; - private int mGlowPaddingRight; - /** * Used for interacting with list items from an accessibility service. */ @@ -3489,17 +3486,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } - invalidate(0, 0, getWidth(), - mEdgeGlowTop.getMaxHeight() + getPaddingTop()); + invalidateTopGlow(); } else if (incrementalDeltaY < 0) { mEdgeGlowBottom.onPull((float) overscroll / getHeight(), 1.f - (float) x / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } - invalidate(0, getHeight() - getPaddingBottom() - - mEdgeGlowBottom.getMaxHeight(), getWidth(), - getHeight()); + invalidateBottomGlow(); } } } @@ -3539,17 +3533,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } - invalidate(0, 0, getWidth(), - mEdgeGlowTop.getMaxHeight() + getPaddingTop()); + invalidateTopGlow(); } else if (rawDeltaY < 0) { mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(), 1.f - (float) x / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } - invalidate(0, getHeight() - getPaddingBottom() - - mEdgeGlowBottom.getMaxHeight(), getWidth(), - getHeight()); + invalidateBottomGlow(); } } } @@ -3581,6 +3572,28 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } + private void invalidateTopGlow() { + if (mEdgeGlowTop == null) { + return; + } + final boolean clipToPadding = getClipToPadding(); + final int top = clipToPadding ? mPaddingTop : 0; + final int left = clipToPadding ? mPaddingLeft : 0; + final int right = clipToPadding ? getWidth() - mPaddingRight : getWidth(); + invalidate(left, top, right, top + mEdgeGlowTop.getMaxHeight()); + } + + private void invalidateBottomGlow() { + if (mEdgeGlowBottom == null) { + return; + } + final boolean clipToPadding = getClipToPadding(); + final int bottom = clipToPadding ? getHeight() - mPaddingBottom : getHeight(); + final int left = clipToPadding ? mPaddingLeft : 0; + final int right = clipToPadding ? getWidth() - mPaddingRight : getWidth(); + invalidate(left, bottom - mEdgeGlowBottom.getMaxHeight(), right, bottom); + } + @Override public void onTouchModeChanged(boolean isInTouchMode) { if (isInTouchMode) { @@ -4142,47 +4155,53 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te super.draw(canvas); if (mEdgeGlowTop != null) { final int scrollY = mScrollY; + final boolean clipToPadding = getClipToPadding(); + final int width; + final int height; + final int translateX; + final int translateY; + + if (clipToPadding) { + width = getWidth() - mPaddingLeft - mPaddingRight; + height = getHeight() - mPaddingTop - mPaddingBottom; + translateX = mPaddingLeft; + translateY = mPaddingTop; + } else { + width = getWidth(); + height = getHeight(); + translateX = 0; + translateY = 0; + } if (!mEdgeGlowTop.isFinished()) { final int restoreCount = canvas.save(); - final int width = getWidth(); - - int edgeY = Math.min(0, scrollY + mFirstPositionDistanceGuess); - canvas.translate(0, edgeY); - mEdgeGlowTop.setSize(width, getHeight()); + canvas.clipRect(translateX, translateY, + translateX + width ,translateY + mEdgeGlowTop.getMaxHeight()); + final int edgeY = Math.min(0, scrollY + mFirstPositionDistanceGuess) + translateY; + canvas.translate(translateX, edgeY); + mEdgeGlowTop.setSize(width, height); if (mEdgeGlowTop.draw(canvas)) { - invalidate(0, 0, getWidth(), - mEdgeGlowTop.getMaxHeight() + getPaddingTop()); + invalidateTopGlow(); } canvas.restoreToCount(restoreCount); } if (!mEdgeGlowBottom.isFinished()) { final int restoreCount = canvas.save(); - final int width = getWidth(); - final int height = getHeight(); - - int edgeX = -width; - int edgeY = Math.max(height, scrollY + mLastPositionDistanceGuess); + canvas.clipRect(translateX, translateY + height - mEdgeGlowBottom.getMaxHeight(), + translateX + width, translateY + height); + final int edgeX = -width + translateX; + final int edgeY = Math.max(getHeight(), scrollY + mLastPositionDistanceGuess) + - (clipToPadding ? mPaddingBottom : 0); canvas.translate(edgeX, edgeY); canvas.rotate(180, width, 0); mEdgeGlowBottom.setSize(width, height); if (mEdgeGlowBottom.draw(canvas)) { - invalidate(0, getHeight() - getPaddingBottom() - - mEdgeGlowBottom.getMaxHeight(), getWidth(), - getHeight()); + invalidateBottomGlow(); } canvas.restoreToCount(restoreCount); } } } - /** - * @hide - */ - public void setOverScrollEffectPadding(int leftPadding, int rightPadding) { - mGlowPaddingLeft = leftPadding; - mGlowPaddingRight = rightPadding; - } - private void initOrResetVelocityTracker() { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 56f9b5c..cd110b7 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -125,6 +125,15 @@ public class Editor { // Tag used when the Editor maintains its own separate UndoManager. private static final String UNDO_OWNER_TAG = "Editor"; + // Ordering constants used to place the Action Mode items in their menu. + private static final int MENU_ITEM_ORDER_CUT = 1; + private static final int MENU_ITEM_ORDER_COPY = 2; + private static final int MENU_ITEM_ORDER_PASTE = 3; + private static final int MENU_ITEM_ORDER_SHARE = 4; + private static final int MENU_ITEM_ORDER_SELECT_ALL = 5; + private static final int MENU_ITEM_ORDER_REPLACE = 6; + private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 10; + // Each Editor manages its own undo stack. private final UndoManager mUndoManager = new UndoManager(); private UndoOwner mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this); @@ -134,7 +143,8 @@ public class Editor { // Cursor Controllers. InsertionPointCursorController mInsertionPointCursorController; SelectionModifierCursorController mSelectionModifierCursorController; - ActionMode mSelectionActionMode; + // Action mode used when text is selected or when actions on an insertion cursor are triggered. + ActionMode mTextActionMode; boolean mInsertionControllerEnabled; boolean mSelectionControllerEnabled; @@ -205,13 +215,14 @@ public class Editor { float mLastDownPositionX, mLastDownPositionY; Callback mCustomSelectionActionModeCallback; + Callback mCustomInsertionActionModeCallback; // Set when this TextView gained focus with some text selected. Will start selection mode. boolean mCreatedWithASelection; boolean mDoubleTap = false; - private Runnable mSelectionModeWithoutSelectionRunnable; + private Runnable mInsertionActionModeRunnable; // The span controller helps monitoring the changes to which the Editor needs to react: // - EasyEditSpans, for which we have some UI to display on attach and on hide @@ -236,8 +247,8 @@ public class Editor { private final Runnable mHideFloatingToolbar = new Runnable() { @Override public void run() { - if (mSelectionActionMode != null) { - mSelectionActionMode.snooze(ActionMode.SNOOZE_TIME_DEFAULT); + if (mTextActionMode != null) { + mTextActionMode.hide(ActionMode.DEFAULT_HIDE_DURATION); } } }; @@ -245,8 +256,8 @@ public class Editor { private final Runnable mShowFloatingToolbar = new Runnable() { @Override public void run() { - if (mSelectionActionMode != null) { - mSelectionActionMode.snooze(0); // snooze off. + if (mTextActionMode != null) { + mTextActionMode.hide(0); // hide off. } } }; @@ -310,7 +321,7 @@ public class Editor { void replace() { int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2; - stopSelectionActionMode(); + stopTextActionMode(); Selection.setSelection((Spannable) mTextView.getText(), middle); showSuggestions(); } @@ -343,7 +354,7 @@ public class Editor { mTextView.setHasTransientState(false); // We had an active selection from before, start the selection mode. - startSelectionActionModeWithSelection(); + startSelectionActionMode(); } getPositionListener().addSubscriber(mCursorAnchorInfoNotifier, true); @@ -372,8 +383,8 @@ public class Editor { } // Cancel the single tap delayed runnable. - if (mSelectionModeWithoutSelectionRunnable != null) { - mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable); + if (mInsertionActionModeRunnable != null) { + mTextView.removeCallbacks(mInsertionActionModeRunnable); } mTextView.removeCallbacks(mHideFloatingToolbar); @@ -390,7 +401,7 @@ public class Editor { mPreserveDetachedSelection = true; hideControllers(); - stopSelectionActionMode(); + stopTextActionMode(); mPreserveDetachedSelection = false; mTemporaryDetach = false; } @@ -586,7 +597,7 @@ public class Editor { } if (!mSelectionControllerEnabled) { - stopSelectionActionMode(); + stopTextActionMode(); if (mSelectionModifierCursorController != null) { mSelectionModifierCursorController.onDetached(); mSelectionModifierCursorController = null; @@ -984,14 +995,14 @@ public class Editor { mInsertionControllerEnabled) { final int offset = mTextView.getOffsetForPosition(mLastDownPositionX, mLastDownPositionY); - stopSelectionActionMode(); + stopTextActionMode(); Selection.setSelection((Spannable) mTextView.getText(), offset); getInsertionController().show(); - startSelectionActionModeWithoutSelection(); + startInsertionActionMode(); handled = true; } - if (!handled && mSelectionActionMode != null) { + if (!handled && mTextActionMode != null) { if (touchPositionIsInSelection()) { // Start a drag final int start = mTextView.getSelectionStart(); @@ -1001,9 +1012,9 @@ public class Editor { DragLocalState localState = new DragLocalState(mTextView, start, end); mTextView.startDrag(data, getTextThumbnailBuilder(selectedText), localState, View.DRAG_FLAG_GLOBAL); - stopSelectionActionMode(); + stopTextActionMode(); } else { - stopSelectionActionMode(); + stopTextActionMode(); selectCurrentWordAndStartDrag(); } handled = true; @@ -1101,12 +1112,12 @@ public class Editor { final int selStart = mTextView.getSelectionStart(); final int selEnd = mTextView.getSelectionEnd(); hideControllers(); - stopSelectionActionMode(); + stopTextActionMode(); Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd); } else { if (mTemporaryDetach) mPreserveDetachedSelection = true; hideControllers(); - stopSelectionActionMode(); + stopTextActionMode(); if (mTemporaryDetach) mPreserveDetachedSelection = false; downgradeEasyCorrectionSpans(); } @@ -1149,7 +1160,7 @@ public class Editor { // We do not hide the span controllers, since they can be added when a new text is // inserted into the text view (voice IME). hideCursorControllers(); - stopSelectionActionMode(); + stopTextActionMode(); } private int getLastTapPosition() { @@ -1216,7 +1227,7 @@ public class Editor { } private void updateFloatingToolbarVisibility(MotionEvent event) { - if (mSelectionActionMode != null) { + if (mTextActionMode != null) { switch (event.getActionMasked()) { case MotionEvent.ACTION_MOVE: hideFloatingToolbar(); @@ -1229,7 +1240,7 @@ public class Editor { } private void hideFloatingToolbar() { - if (mSelectionActionMode != null) { + if (mTextActionMode != null) { mTextView.removeCallbacks(mShowFloatingToolbar); // Delay the "hide" a little bit just in case a "show" will happen almost immediately. mTextView.postDelayed(mHideFloatingToolbar, 100); @@ -1237,7 +1248,7 @@ public class Editor { } private void showFloatingToolbar() { - if (mSelectionActionMode != null) { + if (mTextActionMode != null) { mTextView.removeCallbacks(mHideFloatingToolbar); // Delay "show" so it doesn't interfere with click confirmations // or double-clicks that could "dismiss" the floating toolbar. @@ -1701,26 +1712,20 @@ public class Editor { /** * @return true if the selection mode was actually started. */ - private boolean startSelectionActionModeWithoutSelection() { + private boolean startInsertionActionMode() { + if (mInsertionActionModeRunnable != null) { + mTextView.removeCallbacks(mInsertionActionModeRunnable); + } if (extractedTextModeWillBeStarted()) { - // Cancel the single tap delayed runnable. - if (mSelectionModeWithoutSelectionRunnable != null) { - mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable); - } - return false; } + stopTextActionMode(); - if (mSelectionActionMode != null) { - // Selection action mode is already started - // TODO: revisit invocations to minimize this case. - mSelectionActionMode.invalidate(); - return false; - } - ActionMode.Callback actionModeCallback = new SelectionActionModeCallback(); - mSelectionActionMode = mTextView.startActionMode( + ActionMode.Callback actionModeCallback = + new TextActionModeCallback(false /* hasSelection */); + mTextActionMode = mTextView.startActionMode( actionModeCallback, ActionMode.TYPE_FLOATING); - return mSelectionActionMode != null; + return mTextActionMode != null; } /** @@ -1730,8 +1735,8 @@ public class Editor { * * @return true if the selection mode was actually started. */ - boolean startSelectionActionModeWithSelection() { - boolean selectionStarted = startSelectionActionModeWithSelectionInternal(); + boolean startSelectionActionMode() { + boolean selectionStarted = startSelectionActionModeInternal(); if (selectionStarted) { getSelectionController().show(); } else if (getInsertionController() != null) { @@ -1747,19 +1752,24 @@ public class Editor { * @return true if the drag was started. */ private boolean selectCurrentWordAndStartDrag() { + if (mInsertionActionModeRunnable != null) { + mTextView.removeCallbacks(mInsertionActionModeRunnable); + } if (extractedTextModeWillBeStarted()) { - // Cancel the single tap delayed runnable. - if (mSelectionModeWithoutSelectionRunnable != null) { - mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable); - } return false; } - if (mSelectionActionMode != null) { - mSelectionActionMode.finish(); + if (mTextActionMode != null) { + mTextActionMode.finish(); } if (!checkFieldAndSelectCurrentWord()) { return false; } + + // Avoid dismissing the selection if it exists. + mPreserveDetachedSelection = true; + stopTextActionMode(); + mPreserveDetachedSelection = false; + getSelectionController().enterDrag(); return true; } @@ -1784,10 +1794,10 @@ public class Editor { return true; } - private boolean startSelectionActionModeWithSelectionInternal() { - if (mSelectionActionMode != null) { + private boolean startSelectionActionModeInternal() { + if (mTextActionMode != null) { // Selection action mode is already started - mSelectionActionMode.invalidate(); + mTextActionMode.invalidate(); return false; } @@ -1800,12 +1810,13 @@ public class Editor { // Do not start the action mode when extracted text will show up full screen, which would // immediately hide the newly created action bar and would be visually distracting. if (!willExtract) { - ActionMode.Callback actionModeCallback = new SelectionActionModeCallback(); - mSelectionActionMode = mTextView.startActionMode( + ActionMode.Callback actionModeCallback = + new TextActionModeCallback(true /* hasSelection */); + mTextActionMode = mTextView.startActionMode( actionModeCallback, ActionMode.TYPE_FLOATING); } - final boolean selectionStarted = mSelectionActionMode != null || willExtract; + final boolean selectionStarted = mTextActionMode != null || willExtract; if (selectionStarted && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) { // Show the IME to be able to replace text, except when selecting non editable text. final InputMethodManager imm = InputMethodManager.peekInstance(); @@ -1906,7 +1917,7 @@ public class Editor { void onTouchUpEvent(MotionEvent event) { boolean selectAllGotFocus = mSelectAllOnFocus && mTextView.didTouchFocusSelect(); hideControllers(); - stopSelectionActionMode(); + stopTextActionMode(); CharSequence text = mTextView.getText(); if (!selectAllGotFocus && text.length() > 0) { // Move cursor @@ -1920,8 +1931,8 @@ public class Editor { if (!extractedTextModeWillBeStarted()) { if (isCursorInsideEasyCorrectionSpan()) { // Cancel the single tap delayed runnable. - if (mSelectionModeWithoutSelectionRunnable != null) { - mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable); + if (mInsertionActionModeRunnable != null) { + mTextView.removeCallbacks(mInsertionActionModeRunnable); } mShowSuggestionRunnable = new Runnable() { @@ -1939,10 +1950,10 @@ public class Editor { } } - protected void stopSelectionActionMode() { - if (mSelectionActionMode != null) { + protected void stopTextActionMode() { + if (mTextActionMode != null) { // This will hide the mSelectionModifierCursorController - mSelectionActionMode.finish(); + mTextActionMode.finish(); } } @@ -2027,7 +2038,7 @@ public class Editor { mSuggestionsPopupWindow = new SuggestionsPopupWindow(); } hideControllers(); - stopSelectionActionMode(); + stopTextActionMode(); mSuggestionsPopupWindow.show(); } @@ -2035,8 +2046,8 @@ public class Editor { if (mPositionListener != null) { mPositionListener.onScrollChanged(); } - if (mSelectionActionMode != null) { - mSelectionActionMode.invalidateContentRect(); + if (mTextActionMode != null) { + mTextActionMode.invalidateContentRect(); } } @@ -3087,46 +3098,54 @@ public class Editor { } /** - * An ActionMode Callback class that is used to provide actions while in text selection mode. + * An ActionMode Callback class that is used to provide actions while in text insertion or + * selection mode. * - * The default callback provides a subset of Select All, Cut, Copy and Paste actions, depending - * on which of these this TextView supports. + * The default callback provides a subset of Select All, Cut, Copy, Paste, Share and Replace + * actions, depending on which of these this TextView supports and the current selection. */ - private class SelectionActionModeCallback extends ActionMode.Callback2 { + private class TextActionModeCallback extends ActionMode.Callback2 { private final Path mSelectionPath = new Path(); private final RectF mSelectionBounds = new RectF(); - - private int mSelectionHandleHeight; - private int mInsertionHandleHeight; - - public SelectionActionModeCallback() { - SelectionModifierCursorController selectionController = getSelectionController(); - if (selectionController.mStartHandle == null) { - // As these are for initializing selectionController, hide() must be called. - selectionController.initDrawables(); - selectionController.initHandles(); - selectionController.hide(); - } - mSelectionHandleHeight = Math.max( - mSelectHandleLeft.getMinimumHeight(), mSelectHandleRight.getMinimumHeight()); - InsertionPointCursorController insertionController = getInsertionController(); - if (insertionController != null) { - insertionController.getHandle(); - mInsertionHandleHeight = mSelectHandleCenter.getMinimumHeight(); + private final boolean mHasSelection; + + private int mHandleHeight; + + public TextActionModeCallback(boolean hasSelection) { + mHasSelection = hasSelection; + if (mHasSelection) { + SelectionModifierCursorController selectionController = getSelectionController(); + if (selectionController.mStartHandle == null) { + // As these are for initializing selectionController, hide() must be called. + selectionController.initDrawables(); + selectionController.initHandles(); + selectionController.hide(); + } + mHandleHeight = Math.max( + mSelectHandleLeft.getMinimumHeight(), + mSelectHandleRight.getMinimumHeight()); + } else { + InsertionPointCursorController insertionController = getInsertionController(); + if (insertionController != null) { + insertionController.getHandle(); + mHandleHeight = mSelectHandleCenter.getMinimumHeight(); + } } } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { - mode.setTitle(mTextView.getContext().getString( - com.android.internal.R.string.textSelectionCABTitle)); + mode.setTitle(null); mode.setSubtitle(null); mode.setTitleOptionalHint(true); populateMenuWithItems(menu); - if (mCustomSelectionActionModeCallback != null) { - if (!mCustomSelectionActionModeCallback.onCreateActionMode(mode, menu)) { - // The custom mode can choose to cancel the action mode + Callback customCallback = getCustomCallback(); + if (customCallback != null) { + if (!customCallback.onCreateActionMode(mode, menu)) { + // The custom mode can choose to cancel the action mode, dismiss selection. + Selection.setSelection((Spannable) mTextView.getText(), + mTextView.getSelectionEnd()); return false; } } @@ -3141,36 +3160,41 @@ public class Editor { } } + private Callback getCustomCallback() { + return mHasSelection + ? mCustomSelectionActionModeCallback + : mCustomInsertionActionModeCallback; + } + private void populateMenuWithItems(Menu menu) { if (mTextView.canCut()) { - menu.add(0, TextView.ID_CUT, 0, com.android.internal.R.string.cut). + menu.add(Menu.NONE, TextView.ID_CUT, MENU_ITEM_ORDER_CUT, + com.android.internal.R.string.cut). setAlphabeticShortcut('x'). setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } if (mTextView.canCopy()) { - menu.add(0, TextView.ID_COPY, 0, com.android.internal.R.string.copy). + menu.add(Menu.NONE, TextView.ID_COPY, MENU_ITEM_ORDER_COPY, + com.android.internal.R.string.copy). setAlphabeticShortcut('c'). setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } if (mTextView.canPaste()) { - menu.add(0, TextView.ID_PASTE, 0, com.android.internal.R.string.paste). - setAlphabeticShortcut('v'). - setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + menu.add(Menu.NONE, TextView.ID_PASTE, MENU_ITEM_ORDER_PASTE, + com.android.internal.R.string.paste). + setAlphabeticShortcut('v'). + setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } if (mTextView.canShare()) { - menu.add(0, TextView.ID_SHARE, 0, com.android.internal.R.string.share). - setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - } - - if (mTextView.canSelectAllText()) { - menu.add(0, TextView.ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll). - setAlphabeticShortcut('a'). - setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + menu.add(Menu.NONE, TextView.ID_SHARE, MENU_ITEM_ORDER_SHARE, + com.android.internal.R.string.share). + setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } + updateSelectAllItem(menu); updateReplaceItem(menu); } @@ -3179,8 +3203,11 @@ public class Editor { PackageManager packageManager = mTextView.getContext().getPackageManager(); List<ResolveInfo> supportedActivities = packageManager.queryIntentActivities(createProcessTextIntent(), 0); - for (ResolveInfo info : supportedActivities) { - menu.add(info.loadLabel(packageManager)) + for (int i = 0; i < supportedActivities.size(); ++i) { + ResolveInfo info = supportedActivities.get(i); + menu.add(Menu.NONE, Menu.NONE, + MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i, + info.loadLabel(packageManager)) .setIntent(createProcessTextIntentForResolveInfo(info)) .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } @@ -3201,20 +3228,35 @@ public class Editor { @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + updateSelectAllItem(menu); updateReplaceItem(menu); - if (mCustomSelectionActionModeCallback != null) { - return mCustomSelectionActionModeCallback.onPrepareActionMode(mode, menu); + Callback customCallback = getCustomCallback(); + if (customCallback != null) { + return customCallback.onPrepareActionMode(mode, menu); } return true; } + private void updateSelectAllItem(Menu menu) { + boolean canSelectAll = mTextView.canSelectAllText(); + boolean selectAllItemExists = menu.findItem(TextView.ID_SELECT_ALL) != null; + if (canSelectAll && !selectAllItemExists) { + menu.add(Menu.NONE, TextView.ID_SELECT_ALL, MENU_ITEM_ORDER_SELECT_ALL, + com.android.internal.R.string.selectAll) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + } else if (!canSelectAll && selectAllItemExists) { + menu.removeItem(TextView.ID_SELECT_ALL); + } + } + private void updateReplaceItem(Menu menu) { boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions(); boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null; if (canReplace && !replaceItemExists) { - menu.add(0, TextView.ID_REPLACE, 0, com.android.internal.R.string.replace). - setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + menu.add(Menu.NONE, TextView.ID_REPLACE, MENU_ITEM_ORDER_REPLACE, + com.android.internal.R.string.replace) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } else if (!canReplace && replaceItemExists) { menu.removeItem(TextView.ID_REPLACE); } @@ -3230,8 +3272,8 @@ public class Editor { item.getIntent(), TextView.PROCESS_TEXT_REQUEST_CODE); return true; } - if (mCustomSelectionActionModeCallback != null && - mCustomSelectionActionModeCallback.onActionItemClicked(mode, item)) { + Callback customCallback = getCustomCallback(); + if (customCallback != null && customCallback.onActionItemClicked(mode, item)) { return true; } return mTextView.onTextContextMenuItem(item.getItemId()); @@ -3239,8 +3281,9 @@ public class Editor { @Override public void onDestroyActionMode(ActionMode mode) { - if (mCustomSelectionActionModeCallback != null) { - mCustomSelectionActionModeCallback.onDestroyActionMode(mode); + Callback customCallback = getCustomCallback(); + if (customCallback != null) { + customCallback.onDestroyActionMode(mode); } /* @@ -3259,7 +3302,7 @@ public class Editor { mSelectionModifierCursorController.resetTouchOffsets(); } - mSelectionActionMode = null; + mTextActionMode = null; } @Override @@ -3274,7 +3317,7 @@ public class Editor { mTextView.getLayout().getSelectionPath( mTextView.getSelectionStart(), mTextView.getSelectionEnd(), mSelectionPath); mSelectionPath.computeBounds(mSelectionBounds, true); - mSelectionBounds.bottom += mSelectionHandleHeight; + mSelectionBounds.bottom += mHandleHeight; } else if (mCursorCount == 2) { // We have a split cursor. In this case, we take the rectangle that includes both // parts of the cursor to ensure we don't obscure either of them. @@ -3285,7 +3328,7 @@ public class Editor { Math.min(firstCursorBounds.top, secondCursorBounds.top), Math.max(firstCursorBounds.right, secondCursorBounds.right), Math.max(firstCursorBounds.bottom, secondCursorBounds.bottom) - + mInsertionHandleHeight); + + mHandleHeight); } else { // We have a single cursor. int line = mTextView.getLayout().getLineForOffset(mTextView.getSelectionStart()); @@ -3295,7 +3338,7 @@ public class Editor { primaryHorizontal, mTextView.getLayout().getLineTop(line), primaryHorizontal + 1, - mTextView.getLayout().getLineTop(line + 1) + mInsertionHandleHeight); + mTextView.getLayout().getLineTop(line + 1) + mHandleHeight); } // Take TextView's padding and scroll into account. int textHorizontalOffset = mTextView.viewportToContentHorizontalOffset(); @@ -3847,25 +3890,25 @@ public class Editor { SystemClock.uptimeMillis() - TextView.sLastCutCopyOrTextChangedTime; // Cancel the single tap delayed runnable. - if (mSelectionModeWithoutSelectionRunnable != null + if (mInsertionActionModeRunnable != null && (mDoubleTap || isCursorInsideEasyCorrectionSpan())) { - mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable); + mTextView.removeCallbacks(mInsertionActionModeRunnable); } // Prepare and schedule the single tap runnable to run exactly after the double tap // timeout has passed. if (!mDoubleTap && !isCursorInsideEasyCorrectionSpan() && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) { - if (mSelectionModeWithoutSelectionRunnable == null) { - mSelectionModeWithoutSelectionRunnable = new Runnable() { + if (mInsertionActionModeRunnable == null) { + mInsertionActionModeRunnable = new Runnable() { public void run() { - startSelectionActionModeWithoutSelection(); + startInsertionActionMode(); } }; } mTextView.postDelayed( - mSelectionModeWithoutSelectionRunnable, + mInsertionActionModeRunnable, ViewConfiguration.getDoubleTapTimeout() + 1); } @@ -3934,15 +3977,15 @@ public class Editor { if (distanceSquared < touchSlop * touchSlop) { // Tapping on the handle toggles the selection action mode. - if (mSelectionActionMode != null) { - mSelectionActionMode.finish(); + if (mTextActionMode != null) { + mTextActionMode.finish(); } else { - startSelectionActionModeWithoutSelection(); + startInsertionActionMode(); } } } else { - if (mSelectionActionMode != null) { - mSelectionActionMode.invalidateContentRect(); + if (mTextActionMode != null) { + mTextActionMode.invalidateContentRect(); } } hideAfterDelay(); @@ -3972,8 +4015,8 @@ public class Editor { @Override public void updatePosition(float x, float y) { positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false); - if (mSelectionActionMode != null) { - mSelectionActionMode.invalidate(); + if (mTextActionMode != null) { + mTextActionMode.invalidate(); } } @@ -4024,8 +4067,8 @@ public class Editor { Selection.setSelection((Spannable) mTextView.getText(), offset, mTextView.getSelectionEnd()); updateDrawable(); - if (mSelectionActionMode != null) { - mSelectionActionMode.invalidate(); + if (mTextActionMode != null) { + mTextActionMode.invalidate(); } } @@ -4150,8 +4193,8 @@ public class Editor { public void updateSelection(int offset) { Selection.setSelection((Spannable) mTextView.getText(), mTextView.getSelectionStart(), offset); - if (mSelectionActionMode != null) { - mSelectionActionMode.invalidate(); + if (mTextActionMode != null) { + mTextActionMode.invalidate(); } updateDrawable(); } @@ -4515,7 +4558,7 @@ public class Editor { mEndHandle.showAtLocation(endOffset); // No longer the first dragging motion, reset. - startSelectionActionModeWithSelection(); + startSelectionActionMode(); mDragAcceleratorActive = false; mStartOffset = -1; } diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 73a873a..6b28f89 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -1088,8 +1088,8 @@ public class ImageView extends View { } else if (ScaleType.CENTER == mScaleType) { // Center bitmap in view, no scaling. mDrawMatrix = mMatrix; - mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f), - (int) ((vheight - dheight) * 0.5f + 0.5f)); + mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f), + Math.round((vheight - dheight) * 0.5f)); } else if (ScaleType.CENTER_CROP == mScaleType) { mDrawMatrix = mMatrix; @@ -1105,7 +1105,7 @@ public class ImageView extends View { } mDrawMatrix.setScale(scale, scale); - mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f)); + mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy)); } else if (ScaleType.CENTER_INSIDE == mScaleType) { mDrawMatrix = mMatrix; float scale; @@ -1119,8 +1119,8 @@ public class ImageView extends View { (float) vheight / (float) dheight); } - dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f); - dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f); + dx = Math.round((vwidth - dwidth * scale) * 0.5f); + dy = Math.round((vheight - dheight * scale) * 0.5f); mDrawMatrix.setScale(scale, scale); mDrawMatrix.postTranslate(dx, dy); diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java index f153ce5..9d14254 100644 --- a/core/java/android/widget/LinearLayout.java +++ b/core/java/android/widget/LinearLayout.java @@ -185,6 +185,8 @@ public class LinearLayout extends ViewGroup { private int mShowDividers; private int mDividerPadding; + private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED; + public LinearLayout(Context context) { this(context, null); } @@ -1567,6 +1569,17 @@ public class LinearLayout extends ViewGroup { } } + @Override + public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { + super.onRtlPropertiesChanged(layoutDirection); + if (layoutDirection != mLayoutDirection) { + mLayoutDirection = layoutDirection; + if (mOrientation == HORIZONTAL) { + requestLayout(); + } + } + } + /** * Position the children during a layout pass if the orientation of this * LinearLayout is set to {@link #HORIZONTAL}. diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java index 97348e30..ff2f22b 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -28,13 +28,15 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; -import com.android.internal.policy.PhoneWindow; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import android.widget.SeekBar.OnSeekBarChangeListener; +import com.android.internal.policy.PhoneWindow; + import java.util.Formatter; import java.util.Locale; @@ -44,7 +46,7 @@ import java.util.Locale; * slider. It takes care of synchronizing the controls with the state * of the MediaPlayer. * <p> - * The way to use this class is to instantiate it programatically. + * The way to use this class is to instantiate it programmatically. * The MediaController will create a default set of controls * and put them in a window floating above your application. Specifically, * the controls will float above the view specified with setAnchorView(). @@ -69,7 +71,7 @@ import java.util.Locale; public class MediaController extends FrameLayout { private MediaPlayerControl mPlayer; - private Context mContext; + private final Context mContext; private View mAnchor; private View mRoot; private WindowManager mWindowManager; @@ -83,7 +85,7 @@ public class MediaController extends FrameLayout { private static final int sDefaultTimeout = 3000; private static final int FADE_OUT = 1; private static final int SHOW_PROGRESS = 2; - private boolean mUseFastForward; + private final boolean mUseFastForward; private boolean mFromXml; private boolean mListenersSet; private View.OnClickListener mNextListener, mPrevListener; @@ -96,6 +98,7 @@ public class MediaController extends FrameLayout { private ImageButton mPrevButton; private CharSequence mPlayDescription; private CharSequence mPauseDescription; + private final AccessibilityManager mAccessibilityManager; public MediaController(Context context, AttributeSet attrs) { super(context, attrs); @@ -103,6 +106,7 @@ public class MediaController extends FrameLayout { mContext = context; mUseFastForward = true; mFromXml = true; + mAccessibilityManager = AccessibilityManager.getInstance(context); } @Override @@ -117,6 +121,7 @@ public class MediaController extends FrameLayout { mUseFastForward = useFastForward; initFloatingWindowLayout(); initFloatingWindow(); + mAccessibilityManager = AccessibilityManager.getInstance(context); } public MediaController(Context context) { @@ -179,8 +184,9 @@ public class MediaController extends FrameLayout { } // This is called whenever mAnchor's layout bound changes - private OnLayoutChangeListener mLayoutChangeListener = + private final OnLayoutChangeListener mLayoutChangeListener = new OnLayoutChangeListener() { + @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { @@ -191,7 +197,8 @@ public class MediaController extends FrameLayout { } }; - private OnTouchListener mTouchListener = new OnTouchListener() { + private final OnTouchListener mTouchListener = new OnTouchListener() { + @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (mShowing) { @@ -368,9 +375,9 @@ public class MediaController extends FrameLayout { // paused with the progress bar showing the user hits play. mHandler.sendEmptyMessage(SHOW_PROGRESS); - Message msg = mHandler.obtainMessage(FADE_OUT); - if (timeout != 0) { + if (timeout != 0 && !mAccessibilityManager.isTouchExplorationEnabled()) { mHandler.removeMessages(FADE_OUT); + Message msg = mHandler.obtainMessage(FADE_OUT); mHandler.sendMessageDelayed(msg, timeout); } } @@ -397,7 +404,7 @@ public class MediaController extends FrameLayout { } } - private Handler mHandler = new Handler() { + private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { int pos; @@ -527,7 +534,8 @@ public class MediaController extends FrameLayout { return super.dispatchKeyEvent(event); } - private View.OnClickListener mPauseListener = new View.OnClickListener() { + private final View.OnClickListener mPauseListener = new View.OnClickListener() { + @Override public void onClick(View v) { doPauseResume(); show(sDefaultTimeout); @@ -567,7 +575,8 @@ public class MediaController extends FrameLayout { // The second scenario involves the user operating the scroll ball, in this // case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications, // we will simply apply the updated position without suspending regular updates. - private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { + private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { + @Override public void onStartTrackingTouch(SeekBar bar) { show(3600000); @@ -581,6 +590,7 @@ public class MediaController extends FrameLayout { mHandler.removeMessages(SHOW_PROGRESS); } + @Override public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) { if (!fromuser) { // We're not interested in programmatically generated changes to @@ -595,6 +605,7 @@ public class MediaController extends FrameLayout { mCurrentTime.setText(stringForTime( (int) newposition)); } + @Override public void onStopTrackingTouch(SeekBar bar) { mDragging = false; setProgress(); @@ -637,7 +648,8 @@ public class MediaController extends FrameLayout { return MediaController.class.getName(); } - private View.OnClickListener mRewListener = new View.OnClickListener() { + private final View.OnClickListener mRewListener = new View.OnClickListener() { + @Override public void onClick(View v) { int pos = mPlayer.getCurrentPosition(); pos -= 5000; // milliseconds @@ -648,7 +660,8 @@ public class MediaController extends FrameLayout { } }; - private View.OnClickListener mFfwdListener = new View.OnClickListener() { + private final View.OnClickListener mFfwdListener = new View.OnClickListener() { + @Override public void onClick(View v) { int pos = mPlayer.getCurrentPosition(); pos += 15000; // milliseconds diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index ca57d1a..11904e1 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -18,6 +18,7 @@ package android.widget; import android.annotation.NonNull; import android.os.Build; +import android.os.Build.VERSION_CODES; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.R; @@ -349,17 +350,24 @@ public class ScrollView extends FrameLayout { if (getChildCount() > 0) { final View child = getChildAt(0); - int height = getMeasuredHeight(); + final int height = getMeasuredHeight(); if (child.getMeasuredHeight() < height) { + final int widthPadding; + final int heightPadding; final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams(); + final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; + if (targetSdkVersion >= VERSION_CODES.MNC) { + widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin; + heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin; + } else { + widthPadding = mPaddingLeft + mPaddingRight; + heightPadding = mPaddingTop + mPaddingBottom; + } - int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, - mPaddingLeft + mPaddingRight, lp.width); - height -= mPaddingTop; - height -= mPaddingBottom; - int childHeightMeasureSpec = - MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); - + final int childWidthMeasureSpec = getChildMeasureSpec( + widthMeasureSpec, widthPadding, lp.width); + final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( + height - heightPadding, MeasureSpec.EXACTLY); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3a85476..b68934b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1481,7 +1481,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } if (mEditor.hasSelectionController()) { - mEditor.startSelectionActionModeWithSelection(); + mEditor.startSelectionActionMode(); } } } @@ -5282,7 +5282,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // - onFocusChanged cannot start it when focus is given to a view with selected text (after // a screen rotation) since layout is not yet initialized at that point. if (mEditor != null && mEditor.mCreatedWithASelection) { - mEditor.startSelectionActionModeWithSelection(); + mEditor.startSelectionActionMode(); mEditor.mCreatedWithASelection = false; } @@ -5290,7 +5290,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // ExtractEditText does not call onFocus when it is displayed, and mHasSelectionOnFocus can // not be set. Do the test here instead. if (this instanceof ExtractEditText && hasSelection() && mEditor != null) { - mEditor.startSelectionActionModeWithSelection(); + mEditor.startSelectionActionMode(); } unregisterForPreDraw(); @@ -5908,7 +5908,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public boolean onKeyPreIme(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - boolean isInSelectionMode = mEditor != null && mEditor.mSelectionActionMode != null; + boolean isInSelectionMode = mEditor != null && mEditor.mTextActionMode != null; if (isInSelectionMode) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { @@ -5923,7 +5923,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener state.handleUpEvent(event); } if (event.isTracking() && !event.isCanceled()) { - stopSelectionActionMode(); + stopTextActionMode(); return true; } } @@ -6092,8 +6092,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Has to be done on key down (and not on key up) to correctly be intercepted. case KeyEvent.KEYCODE_BACK: - if (mEditor != null && mEditor.mSelectionActionMode != null) { - stopSelectionActionMode(); + if (mEditor != null && mEditor.mTextActionMode != null) { + stopTextActionMode(); return -1; } break; @@ -6423,7 +6423,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // extracted mode will start. Some text is selected though, and will trigger an action mode // in the extracted view. mEditor.hideControllers(); - stopSelectionActionMode(); + stopTextActionMode(); } /** @@ -8258,7 +8258,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener super.onVisibilityChanged(changedView, visibility); if (mEditor != null && visibility != VISIBLE) { mEditor.hideControllers(); - stopSelectionActionMode(); + stopTextActionMode(); } } @@ -8976,7 +8976,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener Selection.setSelection((Spannable) text, start, end); // Make sure selection mode is engaged. if (mEditor != null) { - mEditor.startSelectionActionModeWithSelection(); + mEditor.startSelectionActionMode(); } return true; } @@ -9072,9 +9072,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener switch (id) { case ID_SELECT_ALL: - // This does not enter text selection mode. Text is highlighted, so that it can be - // bulk edited, like selectAllOnFocus does. Returns true even if text is empty. + // This starts an action mode if triggered from another action mode. Text is + // highlighted, so that it can be bulk edited, like selectAllOnFocus does. Returns + // true even if text is empty. + boolean shouldRestartActionMode = + mEditor != null && mEditor.mTextActionMode != null; + stopTextActionMode(); selectAllText(); + if (shouldRestartActionMode) { + mEditor.startSelectionActionMode(); + } return true; case ID_UNDO: @@ -9100,12 +9107,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case ID_CUT: setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max))); deleteText_internal(min, max); - stopSelectionActionMode(); + stopTextActionMode(); return true; case ID_COPY: setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max))); - stopSelectionActionMode(); + stopTextActionMode(); return true; case ID_REPLACE: @@ -9195,14 +9202,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * selection is initiated in this View. * * The standard implementation populates the menu with a subset of Select All, Cut, Copy, - * Paste and Share actions, depending on what this View supports. + * Paste, Replace and Share actions, depending on what this View supports. * * A custom implementation can add new entries in the default menu in its * {@link android.view.ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The * default actions can also be removed from the menu using * {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll}, - * {@link android.R.id#cut}, {@link android.R.id#copy}, {@link android.R.id#paste} or - * {@link android.R.id#shareText} ids as parameters. + * {@link android.R.id#cut}, {@link android.R.id#copy}, {@link android.R.id#paste}, + * {@link android.R.id#replaceText} or {@link android.R.id#shareText} ids as parameters. * * Returning false from * {@link android.view.ActionMode.Callback#onCreateActionMode(ActionMode, Menu)} will prevent @@ -9230,11 +9237,48 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * If provided, this ActionMode.Callback will be used to create the ActionMode when text + * insertion is initiated in this View. + * + * The standard implementation populates the menu with a subset of Select All, + * Paste and Replace actions, depending on what this View supports. + * + * A custom implementation can add new entries in the default menu in its + * {@link android.view.ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The + * default actions can also be removed from the menu using + * {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll}, + * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters. + * + * Returning false from + * {@link android.view.ActionMode.Callback#onCreateActionMode(ActionMode, Menu)} will prevent + * the action mode from being started. + * + * Action click events should be handled by the custom implementation of + * {@link android.view.ActionMode.Callback#onActionItemClicked(ActionMode, MenuItem)}. + * + * Note that text insertion mode is not started when a TextView receives focus and the + * {@link android.R.attr#selectAllOnFocus} flag has been set. + */ + public void setCustomInsertionActionModeCallback(ActionMode.Callback actionModeCallback) { + createEditorIfNeeded(); + mEditor.mCustomInsertionActionModeCallback = actionModeCallback; + } + + /** + * Retrieves the value set in {@link #setCustomInsertionActionModeCallback}. Default is null. + * + * @return The current custom insertion callback. + */ + public ActionMode.Callback getCustomInsertionActionModeCallback() { + return mEditor == null ? null : mEditor.mCustomInsertionActionModeCallback; + } + + /** * @hide */ - protected void stopSelectionActionMode() { + protected void stopTextActionMode() { if (mEditor != null) { - mEditor.stopSelectionActionMode(); + mEditor.stopTextActionMode(); } } @@ -9298,7 +9342,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } boolean canSelectAllText() { - return canSelectText() && !hasPasswordTransformationMethod(); + return canSelectText() && !hasPasswordTransformationMethod() + && !(getSelectionStart() == 0 && getSelectionEnd() == mText.length()); } boolean selectAllText() { @@ -9346,7 +9391,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } } - stopSelectionActionMode(); + stopTextActionMode(); sLastCutCopyOrTextChangedTime = 0; } } @@ -9359,7 +9404,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener sharingIntent.removeExtra(android.content.Intent.EXTRA_TEXT); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, selectedText); getContext().startActivity(Intent.createChooser(sharingIntent, null)); - stopSelectionActionMode(); + stopTextActionMode(); } } diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index 644adb6..a2bd700 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -97,6 +97,11 @@ interface IVoiceInteractionManagerService { void showSessionForActiveService(IVoiceInteractionSessionShowCallback showCallback); /** + * Hides the session from the active service, if it is showing. + */ + void hideCurrentSession(); + + /** * Notifies the active service that a launch was requested from the Keyguard. This will only * be called if {@link #activeServiceSupportsLaunchFromKeyguard()} returns true. */ diff --git a/core/java/com/android/internal/app/IVoiceInteractor.aidl b/core/java/com/android/internal/app/IVoiceInteractor.aidl index 84e9cf0..44feafb 100644 --- a/core/java/com/android/internal/app/IVoiceInteractor.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractor.aidl @@ -27,14 +27,14 @@ import com.android.internal.app.IVoiceInteractorRequest; */ interface IVoiceInteractor { IVoiceInteractorRequest startConfirmation(String callingPackage, - IVoiceInteractorCallback callback, CharSequence prompt, in Bundle extras); + IVoiceInteractorCallback callback, in VoiceInteractor.Prompt prompt, in Bundle extras); IVoiceInteractorRequest startPickOption(String callingPackage, - IVoiceInteractorCallback callback, CharSequence prompt, + IVoiceInteractorCallback callback, in VoiceInteractor.Prompt prompt, in VoiceInteractor.PickOptionRequest.Option[] options, in Bundle extras); IVoiceInteractorRequest startCompleteVoice(String callingPackage, - IVoiceInteractorCallback callback, CharSequence message, in Bundle extras); + IVoiceInteractorCallback callback, in VoiceInteractor.Prompt prompt, in Bundle extras); IVoiceInteractorRequest startAbortVoice(String callingPackage, - IVoiceInteractorCallback callback, CharSequence message, in Bundle extras); + IVoiceInteractorCallback callback, in VoiceInteractor.Prompt prompt, in Bundle extras); IVoiceInteractorRequest startCommand(String callingPackage, IVoiceInteractorCallback callback, String command, in Bundle extras); boolean[] supportsCommands(String callingPackage, in String[] commands); diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 230d96d..2f21efd 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -27,6 +27,7 @@ import android.view.View; */ public class MetricsLogger implements MetricsConstants { // Temporary constants go here, to await migration to MetricsConstants. + public static final int ACTION_EMERGENCY_CALL = 200; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index 056b0aa..049d3eb 100644 --- a/core/java/com/android/internal/os/BatterySipper.java +++ b/core/java/com/android/internal/os/BatterySipper.java @@ -42,6 +42,8 @@ public class BatterySipper implements Comparable<BatterySipper> { public long wifiRunningTimeMs; public long cpuFgTimeMs; public long wakeLockTimeMs; + public long cameraTimeMs; + public long flashlightTimeMs; public long mobileRxPackets; public long mobileTxPackets; @@ -67,6 +69,8 @@ public class BatterySipper implements Comparable<BatterySipper> { public double mobileRadioPowerMah; public double gpsPowerMah; public double sensorPowerMah; + public double cameraPowerMah; + public double flashlightPowerMah; public enum DrainType { IDLE, @@ -79,7 +83,8 @@ public class BatterySipper implements Comparable<BatterySipper> { APP, USER, UNACCOUNTED, - OVERCOUNTED + OVERCOUNTED, + CAMERA } public BatterySipper(DrainType drainType, Uid uid, double value) { @@ -135,6 +140,8 @@ public class BatterySipper implements Comparable<BatterySipper> { wifiRunningTimeMs += other.wifiRunningTimeMs; cpuFgTimeMs += other.cpuFgTimeMs; wakeLockTimeMs += other.wakeLockTimeMs; + cameraTimeMs += other.cameraTimeMs; + flashlightTimeMs += other.flashlightTimeMs; mobileRxPackets += other.mobileRxPackets; mobileTxPackets += other.mobileTxPackets; mobileActive += other.mobileActive; @@ -151,6 +158,8 @@ public class BatterySipper implements Comparable<BatterySipper> { sensorPowerMah += other.sensorPowerMah; mobileRadioPowerMah += other.mobileRadioPowerMah; wakeLockPowerMah += other.wakeLockPowerMah; + cameraPowerMah += other.cameraPowerMah; + flashlightPowerMah += other.flashlightPowerMah; } /** @@ -158,7 +167,8 @@ public class BatterySipper implements Comparable<BatterySipper> { * @return the sum of all the power in this BatterySipper. */ public double sumPower() { - return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + sensorPowerMah - + mobileRadioPowerMah + wakeLockPowerMah; + return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + + sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah + + flashlightPowerMah; } } diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index fbe87c5..4290e22 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -122,6 +122,8 @@ public final class BatteryStatsHelper { PowerCalculator mWifiPowerCalculator; PowerCalculator mBluetoothPowerCalculator; PowerCalculator mSensorPowerCalculator; + PowerCalculator mCameraPowerCalculator; + PowerCalculator mFlashlightPowerCalculator; public static boolean checkWifiOnly(Context context) { ConnectivityManager cm = (ConnectivityManager)context.getSystemService( @@ -352,9 +354,9 @@ public final class BatteryStatsHelper { if (mBluetoothPowerCalculator == null) { if (checkHasBluetoothPowerReporting(mStats, mPowerProfile)) { - mBluetoothPowerCalculator = new BluetoothPowerCalculator(); + mBluetoothPowerCalculator = new BluetoothPowerCalculator(mPowerProfile); } else { - mBluetoothPowerCalculator = new BluetoothPowerCalculator(); + mBluetoothPowerCalculator = new BluetoothPowerCalculator(mPowerProfile); } } mBluetoothPowerCalculator.reset(); @@ -365,6 +367,16 @@ public final class BatteryStatsHelper { } mSensorPowerCalculator.reset(); + if (mCameraPowerCalculator == null) { + mCameraPowerCalculator = new CameraPowerCalculator(mPowerProfile); + } + mCameraPowerCalculator.reset(); + + if (mFlashlightPowerCalculator == null) { + mFlashlightPowerCalculator = new FlashlightPowerCalculator(mPowerProfile); + } + mFlashlightPowerCalculator.reset(); + mStatsType = statsType; mRawUptime = rawUptimeUs; mRawRealtime = rawRealtimeUs; @@ -480,6 +492,8 @@ public final class BatteryStatsHelper { mWifiPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); mSensorPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); + mCameraPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); + mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType); final double totalPower = app.sumPower(); if (DEBUG && totalPower != 0) { @@ -619,15 +633,6 @@ public final class BatteryStatsHelper { } } - private void addFlashlightUsage() { - long flashlightOnTimeMs = mStats.getFlashlightOnTime(mRawRealtime, mStatsType) / 1000; - double flashlightPower = flashlightOnTimeMs - * mPowerProfile.getAveragePower(PowerProfile.POWER_FLASHLIGHT) / (60*60*1000); - if (flashlightPower != 0) { - addEntry(BatterySipper.DrainType.FLASHLIGHT, flashlightOnTimeMs, flashlightPower); - } - } - private void addUserUsage() { for (int i = 0; i < mUserSippers.size(); i++) { final int userId = mUserSippers.keyAt(i); @@ -643,7 +648,6 @@ public final class BatteryStatsHelper { addUserUsage(); addPhoneUsage(); addScreenUsage(); - addFlashlightUsage(); addWiFiUsage(); addBluetoothUsage(); addIdleUsage(); // Not including cellular idle power diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 62745d4..087db78 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -105,7 +105,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 126 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 127 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -272,18 +272,19 @@ public final class BatteryStatsImpl extends BatteryStats { final HistoryStepDetails mCurHistoryStepDetails = new HistoryStepDetails(); final HistoryStepDetails mReadHistoryStepDetails = new HistoryStepDetails(); final HistoryStepDetails mTmpHistoryStepDetails = new HistoryStepDetails(); + /** - * Total time (in 1/100 sec) spent executing in user code. + * Total time (in milliseconds) spent executing in user code. */ long mLastStepCpuUserTime; long mCurStepCpuUserTime; /** - * Total time (in 1/100 sec) spent executing in kernel code. + * Total time (in milliseconds) spent executing in kernel code. */ long mLastStepCpuSystemTime; long mCurStepCpuSystemTime; /** - * Times from /proc/stat + * Times from /proc/stat (but measured in milliseconds). */ long mLastStepStatUserTime; long mLastStepStatSystemTime; @@ -4337,15 +4338,22 @@ public final class BatteryStatsImpl extends BatteryStats { return 0; } - @Override public long getFlashlightOnTime(long elapsedRealtimeUs, int which) { + @Override + public long getFlashlightOnTime(long elapsedRealtimeUs, int which) { return mFlashlightOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which); } - @Override public long getFlashlightOnCount(int which) { + @Override + public long getFlashlightOnCount(int which) { return mFlashlightOnTimer.getCountLocked(which); } @Override + public long getCameraOnTime(long elapsedRealtimeUs, int which) { + return mCameraOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which); + } + + @Override public long getNetworkActivityBytes(int type, int which) { if (type >= 0 && type < mNetworkByteActivityCounters.length) { return mNetworkByteActivityCounters[type].getCountLocked(which); @@ -7806,11 +7814,13 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( info.getControllerIdleTimeMillis()); - final double opVoltage = mPowerProfile.getAveragePower( - PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE); - if (opVoltage != 0) { + // POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V. + final double opVolt = mPowerProfile.getAveragePower( + PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0; + if (opVolt != 0) { + // We store the power drain as mAms. mWifiActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked( - (long)(info.getControllerEnergyUsed() / opVoltage)); + (long)(info.getControllerEnergyUsed() / opVolt)); } } } @@ -7900,11 +7910,13 @@ public final class BatteryStatsImpl extends BatteryStats { mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked( info.getControllerIdleTimeMillis()); - final double opVoltage = mPowerProfile.getAveragePower( - PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE); - if (opVoltage != 0) { + // POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V. + final double opVolt = mPowerProfile.getAveragePower( + PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE) / 1000.0; + if (opVolt != 0) { + // We store the power drain as mAms. mBluetoothActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked( - (long) (info.getControllerEnergyUsed() / opVoltage)); + (long) (info.getControllerEnergyUsed() / opVolt)); } } } diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java index 3557209..1f59672 100644 --- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java +++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java @@ -21,6 +21,15 @@ import android.util.Log; public class BluetoothPowerCalculator extends PowerCalculator { private static final boolean DEBUG = BatteryStatsHelper.DEBUG; private static final String TAG = "BluetoothPowerCalculator"; + private final double mIdleMa; + private final double mRxMa; + private final double mTxMa; + + public BluetoothPowerCalculator(PowerProfile profile) { + mIdleMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE); + mRxMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX); + mTxMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX); + } @Override public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, @@ -37,10 +46,15 @@ public class BluetoothPowerCalculator extends PowerCalculator { BatteryStats.CONTROLLER_TX_TIME, statsType); final long rxTimeMs = stats.getBluetoothControllerActivity( BatteryStats.CONTROLLER_RX_TIME, statsType); - final long powerMaMs = stats.getBluetoothControllerActivity( - BatteryStats.CONTROLLER_POWER_DRAIN, statsType); - final double powerMah = powerMaMs / (double)(1000*60*60); final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs; + double powerMah = stats.getBluetoothControllerActivity( + BatteryStats.CONTROLLER_POWER_DRAIN, statsType) / (double)(1000*60*60); + + if (powerMah == 0) { + // Some devices do not report the power, so calculate it. + powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa)) + / (1000*60*60); + } if (DEBUG && powerMah != 0) { Log.d(TAG, "Bluetooth active: time=" + (totalTimeMs) diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java new file mode 100644 index 0000000..3273080 --- /dev/null +++ b/core/java/com/android/internal/os/CameraPowerCalculator.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import android.os.BatteryStats; + +/** + * Power calculator for the camera subsystem, excluding the flashlight. + * + * Note: Power draw for the flash unit should be included in the FlashlightPowerCalculator. + */ +public class CameraPowerCalculator extends PowerCalculator { + private final double mCameraPowerOnAvg; + + public CameraPowerCalculator(PowerProfile profile) { + mCameraPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_CAMERA); + } + + @Override + public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, + long rawUptimeUs, int statsType) { + + // Calculate camera power usage. Right now, this is a (very) rough estimate based on the + // average power usage for a typical camera application. + final BatteryStats.Timer timer = u.getCameraTurnedOnTimer(); + if (timer != null) { + final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; + app.cameraTimeMs = totalTime; + app.cameraPowerMah = (totalTime * mCameraPowerOnAvg) / (1000*60*60); + } else { + app.cameraTimeMs = 0; + app.cameraPowerMah = 0; + } + } +} diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java new file mode 100644 index 0000000..fef66ff --- /dev/null +++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import android.os.BatteryStats; + +/** + * Power calculator for the flashlight. + */ +public class FlashlightPowerCalculator extends PowerCalculator { + private final double mFlashlightPowerOnAvg; + + public FlashlightPowerCalculator(PowerProfile profile) { + mFlashlightPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_FLASHLIGHT); + } + + @Override + public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, + long rawUptimeUs, int statsType) { + + // Calculate flashlight power usage. Right now, this is based on the average power draw + // of the flash unit when kept on over a short period of time. + final BatteryStats.Timer timer = u.getFlashlightTurnedOnTimer(); + if (timer != null) { + final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; + app.flashlightTimeMs = totalTime; + app.flashlightPowerMah = (totalTime * mFlashlightPowerOnAvg) / (1000*60*60); + } else { + app.flashlightTimeMs = 0; + app.flashlightPowerMah = 0; + } + } +} diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index 1efa565..4ede8dd 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -152,10 +152,17 @@ public class PowerProfile { public static final String POWER_VIDEO = "dsp.video"; /** - * Power consumption when camera flashlight is on. + * Average power consumption when camera flashlight is on. */ public static final String POWER_FLASHLIGHT = "camera.flashlight"; + /** + * Average power consumption when the camera is on over all standard use cases. + * + * TODO: Add more fine-grained camera power metrics. + */ + public static final String POWER_CAMERA = "camera.avg"; + public static final String POWER_CPU_SPEEDS = "cpu.speeds"; /** diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java index 8393e2a..bf97f1f 100644 --- a/core/java/com/android/internal/os/ProcessCpuTracker.java +++ b/core/java/com/android/internal/os/ProcessCpuTracker.java @@ -139,6 +139,8 @@ public class ProcessCpuTracker { private float mLoad5 = 0; private float mLoad15 = 0; + // All times are in milliseconds. They are converted from jiffies to milliseconds + // when extracted from the kernel. private long mCurrentSampleTime; private long mLastSampleTime; @@ -191,12 +193,34 @@ public class ProcessCpuTracker { // filter out kernel processes. public long vsize; + /** + * Time in milliseconds. + */ public long base_uptime; + + /** + * Time in milliseconds. + */ public long rel_uptime; + /** + * Time in milliseconds. + */ public long base_utime; + + /** + * Time in milliseconds. + */ public long base_stime; + + /** + * Time in milliseconds. + */ public int rel_utime; + + /** + * Time in milliseconds. + */ public int rel_stime; public long base_minfaults; @@ -558,7 +582,7 @@ public class ProcessCpuTracker { } /** - * Returns the total time (in clock ticks, or 1/100 sec) spent executing in + * Returns the total time (in milliseconds) spent executing in * both user and system code. Safe to call without lock held. */ public long getCpuTimeForPid(int pid) { @@ -575,26 +599,44 @@ public class ProcessCpuTracker { } } + /** + * @return time in milliseconds. + */ final public int getLastUserTime() { return mRelUserTime; } + /** + * @return time in milliseconds. + */ final public int getLastSystemTime() { return mRelSystemTime; } + /** + * @return time in milliseconds. + */ final public int getLastIoWaitTime() { return mRelIoWaitTime; } + /** + * @return time in milliseconds. + */ final public int getLastIrqTime() { return mRelIrqTime; } + /** + * @return time in milliseconds. + */ final public int getLastSoftIrqTime() { return mRelSoftIrqTime; } + /** + * @return time in milliseconds. + */ final public int getLastIdleTime() { return mRelIdleTime; } diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java index 961b0df..da98a67 100644 --- a/core/java/com/android/internal/os/WifiPowerCalculator.java +++ b/core/java/com/android/internal/os/WifiPowerCalculator.java @@ -70,14 +70,14 @@ public class WifiPowerCalculator extends PowerCalculator { statsType); app.wifiRunningTimeMs = idleTimeMs + rxTimeMs + txTimeMs; - double powerDrain = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_POWER_DRAIN, + double powerDrainMah = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_POWER_DRAIN, statsType) / (double)(1000*60*60); - if (powerDrain == 0) { + if (powerDrainMah == 0) { // Some controllers do not report power drain, so we can calculate it here. - powerDrain = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa) + powerDrainMah = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa) + (rxTimeMs * mRxCurrentMa)) / (1000*60*60); } - app.wifiPowerMah = Math.max(0, powerDrain - mTotalAppPowerDrain); + app.wifiPowerMah = Math.max(0, powerDrainMah - mTotalAppPowerDrain); if (DEBUG) { Log.d(TAG, "left over WiFi power: " + BatteryStatsHelper.makemAh(app.wifiPowerMah)); diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 5ed4f70..971da77 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -508,7 +508,7 @@ public class ZygoteInit { String args[] = { "--setuid=1000", "--setgid=1000", - "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007", + "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 14065b1..294e4ba 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -75,6 +75,7 @@ import com.android.internal.widget.SwipeDismissLayout; import android.app.ActivityManager; import android.app.KeyguardManager; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources.Theme; @@ -2740,7 +2741,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { try { mode = getCallback().onWindowStartingActionMode(wrappedCallback, type); } catch (AbstractMethodError ame) { - // Older apps might not implement this callback method. + // Older apps might not implement the typed version of this method. + if (type == ActionMode.TYPE_PRIMARY) { + try { + mode = getCallback().onWindowStartingActionMode(wrappedCallback); + } catch (AbstractMethodError ame2) { + // Older apps might not implement this callback method at all. + } + } } } if (mode != null) { @@ -4319,8 +4327,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (!result && (getContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) { // On TVs, if the app doesn't implement search, we want to launch assist. + Bundle args = new Bundle(); + args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, event.getDeviceId()); return ((SearchManager)getContext().getSystemService(Context.SEARCH_SERVICE)) - .launchAssistAction(null, UserHandle.myUserId()); + .launchAssistAction(null, UserHandle.myUserId(), args); } return result; } diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index 93d2a1d..661dce1 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -23,6 +23,7 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.ViewConfiguration; import com.android.internal.util.Preconditions; import com.android.internal.view.menu.MenuBuilder; @@ -30,7 +31,7 @@ import com.android.internal.widget.FloatingToolbar; public class FloatingActionMode extends ActionMode { - private static final int MAX_SNOOZE_TIME = 3000; + private static final int MAX_HIDE_DURATION = 3000; private static final int MOVING_HIDE_DELAY = 300; private final Context mContext; @@ -50,9 +51,9 @@ public class FloatingActionMode extends ActionMode { } }; - private final Runnable mSnoozeOff = new Runnable() { + private final Runnable mHideOff = new Runnable() { public void run() { - mFloatingToolbarVisibilityHelper.setSnoozed(false); + mFloatingToolbarVisibilityHelper.setHideRequested(false); } }; @@ -127,11 +128,16 @@ public class FloatingActionMode extends ActionMode { private void repositionToolbar() { checkToolbarInitialized(); + + mContentRectOnWindow.set(mContentRect); + mContentRectOnWindow.offset(mViewPosition[0], mViewPosition[1]); + // Make sure that content rect is not out of the view's visible bounds. mContentRectOnWindow.set( - mContentRect.left + mViewPosition[0], - mContentRect.top + mViewPosition[1], - mContentRect.right + mViewPosition[0], - mContentRect.bottom + mViewPosition[1]); + Math.max(mContentRectOnWindow.left, mViewRect.left), + Math.max(mContentRectOnWindow.top, mViewRect.top), + Math.min(mContentRectOnWindow.right, mViewRect.right), + Math.min(mContentRectOnWindow.bottom, mViewRect.bottom)); + if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) { if (!mPreviousContentRectOnWindow.isEmpty()) { notifyContentRectMoving(); @@ -166,15 +172,19 @@ public class FloatingActionMode extends ActionMode { } @Override - public void snooze(int snoozeTime) { + public void hide(long duration) { checkToolbarInitialized(); - snoozeTime = Math.min(MAX_SNOOZE_TIME, snoozeTime); - mOriginatingView.removeCallbacks(mSnoozeOff); - if (snoozeTime <= 0) { - mSnoozeOff.run(); + + if (duration == ActionMode.DEFAULT_HIDE_DURATION) { + duration = ViewConfiguration.getDefaultActionModeHideDuration(); + } + duration = Math.min(MAX_HIDE_DURATION, duration); + mOriginatingView.removeCallbacks(mHideOff); + if (duration <= 0) { + mHideOff.run(); } else { - mFloatingToolbarVisibilityHelper.setSnoozed(true); - mOriginatingView.postDelayed(mSnoozeOff, snoozeTime); + mFloatingToolbarVisibilityHelper.setHideRequested(true); + mOriginatingView.postDelayed(mHideOff, duration); } } @@ -220,7 +230,7 @@ public class FloatingActionMode extends ActionMode { private void reset() { mOriginatingView.removeCallbacks(mMovingOff); - mOriginatingView.removeCallbacks(mSnoozeOff); + mOriginatingView.removeCallbacks(mHideOff); } @@ -231,7 +241,7 @@ public class FloatingActionMode extends ActionMode { private final FloatingToolbar mToolbar; - private boolean mSnoozed; + private boolean mHideRequested; private boolean mMoving; private boolean mOutOfBounds; @@ -239,8 +249,8 @@ public class FloatingActionMode extends ActionMode { mToolbar = Preconditions.checkNotNull(toolbar); } - public void setSnoozed(boolean snoozed) { - mSnoozed = snoozed; + public void setHideRequested(boolean hide) { + mHideRequested = hide; updateToolbarVisibility(); } @@ -255,7 +265,7 @@ public class FloatingActionMode extends ActionMode { } private void updateToolbarVisibility() { - if (mSnoozed || mMoving || mOutOfBounds) { + if (mHideRequested || mMoving || mOutOfBounds) { mToolbar.hide(); } else if (mToolbar.isHidden()) { mToolbar.show(); |