diff options
Diffstat (limited to 'core/java')
42 files changed, 831 insertions, 419 deletions
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index da48709..aa1be9a 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -211,11 +211,15 @@ public abstract class Animator implements Cloneable { public abstract boolean isRunning(); /** - * Returns whether this Animator has been started and not yet ended. This state is a superset - * of the state of {@link #isRunning()}, because an Animator with a nonzero - * {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during the - * delay phase, whereas {@link #isRunning()} will return true only after the delay phase - * is complete. + * Returns whether this Animator has been started and not yet ended. For reusable + * Animators (which most Animators are, apart from the one-shot animator produced by + * {@link android.view.ViewAnimationUtils#createCircularReveal( + * android.view.View, int, int, float, float) createCircularReveal()}), + * this state is a superset of {@link #isRunning()}, because an Animator with a + * nonzero {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during + * the delay phase, whereas {@link #isRunning()} will return true only after the delay phase + * is complete. Non-reusable animators will always return true after they have been + * started, because they cannot return to a non-started state. * * @return Whether the Animator has been started and not yet ended. */ diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 41e3db8..cb1e7aa 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -31,6 +31,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; import android.content.pm.ContainerEncryptionParams; import android.content.pm.FeatureInfo; +import android.content.pm.IOnPermissionsChangeListener; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; @@ -88,6 +89,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Objects; /*package*/ @@ -1048,6 +1050,38 @@ final class ApplicationPackageManager extends PackageManager { } } + @Override + public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) { + synchronized (mPermissionListeners) { + if (mPermissionListeners.get(listener) != null) { + return; + } + OnPermissionsChangeListenerDelegate delegate = + new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper()); + try { + mPM.addOnPermissionsChangeListener(delegate); + mPermissionListeners.put(listener, delegate); + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + } + } + + @Override + public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) { + synchronized (mPermissionListeners) { + IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener); + if (delegate != null) { + try { + mPM.removeOnPermissionsChangeListener(delegate); + mPermissionListeners.remove(listener); + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + } + } + } + static void configurationChanged() { synchronized (sSync) { sIconCache.clear(); @@ -2139,4 +2173,39 @@ final class ApplicationPackageManager extends PackageManager { = new ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>>(); private static ArrayMap<ResourceName, WeakReference<CharSequence>> sStringCache = new ArrayMap<ResourceName, WeakReference<CharSequence>>(); + + private final Map<OnPermissionsChangedListener, IOnPermissionsChangeListener> + mPermissionListeners = new ArrayMap<>(); + + public class OnPermissionsChangeListenerDelegate extends IOnPermissionsChangeListener.Stub + implements Handler.Callback{ + private static final int MSG_PERMISSIONS_CHANGED = 1; + + private final OnPermissionsChangedListener mListener; + private final Handler mHandler; + + + public OnPermissionsChangeListenerDelegate(OnPermissionsChangedListener listener, + Looper looper) { + mListener = listener; + mHandler = new Handler(looper, this); + } + + @Override + public void onPermissionsChanged(int uid) { + mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget(); + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_PERMISSIONS_CHANGED: { + final int uid = msg.arg1; + mListener.onPermissionsChanged(uid); + return true; + } + } + return false; + } + } } diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index bb45abb4..e110dcb 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -213,7 +213,7 @@ public class Presentation extends Dialog { // dismiss the presentation immediately. This case is expected // to be rare but surprising, so we'll write a log message about it. if (!isConfigurationStillValid()) { - Log.i(TAG, "Presentation is being immediately dismissed because the " + Log.i(TAG, "Presentation is being dismissed because the " + "display metrics have changed since it was created."); mHandler.sendEmptyMessage(MSG_CANCEL); } @@ -274,6 +274,8 @@ public class Presentation extends Dialog { // is invalid and the application must recreate the presentation to get // a new context. if (!isConfigurationStillValid()) { + Log.i(TAG, "Presentation is being dismissed because the " + + "display metrics have changed since it was created."); cancel(); } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 3ab0e01..bf44746 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2275,7 +2275,7 @@ public class DevicePolicyManager { if (mService != null) { try { final String alias = getCaCertAlias(certBuffer); - mService.uninstallCaCert(admin, alias); + mService.uninstallCaCerts(admin, new String[] {alias}); } catch (CertificateException e) { Log.w(TAG, "Unable to parse certificate", e); } catch (RemoteException e) { @@ -2322,12 +2322,11 @@ public class DevicePolicyManager { */ public void uninstallAllUserCaCerts(@Nullable ComponentName admin) { if (mService != null) { - for (String alias : new TrustedCertificateStore().userAliases()) { - try { - mService.uninstallCaCert(admin, alias); - } catch (RemoteException re) { - Log.w(TAG, "Failed talking with device policy service", re); - } + try { + mService.uninstallCaCerts(admin, new TrustedCertificateStore().userAliases() + .toArray(new String[0])); + } catch (RemoteException re) { + Log.w(TAG, "Failed talking with device policy service", re); } } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 8c7b20a..a700806 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -128,7 +128,7 @@ interface IDevicePolicyManager { boolean hasUserSetupCompleted(); boolean installCaCert(in ComponentName admin, in byte[] certBuffer); - void uninstallCaCert(in ComponentName admin, in String alias); + void uninstallCaCerts(in ComponentName admin, in String[] aliases); void enforceCanManageCaCerts(in ComponentName admin); boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias); diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index 49ac062..fd1e24a 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -28,6 +28,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +/** + * Represents a single operation to be performed as part of a batch of operations. + * + * @see ContentProvider#applyBatch(ArrayList) + */ public class ContentProviderOperation implements Parcelable { /** @hide exposed for unit tests */ public final static int TYPE_INSERT = 1; @@ -195,10 +200,19 @@ public class ContentProviderOperation implements Parcelable { return new Builder(TYPE_ASSERT, uri); } + /** + * Gets the Uri for the target of the operation. + */ public Uri getUri() { return mUri; } + /** + * Returns true if the operation allows yielding the database to other transactions + * if the database is contended. + * + * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely() + */ public boolean isYieldAllowed() { return mYieldAllowed; } @@ -208,26 +222,58 @@ public class ContentProviderOperation implements Parcelable { return mType; } + /** + * Returns true if the operation represents an insertion. + * + * @see #newInsert + */ public boolean isInsert() { return mType == TYPE_INSERT; } + /** + * Returns true if the operation represents a deletion. + * + * @see #newDelete + */ public boolean isDelete() { return mType == TYPE_DELETE; } + /** + * Returns true if the operation represents an update. + * + * @see #newUpdate + */ public boolean isUpdate() { return mType == TYPE_UPDATE; } + /** + * Returns true if the operation represents an assert query. + * + * @see #newAssertQuery + */ public boolean isAssertQuery() { return mType == TYPE_ASSERT; } + /** + * Returns true if the operation represents an insertion, deletion, or update. + * + * @see #isInsert + * @see #isDelete + * @see #isUpdate + */ public boolean isWriteOperation() { return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE; } + /** + * Returns true if the operation represents an assert query. + * + * @see #isAssertQuery + */ public boolean isReadOperation() { return mType == TYPE_ASSERT; } @@ -617,7 +663,7 @@ public class ContentProviderOperation implements Parcelable { } /** - * If set then if the number of rows affected by this operation do not match + * If set then if the number of rows affected by this operation does not match * this count {@link OperationApplicationException} will be throw. * This can only be used with builders of type update, delete, or assert. * @return this builder, to allow for chaining. @@ -631,6 +677,12 @@ public class ContentProviderOperation implements Parcelable { return this; } + /** + * If set to true then the operation allows yielding the database to other transactions + * if the database is contended. + * @return this builder, to allow for chaining. + * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely() + */ public Builder withYieldAllowed(boolean yieldAllowed) { mYieldAllowed = yieldAllowed; return this; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index a434c7b..33f38fb 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2443,8 +2443,6 @@ public abstract class Context { * * @param serviceClass The class of the desired service. * @return The service name or null if the class is not a supported system service. - * - * @hide */ public abstract String getSystemServiceName(Class<?> serviceClass); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 25be96a..5190037 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1576,13 +1576,17 @@ public class Intent implements Parcelable, Cloneable { * Broadcast action that requests current permission granted information. It will respond * to the request by sending a broadcast with action defined by * {@link #EXTRA_GET_PERMISSIONS_RESPONSE_INTENT}. The response will contain - * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT} with contents described below or a null upon - * failure. + * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT}, as well as + * {@link #EXTRA_GET_PERMISSIONS_GROUP_LIST_RESULT}, with contents described below or + * a null upon failure. * - * <p>If {@link #EXTRA_PACKAGE_NAME} is included then the number of permissions granted and the - * number of permissions requested by that package will be calculated and included as the first + * <p>If {@link #EXTRA_PACKAGE_NAME} is included then the number of permissions granted, the + * number of permissions requested and the number of granted additional permissions + * by that package will be calculated and included as the first * and second elements respectively of an int[] in the response as - * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT}. + * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT}. The response will also deliver the list + * of localized permission group names that are granted in + * {@link #EXTRA_GET_PERMISSIONS_GROUP_LIST_RESULT}. * * <p>If {@link #EXTRA_PACKAGE_NAME} is not included then the number of apps granted any runtime * permissions and the total number of apps requesting runtime permissions will be the first @@ -1602,7 +1606,14 @@ public class Intent implements Parcelable, Cloneable { = "android.intent.extra.GET_PERMISSIONS_COUNT_RESULT"; /** - * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_COUNT} broadcast. + * List of CharSequence of localized permission group labels. + * @hide + */ + public static final String EXTRA_GET_PERMISSIONS_GROUP_LIST_RESULT + = "android.intent.extra.GET_PERMISSIONS_GROUP_LIST_RESULT"; + + /** + * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_COUNT} broadcasts. * @hide */ public static final String EXTRA_GET_PERMISSIONS_RESPONSE_INTENT diff --git a/core/java/android/content/pm/IOnPermissionsChangeListener.aidl b/core/java/android/content/pm/IOnPermissionsChangeListener.aidl new file mode 100644 index 0000000..7791b50 --- /dev/null +++ b/core/java/android/content/pm/IOnPermissionsChangeListener.aidl @@ -0,0 +1,25 @@ +/* + * 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.content.pm; + +/** + * Listener for changes in the permissions for installed packages. + * {@hide} + */ +oneway interface IOnPermissionsChangeListener { + void onPermissionsChanged(int uid); +} diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 00b8c71..0c07bc3 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -31,6 +31,7 @@ import android.content.pm.IPackageDeleteObserver2; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; +import android.content.pm.IOnPermissionsChangeListener; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.InstrumentationInfo; import android.content.pm.KeySet; @@ -490,4 +491,7 @@ interface IPackageManager { KeySet getSigningKeySet(String packageName); boolean isPackageSignedByKeySet(String packageName, in KeySet ks); boolean isPackageSignedByKeySetExactly(String packageName, in KeySet ks); + + void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener); + void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 68092c8..bd50ca0 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -16,11 +16,13 @@ package android.content.pm; +import android.Manifest; import android.annotation.CheckResult; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.StringRes; @@ -78,6 +80,21 @@ public abstract class PackageManager { } /** + * Listener for changes in permissions granted to a UID. + * + * @hide + */ + @SystemApi + public interface OnPermissionsChangedListener { + + /** + * Called when the permissions for a UID change. + * @param uid The UID with a change. + */ + public void onPermissionsChanged(int uid); + } + + /** * {@link PackageInfo} flag: return information about * activities in the package in {@link PackageInfo#activities}. */ @@ -2636,7 +2653,7 @@ public abstract class PackageManager { /** * Retrieve the official name associated with a user id. This name is - * guaranteed to never change, though it is possibly for the underlying + * guaranteed to never change, though it is possible for the underlying * user id to be changed. That is, if you are storing information about * user ids in persistent storage, you should use the string returned * by this function instead of the raw user-id. @@ -4295,6 +4312,27 @@ public abstract class PackageManager { public abstract boolean isSafeMode(); /** + * Adds a listener for permission changes for installed packages. + * + * @param listener The listener to add. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS) + public abstract void addOnPermissionsChangeListener(OnPermissionsChangedListener listener); + + /** + * Remvoes a listener for permission changes for installed packages. + * + * @param listener The listener to remove. + * + * @hide + */ + @SystemApi + public abstract void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener); + + /** * Return the {@link KeySet} associated with the String alias for this * application. * diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index fda889f..d6b1142 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -1577,7 +1577,7 @@ public abstract class SensorManager { * Significant Motion, Step Counter etc. * * The tests which call this API need to have {@code - * android.permission.HARDWARE_TEST} permission which isn't + * android.permission.LOCATION_HADWARE} permission which isn't * available for third party applications. * * @param enable True to set the HAL in DATA_INJECTION mode. @@ -1607,7 +1607,7 @@ public abstract class SensorManager { * the HAL is already in data injection mode. * * The tests which call this API need to have {@code - * android.permission.HARDWARE_TEST} permission which isn't + * android.permission.LOCATION_HARDWARE} permission which isn't * available for third party applications. * * @param sensor The sensor to inject. diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index 22a9e9c..d7960af 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -80,7 +80,7 @@ public class SystemSensorManager extends SensorManager { nativeClassInit(); } mHasDataInjectionPermissions = context.checkSelfPermission( - Manifest.permission.HARDWARE_TEST) == PackageManager.PERMISSION_GRANTED; + Manifest.permission.LOCATION_HARDWARE) == PackageManager.PERMISSION_GRANTED; } // initialize the sensor list @@ -233,7 +233,7 @@ public class SystemSensorManager extends SensorManager { protected boolean enableDataInjectionImpl(boolean enable) { if (!mHasDataInjectionPermissions) { throw new SecurityException("Permission denial. Calling enableDataInjection without " - + Manifest.permission.HARDWARE_TEST); + + Manifest.permission.LOCATION_HARDWARE); } synchronized (mLock) { int ret = nativeEnableDataInjection(mNativeInstance, enable); @@ -256,7 +256,7 @@ public class SystemSensorManager extends SensorManager { long timestamp) { if (!mHasDataInjectionPermissions) { throw new SecurityException("Permission denial. Calling injectSensorData without " - + Manifest.permission.HARDWARE_TEST); + + Manifest.permission.LOCATION_HARDWARE); } synchronized (mLock) { if (!mDataInjectionMode) { diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index 82d40d3..c547b06 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -150,9 +150,17 @@ public abstract class CameraCaptureSession implements AutoCloseable { * {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces provided when this * capture session was created.</p> * - * <p>Multiple requests can be in progress at once. They are processed in - * first-in, first-out order, with minimal delays between each - * capture. Requests submitted through this method have higher priority than + * <p>Multiple regular and reprocess requests can be in progress at once. If there are only + * regular requests or reprocess requests in progress, they are processed in first-in, + * first-out order. If there are both regular and reprocess requests in progress, regular + * requests are processed in first-in, first-out order and reprocess requests are processed in + * first-in, first-out order, respectively. However, the processing order of a regular request + * and a reprocess request in progress is not specified. In other words, a regular request + * will always be processed before regular requets that are submitted later. A reprocess request + * will always be processed before reprocess requests that are submitted later. However, a + * regular request may not be processed before reprocess requests that are submitted later.<p> + * + * <p>Requests submitted through this method have higher priority than * those submitted through {@link #setRepeatingRequest} or * {@link #setRepeatingBurst}, and will be processed as soon as the current * repeat/repeatBurst processing completes.</p> @@ -207,10 +215,13 @@ public abstract class CameraCaptureSession implements AutoCloseable { * not be interleaved with requests submitted by other capture or repeat * calls. * - * <p>The requests will be captured in order, each capture producing one {@link CaptureResult} - * and image buffers for one or more target {@link android.view.Surface surfaces}. The target - * surfaces (set with {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces - * provided when this capture session was created.</p> + * <p>Regular and reprocess requests can be mixed together in a single burst. Regular requests + * will be captured in order and reprocess requests will be processed in order, respectively. + * However, the processing order between a regular request and a reprocess request is not + * specified. Each capture produces one {@link CaptureResult} and image buffers for one or more + * target {@link android.view.Surface surfaces}. The target surfaces (set with + * {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces provided when + * this capture session was created.</p> * * <p>The main difference between this method and simply calling * {@link #capture} repeatedly is that this method guarantees that no diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index c073ba5..ed167f0 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -1924,6 +1924,28 @@ public class CameraDeviceImpl extends CameraDevice { return mCharacteristics; } + /** + * A high speed output surface can only be preview or hardware encoder surface. + * + * @param surface The high speed output surface to be checked. + */ + private void checkHighSpeedSurfaceFormat(Surface surface) { + // TODO: remove this override since the default format should be + // ImageFormat.PRIVATE. b/9487482 + final int HAL_FORMAT_RGB_START = 1; // HAL_PIXEL_FORMAT_RGBA_8888 from graphics.h + final int HAL_FORMAT_RGB_END = 5; // HAL_PIXEL_FORMAT_BGRA_8888 from graphics.h + int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface); + if (surfaceFormat >= HAL_FORMAT_RGB_START && + surfaceFormat <= HAL_FORMAT_RGB_END) { + surfaceFormat = ImageFormat.PRIVATE; + } + + if (surfaceFormat != ImageFormat.PRIVATE) { + throw new IllegalArgumentException("Surface format(" + surfaceFormat + ") is not" + + " for preview or hardware video encoding!"); + } + } + private void checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces, Range<Integer> fpsRange) { if (surfaces == null || surfaces.size() == 0 || surfaces.size() > 2) { @@ -1948,15 +1970,10 @@ public class CameraDeviceImpl extends CameraDevice { } for (Surface surface : surfaces) { + checkHighSpeedSurfaceFormat(surface); + // 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 " + diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index cc9d496..a3a998e 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -565,7 +565,7 @@ public class LegacyCameraDevice implements AutoCloseable { throw new IllegalArgumentException("Surface was abandoned", e); } - return previewConsumer && (surfaceFormat == ImageFormat.PRIVATE); + return previewConsumer; } public static boolean isVideoEncoderConsumer(Surface output) { @@ -583,7 +583,7 @@ public class LegacyCameraDevice implements AutoCloseable { throw new IllegalArgumentException("Surface was abandoned", e); } - return videoEncoderConsumer && (surfaceFormat == ImageFormat.PRIVATE); + return videoEncoderConsumer; } /** diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java index 32e74e2..40005a5 100644 --- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java +++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java @@ -16,6 +16,7 @@ package android.hardware.camera2.utils; +import android.graphics.ImageFormat; import android.hardware.camera2.legacy.LegacyCameraDevice; import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException; import android.util.Size; @@ -27,7 +28,7 @@ import android.view.Surface; public class SurfaceUtils { /** - * Check if a surface is for preview consumer. + * Check if a surface is for preview consumer based on consumer end point Gralloc usage flags. * * @param surface The surface to be checked. * @return true if the surface is for preview consumer, false otherwise. @@ -37,7 +38,8 @@ public class SurfaceUtils { } /** - * Check if the surface is for hardware video encoder consumer. + * Check if the surface is for hardware video encoder consumer based on consumer end point + * Gralloc usage flags. * * @param surface The surface to be checked. * @return true if the surface is for hardware video encoder consumer, false otherwise. diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index 881dc0f..31a6a96 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -85,6 +85,16 @@ interface IUsbManager /* Sets the current USB function. */ void setCurrentFunction(String function); + /* Sets whether USB data (for example, MTP exposed pictures) should be made + * available on the USB connection. Unlocking data should only be done with + * user involvement, since exposing pictures or other data could leak sensitive + * user information. + */ + void setUsbDataUnlocked(boolean unlock); + + /* Returns true iff sensitive user data is exposed on the USB connection. */ + boolean isUsbDataUnlocked(); + /* Allow USB debugging from the attached host. If alwaysAllow is true, add the * the public key to list of host keys that the user has approved. */ diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 000d41f..c83f466 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -142,6 +142,16 @@ public class UsbManager { public static final String USB_CONFIGURED = "configured"; /** + * Boolean extra indicating whether confidential user data, such as photos, should be + * made available on the USB connection. This variable will only be set when the user + * has explicitly asked for this data to be unlocked. + * Used in extras for the {@link #ACTION_USB_STATE} broadcast. + * + * {@hide} + */ + public static final String USB_DATA_UNLOCKED = "unlocked"; + + /** * Name of the USB mass storage USB function. * Used in extras for the {@link #ACTION_USB_STATE} broadcast * @@ -464,4 +474,34 @@ public class UsbManager { Log.e(TAG, "RemoteException in setCurrentFunction", e); } } + + /** + * Sets whether USB data (for example, MTP exposed pictures) should be made available + * on the USB connection. Unlocking usb data should only be done with user involvement, + * since exposing pictures or other data could leak sensitive user information. + * + * {@hide} + */ + public void setUsbDataUnlocked(boolean unlocked) { + try { + mService.setUsbDataUnlocked(unlocked); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in setUsbDataUnlocked", e); + } + } + + /** + * Returns {@code true} iff access to sensitive USB data is currently allowed. + * + * {@hide} + */ + public boolean isUsbDataUnlocked() { + try { + return mService.isUsbDataUnlocked(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in isUsbDataUnlocked", e); + } + return false; + } + } diff --git a/core/java/android/inputmethodservice/ExtractEditLayout.java b/core/java/android/inputmethodservice/ExtractEditLayout.java index e902443..37ca4b4 100644 --- a/core/java/android/inputmethodservice/ExtractEditLayout.java +++ b/core/java/android/inputmethodservice/ExtractEditLayout.java @@ -16,30 +16,19 @@ package android.inputmethodservice; -import com.android.internal.view.menu.MenuBuilder; -import com.android.internal.view.menu.MenuPopupHelper; - import android.content.Context; import android.util.AttributeSet; -import android.view.ActionMode; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.accessibility.AccessibilityEvent; import android.widget.Button; import android.widget.LinearLayout; /** - * ExtractEditLayout provides an ActionMode presentation for the - * limited screen real estate in extract mode. + * ExtractEditLayout provides an ActionMode presentation for the limited screen real estate in + * extract mode. * * @hide */ public class ExtractEditLayout extends LinearLayout { - ExtractActionMode mActionMode; Button mExtractActionButton; - Button mEditButton; public ExtractEditLayout(Context context) { super(context); @@ -50,165 +39,8 @@ public class ExtractEditLayout extends LinearLayout { } @Override - public ActionMode startActionModeForChild(View sourceView, ActionMode.Callback cb) { - final ExtractActionMode mode = new ExtractActionMode(cb); - if (mode.dispatchOnCreate()) { - mode.invalidate(); - mExtractActionButton.setVisibility(INVISIBLE); - mEditButton.setVisibility(VISIBLE); - mActionMode = mode; - sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); - return mode; - } - return null; - } - - /** - * @return true if an action mode is currently active. - */ - public boolean isActionModeStarted() { - return mActionMode != null; - } - - /** - * Finishes a possibly started action mode. - */ - public void finishActionMode() { - if (mActionMode != null) { - mActionMode.finish(); - } - } - - @Override public void onFinishInflate() { super.onFinishInflate(); mExtractActionButton = (Button) findViewById(com.android.internal.R.id.inputExtractAction); - mEditButton = (Button) findViewById(com.android.internal.R.id.inputExtractEditButton); - mEditButton.setOnClickListener(new OnClickListener() { - public void onClick(View clicked) { - if (mActionMode != null) { - new MenuPopupHelper(getContext(), mActionMode.mMenu, clicked).show(); - } - } - }); - } - - private class ExtractActionMode extends ActionMode implements MenuBuilder.Callback { - private ActionMode.Callback mCallback; - MenuBuilder mMenu; - - public ExtractActionMode(Callback cb) { - mMenu = new MenuBuilder(getContext()); - mMenu.setCallback(this); - mCallback = cb; - } - - @Override - public void setTitle(CharSequence title) { - // Title will not be shown. - } - - @Override - public void setTitle(int resId) { - // Title will not be shown. - } - - @Override - public void setSubtitle(CharSequence subtitle) { - // Subtitle will not be shown. - } - - @Override - public void setSubtitle(int resId) { - // Subtitle will not be shown. - } - - @Override - public boolean isTitleOptional() { - // Not only is it optional, it will *never* be shown. - return true; - } - - @Override - public void setCustomView(View view) { - // Custom view is not supported here. - } - - @Override - public void invalidate() { - mMenu.stopDispatchingItemsChanged(); - try { - mCallback.onPrepareActionMode(this, mMenu); - } finally { - mMenu.startDispatchingItemsChanged(); - } - } - - public boolean dispatchOnCreate() { - mMenu.stopDispatchingItemsChanged(); - try { - return mCallback.onCreateActionMode(this, mMenu); - } finally { - mMenu.startDispatchingItemsChanged(); - } - } - - @Override - public void finish() { - if (mActionMode != this) { - // Not the active action mode - no-op - return; - } - - mCallback.onDestroyActionMode(this); - mCallback = null; - - mMenu.close(); - - mExtractActionButton.setVisibility(VISIBLE); - mEditButton.setVisibility(INVISIBLE); - - sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); - - mActionMode = null; - } - - @Override - public Menu getMenu() { - return mMenu; - } - - @Override - public CharSequence getTitle() { - return null; - } - - @Override - public CharSequence getSubtitle() { - return null; - } - - @Override - public View getCustomView() { - return null; - } - - @Override - public MenuInflater getMenuInflater() { - return new MenuInflater(getContext()); - } - - @Override - public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { - if (mCallback != null) { - return mCallback.onActionItemClicked(this, item); - } - return false; - } - - @Override - public void onMenuModeChange(MenuBuilder menu) { - } - } } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index a7afa91..ae74b9a 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1797,16 +1797,9 @@ public class InputMethodService extends AbstractInputMethodService { private void requestShowSelf(int flags) { mImm.showSoftInputFromInputMethod(mToken, flags); } - + private boolean handleBack(boolean doIt) { if (mShowInputRequested) { - if (isExtractViewShown() && mExtractView instanceof ExtractEditLayout) { - ExtractEditLayout extractEditLayout = (ExtractEditLayout) mExtractView; - if (extractEditLayout.isActionModeStarted()) { - if (doIt) extractEditLayout.finishActionMode(); - return true; - } - } // If the soft input area is shown, back closes it and we // consume the back key. if (doIt) requestHideSelf(0); diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java index e47220b..5f46c73 100644 --- a/core/java/android/net/NetworkFactory.java +++ b/core/java/android/net/NetworkFactory.java @@ -24,8 +24,13 @@ import android.os.Messenger; import android.util.Log; import android.util.SparseArray; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Protocol; +import java.io.FileDescriptor; +import java.io.PrintWriter; + /** * A NetworkFactory is an entity that creates NetworkAgent objects. * The bearers register with ConnectivityService using {@link #register} and @@ -157,6 +162,11 @@ public class NetworkFactory extends Handler { this.score = score; this.requested = false; } + + @Override + public String toString() { + return "{" + request + ", score=" + score + ", requested=" + requested + "}"; + } } private void handleAddRequest(NetworkRequest request, int score) { @@ -176,9 +186,9 @@ public class NetworkFactory extends Handler { private void handleRemoveRequest(NetworkRequest request) { NetworkRequestInfo n = mNetworkRequests.get(request.requestId); - if (n != null && n.requested) { + if (n != null) { mNetworkRequests.remove(request.requestId); - releaseNetworkFor(n.request); + if (n.requested) releaseNetworkFor(n.request); } } @@ -273,15 +283,31 @@ public class NetworkFactory extends Handler { sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); } + @VisibleForTesting + protected int getRequestCount() { + return mNetworkRequests.size(); + } + protected void log(String s) { Log.d(LOG_TAG, s); } + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + pw.println(toString()); + pw.increaseIndent(); + for (int i = 0; i < mNetworkRequests.size(); i++) { + pw.println(mNetworkRequests.valueAt(i)); + } + pw.decreaseIndent(); + } + @Override public String toString() { StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - ScoreFilter="). append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests="). - append(mNetworkRequests.size()).append("}"); + append(mNetworkRequests.size()).append(", refCount=").append(mRefCount). + append("}"); return sb.toString(); } } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index c9609e5..a6efc58 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -3489,57 +3489,90 @@ public abstract class BatteryStats implements Parcelable { pw.println(); for (int i=0; i<sippers.size(); i++) { final BatterySipper bs = sippers.get(i); + pw.print(prefix); switch (bs.drainType) { case IDLE: - pw.print(prefix); pw.print(" Idle: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Idle: "); break; case CELL: - pw.print(prefix); pw.print(" Cell standby: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Cell standby: "); break; case PHONE: - pw.print(prefix); pw.print(" Phone calls: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Phone calls: "); break; case WIFI: - pw.print(prefix); pw.print(" Wifi: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Wifi: "); break; case BLUETOOTH: - pw.print(prefix); pw.print(" Bluetooth: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Bluetooth: "); break; case SCREEN: - pw.print(prefix); pw.print(" Screen: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Screen: "); break; case FLASHLIGHT: - pw.print(prefix); pw.print(" Flashlight: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Flashlight: "); break; case APP: - pw.print(prefix); pw.print(" Uid "); + pw.print(" Uid "); UserHandle.formatUid(pw, bs.uidObj.getUid()); - pw.print(": "); printmAh(pw, bs.totalPowerMah); pw.println(); + pw.print(": "); break; case USER: - pw.print(prefix); pw.print(" User "); pw.print(bs.userId); - pw.print(": "); printmAh(pw, bs.totalPowerMah); pw.println(); + pw.print(" User "); pw.print(bs.userId); + pw.print(": "); break; case UNACCOUNTED: - pw.print(prefix); pw.print(" Unaccounted: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Unaccounted: "); break; case OVERCOUNTED: - pw.print(prefix); pw.print(" Over-counted: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Over-counted: "); break; case CAMERA: - pw.print(prefix); pw.print(" Camera: "); printmAh(pw, bs.totalPowerMah); - pw.println(); + pw.print(" Camera: "); + break; + default: + pw.print(" ???: "); break; } + printmAh(pw, bs.totalPowerMah); + + if (bs.drainType == BatterySipper.DrainType.APP) { + pw.print(" ("); + if (bs.cpuPowerMah != 0) { + pw.print(" cpu="); + printmAh(pw, bs.cpuPowerMah); + } + if (bs.wakeLockPowerMah != 0) { + pw.print(" wake="); + printmAh(pw, bs.wakeLockPowerMah); + } + if (bs.mobileRadioPowerMah != 0) { + pw.print(" radio="); + printmAh(pw, bs.mobileRadioPowerMah); + } + if (bs.wifiPowerMah != 0) { + pw.print(" wifi="); + printmAh(pw, bs.wifiPowerMah); + } + if (bs.gpsPowerMah != 0) { + pw.print(" gps="); + printmAh(pw, bs.gpsPowerMah); + } + if (bs.sensorPowerMah != 0) { + pw.print(" sensor="); + printmAh(pw, bs.sensorPowerMah); + } + if (bs.cameraPowerMah != 0) { + pw.print(" camera="); + printmAh(pw, bs.cameraPowerMah); + } + if (bs.flashlightPowerMah != 0) { + pw.print(" flash="); + printmAh(pw, bs.flashlightPowerMah); + } + pw.print(" )"); + } + pw.println(); } pw.println(); } diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index d2a9cdc..5849350 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -77,7 +77,6 @@ public class RemoteCallbackList<E extends IInterface> { public boolean register(E callback) { return register(callback, null); } - /** * Add a new callback to the list. This callback will remain in the list * until a corresponding call to {@link #unregister} or its hosting process diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index 2622ee0..372725f 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -32,7 +32,9 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.DebugUtils; import android.util.SparseArray; +import android.util.SparseIntArray; +import com.android.internal.R; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; @@ -80,6 +82,7 @@ public class VolumeInfo implements Parcelable { private static SparseArray<String> sStateToEnvironment = new SparseArray<>(); private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>(); + private static SparseIntArray sStateToDescrip = new SparseIntArray(); private static final Comparator<VolumeInfo> sDescriptionComparator = new Comparator<VolumeInfo>() { @@ -116,6 +119,16 @@ public class VolumeInfo implements Parcelable { sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTABLE, Intent.ACTION_MEDIA_UNMOUNTABLE); sEnvironmentToBroadcast.put(Environment.MEDIA_REMOVED, Intent.ACTION_MEDIA_REMOVED); sEnvironmentToBroadcast.put(Environment.MEDIA_BAD_REMOVAL, Intent.ACTION_MEDIA_BAD_REMOVAL); + + sStateToDescrip.put(VolumeInfo.STATE_UNMOUNTED, R.string.ext_media_status_unmounted); + sStateToDescrip.put(VolumeInfo.STATE_CHECKING, R.string.ext_media_status_checking); + sStateToDescrip.put(VolumeInfo.STATE_MOUNTED, R.string.ext_media_status_mounted); + sStateToDescrip.put(VolumeInfo.STATE_MOUNTED_READ_ONLY, R.string.ext_media_status_mounted_ro); + sStateToDescrip.put(VolumeInfo.STATE_FORMATTING, R.string.ext_media_status_formatting); + sStateToDescrip.put(VolumeInfo.STATE_EJECTING, R.string.ext_media_status_ejecting); + sStateToDescrip.put(VolumeInfo.STATE_UNMOUNTABLE, R.string.ext_media_status_unmountable); + sStateToDescrip.put(VolumeInfo.STATE_REMOVED, R.string.ext_media_status_removed); + sStateToDescrip.put(VolumeInfo.STATE_BAD_REMOVAL, R.string.ext_media_status_bad_removal); } /** vold state */ @@ -201,6 +214,10 @@ public class VolumeInfo implements Parcelable { return state; } + public int getStateDescription() { + return sStateToDescrip.get(state, 0); + } + public @Nullable String getFsUuid() { return fsUuid; } diff --git a/core/java/android/preference/SeekBarDialogPreference.java b/core/java/android/preference/SeekBarDialogPreference.java index 9a08827..eeb69a3 100644 --- a/core/java/android/preference/SeekBarDialogPreference.java +++ b/core/java/android/preference/SeekBarDialogPreference.java @@ -18,29 +18,28 @@ package android.preference; import android.content.Context; import android.graphics.drawable.Drawable; -import android.preference.DialogPreference; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; import android.widget.SeekBar; +import com.android.internal.R; + /** * @hide */ public class SeekBarDialogPreference extends DialogPreference { - private static final String TAG = "SeekBarDialogPreference"; - - private Drawable mMyIcon; + private final Drawable mMyIcon; public SeekBarDialogPreference( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - setDialogLayoutResource(com.android.internal.R.layout.seekbar_dialog); createActionButtons(); // Steal the XML dialogIcon attribute's value mMyIcon = getDialogIcon(); + setDialogIcon(null); } @@ -49,7 +48,7 @@ public class SeekBarDialogPreference extends DialogPreference { } public SeekBarDialogPreference(Context context, AttributeSet attrs) { - this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle); + this(context, attrs, R.attr.seekBarDialogPreferenceStyle); } public SeekBarDialogPreference(Context context) { @@ -58,15 +57,15 @@ public class SeekBarDialogPreference extends DialogPreference { // Allow subclasses to override the action buttons public void createActionButtons() { - setPositiveButtonText(android.R.string.ok); - setNegativeButtonText(android.R.string.cancel); + setPositiveButtonText(R.string.ok); + setNegativeButtonText(R.string.cancel); } @Override protected void onBindDialogView(View view) { super.onBindDialogView(view); - final ImageView iconView = (ImageView) view.findViewById(android.R.id.icon); + final ImageView iconView = (ImageView) view.findViewById(R.id.icon); if (mMyIcon != null) { iconView.setImageDrawable(mMyIcon); } else { @@ -75,6 +74,6 @@ public class SeekBarDialogPreference extends DialogPreference { } protected static SeekBar getSeekBar(View dialogView) { - return (SeekBar) dialogView.findViewById(com.android.internal.R.id.seekbar); + return (SeekBar) dialogView.findViewById(R.id.seekbar); } } diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index a2da01b..573499a 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -26,14 +26,13 @@ import android.view.KeyEvent; import android.view.View; import android.widget.SeekBar; +import com.android.internal.R; + /** * @hide */ public class VolumePreference extends SeekBarDialogPreference implements PreferenceManager.OnActivityStopListener, View.OnKeyListener, SeekBarVolumizer.Callback { - - static final String TAG = "VolumePreference"; - private int mStreamType; /** May be null if the dialog isn't visible. */ @@ -44,7 +43,7 @@ public class VolumePreference extends SeekBarDialogPreference implements super(context, attrs, defStyleAttr, defStyleRes); final TypedArray a = context.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.VolumePreference, defStyleAttr, defStyleRes); + R.styleable.VolumePreference, defStyleAttr, defStyleRes); mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0); a.recycle(); } @@ -54,7 +53,11 @@ public class VolumePreference extends SeekBarDialogPreference implements } public VolumePreference(Context context, AttributeSet attrs) { - this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle); + this(context, attrs, R.attr.seekBarDialogPreferenceStyle); + } + + public VolumePreference(Context context) { + this(context, null); } public void setStreamType(int streamType) { @@ -65,7 +68,7 @@ public class VolumePreference extends SeekBarDialogPreference implements protected void onBindDialogView(View view) { super.onBindDialogView(view); - final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar); + final SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar); mSeekBarVolumizer = new SeekBarVolumizer(getContext(), mStreamType, null, this); mSeekBarVolumizer.start(); mSeekBarVolumizer.setSeekBar(seekBar); @@ -128,14 +131,17 @@ public class VolumePreference extends SeekBarDialogPreference implements getPreferenceManager().unregisterOnActivityStopListener(this); if (mSeekBarVolumizer != null) { - Dialog dialog = getDialog(); + final Dialog dialog = getDialog(); if (dialog != null && dialog.isShowing()) { - View view = dialog.getWindow().getDecorView() - .findViewById(com.android.internal.R.id.seekbar); - if (view != null) view.setOnKeyListener(null); + final View view = dialog.getWindow().getDecorView().findViewById(R.id.seekbar); + if (view != null) { + view.setOnKeyListener(null); + } + // Stopped while dialog was showing, revert changes mSeekBarVolumizer.revertVolume(); } + mSeekBarVolumizer.stop(); mSeekBarVolumizer = null; } diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 69338b0..30535ff 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -93,6 +93,12 @@ public final class DocumentsContract { public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED"; /** + * Set this in a DocumentsUI intent to cause a package's own roots to be + * excluded from the roots list. + */ + public static final String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF"; + + /** * Included in {@link AssetFileDescriptor#getExtras()} when returned * thumbnail should be rotated. * diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 640f434..167d8e5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -577,6 +577,21 @@ public final class Settings { "android.settings.APPLICATION_DETAILS_SETTINGS"; /** + * Activity Action: Show screen for controlling which apps can ignore battery optimizations. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: The Intent's data URI specifies the application package name + * to be shown, with the "package" scheme. That is "package:com.my.app". + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = + "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS"; + + /** * @hide * Activity Action: Show the "app ops" settings screen. * <p> diff --git a/core/java/android/service/carrier/CarrierService.java b/core/java/android/service/carrier/CarrierService.java index 5f83452..225e70d 100644 --- a/core/java/android/service/carrier/CarrierService.java +++ b/core/java/android/service/carrier/CarrierService.java @@ -14,10 +14,15 @@ package android.service.carrier; +import android.annotation.CallSuper; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.PersistableBundle; +import android.os.RemoteException; +import android.os.ServiceManager; + +import com.android.internal.telephony.ITelephonyRegistry; /** * A service that exposes carrier-specific functionality to the system. @@ -45,10 +50,16 @@ public abstract class CarrierService extends Service { public static final String CONFIG_SERVICE_INTERFACE = "android.service.carrier.ConfigService"; public static final String BIND_SERVICE_INTERFACE = "android.service.carrier.BindService"; + private static ITelephonyRegistry sRegistry; + private final ICarrierService.Stub mStubWrapper; public CarrierService() { mStubWrapper = new ICarrierServiceWrapper(); + if (sRegistry == null) { + sRegistry = ITelephonyRegistry.Stub.asInterface( + ServiceManager.getService("telephony.registry")); + } } /** @@ -83,9 +94,39 @@ public abstract class CarrierService extends Service { */ public abstract PersistableBundle onLoadConfig(CarrierIdentifier id); - /** @hide */ + /** + * Informs the system of an intentional upcoming carrier network change by + * a carrier app. This call is optional and is only used to allow the + * system to provide alternative UI while telephony is performing an action + * that may result in intentional, temporary network lack of connectivity. + * <p> + * Based on the active parameter passed in, this method will either show or + * hide the alternative UI. There is no timeout associated with showing + * this UX, so a carrier app must be sure to call with active set to false + * sometime after calling with it set to true. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. + * @see {@link android.telephony.TelephonyManager#hasCarrierPrivileges} + * + * @param active Whether the carrier network change is or shortly will be + * active. Set this value to true to begin showing + * alternative UI and false to stop. + */ + public final void notifyCarrierNetworkChange(boolean active) { + try { + if (sRegistry != null) sRegistry.notifyCarrierNetworkChange(active); + } catch (RemoteException | NullPointerException ex) {} + } + + /** + * If overriding this method, call through to the super method for any unknown actions. + * {@inheritDoc} + */ @Override - public final IBinder onBind(Intent intent) { + @CallSuper + public IBinder onBind(Intent intent) { switch (intent.getAction()) { case CONFIG_SERVICE_INTERFACE: case BIND_SERVICE_INTERFACE: @@ -98,11 +139,8 @@ public abstract class CarrierService extends Service { /** * A wrapper around ICarrierService that forwards calls to implementations of * {@link CarrierService}. - * - * @hide */ private class ICarrierServiceWrapper extends ICarrierService.Stub { - @Override public PersistableBundle getCarrierConfig(CarrierIdentifier id) { return CarrierService.this.onLoadConfig(id); diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index b8493d4..8c6cd09 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -646,7 +646,7 @@ public abstract class NotificationListenerService extends Service { private void createLegacyIconExtras(Notification n) { Icon smallIcon = n.getSmallIcon(); Icon largeIcon = n.getLargeIcon(); - if (smallIcon.getType() == Icon.TYPE_RESOURCE) { + if (smallIcon != null && smallIcon.getType() == Icon.TYPE_RESOURCE) { n.extras.putInt(Notification.EXTRA_SMALL_ICON, smallIcon.getResId()); n.icon = smallIcon.getResId(); } diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java index b4622e0..a785d1b 100644 --- a/core/java/android/text/Spanned.java +++ b/core/java/android/text/Spanned.java @@ -187,12 +187,11 @@ extends CharSequence public int getSpanFlags(Object tag); /** - * Return the first offset greater than or equal to <code>start</code> - * where a markup object of class <code>type</code> begins or ends, - * or <code>limit</code> if there are no starts or ends greater than or - * equal to <code>start</code> but less than <code>limit</code>. Specify - * <code>null</code> or Object.class for the type if you want every - * transition regardless of type. + * Return the first offset greater than <code>start</code> where a markup + * object of class <code>type</code> begins or ends, or <code>limit</code> + * if there are no starts or ends greater than <code>start</code> but less + * than <code>limit</code>. Specify <code>null</code> or Object.class for + * the type if you want every transition regardless of type. */ public int nextSpanTransition(int start, int limit, Class type); } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 160c662..7d48a9a 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -523,7 +523,7 @@ public class SurfaceView extends View { mVisibleInsets, mStableInsets, mOutsets, mConfiguration, mNewSurface); if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { - mReportDrawNeeded = true; + reportDrawNeeded = true; } if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java index f18b7ac..bd45007 100644 --- a/core/java/android/view/ViewPropertyAnimator.java +++ b/core/java/android/view/ViewPropertyAnimator.java @@ -80,18 +80,12 @@ public class ViewPropertyAnimator { /** * The interpolator of the underlying Animator object. By default, we don't set the interpolator - * on the Animator and just use its default interpolator. If the interpolator is ever set on - * this Animator, then we use the interpolator that it was set to. + * on the Animator and just use its default interpolator. If the interpolator is set to a + * non-null value on this Animator, then we use the interpolator that it was set to. */ private TimeInterpolator mInterpolator; /** - * A flag indicating whether the interpolator has been set on this object. If not, we don't set - * the interpolator on the underlying Animator, but instead just use its default interpolator. - */ - private boolean mInterpolatorSet = false; - - /** * Listener for the lifecycle events of the underlying ValueAnimator object. */ private Animator.AnimatorListener mListener = null; @@ -338,7 +332,6 @@ public class ViewPropertyAnimator { * @return This object, allowing calls to methods in this class to be chained. */ public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) { - mInterpolatorSet = true; mInterpolator = interpolator; return this; } @@ -349,7 +342,7 @@ public class ViewPropertyAnimator { * @return The timing interpolator for this animation. */ public TimeInterpolator getInterpolator() { - if (mInterpolatorSet) { + if (mInterpolator != null) { return mInterpolator; } else { // Just return the default from ValueAnimator, since that's what we'd get if @@ -897,7 +890,7 @@ public class ViewPropertyAnimator { if (mDurationSet) { animator.setDuration(mDuration); } - if (mInterpolatorSet) { + if (mInterpolator != null) { animator.setInterpolator(mInterpolator); } animator.start(); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index cd110b7..e43237a 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -262,6 +262,8 @@ public class Editor { } }; + boolean mIsInsertionActionModeStartPending = false; + Editor(TextView textView) { mTextView = textView; // Synchronize the filter list, which places the undo input filter at the end. @@ -990,7 +992,7 @@ public class Editor { } public boolean performLongClick(boolean handled) { - // Long press in empty space moves cursor and starts the selection action mode. + // Long press in empty space moves cursor and starts the insertion action mode. if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY) && mInsertionControllerEnabled) { final int offset = mTextView.getOffsetForPosition(mLastDownPositionX, @@ -998,7 +1000,7 @@ public class Editor { stopTextActionMode(); Selection.setSelection((Spannable) mTextView.getText(), offset); getInsertionController().show(); - startInsertionActionMode(); + mIsInsertionActionModeStartPending = true; handled = true; } @@ -1710,14 +1712,14 @@ public class Editor { } /** - * @return true if the selection mode was actually started. + * Start an Insertion action mode. */ - private boolean startInsertionActionMode() { + void startInsertionActionMode() { if (mInsertionActionModeRunnable != null) { mTextView.removeCallbacks(mInsertionActionModeRunnable); } if (extractedTextModeWillBeStarted()) { - return false; + return; } stopTextActionMode(); @@ -1725,7 +1727,9 @@ public class Editor { new TextActionModeCallback(false /* hasSelection */); mTextActionMode = mTextView.startActionMode( actionModeCallback, ActionMode.TYPE_FLOATING); - return mTextActionMode != null; + if (mTextActionMode != null && getInsertionController() != null) { + getInsertionController().show(); + } } /** @@ -1796,7 +1800,7 @@ public class Editor { private boolean startSelectionActionModeInternal() { if (mTextActionMode != null) { - // Selection action mode is already started + // Text action mode is already started mTextActionMode.invalidate(); return false; } @@ -3299,7 +3303,6 @@ public class Editor { if (mSelectionModifierCursorController != null) { mSelectionModifierCursorController.hide(); - mSelectionModifierCursorController.resetTouchOffsets(); } mTextActionMode = null; @@ -3874,7 +3877,7 @@ public class Editor { private static final int DELAY_BEFORE_HANDLE_FADES_OUT = 4000; private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; // seconds - // Used to detect taps on the insertion handle, which will affect the selection action mode + // Used to detect taps on the insertion handle, which will affect the insertion action mode private float mDownPositionX, mDownPositionY; private Runnable mHider; @@ -3899,17 +3902,20 @@ public class Editor { // timeout has passed. if (!mDoubleTap && !isCursorInsideEasyCorrectionSpan() && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) { - if (mInsertionActionModeRunnable == null) { - mInsertionActionModeRunnable = new Runnable() { - public void run() { - startInsertionActionMode(); - } - }; + if (mTextActionMode == null) { + if (mInsertionActionModeRunnable == null) { + mInsertionActionModeRunnable = new Runnable() { + @Override + public void run() { + startInsertionActionMode(); + } + }; + } + mTextView.postDelayed( + mInsertionActionModeRunnable, + ViewConfiguration.getDoubleTapTimeout() + 1); } - mTextView.postDelayed( - mInsertionActionModeRunnable, - ViewConfiguration.getDoubleTapTimeout() + 1); } hideAfterDelay(); @@ -3976,7 +3982,7 @@ public class Editor { final int touchSlop = viewConfiguration.getScaledTouchSlop(); if (distanceSquared < touchSlop * touchSlop) { - // Tapping on the handle toggles the selection action mode. + // Tapping on the handle toggles the insertion action mode. if (mTextActionMode != null) { mTextActionMode.finish(); } else { diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 94b9416..afc683a 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -618,12 +618,11 @@ public class ListPopupWindow { heightSpec = mDropDownHeight; } - mPopup.setWidth(widthSpec); - mPopup.setHeight(heightSpec); mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible); mPopup.update(getAnchorView(), mDropDownHorizontalOffset, - mDropDownVerticalOffset, -1, -1); + mDropDownVerticalOffset, (widthSpec < 0)? -1 : widthSpec, + (heightSpec < 0)? -1 : heightSpec); } else { final int widthSpec; if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index b68934b..353901c 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8320,12 +8320,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean superResult = super.onTouchEvent(event); /* - * Don't handle the release after a long press, because it will - * move the selection away from whatever the menu action was - * trying to affect. + * Don't handle the release after a long press, because it will move the selection away from + * whatever the menu action was trying to affect. If the long press should have triggered an + * insertion action mode, we can now actually show it. */ if (mEditor != null && mEditor.mDiscardNextActionUp && action == MotionEvent.ACTION_UP) { mEditor.mDiscardNextActionUp = false; + + if (mEditor.mIsInsertionActionModeStartPending) { + mEditor.startInsertionActionMode(); + mEditor.mIsInsertionActionModeStartPending = false; + } return superResult; } diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index ba4af89..39c86f9 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -18,8 +18,6 @@ package com.android.internal.app; import android.app.Activity; import android.app.ActivityThread; -import android.app.usage.UsageStats; -import android.app.usage.UsageStatsManager; import android.os.AsyncTask; import android.provider.Settings; import android.text.TextUtils; @@ -64,14 +62,11 @@ import android.widget.TextView; import android.widget.Toast; import com.android.internal.widget.ResolverDrawerLayout; -import java.text.Collator; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; @@ -100,10 +95,7 @@ public class ResolverActivity extends Activity { private boolean mResolvingHome = false; private int mProfileSwitchMessageId = -1; private final ArrayList<Intent> mIntents = new ArrayList<>(); - - private UsageStatsManager mUsm; - private Map<String, UsageStats> mStats; - private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14; + private ResolverComparator mResolverComparator; private boolean mRegistered; private final PackageMonitor mPackageMonitor = new PackageMonitor() { @@ -222,10 +214,6 @@ public class ResolverActivity extends Activity { } mPm = getPackageManager(); - mUsm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); - - final long sinceTime = System.currentTimeMillis() - USAGE_STATS_PERIOD; - mStats = mUsm.queryAndAggregateUsageStats(sinceTime, System.currentTimeMillis()); mPackageMonitor.register(this, getMainLooper(), false); mRegistered = true; @@ -236,6 +224,10 @@ public class ResolverActivity extends Activity { // Add our initial intent as the first item, regardless of what else has already been added. mIntents.add(0, new Intent(intent)); + final String referrerPackage = getReferrerPackageName(); + + mResolverComparator = new ResolverComparator(this, getTargetIntent(), referrerPackage); + configureContentView(mIntents, initialIntents, rList, alwaysUseOption); // Prevent the Resolver window from becoming the top fullscreen window and thus from taking @@ -265,7 +257,6 @@ public class ResolverActivity extends Activity { // Try to initialize the title icon if we have a view for it and a title to match final ImageView titleIcon = (ImageView) findViewById(R.id.title_icon); if (titleIcon != null) { - final String referrerPackage = getReferrerPackageName(); ApplicationInfo ai = null; try { if (!TextUtils.isEmpty(referrerPackage)) { @@ -1175,8 +1166,8 @@ public class ResolverActivity extends Activity { } } if (N > 1) { - Collections.sort(currentResolveList, - new ResolverComparator(ResolverActivity.this, getTargetIntent())); + mResolverComparator.compute(currentResolveList); + Collections.sort(currentResolveList, mResolverComparator); } // First put the initial items at the top. if (mInitialIntents != null) { @@ -1651,63 +1642,4 @@ public class ResolverActivity extends Activity { && match <= IntentFilter.MATCH_CATEGORY_PATH; } - class ResolverComparator implements Comparator<ResolvedComponentInfo> { - private final Collator mCollator; - private final boolean mHttp; - - public ResolverComparator(Context context, Intent intent) { - mCollator = Collator.getInstance(context.getResources().getConfiguration().locale); - String scheme = intent.getScheme(); - mHttp = "http".equals(scheme) || "https".equals(scheme); - } - - @Override - public int compare(ResolvedComponentInfo lhsp, ResolvedComponentInfo rhsp) { - final ResolveInfo lhs = lhsp.getResolveInfoAt(0); - final ResolveInfo rhs = rhsp.getResolveInfoAt(0); - - // We want to put the one targeted to another user at the end of the dialog. - if (lhs.targetUserId != UserHandle.USER_CURRENT) { - return 1; - } - - if (mHttp) { - // Special case: we want filters that match URI paths/schemes to be - // ordered before others. This is for the case when opening URIs, - // to make native apps go above browsers. - final boolean lhsSpecific = isSpecificUriMatch(lhs.match); - final boolean rhsSpecific = isSpecificUriMatch(rhs.match); - if (lhsSpecific != rhsSpecific) { - return lhsSpecific ? -1 : 1; - } - } - - if (mStats != null) { - final long timeDiff = - getPackageTimeSpent(rhs.activityInfo.packageName) - - getPackageTimeSpent(lhs.activityInfo.packageName); - - if (timeDiff != 0) { - return timeDiff > 0 ? 1 : -1; - } - } - - CharSequence sa = lhs.loadLabel(mPm); - if (sa == null) sa = lhs.activityInfo.name; - CharSequence sb = rhs.loadLabel(mPm); - if (sb == null) sb = rhs.activityInfo.name; - - return mCollator.compare(sa.toString(), sb.toString()); - } - - private long getPackageTimeSpent(String packageName) { - if (mStats != null) { - final UsageStats stats = mStats.get(packageName); - if (stats != null) { - return stats.getTotalTimeInForeground(); - } - } - return 0; - } - } } diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java new file mode 100644 index 0000000..42668f1 --- /dev/null +++ b/core/java/com/android/internal/app/ResolverComparator.java @@ -0,0 +1,215 @@ +/* + * 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.app; + +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.Log; +import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Ranks and compares packages based on usage stats. + */ +class ResolverComparator implements Comparator<ResolvedComponentInfo> { + private static final String TAG = "ResolverComparator"; + + private static final boolean DEBUG = true; + + // Two weeks + private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14; + + private static final long RECENCY_TIME_PERIOD = 1000 * 60 * 60 * 12; + + private static final float RECENCY_MULTIPLIER = 3.f; + + private final Collator mCollator; + private final boolean mHttp; + private final PackageManager mPm; + private final UsageStatsManager mUsm; + private final Map<String, UsageStats> mStats; + private final long mCurrentTime; + private final long mSinceTime; + private final LinkedHashMap<ComponentName, ScoredTarget> mScoredTargets = new LinkedHashMap<>(); + private final String mReferrerPackage; + + public ResolverComparator(Context context, Intent intent, String referrerPackage) { + mCollator = Collator.getInstance(context.getResources().getConfiguration().locale); + String scheme = intent.getScheme(); + mHttp = "http".equals(scheme) || "https".equals(scheme); + mReferrerPackage = referrerPackage; + + mPm = context.getPackageManager(); + mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE); + + mCurrentTime = System.currentTimeMillis(); + mSinceTime = mCurrentTime - USAGE_STATS_PERIOD; + mStats = mUsm.queryAndAggregateUsageStats(mSinceTime, mCurrentTime); + } + + public void compute(List<ResolvedComponentInfo> targets) { + mScoredTargets.clear(); + + final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD; + + long mostRecentlyUsedTime = recentSinceTime + 1; + long mostTimeSpent = 1; + int mostLaunched = 1; + + for (ResolvedComponentInfo target : targets) { + final ScoredTarget scoredTarget + = new ScoredTarget(target.getResolveInfoAt(0).activityInfo); + mScoredTargets.put(target.name, scoredTarget); + final UsageStats pkStats = mStats.get(target.name.getPackageName()); + if (pkStats != null) { + // Only count recency for apps that weren't the caller + // since the caller is always the most recent. + // Persistent processes muck this up, so omit them too. + if (!target.name.getPackageName().equals(mReferrerPackage) + && !isPersistentProcess(target)) { + final long lastTimeUsed = pkStats.getLastTimeUsed(); + scoredTarget.lastTimeUsed = lastTimeUsed; + if (lastTimeUsed > mostRecentlyUsedTime) { + mostRecentlyUsedTime = lastTimeUsed; + } + } + final long timeSpent = pkStats.getTotalTimeInForeground(); + scoredTarget.timeSpent = timeSpent; + if (timeSpent > mostTimeSpent) { + mostTimeSpent = timeSpent; + } + final int launched = pkStats.mLaunchCount; + scoredTarget.launchCount = launched; + if (launched > mostLaunched) { + mostLaunched = launched; + } + } + } + + + if (DEBUG) { + Log.d(TAG, "compute - mostRecentlyUsedTime: " + mostRecentlyUsedTime + + " mostTimeSpent: " + mostTimeSpent + + " recentSinceTime: " + recentSinceTime + + " mostLaunched: " + mostLaunched); + } + + for (ScoredTarget target : mScoredTargets.values()) { + final float recency = (float) Math.max(target.lastTimeUsed - recentSinceTime, 0) + / (mostRecentlyUsedTime - recentSinceTime); + final float recencyScore = recency * recency * RECENCY_MULTIPLIER; + final float usageTimeScore = (float) target.timeSpent / mostTimeSpent; + final float launchCountScore = (float) target.launchCount / mostLaunched; + + target.score = recencyScore + usageTimeScore + launchCountScore; + if (DEBUG) { + Log.d(TAG, "Scores: recencyScore: " + recencyScore + + " usageTimeScore: " + usageTimeScore + + " launchCountScore: " + launchCountScore + + " - " + target); + } + } + } + + static boolean isPersistentProcess(ResolvedComponentInfo rci) { + if (rci != null && rci.getCount() > 0) { + return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags & + ApplicationInfo.FLAG_PERSISTENT) != 0; + } + return false; + } + + @Override + public int compare(ResolvedComponentInfo lhsp, ResolvedComponentInfo rhsp) { + final ResolveInfo lhs = lhsp.getResolveInfoAt(0); + final ResolveInfo rhs = rhsp.getResolveInfoAt(0); + + // We want to put the one targeted to another user at the end of the dialog. + if (lhs.targetUserId != UserHandle.USER_CURRENT) { + return 1; + } + + if (mHttp) { + // Special case: we want filters that match URI paths/schemes to be + // ordered before others. This is for the case when opening URIs, + // to make native apps go above browsers. + final boolean lhsSpecific = ResolverActivity.isSpecificUriMatch(lhs.match); + final boolean rhsSpecific = ResolverActivity.isSpecificUriMatch(rhs.match); + if (lhsSpecific != rhsSpecific) { + return lhsSpecific ? -1 : 1; + } + } + + if (mStats != null) { + final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName( + lhs.activityInfo.packageName, lhs.activityInfo.name)); + final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName( + rhs.activityInfo.packageName, rhs.activityInfo.name)); + final float diff = rhsTarget.score - lhsTarget.score; + + if (diff != 0) { + return diff > 0 ? 1 : -1; + } + } + + CharSequence sa = lhs.loadLabel(mPm); + if (sa == null) sa = lhs.activityInfo.name; + CharSequence sb = rhs.loadLabel(mPm); + if (sb == null) sb = rhs.activityInfo.name; + + return mCollator.compare(sa.toString().trim(), sb.toString().trim()); + } + + static class ScoredTarget { + public final ComponentInfo componentInfo; + public float score; + public long lastTimeUsed; + public long timeSpent; + public long launchCount; + + public ScoredTarget(ComponentInfo ci) { + componentInfo = ci; + } + + @Override + public String toString() { + return "ScoredTarget{" + componentInfo + + " score: " + score + + " lastTimeUsed: " + lastTimeUsed + + " timeSpent: " + timeSpent + + " launchCount: " + launchCount + + "}"; + } + } +} diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java index 65dc743..8c6b79b 100644 --- a/core/java/com/android/internal/logging/MetricsConstants.java +++ b/core/java/com/android/internal/logging/MetricsConstants.java @@ -208,6 +208,27 @@ public interface MetricsConstants { public static final int APPLICATIONS_USAGE_ACCESS_DETAIL = 183; public static final int APPLICATIONS_HIGH_POWER_APPS = 184; public static final int FUELGAUGE_HIGH_POWER_DETAILS = 185; + public static final int ACTION_LS_UNLOCK = 186; + public static final int ACTION_LS_SHADE = 187; + public static final int ACTION_LS_HINT = 188; + public static final int ACTION_LS_CAMERA = 189; + public static final int ACTION_LS_DIALER = 190; + public static final int ACTION_LS_LOCK = 191; + public static final int ACTION_LS_NOTE = 192; + public static final int ACTION_LS_QS = 193; + public static final int ACTION_SHADE_QS_PULL = 194; + public static final int ACTION_SHADE_QS_TAP = 195; + public static final int LOCKSCREEN = 196; + public static final int BOUNCER = 197; + public static final int SCREEN = 198; + public static final int NOTIFICATION_ALERT = 199; + public static final int ACTION_EMERGENCY_CALL = 200; + public static final int APPLICATIONS_MANAGE_ASSIST = 201; + public static final int PROCESS_STATS_SUMMARY = 202; + public static final int ACTION_ROTATION_LOCK = 203; + public static final int ACTION_NOTE_CONTROLS = 204; + public static final int ACTION_NOTE_INFO = 205; + public static final int ACTION_APP_NOTE_SETTINGS = 206; //aliases public static final int DEVICEINFO_STORAGE = DEVICEINFO_MEMORY; diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 2f21efd..230d96d 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -27,7 +27,6 @@ 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/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index c77d614..2d0989f 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -361,7 +361,7 @@ public final class FloatingToolbar { mParent = Preconditions.checkNotNull(parent); mContentContainer = createContentContainer(parent.getContext()); mPopupWindow = createPopupWindow(mContentContainer); - mDismissAnimation = createShrinkFadeOutFromBottomAnimation( + mDismissAnimation = createExitAnimation( mContentContainer, 150, // startDelay new AnimatorListenerAdapter() { @@ -371,7 +371,7 @@ public final class FloatingToolbar { mContentContainer.removeAllViews(); } }); - mHideAnimation = createShrinkFadeOutFromBottomAnimation( + mHideAnimation = createExitAnimation( mContentContainer, 0, // startDelay new AnimatorListenerAdapter() { @@ -561,7 +561,7 @@ public final class FloatingToolbar { * Performs the "show" animation on the floating popup. */ private void runShowAnimation() { - createGrowFadeInFromBottom(mContentContainer).start(); + createEnterAnimation(mContentContainer).start(); } /** @@ -1369,38 +1369,35 @@ public final class FloatingToolbar { } /** - * Creates a "grow and fade in from the bottom" animation for the specified view. + * Creates an "appear" animation for the specified view. * * @param view The view to animate */ - private static AnimatorSet createGrowFadeInFromBottom(View view) { - AnimatorSet growFadeInFromBottomAnimation = new AnimatorSet(); - growFadeInFromBottomAnimation.playTogether( - ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125), - ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125), - ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75), + private static AnimatorSet createEnterAnimation(View view) { + AnimatorSet animation = new AnimatorSet(); + animation.playTogether( + ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(200), // Make sure that view.x is always fixed throughout the duration of this animation. ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX())); - growFadeInFromBottomAnimation.setStartDelay(50); - return growFadeInFromBottomAnimation; + animation.setStartDelay(50); + return animation; } /** - * Creates a "shrink and fade out from bottom" animation for the specified view. + * Creates a "disappear" animation for the specified view. * * @param view The view to animate * @param startDelay The start delay of the animation * @param listener The animation listener */ - private static AnimatorSet createShrinkFadeOutFromBottomAnimation( + private static AnimatorSet createExitAnimation( View view, int startDelay, Animator.AnimatorListener listener) { - AnimatorSet shrinkFadeOutFromBottomAnimation = new AnimatorSet(); - shrinkFadeOutFromBottomAnimation.playTogether( - ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125), - ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75)); - shrinkFadeOutFromBottomAnimation.setStartDelay(startDelay); - shrinkFadeOutFromBottomAnimation.addListener(listener); - return shrinkFadeOutFromBottomAnimation; + AnimatorSet animation = new AnimatorSet(); + animation.playTogether( + ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(200)); + animation.setStartDelay(startDelay); + animation.addListener(listener); + return animation; } private static int getEstimatedToolbarHeight(Context context) { |
