diff options
97 files changed, 1151 insertions, 433 deletions
diff --git a/api/current.txt b/api/current.txt index 05d9b9bf5a67..5dd3839b48a9 100644 --- a/api/current.txt +++ b/api/current.txt @@ -69831,7 +69831,6 @@ package javax.net.ssl { public abstract class SSLSocketFactory extends javax.net.SocketFactory { ctor public SSLSocketFactory(); method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException; - method public java.net.Socket createSocket(java.net.Socket, java.io.InputStream, boolean) throws java.io.IOException; method public static synchronized javax.net.SocketFactory getDefault(); method public abstract java.lang.String[] getDefaultCipherSuites(); method public abstract java.lang.String[] getSupportedCipherSuites(); diff --git a/api/system-current.txt b/api/system-current.txt index 6e27ffbf8967..dfad7a2d6883 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -73739,7 +73739,6 @@ package javax.net.ssl { public abstract class SSLSocketFactory extends javax.net.SocketFactory { ctor public SSLSocketFactory(); method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException; - method public java.net.Socket createSocket(java.net.Socket, java.io.InputStream, boolean) throws java.io.IOException; method public static synchronized javax.net.SocketFactory getDefault(); method public abstract java.lang.String[] getDefaultCipherSuites(); method public abstract java.lang.String[] getSupportedCipherSuites(); diff --git a/api/test-current.txt b/api/test-current.txt index 5a265cc6bd84..9bafd5f74b14 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -70271,7 +70271,6 @@ package javax.net.ssl { public abstract class SSLSocketFactory extends javax.net.SocketFactory { ctor public SSLSocketFactory(); method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException; - method public java.net.Socket createSocket(java.net.Socket, java.io.InputStream, boolean) throws java.io.IOException; method public static synchronized javax.net.SocketFactory getDefault(); method public abstract java.lang.String[] getDefaultCipherSuites(); method public abstract java.lang.String[] getSupportedCipherSuites(); diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index d71573f7ca50..c4193f647c32 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -1473,7 +1473,7 @@ public final class Pm { ClearDataObserver obs = new ClearDataObserver(); try { mPm.freeStorageAndNotify(volumeUuid, sizeVal, - StorageManager.FLAG_ALLOCATE_DEFY_RESERVED, obs); + StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED, obs); synchronized (obs) { while (!obs.finished) { try { diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index e686a89accef..ee89ca8d55e2 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -1469,24 +1469,21 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio if (!mSelfPulse) { return; } - AnimationHandler handler = AnimationHandler.getInstance(); - handler.addOneShotCommitCallback(this); + getAnimationHandler().addOneShotCommitCallback(this); } private void removeAnimationCallback() { if (!mSelfPulse) { return; } - AnimationHandler handler = AnimationHandler.getInstance(); - handler.removeCallback(this); + getAnimationHandler().removeCallback(this); } private void addAnimationCallback(long delay) { if (!mSelfPulse) { return; } - AnimationHandler handler = AnimationHandler.getInstance(); - handler.addAnimationFrameCallback(this, delay); + getAnimationHandler().addAnimationFrameCallback(this, delay); } /** @@ -1643,4 +1640,12 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio public void setAllowRunningAsynchronously(boolean mayRunAsync) { // It is up to subclasses to support this, if they can. } + + /** + * @return The {@link AnimationHandler} that will be used to schedule updates for this animator. + * @hide + */ + public AnimationHandler getAnimationHandler() { + return AnimationHandler.getInstance(); + } } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index e672ada3cbb4..b331d84010d0 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1947,4 +1947,13 @@ public class AppOpsManager { public void finishOp(int op) { finishOp(op, Process.myUid(), mContext.getOpPackageName()); } + + /** @hide */ + public boolean isOperationActive(int code, int uid, String packageName) { + try { + return mService.isOperationActive(code, uid, packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java index 3665d1b85bcb..4ee38fe4990e 100644 --- a/core/java/android/companion/BluetoothDeviceFilterUtils.java +++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java @@ -58,7 +58,7 @@ public class BluetoothDeviceFilterUtils { static boolean matchesAddress(String deviceAddress, BluetoothDevice device) { final boolean result = deviceAddress == null - || (device == null || !deviceAddress.equals(device.getAddress())); + || (device != null && deviceAddress.equals(device.getAddress())); if (DEBUG) debugLogMatchResult(result, device, deviceAddress); return result; } diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 9d46da16965e..64e464c318d3 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -44,6 +44,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.os.storage.StorageManager; import android.text.TextUtils; import android.util.Log; import android.util.MathUtils; @@ -1376,6 +1377,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)}, * {@link ParcelFileDescriptor#createReliablePipe()}, or * {@link ParcelFileDescriptor#createReliableSocketPair()}. + * <p> + * If you need to return a large file that isn't backed by a real file on + * disk, such as a file on a network share or cloud storage service, + * consider using + * {@link StorageManager#openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler)} + * which will let you to stream the content on-demand. * * <p class="note">For use in Intents, you will want to implement {@link #getType} * to return the appropriate MIME type for the data returned here with diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 9b0bab427478..fdb0f2bae64b 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -6852,7 +6852,7 @@ public class PackageParser { ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName); } ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state); - ai.resourceDirs = state.resourceDirs; + ai.resourceDirs = state.overlayPaths; } public static ApplicationInfo generateApplicationInfo(Package p, int flags, @@ -7000,6 +7000,7 @@ public class PackageParser { return null; } if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) { + updateApplicationInfo(a.info.applicationInfo, flags, state); return a.info; } // Make shallow copies so we can store the metadata safely @@ -7088,6 +7089,7 @@ public class PackageParser { return null; } if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) { + updateApplicationInfo(s.info.applicationInfo, flags, state); return s.info; } // Make shallow copies so we can store the metadata safely @@ -7183,6 +7185,7 @@ public class PackageParser { if (!copyNeeded(flags, p.owner, state, p.metaData, userId) && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 || p.info.uriPermissionPatterns == null)) { + updateApplicationInfo(p.info.applicationInfo, flags, state); return p.info; } // Make shallow copies so we can store the metadata safely diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 4e53914a3c68..470336cc70c7 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -55,7 +55,7 @@ public class PackageUserState { public ArraySet<String> disabledComponents; public ArraySet<String> enabledComponents; - public String[] resourceDirs; + public String[] overlayPaths; public PackageUserState() { installed = true; @@ -83,8 +83,8 @@ public class PackageUserState { installReason = o.installReason; disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents); enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents); - resourceDirs = - o.resourceDirs == null ? null : Arrays.copyOf(o.resourceDirs, o.resourceDirs.length); + overlayPaths = + o.overlayPaths == null ? null : Arrays.copyOf(o.overlayPaths, o.overlayPaths.length); } /** diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java index c66a3a40718f..8296b7a915a4 100644 --- a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java +++ b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java @@ -15,13 +15,13 @@ */ package android.hardware.camera2.dispatch; +import static com.android.internal.util.Preconditions.checkNotNull; + import android.hardware.camera2.utils.UncheckedThrow; import java.lang.reflect.Method; import java.util.concurrent.ConcurrentHashMap; -import static com.android.internal.util.Preconditions.*; - /** * Invoke a method on a dispatchable by its name (without knowing the {@code Method} ahead of time). * @@ -31,6 +31,7 @@ public class MethodNameInvoker<T> { private final Dispatchable<T> mTarget; private final Class<T> mTargetClass; + private final Method[] mTargetClassMethods; private final ConcurrentHashMap<String, Method> mMethods = new ConcurrentHashMap<>(); @@ -42,6 +43,7 @@ public class MethodNameInvoker<T> { */ public MethodNameInvoker(Dispatchable<T> target, Class<T> targetClass) { mTargetClass = targetClass; + mTargetClassMethods = targetClass.getMethods(); mTarget = target; } @@ -68,7 +70,7 @@ public class MethodNameInvoker<T> { Method targetMethod = mMethods.get(methodName); if (targetMethod == null) { - for (Method method : mTargetClass.getMethods()) { + for (Method method : mTargetClassMethods) { // TODO future: match types of params if possible if (method.getName().equals(methodName) && (params.length == method.getParameterTypes().length) ) { diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index 92f7f319a14b..50855bb349d9 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -293,7 +293,7 @@ interface IStorageManager { ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74; long getCacheQuotaBytes(String volumeUuid, int uid) = 75; long getCacheSizeBytes(String volumeUuid, int uid) = 76; - long getAllocatableBytes(String volumeUuid, int flags) = 77; - void allocateBytes(String volumeUuid, long bytes, int flags) = 78; + long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) = 77; + void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) = 78; void secdiscard(in String path) = 79; } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 504673529238..f2aa113ea28e 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -29,6 +29,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.WorkerThread; +import android.app.Activity; import android.app.ActivityThread; import android.content.ContentResolver; import android.content.Context; @@ -159,6 +160,12 @@ public class StorageManager { * If the sending application has a specific storage device or allocation * size in mind, they can optionally define {@link #EXTRA_UUID} or * {@link #EXTRA_REQUESTED_BYTES}, respectively. + * <p> + * This intent should be launched using + * {@link Activity#startActivityForResult(Intent, int)} so that the user + * knows which app is requesting the storage space. The returned result will + * be {@link Activity#RESULT_OK} if the requested space was made available, + * or {@link Activity#RESULT_CANCELED} otherwise. */ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; @@ -1174,7 +1181,7 @@ public class StorageManager { * * @hide */ - public long getStorageCacheBytes(File path) { + public long getStorageCacheBytes(File path, @AllocateFlags int flags) { final long cachePercent = Settings.Global.getInt(mResolver, Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE, DEFAULT_CACHE_PERCENTAGE); final long cacheBytes = (path.getTotalSpace() * cachePercent) / 100; @@ -1182,7 +1189,16 @@ public class StorageManager { final long maxCacheBytes = Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, DEFAULT_CACHE_MAX_BYTES); - return Math.min(cacheBytes, maxCacheBytes); + final long result = Math.min(cacheBytes, maxCacheBytes); + if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { + return 0; + } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) { + return 0; + } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) { + return result / 2; + } else { + return result; + } } /** @@ -1467,15 +1483,26 @@ public class StorageManager { } /** - * Opens seekable ParcelFileDescriptor that routes file operation requests to - * ProxyFileDescriptorCallback. + * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level + * I/O requests back to the given {@link ProxyFileDescriptorCallback}. + * <p> + * This can be useful when you want to provide quick access to a large file + * that isn't backed by a real file on disk, such as a file on a network + * share, cloud storage service, etc. As an example, you could respond to a + * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)} + * request by returning a {@link ParcelFileDescriptor} created with this + * method, and then stream the content on-demand as requested. + * <p> + * Another useful example might be where you have an encrypted file that + * you're willing to decrypt on-demand, but where you want to avoid + * persisting the cleartext version. * * @param mode The desired access mode, must be one of - * {@link ParcelFileDescriptor#MODE_READ_ONLY}, - * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or - * {@link ParcelFileDescriptor#MODE_READ_WRITE} - * @param callback Callback to process file operation requests issued on returned file - * descriptor. + * {@link ParcelFileDescriptor#MODE_READ_ONLY}, + * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or + * {@link ParcelFileDescriptor#MODE_READ_WRITE} + * @param callback Callback to process file operation requests issued on + * returned file descriptor. * @param handler Handler that invokes callback methods. * @return Seekable ParcelFileDescriptor. * @throws IOException @@ -1487,7 +1514,6 @@ public class StorageManager { return openProxyFileDescriptor(mode, callback, handler, null); } - /** {@hide} */ @VisibleForTesting public int getProxyFileDescriptorMountPointId() { @@ -1628,17 +1654,26 @@ public class StorageManager { public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0; /** - * Flag indicating that a disk space allocation request should defy any - * reserved disk space. + * Flag indicating that a disk space allocation request should be allowed to + * clear up to all reserved disk space. + * + * @hide + */ + public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1; + + /** + * Flag indicating that a disk space allocation request should be allowed to + * clear up to half of all reserved disk space. * * @hide */ - public static final int FLAG_ALLOCATE_DEFY_RESERVED = 1 << 1; + public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2; /** @hide */ @IntDef(flag = true, value = { FLAG_ALLOCATE_AGGRESSIVE, - FLAG_ALLOCATE_DEFY_RESERVED, + FLAG_ALLOCATE_DEFY_ALL_RESERVED, + FLAG_ALLOCATE_DEFY_HALF_RESERVED, }) @Retention(RetentionPolicy.SOURCE) public @interface AllocateFlags {} @@ -1660,6 +1695,10 @@ public class StorageManager { * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help * involve the user in freeing up disk space. + * <p> + * If you're progressively allocating an unbounded amount of storage space + * (such as when recording a video) you should avoid calling this method + * more than once every 30 seconds. * <p class="note"> * Note: if your app uses the {@code android:sharedUserId} manifest feature, * then allocatable space for all packages in your shared UID is tracked @@ -1677,6 +1716,7 @@ public class StorageManager { * @throws IOException when the storage device isn't present, or when it * doesn't support allocating space. */ + @WorkerThread public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid) throws IOException { return getAllocatableBytes(storageUuid, 0); @@ -1684,11 +1724,13 @@ public class StorageManager { /** @hide */ @SystemApi + @WorkerThread @SuppressLint("Doclava125") public long getAllocatableBytes(@NonNull UUID storageUuid, @RequiresPermission @AllocateFlags int flags) throws IOException { try { - return mStorageManager.getAllocatableBytes(convert(storageUuid), flags); + return mStorageManager.getAllocatableBytes(convert(storageUuid), flags, + mContext.getOpPackageName()); } catch (ParcelableException e) { e.maybeRethrow(IOException.class); throw new RuntimeException(e); @@ -1699,6 +1741,7 @@ public class StorageManager { /** @removed */ @Deprecated + @WorkerThread @SuppressLint("Doclava125") public long getAllocatableBytes(@NonNull File path, @RequiresPermission @AllocateFlags int flags) throws IOException { @@ -1717,6 +1760,10 @@ public class StorageManager { * subject to race conditions. If possible, consider using * {@link #allocateBytes(FileDescriptor, long, int)} which will guarantee * that bytes are allocated to an opened file. + * <p> + * If you're progressively allocating an unbounded amount of storage space + * (such as when recording a video) you should avoid calling this method + * more than once every 60 seconds. * * @param storageUuid the UUID of the storage volume where you'd like to * allocate disk space. The UUID for a specific path can be @@ -1727,6 +1774,7 @@ public class StorageManager { * trouble allocating the requested space. * @see #getAllocatableBytes(UUID, int) */ + @WorkerThread public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes) throws IOException { allocateBytes(storageUuid, bytes, 0); @@ -1734,11 +1782,13 @@ public class StorageManager { /** @hide */ @SystemApi + @WorkerThread @SuppressLint("Doclava125") public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags) throws IOException { try { - mStorageManager.allocateBytes(convert(storageUuid), bytes, flags); + mStorageManager.allocateBytes(convert(storageUuid), bytes, flags, + mContext.getOpPackageName()); } catch (ParcelableException e) { e.maybeRethrow(IOException.class); } catch (RemoteException e) { @@ -1748,6 +1798,7 @@ public class StorageManager { /** @removed */ @Deprecated + @WorkerThread @SuppressLint("Doclava125") public void allocateBytes(@NonNull File path, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags) throws IOException { @@ -1766,6 +1817,10 @@ public class StorageManager { * otherwise it will throw if fast allocation is not possible. Fast * allocation is typically only supported in private app data directories, * and on shared/external storage devices which are emulated. + * <p> + * If you're progressively allocating an unbounded amount of storage space + * (such as when recording a video) you should avoid calling this method + * more than once every 60 seconds. * * @param fd the open file that you'd like to allocate disk space for. * @param bytes the number of bytes to allocate. This is the desired final @@ -1779,12 +1834,14 @@ public class StorageManager { * @see #getAllocatableBytes(UUID, int) * @see Environment#isExternalStorageEmulated(File) */ + @WorkerThread public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException { allocateBytes(fd, bytes, 0); } /** @hide */ @SystemApi + @WorkerThread @SuppressLint("Doclava125") public void allocateBytes(FileDescriptor fd, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags) throws IOException { diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index ef78559e2b53..679a9cd92bc2 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1196,6 +1196,12 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb mBackgroundControl.deferTransactionUntil(handle, frame); } + @Override + public void deferTransactionUntil(Surface barrier, long frame) { + super.deferTransactionUntil(barrier, frame); + mBackgroundControl.deferTransactionUntil(barrier, frame); + } + void updateBackgroundVisibility() { if (mOpaque && mVisible) { mBackgroundControl.show(); diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 35d4ba81bd69..7a119b4351c0 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -48,4 +48,6 @@ interface IAppOpsService { void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle); void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in String[] exceptionPackages); void removeUser(int userHandle); + + boolean isOperationActive(int code, int uid, String packageName); } diff --git a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java new file mode 100644 index 000000000000..931eb9901288 --- /dev/null +++ b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.graphics; + +import android.animation.AnimationHandler.AnimationFrameCallbackProvider; +import android.view.Choreographer; + +/** + * Provider of timing pulse that uses SurfaceFlinger Vsync Choreographer for frame callbacks. + * + * @hide + */ +public final class SfVsyncFrameCallbackProvider implements AnimationFrameCallbackProvider { + + private final Choreographer mChoreographer = Choreographer.getSfInstance(); + + @Override + public void postFrameCallback(Choreographer.FrameCallback callback) { + mChoreographer.postFrameCallback(callback); + } + + @Override + public void postCommitCallback(Runnable runnable) { + mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null); + } + + @Override + public long getFrameTime() { + return mChoreographer.getFrameTime(); + } + + @Override + public long getFrameDelay() { + return Choreographer.getFrameDelay(); + } + + @Override + public void setFrameDelay(long delay) { + Choreographer.setFrameDelay(delay); + } +}
\ No newline at end of file diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java index 96b443d28abc..1f84061a5978 100644 --- a/core/java/com/android/internal/util/CollectionUtils.java +++ b/core/java/com/android/internal/util/CollectionUtils.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.function.Function; import java.util.stream.Stream; @@ -101,7 +102,7 @@ public class CollectionUtils { /** * Returns the given list, or an immutable empty list if the provided list is null * - * This can be used to guaranty null-safety without paying the price of extra allocations + * This can be used to guarantee null-safety without paying the price of extra allocations * * @see Collections#emptyList */ @@ -110,6 +111,17 @@ public class CollectionUtils { } /** + * Returns the given set, or an immutable empty set if the provided set is null + * + * This can be used to guarantee null-safety without paying the price of extra allocations + * + * @see Collections#emptySet + */ + public static @NonNull <T> Set<T> emptyIfNull(@Nullable Set<T> cur) { + return cur == null ? Collections.emptySet() : cur; + } + + /** * Returns the size of the given list, or 0 if the list is null */ public static int size(@Nullable Collection<?> cur) { diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java index d834e6383acd..52357ac486c2 100644 --- a/core/java/com/android/internal/view/TooltipPopup.java +++ b/core/java/com/android/internal/view/TooltipPopup.java @@ -25,7 +25,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import android.view.WindowManagerGlobal; -import android.widget.PopupWindow; import android.widget.TextView; public class TooltipPopup { @@ -33,7 +32,6 @@ public class TooltipPopup { private final Context mContext; - private final PopupWindow mPopupWindow; private final View mContentView; private final TextView mMessageView; @@ -45,8 +43,6 @@ public class TooltipPopup { public TooltipPopup(Context context) { mContext = context; - mPopupWindow = new PopupWindow(context); - mPopupWindow.setBackgroundDrawable(null); mContentView = LayoutInflater.from(mContext).inflate( com.android.internal.R.layout.tooltip, null); mMessageView = (TextView) mContentView.findViewById( @@ -74,16 +70,17 @@ public class TooltipPopup { computePosition(anchorView, anchorX, anchorY, fromTouch, mLayoutParams); - mPopupWindow.setContentView(mContentView); - mPopupWindow.showAtLocation( - anchorView, mLayoutParams.gravity, mLayoutParams.x, mLayoutParams.y); + WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); + wm.addView(mContentView, mLayoutParams); } public void hide() { if (!isShowing()) { return; } - mPopupWindow.dismiss(); + + WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); + wm.removeView(mContentView); } public View getContentView() { @@ -91,7 +88,7 @@ public class TooltipPopup { } public boolean isShowing() { - return mPopupWindow.isShowing(); + return mContentView.getParent() != null; } public void updateContent(CharSequence tooltipText) { @@ -100,6 +97,8 @@ public class TooltipPopup { private void computePosition(View anchorView, int anchorX, int anchorY, boolean fromTouch, WindowManager.LayoutParams outParams) { + outParams.token = anchorView.getWindowToken(); + final int tooltipPreciseAnchorThreshold = mContext.getResources().getDimensionPixelOffset( com.android.internal.R.dimen.tooltip_precise_anchor_threshold); diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index de67c50e7195..26b00344b789 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -29,6 +29,7 @@ #include <sys/types.h> #include <unistd.h> +#include <android-base/stringprintf.h> #include <binder/IInterface.h> #include <binder/IServiceManager.h> #include <binder/IPCThreadState.h> @@ -194,10 +195,34 @@ static void report_exception(JNIEnv* env, jthrowable excep, const char* msg) /* * It's an Error: Reraise the exception and ask the runtime to abort. */ + + // Try to get the exception string. Sometimes logcat isn't available, + // so try to add it to the abort message. + std::string exc_msg = "(Unknown exception message)"; + { + ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(excep)); + jmethodID method_id = env->GetMethodID(exc_class.get(), + "toString", + "()Ljava/lang/String;"); + ScopedLocalRef<jstring> jstr( + env, + reinterpret_cast<jstring>( + env->CallObjectMethod(excep, method_id))); + env->ExceptionClear(); // Just for good measure. + if (jstr.get() != nullptr) { + ScopedUtfChars jstr_utf(env, jstr.get()); + exc_msg = jstr_utf.c_str(); + } + } + env->Throw(excep); ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : "); env->ExceptionDescribe(); - env->FatalError("java.lang.Error thrown during binder transaction."); + + std::string error_msg = base::StringPrintf( + "java.lang.Error thrown during binder transaction: %s", + exc_msg.c_str()); + env->FatalError(error_msg.c_str()); } bail: diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 004ecfcd12cf..b4c5025e2f64 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -454,6 +454,7 @@ <protected-broadcast android:name="com.android.server.NetworkTimeUpdateService.action.POLL" /> <protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" /> <protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" /> + <protected-broadcast android:name="com.android.settings.bluetooth.ACTION_DISMISS_PAIRING" /> <protected-broadcast android:name="NotificationManagerService.TIMEOUT" /> <protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" /> diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java index 2a4ab0f550e5..3b29a6cd7b6c 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java @@ -20,6 +20,8 @@ import static android.companion.BluetoothDeviceFilterUtils.getDeviceDisplayNameI import static android.companion.BluetoothDeviceFilterUtils.getDeviceMacAddress; import static com.android.internal.util.ArrayUtils.isEmpty; +import static com.android.internal.util.CollectionUtils.emptyIfNull; +import static com.android.internal.util.CollectionUtils.size; import android.annotation.NonNull; import android.annotation.Nullable; @@ -154,6 +156,25 @@ public class DeviceDiscoveryService extends Service { onReadyToShowUI(); } + // If filtering to get single device by mac address, also search in the set of already + // bonded devices to allow linking those directly + String singleMacAddressFilter = null; + if (mRequest.isSingleDevice()) { + int numFilters = size(mBluetoothFilters); + for (int i = 0; i < numFilters; i++) { + BluetoothDeviceFilter filter = mBluetoothFilters.get(i); + if (!TextUtils.isEmpty(filter.getAddress())) { + singleMacAddressFilter = filter.getAddress(); + break; + } + } + } + if (singleMacAddressFilter != null) { + for (BluetoothDevice dev : emptyIfNull(mBluetoothAdapter.getBondedDevices())) { + onDeviceFound(DeviceFilterPair.findMatch(dev, mBluetoothFilters)); + } + } + if (shouldScan(mBluetoothFilters)) { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); @@ -211,6 +232,8 @@ public class DeviceDiscoveryService extends Service { } private void onDeviceFound(@Nullable DeviceFilterPair device) { + if (device == null) return; + if (mDevicesFound.contains(device)) { return; } @@ -444,12 +467,9 @@ public class DeviceDiscoveryService extends Service { } for (int i = 0; i < scanResults.size(); i++) { - DeviceFilterPair<android.net.wifi.ScanResult> deviceFilterPair = - DeviceFilterPair.findMatch(scanResults.get(i), mWifiFilters); - if (deviceFilterPair != null) onDeviceFound(deviceFilterPair); + onDeviceFound(DeviceFilterPair.findMatch(scanResults.get(i), mWifiFilters)); } } - } } } diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 06a65c4dbf21..c879100aef9c 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -341,7 +341,7 @@ <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">^1</xliff:g> - <xliff:g id="TIME">^2</xliff:g> حتى يكتمل الشحن"</string> <string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">^1</xliff:g> - <xliff:g id="TIME">^2</xliff:g>"</string> <string name="battery_info_status_unknown" msgid="196130600938058547">"غير معروف"</string> - <string name="battery_info_status_charging" msgid="1705179948350365604">"جاري الشحن"</string> + <string name="battery_info_status_charging" msgid="1705179948350365604">"جارٍ الشحن"</string> <string name="battery_info_status_charging_lower" msgid="8689770213898117994">"جارٍ الشحن"</string> <string name="battery_info_status_discharging" msgid="310932812698268588">"لا يتم الشحن"</string> <string name="battery_info_status_not_charging" msgid="2820070506621483576">"لا يتم الشحن"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 8b834eec5dde..fbdb394976dc 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -281,7 +281,7 @@ <string name="app_process_limit_title" msgid="4280600650253107163">"Límita processos en segon pla"</string> <string name="show_all_anrs" msgid="28462979638729082">"Tots els errors sense resposta"</string> <string name="show_all_anrs_summary" msgid="641908614413544127">"Informa que una aplicació en segon pla no respon"</string> - <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Avisos del canal de notificacions"</string> + <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Mostra avisos del canal de notificacions"</string> <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Mostra un avís a la pantalla quan una app publica una notificació sense canal vàlid"</string> <string name="force_allow_on_external" msgid="3215759785081916381">"Força permís d\'aplicacions a l\'emmagatzem. extern"</string> <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Permet que qualsevol aplicació es pugui escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index c73a44338ed0..36117ed3c706 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -28,12 +28,9 @@ <string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"אין חיבור לרשת, כי איכות הרשת נמוכה"</string> <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"כשל בחיבור Wi-Fi"</string> <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"בעיית אימות"</string> - <!-- no translation found for wifi_cant_connect (5410016875644565884) --> - <skip /> - <!-- no translation found for wifi_cant_connect_to_ap (1222553274052685331) --> - <skip /> - <!-- no translation found for wifi_check_password_try_again (516958988102584767) --> - <skip /> + <string name="wifi_cant_connect" msgid="5410016875644565884">"לא ניתן להתחבר"</string> + <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"לא ניתן להתחבר אל <xliff:g id="AP_NAME">%1$s</xliff:g>"</string> + <string name="wifi_check_password_try_again" msgid="516958988102584767">"בדוק את הסיסמה ונסה שוב"</string> <string name="wifi_not_in_range" msgid="1136191511238508967">"מחוץ לטווח"</string> <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"לא יתבצע חיבור באופן אוטומטי"</string> <string name="wifi_no_internet" msgid="3880396223819116454">"אין גישה לאינטרנט"</string> @@ -45,8 +42,7 @@ <string name="wifi_connected_no_internet" msgid="3149853966840874992">"מחובר. אין אינטרנט"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"איטית מאוד"</string> <string name="speed_label_slow" msgid="813109590815810235">"איטית"</string> - <!-- no translation found for speed_label_okay (2331665440671174858) --> - <skip /> + <string name="speed_label_okay" msgid="2331665440671174858">"אישור"</string> <string name="speed_label_medium" msgid="3175763313268941953">"בינונית"</string> <string name="speed_label_fast" msgid="7715732164050975057">"מהירה"</string> <string name="speed_label_very_fast" msgid="2265363430784523409">"מהירה מאוד"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 5fc93d0ec17c..b2de42177ccc 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -28,12 +28,9 @@ <string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"Желі байланысының сапасы төмен болғандықтан қосылмады"</string> <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi байланысының қатесі"</string> <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Растау мәселесі"</string> - <!-- no translation found for wifi_cant_connect (5410016875644565884) --> - <skip /> - <!-- no translation found for wifi_cant_connect_to_ap (1222553274052685331) --> - <skip /> - <!-- no translation found for wifi_check_password_try_again (516958988102584767) --> - <skip /> + <string name="wifi_cant_connect" msgid="5410016875644565884">"Қосылу мүмкін емес"</string> + <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"\"<xliff:g id="AP_NAME">%1$s</xliff:g>\" қолданбасына қосылу мүмкін емес"</string> + <string name="wifi_check_password_try_again" msgid="516958988102584767">"Құпия сөзді тексеріп, әрекетті қайталаңыз"</string> <string name="wifi_not_in_range" msgid="1136191511238508967">"Аумақта жоқ"</string> <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматты қосылмайды"</string> <string name="wifi_no_internet" msgid="3880396223819116454">"Интернетпен байланыс жоқ"</string> @@ -45,8 +42,7 @@ <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Қосылған, интернет жоқ"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"Өте баяу"</string> <string name="speed_label_slow" msgid="813109590815810235">"Баяу"</string> - <!-- no translation found for speed_label_okay (2331665440671174858) --> - <skip /> + <string name="speed_label_okay" msgid="2331665440671174858">"Жарайды"</string> <string name="speed_label_medium" msgid="3175763313268941953">"Орташа"</string> <string name="speed_label_fast" msgid="7715732164050975057">"Жылдам"</string> <string name="speed_label_very_fast" msgid="2265363430784523409">"Өте жылдам"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 76541a195438..4e5873e21640 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -41,10 +41,10 @@ <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s မှတစ်ဆင့်ရနိုင်သည်"</string> <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ချိတ်ဆက်ထားသည်၊ အင်တာနက်မရှိ"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"အလွန်နှေး"</string> - <string name="speed_label_slow" msgid="813109590815810235">"နှေးသည်"</string> + <string name="speed_label_slow" msgid="813109590815810235">"နှေး"</string> <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string> <string name="speed_label_medium" msgid="3175763313268941953">"အတော်အသင့်"</string> - <string name="speed_label_fast" msgid="7715732164050975057">"မြန်သည်"</string> + <string name="speed_label_fast" msgid="7715732164050975057">"မြန်"</string> <string name="speed_label_very_fast" msgid="2265363430784523409">"အလွန်မြန်"</string> <string name="bluetooth_disconnected" msgid="6557104142667339895">"ချိတ်ဆက်မှုပြတ်တောက်သည်"</string> <string name="bluetooth_disconnecting" msgid="8913264760027764974">"အဆက်အသွယ်ဖြတ်တောက်သည်"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index bbd3569ed9cc..70cc95a2c2db 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -28,8 +28,8 @@ <string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"Sifatsiz tarmoq sababli ulanib bo‘lmadi"</string> <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi ulanishini o‘rnatib bo‘lmadi"</string> <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tasdiqdan o‘tishda muammo"</string> - <string name="wifi_cant_connect" msgid="5410016875644565884">"Ulanib bo‘lmadi"</string> - <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"“<xliff:g id="AP_NAME">%1$s</xliff:g>” tarmog‘iga ulanib bo‘lmadi"</string> + <string name="wifi_cant_connect" msgid="5410016875644565884">"Tarmoqqa ulanilmadi"</string> + <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"“<xliff:g id="AP_NAME">%1$s</xliff:g>” nomli tarmoqqa ulanilmadi"</string> <string name="wifi_check_password_try_again" msgid="516958988102584767">"Parolni tekshirib, qaytadan urining"</string> <string name="wifi_not_in_range" msgid="1136191511238508967">"Xizmat doirasidan tashqarida"</string> <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Avtomatik ravishda ulanilmaydi"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java index 9d09737a14dc..e067de1a5e7a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java @@ -34,6 +34,8 @@ public final class CategoryKey { public static final String CATEGORY_SOUND = "com.android.settings.category.ia.sound"; public static final String CATEGORY_STORAGE = "com.android.settings.category.ia.storage"; public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security"; + public static final String CATEGORY_SECURITY_LOCKSCREEN = + "com.android.settings.category.ia.lockscreen"; public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts"; public static final String CATEGORY_SYSTEM = "com.android.settings.category.ia.system"; public static final String CATEGORY_SYSTEM_LANGUAGE = diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java index 40353e7489b4..9fc8a9607cba 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java @@ -54,13 +54,14 @@ public class CategoryKeyTest { allKeys.add(CategoryKey.CATEGORY_SOUND); allKeys.add(CategoryKey.CATEGORY_STORAGE); allKeys.add(CategoryKey.CATEGORY_SECURITY); + allKeys.add(CategoryKey.CATEGORY_SECURITY_LOCKSCREEN); allKeys.add(CategoryKey.CATEGORY_ACCOUNT); allKeys.add(CategoryKey.CATEGORY_SYSTEM); allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE); allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT); // DO NOT REMOVE ANYTHING ABOVE - assertThat(allKeys.size()).isEqualTo(13); + assertThat(allKeys.size()).isEqualTo(14); } } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java new file mode 100644 index 000000000000..3ca5690af474 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java @@ -0,0 +1,21 @@ +package com.android.systemui.plugins; + +import com.android.systemui.plugins.annotations.ProvidesInterface; + +@ProvidesInterface(action = DozeServicePlugin.ACTION, version = DozeServicePlugin.VERSION) +public interface DozeServicePlugin extends Plugin { + String ACTION = "com.android.systemui.action.PLUGIN_DOZE"; + int VERSION = 1; + + public interface RequestDoze { + void onRequestShowDoze(); + + void onRequestHideDoze(); + } + + void onDreamingStarted(); + + void onDreamingStopped(); + + void setDozeRequester(RequestDoze requester); +} diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 96849d3b66c0..9b28bdaa0e03 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -161,7 +161,9 @@ <string name="accessibility_no_sims" msgid="3957997018324995781">"Keine SIM-Karte"</string> <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Netzwerk des Mobilfunkanbieters wird gewechselt"</string> <string name="accessibility_battery_details" msgid="7645516654955025422">"Akkudetails öffnen"</string> - <string name="accessibility_battery_level" msgid="7451474187113371965">"Akku bei <xliff:g id="NUMBER">%d</xliff:g> Prozent."</string> + <!-- String.format failed for translation --> + <!-- no translation found for accessibility_battery_level (7451474187113371965) --> + <skip /> <!-- String.format failed for translation --> <!-- no translation found for accessibility_battery_level_charging (1147587904439319646) --> <skip /> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 11f82648c732..459b61caa31a 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -553,7 +553,7 @@ <string name="notification_channel_disabled" msgid="2139193533791840539">"သင်သည် ဤအကြောင်းကြားချက်များကို နောက်ထပ် လက်ခံရရှိတော့မည် မဟုတ်ပါ"</string> <string name="notification_num_channels" msgid="2048144408999179471">"အကြောင်းကြားချက် အမျိုးအစား <xliff:g id="NUMBER">%d</xliff:g> ခု"</string> <string name="notification_default_channel_desc" msgid="2506053815870808359">"ဤအက်ပ်တွင် အကြောင်းကြားချက် အမျိုးအစားများ မရှိပါ"</string> - <string name="notification_unblockable_desc" msgid="3561016061737896906">"ဤအက်ပ်မှပို့သော အကြောင်းအကြားချက်များကို ပိတ်ထား၍မရပါ"</string> + <string name="notification_unblockable_desc" msgid="3561016061737896906">"ဤအက်ပ်မှပို့သော အကြောင်းကြားချက်များကို ပိတ်ထား၍မရပါ"</string> <plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663"> <item quantity="other">ဤအက်ပ်ရှိ အကြောင်းကြားချက်အမျိုးအစား <xliff:g id="NUMBER_1">%d</xliff:g> ခု အနက်မှ ၁ ခု</item> <item quantity="one">ဤအက်ပ်ရှိ အကြောင်းကြားချက်အမျိုးအစား <xliff:g id="NUMBER_0">%d</xliff:g> ခု အနက်မှ ၁ ခု</item> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index d3cbe4aa578f..81ca23082367 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -262,6 +262,9 @@ <!-- Doze: alpha to apply to small icons when dozing --> <integer name="doze_small_icon_alpha">222</integer><!-- 87% of 0xff --> + <!-- Doze: whether the double tap sensor reports 2D touch coordinates --> + <bool name="doze_double_tap_reports_touch_coordinates">false</bool> + <!-- Hotspot tile: number of days to show after feature is used. --> <integer name="days_to_show_hotspot_tile">30</integer> diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index 3e424d05373a..5aaa6c78f5fd 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -38,6 +38,8 @@ public interface DozeHost { void setAnimateWakeup(boolean animateWakeup); + void onDoubleTap(float x, float y); + interface Callback { default void onNotificationHeadsUp() {} default void onPowerSaveChanged(boolean active) {} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 73f522244a60..23da716706d3 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -81,17 +81,18 @@ public class DozeSensors { mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION), null /* setting */, dozeParameters.getPulseOnSigMotion(), - DozeLog.PULSE_REASON_SENSOR_SIGMOTION), + DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */), mPickupSensor = new TriggerSensor( mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE), Settings.Secure.DOZE_PULSE_ON_PICK_UP, config.pulseOnPickupAvailable(), - DozeLog.PULSE_REASON_SENSOR_PICKUP), + DozeLog.PULSE_REASON_SENSOR_PICKUP, false /* touchCoords */), new TriggerSensor( findSensorWithType(config.doubleTapSensorType()), Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, true /* configured */, - DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP) + DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP, + dozeParameters.doubleTapReportsTouchCoordinates()) }; mProxSensor = new ProxSensor(); @@ -207,16 +208,19 @@ public class DozeSensors { final boolean mConfigured; final int mPulseReason; final String mSetting; + final boolean mReportsTouchCoordinates; private boolean mRequested; private boolean mRegistered; private boolean mDisabled; - public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason) { + public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason, + boolean reportsTouchCoordinates) { mSensor = sensor; mSetting = setting; mConfigured = configured; mPulseReason = pulseReason; + mReportsTouchCoordinates = reportsTouchCoordinates; } public void setListening(boolean listen) { @@ -276,7 +280,13 @@ public class DozeSensors { } mRegistered = false; - mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck); + float screenX = -1; + float screenY = -1; + if (mReportsTouchCoordinates && event.values.length >= 2) { + screenX = event.values[0]; + screenY = event.values[1]; + } + mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck, screenX, screenY); updateListener(); // reregister, this sensor only fires once })); } @@ -309,7 +319,12 @@ public class DozeSensors { * Called when a sensor requests a pulse * @param pulseReason Requesting sensor, e.g. {@link DozeLog#PULSE_REASON_SENSOR_PICKUP} * @param sensorPerformedProxCheck true if the sensor already checked for FAR proximity. + * @param screenX the location on the screen where the sensor fired or -1 + * if the sensor doesn't support reporting screen locations. + * @param screenY the location on the screen where the sensor fired or -1 + * if the sensor doesn't support reporting screen locations. */ - void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck); + void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck, + float screenX, float screenY); } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index 3271caf598cf..d9fb087a6041 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -16,23 +16,27 @@ package com.android.systemui.doze; +import android.content.Context; import android.os.PowerManager; import android.os.SystemClock; import android.service.dreams.DreamService; import android.util.Log; import com.android.systemui.Dependency; -import com.android.systemui.plugins.Plugin; +import com.android.systemui.plugins.DozeServicePlugin; import com.android.systemui.plugins.PluginManager; - +import com.android.systemui.plugins.DozeServicePlugin.RequestDoze; +import com.android.systemui.plugins.PluginListener; import java.io.FileDescriptor; import java.io.PrintWriter; -public class DozeService extends DreamService implements DozeMachine.Service { +public class DozeService extends DreamService + implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> { private static final String TAG = "DozeService"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private DozeMachine mDozeMachine; + private DozeServicePlugin mDozePlugin; public DozeService() { setDebug(DEBUG); @@ -48,23 +52,44 @@ public class DozeService extends DreamService implements DozeMachine.Service { finish(); return; } - + Dependency.get(PluginManager.class).addPluginListener(this, + DozeServicePlugin.class, false /* Allow multiple */); mDozeMachine = new DozeFactory().assembleMachine(this); } @Override + public void onPluginConnected(DozeServicePlugin plugin, Context pluginContext) { + mDozePlugin = plugin; + mDozePlugin.setDozeRequester(this); + } + + @Override + public void onPluginDisconnected(DozeServicePlugin plugin) { + if (mDozePlugin != null) { + mDozePlugin.onDreamingStopped(); + mDozePlugin = null; + } + } + + @Override public void onDreamingStarted() { super.onDreamingStarted(); mDozeMachine.requestState(DozeMachine.State.INITIALIZED); startDozing(); setDozeScreenBrightness(getResources().getInteger( com.android.internal.R.integer.config_screenBrightnessDoze)); + if (mDozePlugin != null) { + mDozePlugin.onDreamingStarted(); + } } @Override public void onDreamingStopped() { super.onDreamingStopped(); mDozeMachine.requestState(DozeMachine.State.FINISH); + if (mDozePlugin != null) { + mDozePlugin.onDreamingStopped(); + } } @Override @@ -79,4 +104,18 @@ public class DozeService extends DreamService implements DozeMachine.Service { PowerManager pm = getSystemService(PowerManager.class); pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE"); } + + @Override + public void onRequestShowDoze() { + if (mDozeMachine != null) { + mDozeMachine.requestState(DozeMachine.State.DOZE_AOD); + } + } + + @Override + public void onRequestHideDoze() { + if (mDozeMachine != null) { + mDozeMachine.requestState(DozeMachine.State.DOZE); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 693a690d7f59..ae936db7b0e2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -98,12 +98,14 @@ public class DozeTriggers implements DozeMachine.Part { requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */); } - private void onSensor(int pulseReason, boolean sensorPerformedProxCheck) { + private void onSensor(int pulseReason, boolean sensorPerformedProxCheck, + float screenX, float screenY) { boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP; boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP; if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) { if (isDoubleTap) { + mDozeHost.onDoubleTap(screenX, screenY); mMachine.wakeUp(); } else { mDozeHost.extendPulse(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index b8de9f33f900..6d10d9413e66 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1868,12 +1868,7 @@ public class KeyguardViewMediator extends SystemUI { + " isSecure=" + isSecure() + " --> flags=0x" + Integer.toHexString(flags)); } - if (!(mContext instanceof Activity)) { - final int finalFlags = flags; - mUiOffloadThread.submit(() -> { - mStatusBarManager.disable(finalFlags); - }); - } + mStatusBarManager.disable(flags); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java index 867c15c4736f..6733421a8d0e 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java @@ -21,12 +21,15 @@ import static android.view.WindowManager.INPUT_CONSUMER_PIP; import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import android.view.BatchedInputEventReceiver; +import android.view.Choreographer; import android.view.InputChannel; import android.view.InputEvent; -import android.view.InputEventReceiver; import android.view.IWindowManager; import android.view.MotionEvent; +import com.android.systemui.recents.misc.Utilities; + import java.io.PrintWriter; /** @@ -52,12 +55,13 @@ public class InputConsumerController { } /** - * Input handler used for the PiP input consumer. + * Input handler used for the PiP input consumer. Input events are batched and consumed with the + * SurfaceFlinger vsync. */ - private final class PipInputEventReceiver extends InputEventReceiver { + private final class PipInputEventReceiver extends BatchedInputEventReceiver { public PipInputEventReceiver(InputChannel inputChannel, Looper looper) { - super(inputChannel, looper); + super(inputChannel, looper, Choreographer.getSfInstance()); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 013b9ac70118..0f69f471bc24 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -573,13 +573,11 @@ public class PipMenuActivity extends Activity { } private void cancelDelayedFinish() { - View v = getWindow().getDecorView(); - v.removeCallbacks(mFinishRunnable); + mHandler.removeCallbacks(mFinishRunnable); } private void repostDelayedFinish(long delay) { - View v = getWindow().getDecorView(); - v.removeCallbacks(mFinishRunnable); - v.postDelayed(mFinishRunnable, delay); + mHandler.removeCallbacks(mFinishRunnable); + mHandler.postDelayed(mFinishRunnable, delay); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 9fa7ff61a13d..b8771d7e0fb6 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -22,6 +22,7 @@ import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN; import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN; import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN; +import android.animation.AnimationHandler; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; @@ -36,14 +37,15 @@ import android.graphics.PointF; import android.graphics.Rect; import android.os.Debug; import android.os.Handler; +import android.os.Message; import android.os.RemoteException; import android.util.Log; -import android.view.Choreographer; import android.view.animation.Interpolator; -import com.android.internal.os.BackgroundThread; +import com.android.internal.graphics.SfVsyncFrameCallbackProvider; +import com.android.internal.os.SomeArgs; import com.android.internal.policy.PipSnapAlgorithm; -import com.android.internal.view.SurfaceFlingerVsyncChoreographer; +import com.android.systemui.recents.misc.ForegroundThread; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.statusbar.FlingAnimationUtils; @@ -52,7 +54,7 @@ import java.io.PrintWriter; /** * A helper to animate and manipulate the PiP. */ -public class PipMotionHelper { +public class PipMotionHelper implements Handler.Callback { private static final String TAG = "PipMotionHelper"; private static final boolean DEBUG = false; @@ -74,38 +76,34 @@ public class PipMotionHelper { // The fraction of the stack height that the user has to drag offscreen to dismiss the PiP private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f; + private static final int MSG_RESIZE_IMMEDIATE = 1; + private static final int MSG_RESIZE_ANIMATE = 2; + private Context mContext; private IActivityManager mActivityManager; - private SurfaceFlingerVsyncChoreographer mVsyncChoreographer; private Handler mHandler; private PipMenuActivityController mMenuController; private PipSnapAlgorithm mSnapAlgorithm; private FlingAnimationUtils mFlingAnimationUtils; + private AnimationHandler mAnimationHandler; private final Rect mBounds = new Rect(); private final Rect mStableInsets = new Rect(); private ValueAnimator mBoundsAnimator = null; - private ValueAnimator.AnimatorUpdateListener mUpdateBoundsListener = - new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mBounds.set((Rect) animation.getAnimatedValue()); - } - }; public PipMotionHelper(Context context, IActivityManager activityManager, PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils) { mContext = context; - mHandler = BackgroundThread.getHandler(); + mHandler = new Handler(ForegroundThread.get().getLooper(), this); mActivityManager = activityManager; mMenuController = menuController; mSnapAlgorithm = snapAlgorithm; mFlingAnimationUtils = flingAnimationUtils; - mVsyncChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, mContext.getDisplay(), - Choreographer.getInstance()); + mAnimationHandler = new AnimationHandler(); + mAnimationHandler.setProvider(new SfVsyncFrameCallbackProvider()); onConfigurationChanged(); } @@ -252,8 +250,7 @@ public class PipMotionHelper { Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds, 0 /* velocityX */, velocityY); if (!mBounds.equals(toBounds)) { - mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN, - mUpdateBoundsListener); + mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN); mFlingAnimationUtils.apply(mBoundsAnimator, 0, distanceBetweenRectOffsets(mBounds, toBounds), velocityY); @@ -271,7 +268,7 @@ public class PipMotionHelper { Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds); if (!mBounds.equals(toBounds)) { mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, - MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN, mUpdateBoundsListener); + MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN); if (updateListener != null) { mBoundsAnimator.addUpdateListener(updateListener); } @@ -289,8 +286,7 @@ public class PipMotionHelper { Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds, velocityX, velocityY); if (!mBounds.equals(toBounds)) { - mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN, - mUpdateBoundsListener); + mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN); mFlingAnimationUtils.apply(mBoundsAnimator, 0, distanceBetweenRectOffsets(mBounds, toBounds), velocity); @@ -314,7 +310,7 @@ public class PipMotionHelper { Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds); if (!mBounds.equals(toBounds)) { mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, SNAP_STACK_DURATION, - FAST_OUT_SLOW_IN, mUpdateBoundsListener); + FAST_OUT_SLOW_IN); if (updateListener != null) { mBoundsAnimator.addUpdateListener(updateListener); } @@ -379,7 +375,7 @@ public class PipMotionHelper { Rect toBounds = new Rect(pipBounds); toBounds.offsetTo(p.x, p.y); mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, DRAG_TO_DISMISS_STACK_DURATION, - FAST_OUT_LINEAR_IN, mUpdateBoundsListener); + FAST_OUT_LINEAR_IN); mBoundsAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -411,16 +407,20 @@ public class PipMotionHelper { * Creates an animation to move the PiP to give given {@param toBounds}. */ private ValueAnimator createAnimationToBounds(Rect fromBounds, Rect toBounds, int duration, - Interpolator interpolator, ValueAnimator.AnimatorUpdateListener updateListener) { - ValueAnimator anim = ValueAnimator.ofObject(RECT_EVALUATOR, fromBounds, toBounds); + Interpolator interpolator) { + ValueAnimator anim = new ValueAnimator() { + @Override + public AnimationHandler getAnimationHandler() { + return mAnimationHandler; + } + }; + anim.setObjectValues(fromBounds, toBounds); + anim.setEvaluator(RECT_EVALUATOR); anim.setDuration(duration); anim.setInterpolator(interpolator); anim.addUpdateListener((ValueAnimator animation) -> { resizePipUnchecked((Rect) animation.getAnimatedValue()); }); - if (updateListener != null) { - anim.addUpdateListener(updateListener); - } return anim; } @@ -433,14 +433,9 @@ public class PipMotionHelper { + " callers=\n" + Debug.getCallers(5, " ")); } if (!toBounds.equals(mBounds)) { - mVsyncChoreographer.scheduleAtSfVsync(() -> { - try { - mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */); - mBounds.set(toBounds); - } catch (RemoteException e) { - Log.e(TAG, "Could not resize pinned stack to bounds: " + toBounds, e); - } - }); + SomeArgs args = SomeArgs.obtain(); + args.arg1 = toBounds; + mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args)); } } @@ -453,23 +448,10 @@ public class PipMotionHelper { + " duration=" + duration + " callers=\n" + Debug.getCallers(5, " ")); } if (!toBounds.equals(mBounds)) { - mHandler.post(() -> { - try { - StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); - if (stackInfo == null) { - // In the case where we've already re-expanded or dismissed the PiP, then - // just skip the resize - return; - } - - mActivityManager.resizeStack(PINNED_STACK_ID, toBounds, - false /* allowResizeInDockedMode */, true /* preserveWindows */, - true /* animate */, duration); - mBounds.set(toBounds); - } catch (RemoteException e) { - Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e); - } - }); + SomeArgs args = SomeArgs.obtain(); + args.arg1 = toBounds; + args.argi1 = duration; + mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_ANIMATE, args)); } } @@ -524,6 +506,50 @@ public class PipMotionHelper { return PointF.length(r1.left - r2.left, r1.top - r2.top); } + /** + * Handles messages to be processed on the background thread. + */ + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_RESIZE_IMMEDIATE: { + SomeArgs args = (SomeArgs) msg.obj; + Rect toBounds = (Rect) args.arg1; + try { + mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */); + mBounds.set(toBounds); + } catch (RemoteException e) { + Log.e(TAG, "Could not resize pinned stack to bounds: " + toBounds, e); + } + return true; + } + + case MSG_RESIZE_ANIMATE: { + SomeArgs args = (SomeArgs) msg.obj; + Rect toBounds = (Rect) args.arg1; + int duration = args.argi1; + try { + StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); + if (stackInfo == null) { + // In the case where we've already re-expanded or dismissed the PiP, then + // just skip the resize + return true; + } + + mActivityManager.resizeStack(PINNED_STACK_ID, toBounds, + false /* allowResizeInDockedMode */, true /* preserveWindows */, + true /* animate */, duration); + mBounds.set(toBounds); + } catch (RemoteException e) { + Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e); + } + return true; + } + + default: + return false; + } + } + public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java index 603f66beca63..315a815af100 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java @@ -18,12 +18,14 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.widget.ImageView; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.plugins.qs.QSTile.SlashState; import com.android.systemui.qs.SlashDrawable; public class SlashImageView extends ImageView { - private SlashDrawable mSlash; + @VisibleForTesting + protected SlashDrawable mSlash; public SlashImageView(Context context) { super(context); @@ -38,10 +40,13 @@ public class SlashImageView extends ImageView { @Override public void setImageDrawable(Drawable drawable) { - if (mSlash != null) { - mSlash.setDrawable(drawable); - } else { + if (drawable == null) { + mSlash = null; + super.setImageDrawable(null); + } else if (mSlash == null) { super.setImageDrawable(drawable); + } else { + mSlash.setDrawable(drawable); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 703be27ad173..36677a46ed9f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -183,12 +183,6 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { @Override public void onBluetoothDevicesChanged() { - mUiHandler.post(new Runnable() { - @Override - public void run() { - mDetailAdapter.updateItems(); - } - }); refreshState(); if (isShowingDetail()) { mDetailAdapter.updateItems(); @@ -202,6 +196,9 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { } protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback { + // We probably won't ever have space in the UI for more than 20 devices, so don't + // get info for them. + private static final int MAX_DEVICES = 20; private QSDetailItems mItems; @Override @@ -264,13 +261,14 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { final Collection<CachedBluetoothDevice> devices = mController.getDevices(); if (devices != null) { int connectedDevices = 0; + int count = 0; for (CachedBluetoothDevice device : devices) { - if (device.getBondState() == BluetoothDevice.BOND_NONE) continue; + if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue; final Item item = new Item(); item.icon = R.drawable.ic_qs_bluetooth_on; item.line1 = device.getName(); item.tag = device; - int state = device.getMaxConnectionState(); + int state = mController.getMaxConnectionState(device); if (state == BluetoothProfile.STATE_CONNECTED) { item.icon = R.drawable.ic_qs_bluetooth_connected; item.line2 = mContext.getString(R.string.quick_settings_connected); @@ -284,6 +282,9 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { } else { items.add(item); } + if (++count == MAX_DEVICES) { + break; + } } } mItems.setItems(items.toArray(new Item[items.size()])); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 1f13830ec1cc..c66b2dd8eec5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -154,6 +154,13 @@ public class SystemServicesProxy { Canvas mBgProtectionCanvas; private final Handler mHandler = new H(); + private final Runnable mGcRunnable = new Runnable() { + @Override + public void run() { + System.gc(); + System.runFinalization(); + } + }; private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class); @@ -365,13 +372,7 @@ public class SystemServicesProxy { * Requests a gc() from the background thread. */ public void gc() { - BackgroundThread.getHandler().post(new Runnable() { - @Override - public void run() { - System.gc(); - System.runFinalization(); - } - }); + BackgroundThread.getHandler().post(mGcRunnable); } /** @@ -799,11 +800,8 @@ public class SystemServicesProxy { if (RecentsDebugFlags.Static.EnableMockTasks) return; // Remove the task. - BackgroundThread.getHandler().post(new Runnable() { - @Override - public void run() { - mAm.removeTask(taskId); - } + mUiOffloadThread.submit(() -> { + mAm.removeTask(taskId); }); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java index 1f82c1677029..308cece1dfdd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java @@ -20,9 +20,9 @@ import android.content.Context; import android.os.UserHandle; import com.android.internal.content.PackageMonitor; -import com.android.internal.os.BackgroundThread; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.PackagesChangedEvent; +import com.android.systemui.recents.misc.ForegroundThread; /** * The package monitor listens for changes from PackageManager to update the contents of the @@ -36,7 +36,7 @@ public class RecentsPackageMonitor extends PackageMonitor { // We register for events from all users, but will cross-reference them with // packages for the current user and any profiles they have. Ensure that events are // handled in a background thread. - register(context, BackgroundThread.get().getLooper(), UserHandle.ALL, true); + register(context, ForegroundThread.get().getLooper(), UserHandle.ALL, true); } catch (IllegalStateException e) { e.printStackTrace(); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 4022718865e0..da0a43551f1f 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -25,6 +25,8 @@ import android.view.View; import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.recents.Recents; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.ui.RecentsDrawnEvent; import com.android.systemui.recents.misc.SystemServicesProxy; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; @@ -56,6 +58,7 @@ public class Divider extends SystemUI { SystemServicesProxy ssp = Recents.getSystemServices(); ssp.registerDockedStackListener(mDockDividerVisibilityListener); mForcedResizableController = new ForcedResizableInfoActivityController(mContext); + EventBus.getDefault().register(this); } @Override @@ -153,6 +156,18 @@ public class Divider extends SystemUI { mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme); } + /** + * Workaround for b/62528361, at the time RecentsDrawnEvent is sent, it may happen before a + * configuration change to the Divider, and internally, the event will be posted to the + * subscriber, or DividerView, which has been removed and prevented from resizing. Instead, + * register the event handler here and proxy the event to the current DividerView. + */ + public final void onBusEvent(RecentsDrawnEvent drawnEvent) { + if (mView != null) { + mView.onRecentsDrawn(); + } + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.print(" mVisible="); pw.println(mVisible); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 09f459b0b07b..45835d51ff90 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -1224,7 +1224,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mSnapAlgorithm.getMiddleTarget()); } - public final void onBusEvent(RecentsDrawnEvent drawnEvent) { + public void onRecentsDrawn() { if (mState.animateAfterRecentsDrawn) { mState.animateAfterRecentsDrawn = false; updateDockSide(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index d7e7abe4fd9c..6b7397b3f8ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -157,6 +157,10 @@ public class DozeParameters { return 2 * getPulseVisibleDuration(); } + public boolean doubleTapReportsTouchCoordinates() { + return mContext.getResources().getBoolean(R.bool.doze_double_tap_reports_touch_coordinates); + } + /** * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index e8b6e079e261..f6032d3c9bc7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -32,7 +32,6 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCE import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; -import android.R.style; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.NonNull; @@ -5325,6 +5324,37 @@ public class StatusBar extends SystemUI implements DemoMode, mAnimateWakeup = animateWakeup; } + @Override + public void onDoubleTap(float screenX, float screenY) { + if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null + && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) { + mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2); + float viewX = screenX - mTmpInt2[0]; + float viewY = screenY - mTmpInt2[1]; + if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth() + && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) { + dispatchDoubleTap(viewX, viewY); + } + } + } + + public void dispatchDoubleTap(float viewX, float viewY) { + dispatchTap(mAmbientIndicationContainer, viewX, viewY); + dispatchTap(mAmbientIndicationContainer, viewX, viewY); + } + + private void dispatchTap(View view, float x, float y) { + long now = SystemClock.elapsedRealtime(); + dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN); + dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP); + } + + private void dispatchTouchEvent(View view, float x, float y, long now, int action) { + MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */); + view.dispatchTouchEvent(ev); + ev.recycle(); + } + private boolean shouldAnimateWakeup() { return mAnimateWakeup; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 7d69a349f01d..9b0307d6522e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -94,6 +94,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastBouncerDismissible; protected boolean mLastRemoteInputActive; private boolean mLastDozing; + private boolean mLastDeferScrimFadeOut; private OnDismissAction mAfterKeyguardGoneAction; private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>(); @@ -371,7 +372,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration); mFingerprintUnlockController.startKeyguardFadingAway(); mBouncer.hide(true /* destroyView */); - updateStates(); if (wakeUnlockPulsing) { mStatusBarWindowManager.setKeyguardFadingAway(true); mStatusBar.fadeKeyguardWhilePulsing(); @@ -403,6 +403,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mFingerprintUnlockController.finishKeyguardFadingAway(); } } + updateStates(); mStatusBarWindowManager.setKeyguardShowing(false); mViewMediatorCallback.keyguardGone(); } @@ -574,7 +575,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLastBouncerDismissible = bouncerDismissible; mLastRemoteInputActive = remoteInputActive; mLastDozing = mDozing; - + mLastDeferScrimFadeOut = mDeferScrimFadeOut; mStatusBar.onKeyguardViewManagerStatesUpdated(); } @@ -582,15 +583,16 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * @return Whether the navigation bar should be made visible based on the current state. */ protected boolean isNavBarVisible() { - return !(mShowing && !mOccluded) && !mDozing || mBouncer.isShowing() || mRemoteInputActive; + return (!(mShowing && !mOccluded) && !mDozing || mBouncer.isShowing() || mRemoteInputActive) + && !mDeferScrimFadeOut; } /** * @return Whether the navigation bar was made visible based on the last known state. */ protected boolean getLastNavBarVisible() { - return !(mLastShowing && !mLastOccluded) && !mLastDozing || mLastBouncerShowing - || mLastRemoteInputActive; + return (!(mLastShowing && !mLastOccluded) && !mLastDozing || mLastBouncerShowing + || mLastRemoteInputActive) && !mLastDeferScrimFadeOut; } public boolean shouldDismissOnMenuPressed() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java index df30e20ca582..9daa199ee92a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java @@ -37,6 +37,9 @@ public interface BluetoothController extends CallbackController<Callback>, Dumpa void disconnect(CachedBluetoothDevice device); boolean canConfigBluetooth(); + int getMaxConnectionState(CachedBluetoothDevice device); + int getBondState(CachedBluetoothDevice device); + public interface Callback { void onBluetoothStateChange(boolean enabled); void onBluetoothDevicesChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java index 36d24b370b00..dc4b1158c1cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java @@ -18,6 +18,8 @@ package com.android.systemui.statusbar.policy; import android.app.ActivityManager; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; import android.content.Context; import android.os.Handler; import android.os.Looper; @@ -33,8 +35,10 @@ import com.android.systemui.Dependency; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; +import java.util.WeakHashMap; public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback, CachedBluetoothDevice.Callback { @@ -44,18 +48,22 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa private final LocalBluetoothManager mLocalBluetoothManager; private final UserManager mUserManager; private final int mCurrentUser; + private final WeakHashMap<CachedBluetoothDevice, ActuallyCachedState> mCachedState = + new WeakHashMap<>(); + private final Handler mBgHandler; private boolean mEnabled; private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED; private CachedBluetoothDevice mLastDevice; - private final H mHandler = new H(); + private final H mHandler = new H(Looper.getMainLooper()); private int mState; public BluetoothControllerImpl(Context context, Looper bgLooper) { mLocalBluetoothManager = Dependency.get(LocalBluetoothManager.class); + mBgHandler = new Handler(bgLooper); if (mLocalBluetoothManager != null) { - mLocalBluetoothManager.getEventManager().setReceiverHandler(new Handler(bgLooper)); + mLocalBluetoothManager.getEventManager().setReceiverHandler(mBgHandler); mLocalBluetoothManager.getEventManager().registerCallback(this); onBluetoothStateChanged( mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState()); @@ -106,6 +114,16 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa } @Override + public int getBondState(CachedBluetoothDevice device) { + return getCachedState(device).mBondState; + } + + @Override + public int getMaxConnectionState(CachedBluetoothDevice device) { + return getCachedState(device).mMaxConnectionState; + } + + @Override public void addCallback(Callback cb) { mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget(); mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED); @@ -225,12 +243,14 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa @Override public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { + mCachedState.remove(cachedDevice); updateConnected(); mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED); } @Override public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) { + mCachedState.remove(cachedDevice); updateConnected(); mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED); } @@ -243,11 +263,44 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa @Override public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { + mCachedState.remove(cachedDevice); mLastDevice = cachedDevice; updateConnected(); mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED); } + private ActuallyCachedState getCachedState(CachedBluetoothDevice device) { + ActuallyCachedState state = mCachedState.get(device); + if (state == null) { + state = new ActuallyCachedState(device, mHandler); + mBgHandler.post(state); + mCachedState.put(device, state); + return state; + } + return state; + } + + private static class ActuallyCachedState implements Runnable { + + private final WeakReference<CachedBluetoothDevice> mDevice; + private final Handler mUiHandler; + private int mBondState = BluetoothDevice.BOND_NONE; + private int mMaxConnectionState = BluetoothProfile.STATE_DISCONNECTED; + + private ActuallyCachedState(CachedBluetoothDevice device, Handler uiHandler) { + mDevice = new WeakReference<>(device); + mUiHandler = uiHandler; + } + + @Override + public void run() { + mBondState = mDevice.get().getBondState(); + mMaxConnectionState = mDevice.get().getMaxConnectionState(); + mUiHandler.removeMessages(H.MSG_PAIRED_DEVICES_CHANGED); + mUiHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED); + } + } + private final class H extends Handler { private final ArrayList<BluetoothController.Callback> mCallbacks = new ArrayList<>(); @@ -256,6 +309,10 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa private static final int MSG_ADD_CALLBACK = 3; private static final int MSG_REMOVE_CALLBACK = 4; + public H(Looper looper) { + super(looper); + } + @Override public void handleMessage(Message msg) { switch (msg.what) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java index 56c07f905446..23451106a20c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java @@ -28,6 +28,8 @@ class DozeHostFake implements DozeHost { boolean pulseExtended; boolean animateWakeup; boolean dozing; + float doubleTapX; + float doubleTapY; @Override public void addCallback(@NonNull Callback callback) { @@ -88,4 +90,10 @@ class DozeHostFake implements DozeHost { public void setAnimateWakeup(boolean animateWakeup) { this.animateWakeup = animateWakeup; } + + @Override + public void onDoubleTap(float x, float y) { + doubleTapX = y; + doubleTapY = y; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java new file mode 100644 index 000000000000..aef584f8d986 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.qs.QSTile.SlashState; +import com.android.systemui.qs.tileimpl.SlashImageView; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class SlashImageViewTest extends SysuiTestCase { + private TestableSlashImageView mSlashView; + + @Test + public void testSetSlashStateCreatesSlashDrawable() { + SlashState mockState = mock(SlashState.class); + Drawable mockDrawable = mock(Drawable.class); + mSlashView = new TestableSlashImageView(mContext); + assertTrue(mSlashView.getSlashDrawable() == null); + + mSlashView.setImageDrawable(mockDrawable); + mSlashView.setState(mockState); + + assertTrue(mSlashView.getSlashDrawable() != null); + } + + @Test + public void testSetNullDrawableRemovesSlashDrawable() { + SlashState mockState = mock(SlashState.class); + Drawable mockDrawable = mock(Drawable.class); + + mSlashView = new TestableSlashImageView(mContext); + mSlashView.setImageDrawable(mockDrawable); + mSlashView.setState(mockState); + mSlashView.setImageDrawable(null); + + assertTrue(mSlashView.getSlashDrawable() == null); + } + + // Expose getSlashDrawable + private static class TestableSlashImageView extends SlashImageView { + TestableSlashImageView(Context c) { + super(c); + } + + private SlashDrawable getSlashDrawable() { + return mSlash; + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java index 2eb95603cef0..4cc8bcae541a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java @@ -14,16 +14,21 @@ package com.android.systemui.statusbar.policy; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; +import android.os.Looper; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import android.util.Log; import com.android.settingslib.bluetooth.BluetoothEventManager; import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -80,4 +85,56 @@ public class BluetoothControllerImplTest extends SysuiTestCase { BluetoothAdapter.STATE_DISCONNECTED); assertTrue(mBluetoothControllerImpl.isBluetoothConnected()); } + + @Test + public void testDefaultConnectionState() { + CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device)); + assertEquals(BluetoothProfile.STATE_DISCONNECTED, + mBluetoothControllerImpl.getMaxConnectionState(device)); + } + + @Test + public void testAsyncBondState() throws Exception { + CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + BluetoothController.Callback callback = mock(BluetoothController.Callback.class); + mBluetoothControllerImpl.addCallback(callback); + + // Grab the main looper, we'll need it later. + TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper()); + + // Trigger the state getting. + assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device)); + + mTestableLooper.processMessages(1); + mainLooper.processAllMessages(); + + assertEquals(BluetoothDevice.BOND_BONDED, mBluetoothControllerImpl.getBondState(device)); + verify(callback).onBluetoothDevicesChanged(); + mainLooper.destroy(); + } + + @Test + public void testAsyncConnectionState() throws Exception { + CachedBluetoothDevice device = mock(CachedBluetoothDevice.class); + when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED); + BluetoothController.Callback callback = mock(BluetoothController.Callback.class); + mBluetoothControllerImpl.addCallback(callback); + + // Grab the main looper, we'll need it later. + TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper()); + + // Trigger the state getting. + assertEquals(BluetoothProfile.STATE_DISCONNECTED, + mBluetoothControllerImpl.getMaxConnectionState(device)); + + mTestableLooper.processMessages(1); + mainLooper.processAllMessages(); + + assertEquals(BluetoothProfile.STATE_CONNECTED, + mBluetoothControllerImpl.getMaxConnectionState(device)); + verify(callback).onBluetoothDevicesChanged(); + mainLooper.destroy(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java index 0ba031908d90..9ec096ad49e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java @@ -83,4 +83,14 @@ public class FakeBluetoothController extends BaseLeakChecker<Callback> implement public boolean canConfigBluetooth() { return false; } + + @Override + public int getMaxConnectionState(CachedBluetoothDevice device) { + return 0; + } + + @Override + public int getBondState(CachedBluetoothDevice device) { + return 0; + } } diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 1a5ec61a1510..c8e6e2efb240 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -2445,6 +2445,28 @@ public class AppOpsService extends IAppOpsService.Stub { } } + @Override + public boolean isOperationActive(int code, int uid, String packageName) { + verifyIncomingUid(uid); + verifyIncomingOp(code); + String resolvedPackageName = resolvePackageName(uid, packageName); + if (resolvedPackageName == null) { + return false; + } + synchronized (this) { + for (int i = mClients.size() - 1; i >= 0; i--) { + final ClientState client = mClients.valueAt(i); + if (client.mStartedOps == null) continue; + + for (int j = client.mStartedOps.size() - 1; j >= 0; j--) { + final Op op = client.mStartedOps.get(j); + if (op.op == code && op.uid == uid) return true; + } + } + } + return false; + } + private void removeUidsForUserLocked(int userHandle) { for (int i = mUidStates.size() - 1; i >= 0; --i) { final int uid = mUidStates.keyAt(i); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 35b452a12e64..f718e803a973 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -90,14 +90,12 @@ import android.util.AtomicFile; import android.util.Log; import android.util.Pair; import android.util.Slog; -import android.util.SparseArray; import android.util.TimeUtils; import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IMediaContainerService; import com.android.internal.os.AppFuseMount; -import com.android.internal.os.FuseAppLoop; import com.android.internal.os.FuseUnavailableMountException; import com.android.internal.os.SomeArgs; import com.android.internal.os.Zygote; @@ -143,7 +141,6 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; -import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -3291,20 +3288,41 @@ class StorageManagerService extends IStorageManager.Stub } } - @Override - public long getAllocatableBytes(String volumeUuid, int flags) { - final StorageManager storage = mContext.getSystemService(StorageManager.class); - final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class); - - // Apps can't defy reserved space - flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_RESERVED; - - final boolean aggressive = (flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0; - if (aggressive) { + private int adjustAllocateFlags(int flags, int callingUid, String callingPackage) { + // Require permission to allocate aggressively + if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.ALLOCATE_AGGRESSIVE, TAG); } + // Apps normally can't directly defy reserved space + flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED; + flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED; + + // However, if app is actively using the camera, then we're willing to + // clear up to half of the reserved cache space, since the user might be + // trying to capture an important memory. + final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); + final long token = Binder.clearCallingIdentity(); + try { + if (appOps.isOperationActive(AppOpsManager.OP_CAMERA, callingUid, callingPackage)) { + Slog.d(TAG, "UID " + callingUid + " is actively using camera;" + + " letting them defy reserved cached data"); + flags |= StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED; + } + } finally { + Binder.restoreCallingIdentity(token); + } + + return flags; + } + + @Override + public long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) { + flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage); + + final StorageManager storage = mContext.getSystemService(StorageManager.class); + final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class); final long token = Binder.clearCallingIdentity(); try { // In general, apps can allocate as much space as they want, except @@ -3319,18 +3337,18 @@ class StorageManagerService extends IStorageManager.Stub if (stats.isQuotaSupported(volumeUuid)) { final long cacheTotal = stats.getCacheBytes(volumeUuid); - final long cacheReserved = storage.getStorageCacheBytes(path); + final long cacheReserved = storage.getStorageCacheBytes(path, flags); final long cacheClearable = Math.max(0, cacheTotal - cacheReserved); - if (aggressive) { - return Math.max(0, (usable + cacheTotal) - fullReserved); + if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { + return Math.max(0, (usable + cacheClearable) - fullReserved); } else { return Math.max(0, (usable + cacheClearable) - lowReserved); } } else { // When we don't have fast quota information, we ignore cached // data and only consider unused bytes. - if (aggressive) { + if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) { return Math.max(0, usable - fullReserved); } else { return Math.max(0, usable - lowReserved); @@ -3344,20 +3362,16 @@ class StorageManagerService extends IStorageManager.Stub } @Override - public void allocateBytes(String volumeUuid, long bytes, int flags) { - final StorageManager storage = mContext.getSystemService(StorageManager.class); + public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) { + flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage); - // Apps can't defy reserved space - flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_RESERVED; - - // This method call will enforce FLAG_ALLOCATE_AGGRESSIVE permissions so - // we don't have to enforce them locally - final long allocatableBytes = getAllocatableBytes(volumeUuid, flags); + final long allocatableBytes = getAllocatableBytes(volumeUuid, flags, callingPackage); if (bytes > allocatableBytes) { throw new ParcelableException(new IOException("Failed to allocate " + bytes + " because only " + allocatableBytes + " allocatable")); } + final StorageManager storage = mContext.getSystemService(StorageManager.class); final long token = Binder.clearCallingIdentity(); try { // Free up enough disk space to satisfy both the requested allocation diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 76456f3edccc..ad442c714926 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1804,7 +1804,7 @@ public class ActivityManagerService extends IActivityManager.Stub } AppErrorResult res = (AppErrorResult) data.get("result"); if (mShowDialogs && !mSleeping && !mShuttingDown) { - Dialog d = new StrictModeViolationDialog(mContext, + Dialog d = new StrictModeViolationDialog(mUiContext, ActivityManagerService.this, res, proc); d.show(); proc.crashDialog = d; diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index ba8fa31dc46c..f720cd51cd86 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -600,6 +600,7 @@ final class UserController { void finishUserStopping(final int userId, final UserState uss) { // On to the next. final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN); + shutdownIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); // This is the result receiver for the final shutdown broadcast. final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() { @Override diff --git a/services/core/java/com/android/server/job/GrantedUriPermissions.java b/services/core/java/com/android/server/job/GrantedUriPermissions.java index e413d8d1d8c0..c23b109bb9de 100644 --- a/services/core/java/com/android/server/job/GrantedUriPermissions.java +++ b/services/core/java/com/android/server/job/GrantedUriPermissions.java @@ -29,7 +29,7 @@ import android.util.Slog; import java.io.PrintWriter; import java.util.ArrayList; -public class GrantedUriPermissions { +public final class GrantedUriPermissions { private final int mGrantFlags; private final int mSourceUserId; private final String mTag; diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java index 2d2f61f0288d..a53c0885f334 100644 --- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java @@ -26,7 +26,7 @@ import android.os.UserHandle; import java.io.PrintWriter; -public class JobSchedulerShellCommand extends ShellCommand { +public final class JobSchedulerShellCommand extends ShellCommand { public static final int CMD_ERR_NO_PACKAGE = -1000; public static final int CMD_ERR_NO_JOB = -1001; public static final int CMD_ERR_CONSTRAINTS = -1002; diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java index 637db11af6d8..5d3f6f7b804b 100644 --- a/services/core/java/com/android/server/job/JobServiceContext.java +++ b/services/core/java/com/android/server/job/JobServiceContext.java @@ -55,13 +55,13 @@ import com.android.server.job.controllers.JobStatus; * job lands, and again when it is complete. * - Cancelling is trickier, because there are also interactions from the client. It's possible * the {@link com.android.server.job.JobServiceContext.JobServiceHandler} tries to process a - * {@link #doCancelLocked(int)} after the client has already finished. This is handled by having + * {@link #doCancelLocked} after the client has already finished. This is handled by having * {@link com.android.server.job.JobServiceContext.JobServiceHandler#handleCancelLocked} check whether * the context is still valid. * To mitigate this, we avoid sending duplicate onStopJob() * calls to the client after they've specified jobFinished(). */ -public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection { +public final class JobServiceContext implements ServiceConnection { private static final boolean DEBUG = JobSchedulerService.DEBUG; private static final String TAG = "JobServiceContext"; /** Amount of time a job is allowed to execute for before being considered timed-out. */ @@ -112,6 +112,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne * Writes can only be done from the handler thread, or {@link #executeRunnableJob(JobStatus)}. */ private JobStatus mRunningJob; + private JobCallback mRunningCallback; /** Used to store next job to run when current job is to be preempted. */ private int mPreferredUid; IJobService service; @@ -133,6 +134,36 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne // Debugging: time this job was last stopped. public long mStoppedTime; + final class JobCallback extends IJobCallback.Stub { + public String mStoppedReason; + public long mStoppedTime; + + @Override + public void acknowledgeStartMessage(int jobId, boolean ongoing) { + doAcknowledgeStartMessage(this, jobId, ongoing); + } + + @Override + public void acknowledgeStopMessage(int jobId, boolean reschedule) { + doAcknowledgeStopMessage(this, jobId, reschedule); + } + + @Override + public JobWorkItem dequeueWork(int jobId) { + return doDequeueWork(this, jobId); + } + + @Override + public boolean completeWork(int jobId, int workId) { + return doCompleteWork(this, jobId, workId); + } + + @Override + public void jobFinished(int jobId, boolean reschedule) { + doJobFinished(this, jobId, reschedule); + } + } + JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, JobPackageTracker tracker, Looper looper) { this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper); @@ -168,6 +199,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne mPreferredUid = NO_PREFERRED_UID; mRunningJob = job; + mRunningCallback = new JobCallback(); final boolean isDeadlineExpired = job.hasDeadlineConstraint() && (job.getLatestRunTimeElapsed() < SystemClock.elapsedRealtime()); @@ -182,7 +214,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne job.changedAuthorities.toArray(triggeredAuthorities); } final JobInfo ji = job.getJob(); - mParams = new JobParameters(this, job.getJobId(), ji.getExtras(), + mParams = new JobParameters(mRunningCallback, job.getJobId(), ji.getExtras(), ji.getTransientExtras(), ji.getClipData(), ji.getClipGrantFlags(), isDeadlineExpired, triggeredUris, triggeredAuthorities); mExecutionStartTimeElapsed = SystemClock.elapsedRealtime(); @@ -198,6 +230,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne Slog.d(TAG, job.getServiceComponent().getShortClassName() + " unavailable."); } mRunningJob = null; + mRunningCallback = null; mParams = null; mExecutionStartTimeElapsed = 0L; mVerb = VERB_FINISHED; @@ -263,28 +296,29 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne return false; } - @Override - public void jobFinished(int jobId, boolean reschedule) { - doCallback(reschedule, "app called jobFinished"); + void doJobFinished(JobCallback cb, int jobId, boolean reschedule) { + doCallback(cb, reschedule, "app called jobFinished"); } - @Override - public void acknowledgeStopMessage(int jobId, boolean reschedule) { - doCallback(reschedule, null); + void doAcknowledgeStopMessage(JobCallback cb, int jobId, boolean reschedule) { + doCallback(cb, reschedule, null); } - @Override - public void acknowledgeStartMessage(int jobId, boolean ongoing) { - doCallback(ongoing, "finished start"); + void doAcknowledgeStartMessage(JobCallback cb, int jobId, boolean ongoing) { + doCallback(cb, ongoing, "finished start"); } - @Override - public JobWorkItem dequeueWork(int jobId) { - final int callingUid = Binder.getCallingUid(); + JobWorkItem doDequeueWork(JobCallback cb, int jobId) { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - assertCallingUidLocked(callingUid); + assertCallerLocked(cb); + if (mVerb == VERB_STOPPING || mVerb == VERB_FINISHED) { + // This job is either all done, or on its way out. Either way, it + // should not dispatch any more work. We will pick up any remaining + // work the next time we start the job again. + return null; + } final JobWorkItem work = mRunningJob.dequeueWorkLocked(); if (work == null && !mRunningJob.hasExecutingWorkLocked()) { // This will finish the job. @@ -297,13 +331,11 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne } } - @Override - public boolean completeWork(int jobId, int workId) { - final int callingUid = Binder.getCallingUid(); + boolean doCompleteWork(JobCallback cb, int jobId, int workId) { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - assertCallingUidLocked(callingUid); + assertCallerLocked(cb); return mRunningJob.completeWorkLocked(ActivityManager.getService(), workId); } } finally { @@ -369,8 +401,8 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne * whether the client exercising the callback is the client we expect. * @return True if the binder calling is coming from the client we expect. */ - private boolean verifyCallingUidLocked(final int callingUid) { - if (mRunningJob == null || callingUid != mRunningJob.getUid()) { + private boolean verifyCallerLocked(JobCallback cb) { + if (mRunningCallback != cb) { if (DEBUG) { Slog.d(TAG, "Stale callback received, ignoring."); } @@ -379,16 +411,15 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne return true; } - private void assertCallingUidLocked(final int callingUid) { - if (!verifyCallingUidLocked(callingUid)) { + private void assertCallerLocked(JobCallback cb) { + if (!verifyCallerLocked(cb)) { StringBuilder sb = new StringBuilder(128); - sb.append("Bad calling uid "); - sb.append(callingUid); - if (mStoppedReason != null) { + sb.append("Caller no longer running"); + if (cb.mStoppedReason != null) { sb.append(", last stopped "); - TimeUtils.formatDuration(SystemClock.elapsedRealtime() - mStoppedTime, sb); + TimeUtils.formatDuration(SystemClock.elapsedRealtime() - cb.mStoppedTime, sb); sb.append(" because: "); - sb.append(mStoppedReason); + sb.append(cb.mStoppedReason); } throw new SecurityException(sb.toString()); } @@ -421,12 +452,11 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne handleServiceBoundLocked(); } - void doCallback(boolean reschedule, String reason) { - final int callingUid = Binder.getCallingUid(); + void doCallback(JobCallback cb, boolean reschedule, String reason) { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - if (!verifyCallingUidLocked(callingUid)) { + if (!verifyCallerLocked(cb)) { return; } doCallbackLocked(reschedule, reason); @@ -559,7 +589,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne * VERB_BINDING -> Cancelled before bind completed. Mark as cancelled and wait for * {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)} * _STARTING -> Mark as cancelled and wait for - * {@link JobServiceContext#acknowledgeStartMessage(int, boolean)} + * {@link JobServiceContext#doAcknowledgeStartMessage} * _EXECUTING -> call {@link #sendStopMessageLocked}}, but only if there are no callbacks * in the message queue. * _ENDING -> No point in doing anything here, so we ignore. @@ -671,6 +701,7 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne mContext.unbindService(JobServiceContext.this); mWakeLock = null; mRunningJob = null; + mRunningCallback = null; mParams = null; mVerb = VERB_FINISHED; mCancelled = false; @@ -684,6 +715,10 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne if (reason != null && mStoppedReason == null) { mStoppedReason = reason; mStoppedTime = SystemClock.elapsedRealtime(); + if (mRunningCallback != null) { + mRunningCallback.mStoppedReason = mStoppedReason; + mRunningCallback.mStoppedTime = mStoppedTime; + } } } diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java index 22eed3b04250..f0cd8a8569e0 100644 --- a/services/core/java/com/android/server/job/JobStore.java +++ b/services/core/java/com/android/server/job/JobStore.java @@ -66,7 +66,7 @@ import org.xmlpull.v1.XmlSerializer; * and {@link com.android.server.job.JobStore.ReadJobMapFromDiskRunnable} lock on that * object. */ -public class JobStore { +public final class JobStore { private static final String TAG = "JobStore"; private static final boolean DEBUG = JobSchedulerService.DEBUG; @@ -263,7 +263,7 @@ public class JobStore { * Runnable that writes {@link #mJobSet} out to xml. * NOTE: This Runnable locks on mLock */ - private class WriteJobsMapToDiskRunnable implements Runnable { + private final class WriteJobsMapToDiskRunnable implements Runnable { @Override public void run() { final long startElapsed = SystemClock.elapsedRealtime(); @@ -444,7 +444,7 @@ public class JobStore { * Runnable that reads list of persisted job from xml. This is run once at start up, so doesn't * need to go through {@link JobStore#add(com.android.server.job.controllers.JobStatus)}. */ - private class ReadJobMapFromDiskRunnable implements Runnable { + private final class ReadJobMapFromDiskRunnable implements Runnable { private final JobSet jobSet; /** @@ -796,7 +796,7 @@ public class JobStore { } } - static class JobSet { + static final class JobSet { // Key is the getUid() originator of the jobs in each sheaf private SparseArray<ArraySet<JobStatus>> mJobs; diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java index 68dd00ff00c1..39f2a96b30e3 100644 --- a/services/core/java/com/android/server/job/controllers/AppIdleController.java +++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java @@ -33,7 +33,7 @@ import java.io.PrintWriter; * for a certain amount of time (maybe hours or days) are considered idle. When the app comes * out of idle state, it will be allowed to run scheduled jobs. */ -public class AppIdleController extends StateController { +public final class AppIdleController extends StateController { private static final String LOG_TAG = "AppIdleController"; private static final boolean DEBUG = false; @@ -171,7 +171,7 @@ public class AppIdleController extends StateController { } } - private class AppIdleStateChangeListener + private final class AppIdleStateChangeListener extends UsageStatsManagerInternal.AppIdleStateChangeListener { @Override public void onAppIdleStateChanged(String packageName, int userId, boolean idle) { diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java index d275bd94a6f4..91119690617a 100644 --- a/services/core/java/com/android/server/job/controllers/BatteryController.java +++ b/services/core/java/com/android/server/job/controllers/BatteryController.java @@ -39,7 +39,7 @@ import java.io.PrintWriter; * be charging when it's been plugged in for more than two minutes, and the system has broadcast * ACTION_BATTERY_OK. */ -public class BatteryController extends StateController { +public final class BatteryController extends StateController { private static final String TAG = "JobScheduler.Batt"; private static final Object sCreationLock = new Object(); @@ -121,7 +121,7 @@ public class BatteryController extends StateController { } } - public class ChargingTracker extends BroadcastReceiver { + public final class ChargingTracker extends BroadcastReceiver { /** * Track whether we're "charging", where charging means that we're ready to commit to * doing work. diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index f4268185aa40..17c89282f280 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -43,7 +43,7 @@ import java.io.PrintWriter; * status due to user-requested network policies, so we need to check * constraints on a per-UID basis. */ -public class ConnectivityController extends StateController implements +public final class ConnectivityController extends StateController implements ConnectivityManager.OnNetworkActiveListener { private static final String TAG = "JobScheduler.Conn"; private static final boolean DEBUG = false; diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java index cfafc38428f3..ff807eccee7b 100644 --- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java +++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java @@ -39,7 +39,7 @@ import java.util.ArrayList; /** * Controller for monitoring changes to content URIs through a ContentObserver. */ -public class ContentObserverController extends StateController { +public final class ContentObserverController extends StateController { private static final String TAG = "JobScheduler.Content"; private static final boolean DEBUG = false; diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java index 5ccf81288255..85993b900dc9 100644 --- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java +++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java @@ -37,7 +37,7 @@ import java.util.Arrays; * When device is dozing, set constraint for all jobs, except whitelisted apps, as not satisfied. * When device is not dozing, set constraint for all jobs as satisfied. */ -public class DeviceIdleJobsController extends StateController { +public final class DeviceIdleJobsController extends StateController { private static final String LOG_TAG = "DeviceIdleJobsController"; private static final boolean LOG_DEBUG = false; diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java index 7e922930e6e8..9eda046fa1e4 100644 --- a/services/core/java/com/android/server/job/controllers/IdleController.java +++ b/services/core/java/com/android/server/job/controllers/IdleController.java @@ -33,7 +33,7 @@ import com.android.server.am.ActivityManagerService; import com.android.server.job.JobSchedulerService; import com.android.server.job.StateChangedListener; -public class IdleController extends StateController { +public final class IdleController extends StateController { private static final String TAG = "IdleController"; // Policy: we decide that we're "idle" if the device has been unused / @@ -107,7 +107,7 @@ public class IdleController extends StateController { mIdleTracker.startTracking(); } - class IdlenessTracker extends BroadcastReceiver { + final class IdlenessTracker extends BroadcastReceiver { private AlarmManager mAlarm; private PendingIntent mIdleTriggerIntent; boolean mIdle; diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index 53bf40245819..446b0d67ce95 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -698,7 +698,8 @@ public final class JobStatus { static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW | CONSTRAINT_TIMING_DELAY | - CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | CONSTRAINT_NOT_ROAMING | + CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | + CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER; // Soft override covers all non-"functional" constraints @@ -865,6 +866,9 @@ public final class JobStatus { if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) { pw.print(" NOT_ROAMING"); } + if ((constraints&CONSTRAINT_METERED) != 0) { + pw.print(" METERED"); + } if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) { pw.print(" APP_NOT_IDLE"); } diff --git a/services/core/java/com/android/server/job/controllers/StorageController.java b/services/core/java/com/android/server/job/controllers/StorageController.java index 4fe8eca54a6e..c24e563948d4 100644 --- a/services/core/java/com/android/server/job/controllers/StorageController.java +++ b/services/core/java/com/android/server/job/controllers/StorageController.java @@ -35,7 +35,7 @@ import java.io.PrintWriter; /** * Simple controller that tracks the status of the device's storage. */ -public class StorageController extends StateController { +public final class StorageController extends StateController { private static final String TAG = "JobScheduler.Stor"; private static final Object sCreationLock = new Object(); @@ -112,7 +112,7 @@ public class StorageController extends StateController { } } - public class StorageTracker extends BroadcastReceiver { + public final class StorageTracker extends BroadcastReceiver { /** * Track whether storage is low. */ diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java index 01c841e2083c..d90699a61928 100644 --- a/services/core/java/com/android/server/job/controllers/TimeController.java +++ b/services/core/java/com/android/server/job/controllers/TimeController.java @@ -38,7 +38,7 @@ import java.util.ListIterator; * This class sets an alarm for the next expiring job, and determines whether a job's minimum * delay has been satisfied. */ -public class TimeController extends StateController { +public final class TimeController extends StateController { private static final String TAG = "JobScheduler.Time"; /** Deadline alarm tag for logging purposes */ diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java index 34cc6e37d996..d0d306c580ba 100644 --- a/services/core/java/com/android/server/pm/InstantAppResolver.java +++ b/services/core/java/com/android/server/pm/InstantAppResolver.java @@ -121,8 +121,11 @@ public abstract class InstantAppResolver { resolutionStatus = RESOLUTION_FAILURE; } } - logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE, startTime, token, - resolutionStatus); + // Only log successful instant application resolution + if (resolutionStatus == RESOLUTION_SUCCESS) { + logMetrics(ACTION_INSTANT_APP_RESOLUTION_PHASE_ONE, startTime, token, + resolutionStatus); + } if (DEBUG_EPHEMERAL && resolveInfo == null) { if (resolutionStatus == RESOLUTION_BIND_TIMEOUT) { Log.d(TAG, "[" + token + "] Phase1; bind timed out"); diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 6f07973962bb..bf64f6427c7c 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -81,8 +81,10 @@ import android.util.ExceptionUtils; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import android.util.Xml; +import java.io.CharArrayWriter; import libcore.io.IoUtils; import com.android.internal.R; @@ -195,7 +197,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub { /** Historical sessions kept around for debugging purposes */ @GuardedBy("mSessions") - private final SparseArray<PackageInstallerSession> mHistoricalSessions = new SparseArray<>(); + private final List<String> mHistoricalSessions = new ArrayList<>(); + + @GuardedBy("mSessions") + private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray(); /** Sessions allocated to legacy users */ @GuardedBy("mSessions") @@ -371,7 +376,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { // Since this is early during boot we don't send // any observer events about the session, but we // keep details around for dumpsys. - mHistoricalSessions.put(session.sessionId, session); + addHistoricalSessionLocked(session); } mAllocatedSessions.put(session.sessionId, true); } @@ -386,6 +391,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } + private void addHistoricalSessionLocked(PackageInstallerSession session) { + CharArrayWriter writer = new CharArrayWriter(); + IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + session.dump(pw); + mHistoricalSessions.add(writer.toString()); + + // Increment the number of sessions by this installerUid. + mHistoricalSessionsByInstaller.put( + session.installerUid, + mHistoricalSessionsByInstaller.get(session.installerUid) + 1); + } + private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException, XmlPullParserException { final int sessionId = readIntAttribute(in, ATTR_SESSION_ID); @@ -676,7 +693,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { throw new IllegalStateException( "Too many active sessions for UID " + callingUid); } - final int historicalCount = getSessionCount(mHistoricalSessions, callingUid); + final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid); if (historicalCount >= MAX_HISTORICAL_SESSIONS) { throw new IllegalStateException( "Too many historical sessions for UID " + callingUid); @@ -1228,8 +1245,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { pw.increaseIndent(); N = mHistoricalSessions.size(); for (int i = 0; i < N; i++) { - final PackageInstallerSession session = mHistoricalSessions.valueAt(i); - session.dump(pw); + pw.print(mHistoricalSessions.get(i)); pw.println(); } pw.println(); @@ -1264,7 +1280,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { public void run() { synchronized (mSessions) { mSessions.remove(session.sessionId); - mHistoricalSessions.put(session.sessionId, session); + addHistoricalSessionLocked(session); final File appIconFile = buildAppIconFile(session.sessionId); if (appIconFile.exists()) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 48b9c7de650b..bf3e5d37e7ae 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -49,6 +49,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_L import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY; import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED; import static android.content.pm.PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE; +import static android.content.pm.PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE; import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE; import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY; import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; @@ -677,13 +678,6 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mPackages") final SparseIntArray mIsolatedOwners = new SparseIntArray(); - // List of APK paths to load for each user and package. This data is never - // persisted by the package manager. Instead, the overlay manager will - // ensure the data is up-to-date in runtime. - @GuardedBy("mPackages") - final SparseArray<ArrayMap<String, ArrayList<String>>> mEnabledOverlayPaths = - new SparseArray<ArrayMap<String, ArrayList<String>>>(); - /** * Tracks new system packages [received in an OTA] that we expect to * find updated user-installed versions. Keys are package name, values @@ -3584,8 +3578,6 @@ public class PackageManagerService extends IPackageManager.Stub return null; } - rebaseEnabledOverlays(packageInfo.applicationInfo, userId); - packageInfo.packageName = packageInfo.applicationInfo.packageName = resolveExternalPackageNameLPr(p); @@ -4097,7 +4089,6 @@ public class PackageManagerService extends IPackageManager.Stub ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags, ps.readUserState(userId), userId); if (ai != null) { - rebaseEnabledOverlays(ai, userId); ai.packageName = resolveExternalPackageNameLPr(ps.pkg); } return ai; @@ -4146,7 +4137,6 @@ public class PackageManagerService extends IPackageManager.Stub ApplicationInfo ai = PackageParser.generateApplicationInfo( p, flags, ps.readUserState(userId), userId); if (ai != null) { - rebaseEnabledOverlays(ai, userId); ai.packageName = resolveExternalPackageNameLPr(p); } return ai; @@ -4163,26 +4153,6 @@ public class PackageManagerService extends IPackageManager.Stub return null; } - private void rebaseEnabledOverlays(@NonNull ApplicationInfo ai, int userId) { - List<String> paths = new ArrayList<>(); - ArrayMap<String, ArrayList<String>> userSpecificOverlays = - mEnabledOverlayPaths.get(userId); - if (userSpecificOverlays != null) { - if (!"android".equals(ai.packageName)) { - ArrayList<String> frameworkOverlays = userSpecificOverlays.get("android"); - if (frameworkOverlays != null) { - paths.addAll(frameworkOverlays); - } - } - - ArrayList<String> appOverlays = userSpecificOverlays.get(ai.packageName); - if (appOverlays != null) { - paths.addAll(appOverlays); - } - } - ai.resourceDirs = paths.size() > 0 ? paths.toArray(new String[paths.size()]) : null; - } - private String normalizePackageNameLPr(String packageName) { String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName); return normalizedPackageName != null ? normalizedPackageName : packageName; @@ -4258,10 +4228,7 @@ public class PackageManagerService extends IPackageManager.Stub volumeUuid); final boolean aggressive = (storageFlags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0; - final boolean defyReserved = (storageFlags - & StorageManager.FLAG_ALLOCATE_DEFY_RESERVED) != 0; - final long reservedBytes = (aggressive || defyReserved) ? 0 - : storage.getStorageCacheBytes(file); + final long reservedBytes = storage.getStorageCacheBytes(file, storageFlags); // 1. Pre-flight to determine if we have any chance to succeed // 2. Consider preloaded data (after 1w honeymoon, unless aggressive) @@ -4567,24 +4534,6 @@ public class PackageManagerService extends IPackageManager.Stub return updateFlagsForComponent(flags, userId, intent /*cookie*/); } - private ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, PackageUserState state, - int userId) { - ActivityInfo ret = PackageParser.generateActivityInfo(ai, flags, state, userId); - if (ret != null) { - rebaseEnabledOverlays(ret.applicationInfo, userId); - } - return ret; - } - - private ActivityInfo generateActivityInfo(PackageParser.Activity a, int flags, - PackageUserState state, int userId) { - ActivityInfo ai = PackageParser.generateActivityInfo(a, flags, state, userId); - if (ai != null) { - rebaseEnabledOverlays(ai.applicationInfo, userId); - } - return ai; - } - @Override public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId); @@ -4612,11 +4561,12 @@ public class PackageManagerService extends IPackageManager.Stub if (filterAppAccessLPr(ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) { return null; } - return generateActivityInfo(a, flags, ps.readUserState(userId), userId); + return PackageParser.generateActivityInfo( + a, flags, ps.readUserState(userId), userId); } if (mResolveComponentName.equals(component)) { - return generateActivityInfo(mResolveActivity, flags, new PackageUserState(), - userId); + return PackageParser.generateActivityInfo( + mResolveActivity, flags, new PackageUserState(), userId); } } return null; @@ -4670,7 +4620,8 @@ public class PackageManagerService extends IPackageManager.Stub if (filterAppAccessLPr(ps, callingUid, component, TYPE_RECEIVER, userId)) { return null; } - return generateActivityInfo(a, flags, ps.readUserState(userId), userId); + return PackageParser.generateActivityInfo( + a, flags, ps.readUserState(userId), userId); } } return null; @@ -4806,12 +4757,8 @@ public class PackageManagerService extends IPackageManager.Stub if (filterAppAccessLPr(ps, callingUid, component, TYPE_SERVICE, userId)) { return null; } - ServiceInfo si = PackageParser.generateServiceInfo(s, flags, - ps.readUserState(userId), userId); - if (si != null) { - rebaseEnabledOverlays(si.applicationInfo, userId); - } - return si; + return PackageParser.generateServiceInfo( + s, flags, ps.readUserState(userId), userId); } } return null; @@ -4834,12 +4781,8 @@ public class PackageManagerService extends IPackageManager.Stub if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) { return null; } - ProviderInfo pi = PackageParser.generateProviderInfo(p, flags, - ps.readUserState(userId), userId); - if (pi != null) { - rebaseEnabledOverlays(pi.applicationInfo, userId); - } - return pi; + return PackageParser.generateProviderInfo( + p, flags, ps.readUserState(userId), userId); } } return null; @@ -8265,7 +8208,6 @@ public class PackageManagerService extends IPackageManager.Stub ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags, ps.readUserState(userId), userId); if (ai != null) { - rebaseEnabledOverlays(ai, userId); ai.packageName = resolveExternalPackageNameLPr(ps.pkg); } } else { @@ -8292,7 +8234,6 @@ public class PackageManagerService extends IPackageManager.Stub ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId), userId); if (ai != null) { - rebaseEnabledOverlays(ai, userId); ai.packageName = resolveExternalPackageNameLPr(p); list.add(ai); } @@ -8446,7 +8387,6 @@ public class PackageManagerService extends IPackageManager.Stub ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId), userId); if (ai != null) { - rebaseEnabledOverlays(ai, userId); finalList.add(ai); } } @@ -13370,7 +13310,8 @@ public class PackageManagerService extends IPackageManager.Stub return null; } final PackageUserState userState = ps.readUserState(userId); - ActivityInfo ai = generateActivityInfo(activity, mFlags, userState, userId); + ActivityInfo ai = + PackageParser.generateActivityInfo(activity, mFlags, userState, userId); if (ai == null) { return null; } @@ -17899,16 +17840,17 @@ public class PackageManagerService extends IPackageManager.Stub // Instant apps must have target SDK >= O and have targetSanboxVersion >= 2 if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) { - Slog.w(TAG, "Instant app package " + pkg.packageName - + " does not target O, this will be a fatal error."); - // STOPSHIP: Make this a fatal error - pkg.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O; + Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O"); + res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE, + "Instant app package must target O"); + return; } if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) { Slog.w(TAG, "Instant app package " + pkg.packageName - + " does not target targetSandboxVersion 2, this will be a fatal error."); - // STOPSHIP: Make this a fatal error - pkg.applicationInfo.targetSandboxVersion = 2; + + " does not target targetSandboxVersion 2"); + res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE, + "Instant app package must use targetSanboxVersion 2"); + return; } if (pkg.applicationInfo.isStaticSharedLibrary()) { @@ -22349,11 +22291,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); dumpCompilerStatsLPr(pw, packageName); } - if (!checkin && dumpState.isDumping(DumpState.DUMP_ENABLED_OVERLAYS)) { - if (dumpState.onTitlePrinted()) pw.println(); - dumpEnabledOverlaysLPr(pw); - } - if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) { if (dumpState.onTitlePrinted()) pw.println(); mSettings.dumpReadMessagesLPr(pw, dumpState); @@ -22550,23 +22487,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } } - private void dumpEnabledOverlaysLPr(PrintWriter pw) { - pw.println("Enabled overlay paths:"); - final int N = mEnabledOverlayPaths.size(); - for (int i = 0; i < N; i++) { - final int userId = mEnabledOverlayPaths.keyAt(i); - pw.println(String.format(" User %d:", userId)); - final ArrayMap<String, ArrayList<String>> userSpecificOverlays = - mEnabledOverlayPaths.valueAt(i); - final int M = userSpecificOverlays.size(); - for (int j = 0; j < M; j++) { - final String targetPackageName = userSpecificOverlays.keyAt(j); - final ArrayList<String> overlayPackagePaths = userSpecificOverlays.valueAt(j); - pw.println(String.format(" %s: %s", targetPackageName, overlayPackagePaths)); - } - } - } - private String dumpDomainString(String packageName) { List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName) .getList(); @@ -24744,11 +24664,10 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); Slog.e(TAG, "failed to find package " + targetPackageName); return false; } - - ArrayList<String> paths = null; - if (overlayPackageNames != null) { + ArrayList<String> overlayPaths = null; + if (overlayPackageNames != null && overlayPackageNames.size() > 0) { final int N = overlayPackageNames.size(); - paths = new ArrayList<>(N); + overlayPaths = new ArrayList<>(N); for (int i = 0; i < N; i++) { final String packageName = overlayPackageNames.get(i); final PackageParser.Package pkg = mPackages.get(packageName); @@ -24756,22 +24675,17 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); Slog.e(TAG, "failed to find package " + packageName); return false; } - paths.add(pkg.baseCodePath); + overlayPaths.add(pkg.baseCodePath); } } - ArrayMap<String, ArrayList<String>> userSpecificOverlays = - mEnabledOverlayPaths.get(userId); - if (userSpecificOverlays == null) { - userSpecificOverlays = new ArrayMap<>(); - mEnabledOverlayPaths.put(userId, userSpecificOverlays); - } - - if (paths != null && paths.size() > 0) { - userSpecificOverlays.put(targetPackageName, paths); - } else { - userSpecificOverlays.remove(targetPackageName); + final PackageSetting ps = mSettings.mPackages.get(targetPackageName); + String[] frameworkOverlayPaths = null; + if (!"android".equals(targetPackageName)) { + frameworkOverlayPaths = + mSettings.mPackages.get("android").getOverlayPaths(userId); } + ps.setOverlayPaths(overlayPaths, frameworkOverlayPaths, userId); return true; } } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 14f65eb485f4..d17267f38648 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -31,6 +31,7 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; +import com.google.android.collect.Lists; import java.io.File; import java.util.ArrayList; @@ -329,6 +330,27 @@ abstract class PackageSettingBase extends SettingBase { modifyUserState(userId).installReason = installReason; } + void setOverlayPaths(List<String> overlayPaths, String[] frameworkOverlayPaths, int userId) { + if (overlayPaths == null && frameworkOverlayPaths == null) { + modifyUserState(userId).overlayPaths = null; + return; + } + final List<String> paths; + if (frameworkOverlayPaths == null) { + paths = overlayPaths; + } else { + paths = Lists.newArrayList(frameworkOverlayPaths); + if (overlayPaths != null) { + paths.addAll(overlayPaths); + } + } + modifyUserState(userId).overlayPaths = paths.toArray(new String[paths.size()]); + } + + String[] getOverlayPaths(int userId) { + return readUserState(userId).overlayPaths; + } + /** Only use for testing. Do NOT use in production code. */ @VisibleForTesting SparseArray<PackageUserState> getUserState() { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 24cbdbff9153..b006c2d991e6 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4858,6 +4858,15 @@ final class Settings { pw.print(ps.getEnabled(user.id)); pw.print(" instant="); pw.println(ps.getInstantApp(user.id)); + + String[] overlayPaths = ps.getOverlayPaths(user.id); + if (overlayPaths != null && overlayPaths.length > 0) { + pw.println("Overlay paths:"); + for (String path : overlayPaths) { + pw.println(path); + } + } + String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id); if (lastDisabledAppCaller != null) { pw.print(prefix); pw.print(" lastDisabledCaller: "); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 4bc3725fecab..126e3ec30289 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3052,13 +3052,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win + ": transit=" + transit); if (win == mStatusBar) { - boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0; + final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0; + final boolean expanded = win.getAttrs().height == MATCH_PARENT + && win.getAttrs().width == MATCH_PARENT; + if (isKeyguard || expanded) { + return -1; + } if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { - return isKeyguard ? -1 : R.anim.dock_top_exit; + return R.anim.dock_top_exit; } else if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { - return isKeyguard ? -1 : R.anim.dock_top_enter; + return R.anim.dock_top_enter; } } else if (win == mNavigationBar) { if (win.getAttrs().windowAnimations != 0) { @@ -6793,7 +6798,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public boolean isScreenOn() { - return mScreenOnFully; + synchronized (mLock) { + return mScreenOnEarly; + } } /** {@inheritDoc} */ diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 864e83ef1f86..02f2afcb0be8 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -256,7 +256,7 @@ public final class ShutdownThread extends Thread { ProgressDialog pd = new ProgressDialog(context); // Path 1: Reboot to recovery for update - // Condition: mReason == REBOOT_RECOVERY_UPDATE + // Condition: mReason startswith REBOOT_RECOVERY_UPDATE // // Path 1a: uncrypt needed // Condition: if /cache/recovery/uncrypt_file exists but @@ -276,7 +276,9 @@ public final class ShutdownThread extends Thread { // Path 3: Regular reboot / shutdown // Condition: Otherwise // UI: spinning circle only (no progress bar) - if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) { + + // mReason could be "recovery-update" or "recovery-update,quiescent". + if (mReason != null && mReason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) { // We need the progress bar if uncrypt will be invoked during the // reboot, which might be time-consuming. mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists() @@ -295,7 +297,7 @@ public final class ShutdownThread extends Thread { pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_update_reboot)); } - } else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) { + } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) { // Factory reset path. Set the dialog message accordingly. pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title)); pd.setMessage(context.getText( @@ -389,7 +391,8 @@ public final class ShutdownThread extends Thread { // First send the high-level shut down broadcast. mActionDone = false; Intent intent = new Intent(Intent.ACTION_SHUTDOWN); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND + | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, null, br, mHandler, 0, null, null); diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index 410efcdb5038..cff2fadd7649 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -20,6 +20,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.animation.AnimationHandler; +import android.animation.AnimationHandler.AnimationFrameCallbackProvider; import android.animation.Animator; import android.animation.ValueAnimator; import android.annotation.IntDef; @@ -30,11 +32,13 @@ import android.os.IBinder; import android.os.Debug; import android.util.ArrayMap; import android.util.Slog; +import android.view.Choreographer; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.WindowManagerInternal; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -49,7 +53,7 @@ import java.lang.annotation.RetentionPolicy; * * The object that is resized needs to implement {@link BoundsAnimationTarget} interface. * - * NOTE: All calls to methods in this class should be done on the UI thread + * NOTE: All calls to methods in this class should be done on the Animation thread */ public class BoundsAnimationController { private static final boolean DEBUG_LOCAL = false; @@ -111,20 +115,24 @@ public class BoundsAnimationController { private final AppTransitionNotifier mAppTransitionNotifier = new AppTransitionNotifier(); private final Interpolator mFastOutSlowInInterpolator; private boolean mFinishAnimationAfterTransition = false; + private final AnimationHandler mAnimationHandler; private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000; - BoundsAnimationController(Context context, AppTransition transition, Handler handler) { + BoundsAnimationController(Context context, AppTransition transition, Handler handler, + AnimationHandler animationHandler) { mHandler = handler; mAppTransition = transition; mAppTransition.registerListenerLocked(mAppTransitionNotifier); mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.fast_out_slow_in); + mAnimationHandler = animationHandler; } @VisibleForTesting final class BoundsAnimator extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { + private final BoundsAnimationTarget mTarget; private final Rect mFrom = new Rect(); private final Rect mTo = new Rect(); @@ -198,6 +206,10 @@ public class BoundsAnimationController { mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth, mFrom.top + mFrozenTaskHeight); + // Boost the thread priority of the animation thread while the bounds animation is + // running + updateBooster(); + // Ensure that we have prepared the target for animation before // we trigger any size changes, so it can swap surfaces // in to appropriate modes, or do as it wishes otherwise. @@ -308,6 +320,9 @@ public class BoundsAnimationController { removeListener(this); removeUpdateListener(this); mRunningAnimations.remove(mTarget); + + // Reset the thread priority of the animation thread after the bounds animation is done + updateBooster(); } @Override @@ -350,6 +365,14 @@ public class BoundsAnimationController { public void onAnimationRepeat(Animator animation) { // Do nothing } + + @Override + public AnimationHandler getAnimationHandler() { + if (mAnimationHandler != null) { + return mAnimationHandler; + } + return super.getAnimationHandler(); + } } public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to, @@ -430,4 +453,9 @@ public class BoundsAnimationController { b.resume(); } } + + private void updateBooster() { + WindowManagerService.sThreadPriorityBooster.setBoundsAnimationRunning( + !mRunningAnimations.isEmpty()); + } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ccc8f63e4355..54983c8998fc 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -314,6 +314,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // the display's direct children should be allowed. private boolean mRemovingDisplay = false; + // {@code false} if this display is in the processing of being created. + private boolean mDisplayReady = false; + private final WindowLayersController mLayersController; WallpaperController mWallpaperController; int mInputMethodAnimLayerAdjustment; @@ -720,7 +723,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ DisplayContent(Display display, WindowManagerService service, WindowLayersController layersController, WallpaperController wallpaperController) { - if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) { throw new IllegalArgumentException("Display with ID=" + display.getDisplayId() + " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId()) @@ -748,6 +750,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // Add itself as a child to the root container. mService.mRoot.addChild(this, null); + + // TODO(b/62541591): evaluate whether this is the best spot to declare the + // {@link DisplayContent} ready for use. + mDisplayReady = true; + } + + boolean isReady() { + // The display is ready when the system and the individual display are both ready. + return mService.mDisplayReady && mDisplayReady; } int getDisplayId() { diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 03b5b827db74..aabf2bed1dd4 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -108,7 +108,8 @@ public class WindowAnimator { } void addDisplayLocked(final int displayId) { - // Create the DisplayContentsAnimator object by retrieving it. + // Create the DisplayContentsAnimator object by retrieving it if the associated + // {@link DisplayContent} exists. getDisplayContentsAnimatorLocked(displayId); if (displayId == DEFAULT_DISPLAY) { mInitialized = true; @@ -356,8 +357,16 @@ public class WindowAnimator { } private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) { + if (displayId < 0) { + return null; + } + DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId); - if (displayAnimator == null) { + + // It is possible that this underlying {@link DisplayContent} has been removed. In this + // case, we do not want to create an animator associated with it as {link #animate} will + // fail. + if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) { displayAnimator = new DisplayContentsAnimator(); mDisplayContentsAnimators.put(displayId, displayAnimator); } @@ -365,8 +374,10 @@ public class WindowAnimator { } void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) { - if (displayId >= 0) { - getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation; + final DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId); + + if (animator != null) { + animator.mScreenRotationAnimation = animation; } } @@ -374,7 +385,9 @@ public class WindowAnimator { if (displayId < 0) { return null; } - return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation; + + DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId); + return animator != null? animator.mScreenRotationAnimation : null; } void requestRemovalOfReplacedWindows(WindowState win) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f8ede6cee9e3..41ddf0c093cd 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -103,6 +103,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.Manifest; import android.Manifest.permission; +import android.animation.AnimationHandler; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; @@ -211,6 +212,7 @@ import android.view.inputmethod.InputMethodManagerInternal; import com.android.internal.R; import com.android.internal.app.IAssistScreenshotReceiver; +import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.os.IResultReceiver; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; @@ -1046,8 +1048,10 @@ public class WindowManagerService extends IWindowManager.Stub mAppTransition = new AppTransition(context, this); mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier); + final AnimationHandler animationHandler = new AnimationHandler(); + animationHandler.setProvider(new SfVsyncFrameCallbackProvider()); mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition, - UiThread.getHandler()); + AnimationThread.getHandler(), animationHandler); mActivityManager = ActivityManager.getService(); mAmInternal = LocalServices.getService(ActivityManagerInternal.class); @@ -5886,8 +5890,8 @@ public class WindowManagerService extends IWindowManager.Stub return; } - if (!mDisplayReady || !mPolicy.isScreenOn()) { - // No need to freeze the screen before the system is ready or if + if (!displayContent.isReady() || !mPolicy.isScreenOn()) { + // No need to freeze the screen before the display is ready, system is ready, or if // the screen is off. return; } diff --git a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java index 6a244a251537..1b2eb465399a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java +++ b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java @@ -23,6 +23,7 @@ import static android.os.Process.setThreadPriority; import static com.android.server.LockGuard.INDEX_WINDOW; import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST; +import com.android.internal.annotations.GuardedBy; import com.android.server.AnimationThread; import com.android.server.ThreadPriorityBooster; @@ -32,12 +33,18 @@ import com.android.server.ThreadPriorityBooster; */ class WindowManagerThreadPriorityBooster extends ThreadPriorityBooster { - private final AnimationThread mAnimationThread; + private final Object mLock = new Object(); + + private final int mAnimationThreadId; + + @GuardedBy("mLock") private boolean mAppTransitionRunning; + @GuardedBy("mLock") + private boolean mBoundsAnimationRunning; WindowManagerThreadPriorityBooster() { super(THREAD_PRIORITY_DISPLAY, INDEX_WINDOW); - mAnimationThread = AnimationThread.get(); + mAnimationThreadId = AnimationThread.get().getThreadId(); } @Override @@ -45,7 +52,7 @@ class WindowManagerThreadPriorityBooster extends ThreadPriorityBooster { // Do not boost the animation thread. As the animation thread is changing priorities, // boosting it might mess up the priority because we reset it the the previous priority. - if (myTid() == mAnimationThread.getThreadId()) { + if (myTid() == mAnimationThreadId) { return; } super.boost(); @@ -55,24 +62,35 @@ class WindowManagerThreadPriorityBooster extends ThreadPriorityBooster { public void reset() { // See comment in boost(). - if (myTid() == mAnimationThread.getThreadId()) { + if (myTid() == mAnimationThreadId) { return; } super.reset(); } void setAppTransitionRunning(boolean running) { - if (mAppTransitionRunning == running) { - return; + synchronized (mLock) { + if (mAppTransitionRunning != running) { + mAppTransitionRunning = running; + updatePriorityLocked(); + } } + } - final int priority = calculatePriority(running); - setBoostToPriority(priority); - setThreadPriority(mAnimationThread.getThreadId(), priority); - mAppTransitionRunning = running; + void setBoundsAnimationRunning(boolean running) { + synchronized (mLock) { + if (mBoundsAnimationRunning != running) { + mBoundsAnimationRunning = running; + updatePriorityLocked(); + } + } } - private int calculatePriority(boolean appTransitionRunning) { - return appTransitionRunning ? TOP_APP_PRIORITY_BOOST : THREAD_PRIORITY_DISPLAY; + @GuardedBy("mLock") + private void updatePriorityLocked() { + int priority = (mAppTransitionRunning || mBoundsAnimationRunning) + ? TOP_APP_PRIORITY_BOOST : THREAD_PRIORITY_DISPLAY; + setBoostToPriority(priority); + setThreadPriority(mAnimationThreadId, priority); } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 272c11b985c5..eca285a1a27b 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -454,7 +454,7 @@ public final class SystemServer { // If '/cache/recovery/block.map' hasn't been created, stop the // reboot which will fail for sure, and get a chance to capture a // bugreport when that's still feasible. (Bug: 26444951) - if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) { + if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) { File packageFile = new File(UNCRYPT_PACKAGE_FILE); if (packageFile.exists()) { String filename = null; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java index 89e18b4c2f41..40e114bfaef2 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java @@ -491,12 +491,12 @@ public class MockStorageManager implements IStorageManager { } @Override - public long getAllocatableBytes(String path, int flags) { + public long getAllocatableBytes(String path, int flags, String callingPackage) { throw new UnsupportedOperationException(); } @Override - public void allocateBytes(String path, long bytes, int flags) { + public void allocateBytes(String path, long bytes, int flags, String callingPackage) { throw new UnsupportedOperationException(); } @@ -504,5 +504,4 @@ public class MockStorageManager implements IStorageManager { public void secdiscard(String path) throws RemoteException { throw new UnsupportedOperationException(); } - } diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java index ee09f4bf7b94..9d32496c7817 100644 --- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java @@ -395,7 +395,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { mMockAppTransition = new MockAppTransition(context); mMockAnimator = new MockValueAnimator(); mTarget = new TestBoundsAnimationTarget(); - mController = new BoundsAnimationController(context, mMockAppTransition, handler); + mController = new BoundsAnimationController(context, mMockAppTransition, handler, null); mDriver = new BoundsAnimationDriver(mController, mTarget); } diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java index 562443f53546..9f4fb85f64c4 100644 --- a/services/usage/java/com/android/server/usage/StorageStatsService.java +++ b/services/usage/java/com/android/server/usage/StorageStatsService.java @@ -197,7 +197,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { // logic should be kept in sync with getAllocatableBytes(). if (isQuotaSupported(volumeUuid, callingPackage)) { final long cacheTotal = getCacheBytes(volumeUuid, callingPackage); - final long cacheReserved = mStorage.getStorageCacheBytes(path); + final long cacheReserved = mStorage.getStorageCacheBytes(path, 0); final long cacheClearable = Math.max(0, cacheTotal - cacheReserved); return path.getUsableSpace() + cacheClearable; diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java index 640c9e12079b..de205380c3a7 100644 --- a/telecomm/java/android/telecom/Log.java +++ b/telecomm/java/android/telecom/Log.java @@ -325,7 +325,8 @@ public class Log { return sEventManager; } - private static SessionManager getSessionManager() { + @VisibleForTesting + public static SessionManager getSessionManager() { // Checking for null again outside of synchronization because we only need to synchronize // during the lazy loading of the session logger. We don't need to synchronize elsewhere. if (sSessionManager == null) { diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 331328d63841..b1eedf5cad4b 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -369,6 +369,15 @@ public class TelecomManager { public static final String EXTRA_IS_HANDOVER = "android.telecom.extra.IS_HANDOVER"; /** + * Parcelable extra used with {@link #EXTRA_IS_HANDOVER} to indicate the source + * {@link PhoneAccountHandle} when initiating a handover which {@link ConnectionService} + * the handover is from. + * @hide + */ + public static final String EXTRA_HANDOVER_FROM_PHONE_ACCOUNT = + "android.telecom.extra.HANDOVER_FROM_PHONE_ACCOUNT"; + + /** * Extra key specified in the {@link ConnectionRequest#getExtras()} when Telecom calls * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)} * to inform the {@link ConnectionService} what the initial {@link CallAudioState} of the diff --git a/tests/JobSchedulerTestApp/res/layout/activity_main.xml b/tests/JobSchedulerTestApp/res/layout/activity_main.xml index 96e164103bce..41f977707097 100644 --- a/tests/JobSchedulerTestApp/res/layout/activity_main.xml +++ b/tests/JobSchedulerTestApp/res/layout/activity_main.xml @@ -73,10 +73,18 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> + <RadioButton android:id="@+id/checkbox_none" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/none"/> <RadioButton android:id="@+id/checkbox_any" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/any"/> + <RadioButton android:id="@+id/checkbox_metered" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/metered"/> <RadioButton android:id="@+id/checkbox_unmetered" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/tests/JobSchedulerTestApp/res/values/strings.xml b/tests/JobSchedulerTestApp/res/values/strings.xml index 90dd2b672fb2..866b61ecb308 100644 --- a/tests/JobSchedulerTestApp/res/values/strings.xml +++ b/tests/JobSchedulerTestApp/res/values/strings.xml @@ -30,7 +30,9 @@ limitations under the License. <string name="persisted_caption">Persisted:</string> <string name="constraints">Constraints</string> <string name="connectivity">Connectivity:</string> + <string name="none">None</string> <string name="any">Any</string> + <string name="metered">Metered</string> <string name="unmetered">WiFi</string> <string name="timing">Timing:</string> <string name="delay">Delay:</string> diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java index 51cdbb585659..3dfdba719ce5 100644 --- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java +++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java @@ -63,6 +63,7 @@ public class MainActivity extends Activity { mDeadlineEditText = findViewById(R.id.deadline_time); mWiFiConnectivityRadioButton = findViewById(R.id.checkbox_unmetered); mAnyConnectivityRadioButton = findViewById(R.id.checkbox_any); + mCellConnectivityRadioButton = findViewById(R.id.checkbox_metered); mRequiresChargingCheckBox = findViewById(R.id.checkbox_charging); mRequiresIdleCheckbox = findViewById(R.id.checkbox_idle); mIsPersistedCheckbox = findViewById(R.id.checkbox_persisted); @@ -85,6 +86,7 @@ public class MainActivity extends Activity { EditText mDeadlineEditText; RadioButton mWiFiConnectivityRadioButton; RadioButton mAnyConnectivityRadioButton; + RadioButton mCellConnectivityRadioButton; CheckBox mRequiresChargingCheckBox; CheckBox mRequiresIdleCheckbox; CheckBox mIsPersistedCheckbox; @@ -141,9 +143,12 @@ public class MainActivity extends Activity { builder.setOverrideDeadline(Long.parseLong(deadline) * 1000); } boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked(); + boolean requiresMetered = mCellConnectivityRadioButton.isChecked(); boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked(); if (requiresUnmetered) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); + } else if (requiresMetered) { + builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_METERED); } else if (requiresAnyConnectivity) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); } diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java index 9df11fe90553..b698a3a53ff1 100644 --- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java +++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java @@ -81,7 +81,8 @@ public class TestJobService extends JobService { @Override public boolean onStartJob(JobParameters params) { - Log.i(TAG, "on start job: " + params.getJobId()); + Log.i(TAG, "on start job: " + params.getJobId() + + " deadline?=" + params.isOverrideDeadlineExpired()); currentId++; jobParamsMap.put(currentId, params); final int currId = this.currentId; diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java index babbed02a11c..428c8bbe20e5 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java @@ -67,6 +67,7 @@ public class WifiAwareSession implements AutoCloseable { * An application may re-attach after a destroy using * {@link WifiAwareManager#attach(AttachCallback, Handler)} . */ + @Override public void close() { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index 7f085f71e99c..f596eef1bf21 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -683,7 +683,7 @@ public class WifiP2pManager { private DnsSdTxtRecordListener mDnsSdTxtListener; private UpnpServiceResponseListener mUpnpServRspListener; private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>(); - private Object mListenerMapLock = new Object(); + private final Object mListenerMapLock = new Object(); private int mListenerKey = 0; private AsyncChannel mAsyncChannel; |