diff options
193 files changed, 5432 insertions, 3744 deletions
diff --git a/Android.bp b/Android.bp index 344867715a3f..d04eb17adf15 100644 --- a/Android.bp +++ b/Android.bp @@ -962,6 +962,7 @@ metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.x "--hide-package com.android.org.conscrypt --hide-package com.android.server " + "--error UnhiddenSystemApi " + "--hide RequiresPermission " + + "--hide CallbackInterface " + "--hide MissingPermission --hide BroadcastBehavior " + "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " + @@ -1637,6 +1638,7 @@ filegroup { name: "framework-wifistack-shared-srcs", srcs: [ ":framework-annotations", + "core/java/android/os/HandlerExecutor.java", "core/java/android/util/KeyValueListParser.java", "core/java/android/util/LocalLog.java", "core/java/android/util/Rational.java", diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index eb22d0907525..593e49490e94 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -59,9 +59,7 @@ import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteException; -import android.os.ResultReceiver; import android.os.ServiceManager; -import android.os.ShellCallback; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManagerInternal; @@ -2690,12 +2688,13 @@ public class JobSchedulerService extends com.android.server.SystemService } @Override - public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ShellCallback callback, ResultReceiver resultReceiver) { - (new JobSchedulerShellCommand(JobSchedulerService.this)).exec( - this, in, out, err, args, callback, resultReceiver); + protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out, + @NonNull FileDescriptor err, @NonNull String[] args) { + return (new JobSchedulerShellCommand(JobSchedulerService.this)).exec( + this, in, out, err, args); } + /** * <b>For internal system user only!</b> * Returns a list of all currently-executing jobs. diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java index 01d158ba9452..a5c6c0132fc8 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java @@ -20,13 +20,13 @@ import android.app.ActivityManager; import android.app.AppGlobals; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.os.BasicShellCommandHandler; import android.os.Binder; -import android.os.ShellCommand; import android.os.UserHandle; import java.io.PrintWriter; -public final class JobSchedulerShellCommand extends ShellCommand { +public final class JobSchedulerShellCommand extends BasicShellCommandHandler { 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/api/current.txt b/api/current.txt index 55983c86ee4b..e5acc4062377 100644 --- a/api/current.txt +++ b/api/current.txt @@ -42916,6 +42916,7 @@ package android.system { field public static final int IP_MULTICAST_TTL; field public static final int IP_TOS; field public static final int IP_TTL; + field public static final int MAP_ANONYMOUS; field public static final int MAP_FIXED; field public static final int MAP_PRIVATE; field public static final int MAP_SHARED; @@ -50390,34 +50391,34 @@ package android.view { } public class TextureView extends android.view.View { - ctor public TextureView(android.content.Context); - ctor public TextureView(android.content.Context, android.util.AttributeSet); - ctor public TextureView(android.content.Context, android.util.AttributeSet, int); - ctor public TextureView(android.content.Context, android.util.AttributeSet, int, int); + ctor public TextureView(@NonNull android.content.Context); + ctor public TextureView(@NonNull android.content.Context, @Nullable android.util.AttributeSet); + ctor public TextureView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int); + ctor public TextureView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int, int); method public final void draw(android.graphics.Canvas); - method public android.graphics.Bitmap getBitmap(); - method public android.graphics.Bitmap getBitmap(int, int); - method public android.graphics.Bitmap getBitmap(android.graphics.Bitmap); - method public android.graphics.SurfaceTexture getSurfaceTexture(); - method public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener(); - method public android.graphics.Matrix getTransform(android.graphics.Matrix); + method @Nullable public android.graphics.Bitmap getBitmap(); + method @Nullable public android.graphics.Bitmap getBitmap(int, int); + method @NonNull public android.graphics.Bitmap getBitmap(@NonNull android.graphics.Bitmap); + method @Nullable public android.graphics.SurfaceTexture getSurfaceTexture(); + method @Nullable public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener(); + method @NonNull public android.graphics.Matrix getTransform(@Nullable android.graphics.Matrix); method public boolean isAvailable(); - method public android.graphics.Canvas lockCanvas(); - method public android.graphics.Canvas lockCanvas(android.graphics.Rect); + method @Nullable public android.graphics.Canvas lockCanvas(); + method @Nullable public android.graphics.Canvas lockCanvas(@Nullable android.graphics.Rect); method protected final void onDraw(android.graphics.Canvas); method public void setBackgroundDrawable(android.graphics.drawable.Drawable); method public void setOpaque(boolean); - method public void setSurfaceTexture(android.graphics.SurfaceTexture); - method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener); - method public void setTransform(android.graphics.Matrix); - method public void unlockCanvasAndPost(android.graphics.Canvas); + method public void setSurfaceTexture(@NonNull android.graphics.SurfaceTexture); + method public void setSurfaceTextureListener(@Nullable android.view.TextureView.SurfaceTextureListener); + method public void setTransform(@Nullable android.graphics.Matrix); + method public void unlockCanvasAndPost(@NonNull android.graphics.Canvas); } public static interface TextureView.SurfaceTextureListener { - method public void onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int); - method public boolean onSurfaceTextureDestroyed(android.graphics.SurfaceTexture); - method public void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int); - method public void onSurfaceTextureUpdated(android.graphics.SurfaceTexture); + method public void onSurfaceTextureAvailable(@NonNull android.graphics.SurfaceTexture, int, int); + method public boolean onSurfaceTextureDestroyed(@NonNull android.graphics.SurfaceTexture); + method public void onSurfaceTextureSizeChanged(@NonNull android.graphics.SurfaceTexture, int, int); + method public void onSurfaceTextureUpdated(@NonNull android.graphics.SurfaceTexture); } public class TouchDelegate { @@ -50677,7 +50678,7 @@ package android.view { method public final int getScrollY(); method @android.view.ViewDebug.ExportedProperty(category="drawing") @ColorInt public int getSolidColor(); method @LayoutRes public int getSourceLayoutResId(); - method @android.view.ViewDebug.ExportedProperty(category="accessibility") @Nullable public final CharSequence getStateDescription(); + method @android.view.ViewDebug.ExportedProperty(category="accessibility") @Nullable public CharSequence getStateDescription(); method public android.animation.StateListAnimator getStateListAnimator(); method protected int getSuggestedMinimumHeight(); method protected int getSuggestedMinimumWidth(); diff --git a/api/system-current.txt b/api/system-current.txt index 0b1839374298..9a24181d18f5 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -75,6 +75,7 @@ package android { field public static final String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO"; field public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"; field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS"; + field public static final String GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS = "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"; field public static final String HARDWARE_TEST = "android.permission.HARDWARE_TEST"; field public static final String HDMI_CEC = "android.permission.HDMI_CEC"; field public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"; @@ -4754,6 +4755,21 @@ package android.net.wifi { method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String); } + public final class SoftApInfo implements android.os.Parcelable { + method public int describeContents(); + method public int getBandwidth(); + method public int getFrequency(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CHANNEL_WIDTH_160MHZ = 6; // 0x6 + field public static final int CHANNEL_WIDTH_20MHZ = 2; // 0x2 + field public static final int CHANNEL_WIDTH_20MHZ_NOHT = 1; // 0x1 + field public static final int CHANNEL_WIDTH_40MHZ = 3; // 0x3 + field public static final int CHANNEL_WIDTH_80MHZ = 4; // 0x4 + field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 5; // 0x5 + field public static final int CHANNEL_WIDTH_INVALID = 0; // 0x0 + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApInfo> CREATOR; + } + public final class WifiClient implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.net.MacAddress getMacAddress(); @@ -5240,6 +5256,7 @@ package android.os { } public class BatteryStatsManager { + method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.CellularBatteryStats getCellularBatteryStats(); method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats(); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource); @@ -5747,6 +5764,26 @@ package android.os { package android.os.connectivity { + public final class CellularBatteryStats implements android.os.Parcelable { + method public int describeContents(); + method public long getEnergyConsumedMaMillis(); + method public long getIdleTimeMillis(); + method public long getKernelActiveTimeMillis(); + method public long getLoggingDurationMillis(); + method public long getMonitoredRailChargeConsumedMaMillis(); + method public long getNumBytesRx(); + method public long getNumBytesTx(); + method public long getNumPacketsRx(); + method public long getNumPacketsTx(); + method public long getRxTimeMillis(); + method public long getSleepTimeMillis(); + method @NonNull public long[] getTimeInRatMicros(); + method @NonNull public long[] getTimeInRxSignalStrengthLevelMicros(); + method @NonNull public long[] getTxTimeMillis(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.CellularBatteryStats> CREATOR; + } + public final class WifiBatteryStats implements android.os.Parcelable { method public int describeContents(); method public long getEnergyConsumedMaMillis(); @@ -8407,7 +8444,6 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableModemForSlot(int, boolean); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean); - method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset(int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int); @@ -8466,6 +8502,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); + method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings(); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules); @@ -9083,20 +9120,20 @@ package android.telephony.ims { public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAdvancedCallingSettingEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.function.Consumer<java.lang.Boolean>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTtyOverVolteEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiRoamingSettingEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiSettingEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVtSettingEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean); @@ -9556,9 +9593,9 @@ package android.telephony.ims { } public interface RegistrationManager { - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0 field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2 diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 67728840ada8..f91453ea0811 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -1301,8 +1301,8 @@ public class ActivityOptions { /** * Set's whether the activity launched with this option should be a task overlay. That is the - * activity will always be the top activity of the task. If {@param canResume} is true, then - * the task will also not be moved to the front of the stack. + * activity will always be the top activity of the task. + * @param canResume {@code false} if the task will also not be moved to the front of the stack. * @hide */ @TestApi diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index efb9f6bb88f1..47118a81632e 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -17,7 +17,6 @@ package android.app; import static android.annotation.Dimension.DP; -import static android.graphics.drawable.Icon.TYPE_BITMAP; import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast; @@ -8741,26 +8740,20 @@ public class Notification implements Parcelable * If your app produces multiple bubbles, the image should be unique for each of them. * </p> * - * <p>The shape of a bubble icon is adaptive and can match the device theme. + * <p>The shape of a bubble icon is adaptive and will match the device theme. * - * If your icon is bitmap-based, you should create it using - * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise this method will throw. - * - * If your icon is not bitmap-based, you should expect that the icon will be tinted. + * Ideally your icon should be constructed via + * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise, the icon will be shrunk + * and placed on an adaptive shape. * </p> * - * @throws IllegalArgumentException if icon is null or a non-adaptive bitmap + * @throws IllegalArgumentException if icon is null. */ @NonNull public BubbleMetadata.Builder setIcon(@NonNull Icon icon) { if (icon == null) { throw new IllegalArgumentException("Bubbles require non-null icon"); } - if (icon.getType() == TYPE_BITMAP) { - throw new IllegalArgumentException("When using bitmap based icons, Bubbles " - + "require TYPE_ADAPTIVE_BITMAP, please use" - + " Icon#createWithAdaptiveBitmap instead"); - } mIcon = icon; return this; } diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 3ad88829b812..06b95067c2e8 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -1274,7 +1274,12 @@ public final class PendingIntent implements Parcelable { return b != null ? new PendingIntent(b, in.getClassCookie(PendingIntent.class)) : null; } - /*package*/ PendingIntent(IIntentSender target) { + /** + * Creates a PendingIntent with the given target. + * @param target the backing IIntentSender + * @hide + */ + public PendingIntent(IIntentSender target) { mTarget = target; } diff --git a/core/java/android/os/BasicShellCommandHandler.java b/core/java/android/os/BasicShellCommandHandler.java new file mode 100644 index 000000000000..5bd5d61b6361 --- /dev/null +++ b/core/java/android/os/BasicShellCommandHandler.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.util.Log; + +import java.io.BufferedInputStream; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; + +/** + * Helper for implementing {@link Binder#onShellCommand Binder.onShellCommand}. This is meant to + * be copied into mainline modules, so this class must not use any hidden APIs. + * + * @hide + */ +public abstract class BasicShellCommandHandler { + static final String TAG = "ShellCommand"; + static final boolean DEBUG = false; + + private Binder mTarget; + private FileDescriptor mIn; + private FileDescriptor mOut; + private FileDescriptor mErr; + private String[] mArgs; + + private String mCmd; + private int mArgPos; + private String mCurArgData; + + private FileInputStream mFileIn; + private FileOutputStream mFileOut; + private FileOutputStream mFileErr; + + private PrintWriter mOutPrintWriter; + private PrintWriter mErrPrintWriter; + private InputStream mInputStream; + + public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args, int firstArgPos) { + mTarget = target; + mIn = in; + mOut = out; + mErr = err; + mArgs = args; + mCmd = null; + mArgPos = firstArgPos; + mCurArgData = null; + mFileIn = null; + mFileOut = null; + mFileErr = null; + mOutPrintWriter = null; + mErrPrintWriter = null; + mInputStream = null; + } + + public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args) { + String cmd; + int start; + if (args != null && args.length > 0) { + cmd = args[0]; + start = 1; + } else { + cmd = null; + start = 0; + } + init(target, in, out, err, args, start); + mCmd = cmd; + + if (DEBUG) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Log.d(TAG, "Starting command " + mCmd + " on " + mTarget, here); + Log.d(TAG, "Calling uid=" + Binder.getCallingUid() + + " pid=" + Binder.getCallingPid()); + } + int res = -1; + try { + res = onCommand(mCmd); + if (DEBUG) Log.d(TAG, "Executed command " + mCmd + " on " + mTarget); + } catch (Throwable e) { + // Unlike usual calls, in this case if an exception gets thrown + // back to us we want to print it back in to the dump data, since + // that is where the caller expects all interesting information to + // go. + PrintWriter eout = getErrPrintWriter(); + eout.println(); + eout.println("Exception occurred while executing: " + e.getMessage()); + e.printStackTrace(eout); + } finally { + if (DEBUG) Log.d(TAG, "Flushing output streams on " + mTarget); + if (mOutPrintWriter != null) { + mOutPrintWriter.flush(); + } + if (mErrPrintWriter != null) { + mErrPrintWriter.flush(); + } + if (DEBUG) Log.d(TAG, "Sending command result on " + mTarget); + } + if (DEBUG) Log.d(TAG, "Finished command " + mCmd + " on " + mTarget); + return res; + } + + /** + * Return the raw FileDescriptor for the output stream. + */ + public FileDescriptor getOutFileDescriptor() { + return mOut; + } + + /** + * Return direct raw access (not buffered) to the command's output data stream. + */ + public OutputStream getRawOutputStream() { + if (mFileOut == null) { + mFileOut = new FileOutputStream(mOut); + } + return mFileOut; + } + + /** + * Return a PrintWriter for formatting output to {@link #getRawOutputStream()}. + */ + public PrintWriter getOutPrintWriter() { + if (mOutPrintWriter == null) { + mOutPrintWriter = new PrintWriter(getRawOutputStream()); + } + return mOutPrintWriter; + } + + /** + * Return the raw FileDescriptor for the error stream. + */ + public FileDescriptor getErrFileDescriptor() { + return mErr; + } + + /** + * Return direct raw access (not buffered) to the command's error output data stream. + */ + public OutputStream getRawErrorStream() { + if (mFileErr == null) { + mFileErr = new FileOutputStream(mErr); + } + return mFileErr; + } + + /** + * Return a PrintWriter for formatting output to {@link #getRawErrorStream()}. + */ + public PrintWriter getErrPrintWriter() { + if (mErr == null) { + return getOutPrintWriter(); + } + if (mErrPrintWriter == null) { + mErrPrintWriter = new PrintWriter(getRawErrorStream()); + } + return mErrPrintWriter; + } + + /** + * Return the raw FileDescriptor for the input stream. + */ + public FileDescriptor getInFileDescriptor() { + return mIn; + } + + /** + * Return direct raw access (not buffered) to the command's input data stream. + */ + public InputStream getRawInputStream() { + if (mFileIn == null) { + mFileIn = new FileInputStream(mIn); + } + return mFileIn; + } + + /** + * Return buffered access to the command's {@link #getRawInputStream()}. + */ + public InputStream getBufferedInputStream() { + if (mInputStream == null) { + mInputStream = new BufferedInputStream(getRawInputStream()); + } + return mInputStream; + } + + /** + * Return the next option on the command line -- that is an argument that + * starts with '-'. If the next argument is not an option, null is returned. + */ + public String getNextOption() { + if (mCurArgData != null) { + String prev = mArgs[mArgPos - 1]; + throw new IllegalArgumentException("No argument expected after \"" + prev + "\""); + } + if (mArgPos >= mArgs.length) { + return null; + } + String arg = mArgs[mArgPos]; + if (!arg.startsWith("-")) { + return null; + } + mArgPos++; + if (arg.equals("--")) { + return null; + } + if (arg.length() > 1 && arg.charAt(1) != '-') { + if (arg.length() > 2) { + mCurArgData = arg.substring(2); + return arg.substring(0, 2); + } else { + mCurArgData = null; + return arg; + } + } + mCurArgData = null; + return arg; + } + + /** + * Return the next argument on the command line, whatever it is; if there are + * no arguments left, return null. + */ + public String getNextArg() { + if (mCurArgData != null) { + String arg = mCurArgData; + mCurArgData = null; + return arg; + } else if (mArgPos < mArgs.length) { + return mArgs[mArgPos++]; + } else { + return null; + } + } + + public String peekNextArg() { + if (mCurArgData != null) { + return mCurArgData; + } else if (mArgPos < mArgs.length) { + return mArgs[mArgPos]; + } else { + return null; + } + } + + /** + * Return the next argument on the command line, whatever it is; if there are + * no arguments left, throws an IllegalArgumentException to report this to the user. + */ + public String getNextArgRequired() { + String arg = getNextArg(); + if (arg == null) { + String prev = mArgs[mArgPos - 1]; + throw new IllegalArgumentException("Argument expected after \"" + prev + "\""); + } + return arg; + } + + public int handleDefaultCommands(String cmd) { + if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) { + onHelp(); + } else { + getOutPrintWriter().println("Unknown command: " + cmd); + } + return -1; + } + + public Binder getTarget() { + return mTarget; + } + + public String[] getAllArgs() { + return mArgs; + } + + /** + * Implement parsing and execution of a command. If it isn't a command you understand, + * call {@link #handleDefaultCommands(String)} and return its result as a last resort. + * Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()} + * to process additional command line arguments. Command output can be written to + * {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}. + * + * <p class="caution">Note that no permission checking has been done before entering this + * function, so you need to be sure to do your own security verification for any commands you + * are executing. The easiest way to do this is to have the ShellCommand contain + * only a reference to your service's aidl interface, and do all of your command + * implementations on top of that -- that way you can rely entirely on your executing security + * code behind that interface.</p> + * + * @param cmd The first command line argument representing the name of the command to execute. + * @return Return the command result; generally 0 or positive indicates success and + * negative values indicate error. + */ + public abstract int onCommand(String cmd); + + /** + * Implement this to print help text about your command to {@link #getOutPrintWriter()}. + */ + public abstract void onHelp(); +} diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java index 367a868ddef4..e5650aea0522 100644 --- a/core/java/android/os/BatteryStatsManager.java +++ b/core/java/android/os/BatteryStatsManager.java @@ -23,6 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; +import android.os.connectivity.CellularBatteryStats; import android.os.connectivity.WifiBatteryStats; import com.android.internal.app.IBatteryStats; @@ -158,6 +159,21 @@ public class BatteryStatsManager { } /** + * Retrieves all the cellular related battery stats. + * + * @return Instance of {@link CellularBatteryStats}. + */ + @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) + public @NonNull CellularBatteryStats getCellularBatteryStats() { + try { + return mBatteryStats.getCellularBatteryStats(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return null; + } + } + + /** * Retrieves all the wifi related battery stats. * * @return Instance of {@link WifiBatteryStats}. diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index ef3afabfe878..a856975e2501 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -37,7 +37,9 @@ import libcore.io.IoUtils; import libcore.util.NativeAllocationRegistry; import java.io.FileDescriptor; +import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Modifier; @@ -905,11 +907,60 @@ public class Binder implements IBinder { @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) throws RemoteException { - FileOutputStream fout = new FileOutputStream(err != null ? err : out); - PrintWriter pw = new FastPrintWriter(fout); + + // First, convert in, out and err to @NonNull, by redirecting any that's null to /dev/null. + try { + if (in == null) { + in = new FileInputStream("/dev/null").getFD(); + } + if (out == null) { + out = new FileOutputStream("/dev/null").getFD(); + } + if (err == null) { + err = out; + } + } catch (IOException e) { + PrintWriter pw = new FastPrintWriter(new FileOutputStream(err != null ? err : out)); + pw.println("Failed to open /dev/null: " + e.getMessage()); + pw.flush(); + resultReceiver.send(-1, null); + return; + } + // Also make args @NonNull. + if (args == null) { + args = new String[0]; + } + + int result = -1; + try { + result = handleShellCommand(in, out, err, args); + } finally { + resultReceiver.send(result, null); + } + } + + /** + * System services can implement this method to implement ADB shell commands. + * + * TODO More Javadoc. + * TODO Add a generic way to define subcommands and their permissions. + * + * @param in standard input. + * @param out standard output. + * @param err standard error. + * @param args arguments passed to the command. Can be empty. The first argument is typically + * a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}. + * + * @hide + */ + // @SystemApi TODO Make it a system API. + protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out, + @NonNull FileDescriptor err, @NonNull String[] args) { + FileOutputStream ferr = new FileOutputStream(err); + PrintWriter pw = new FastPrintWriter(ferr); pw.println("No shell command implementation."); pw.flush(); - resultReceiver.send(0, null); + return 0; } /** diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java index 2fe8726a0915..f3a6869687dc 100644 --- a/core/java/android/os/ShellCommand.java +++ b/core/java/android/os/ShellCommand.java @@ -33,105 +33,21 @@ import java.io.PrintWriter; * Helper for implementing {@link Binder#onShellCommand Binder.onShellCommand}. * @hide */ -public abstract class ShellCommand { - static final String TAG = "ShellCommand"; - static final boolean DEBUG = false; - - private Binder mTarget; - private FileDescriptor mIn; - private FileDescriptor mOut; - private FileDescriptor mErr; - private String[] mArgs; +public abstract class ShellCommand extends BasicShellCommandHandler { private ShellCallback mShellCallback; private ResultReceiver mResultReceiver; - private String mCmd; - private int mArgPos; - private String mCurArgData; - - private FileInputStream mFileIn; - private FileOutputStream mFileOut; - private FileOutputStream mFileErr; - - private FastPrintWriter mOutPrintWriter; - private FastPrintWriter mErrPrintWriter; - private InputStream mInputStream; - - public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ShellCallback callback, int firstArgPos) { - mTarget = target; - mIn = in; - mOut = out; - mErr = err; - mArgs = args; - mShellCallback = callback; - mResultReceiver = null; - mCmd = null; - mArgPos = firstArgPos; - mCurArgData = null; - mFileIn = null; - mFileOut = null; - mFileErr = null; - mOutPrintWriter = null; - mErrPrintWriter = null; - mInputStream = null; - } - public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { - String cmd; - int start; - if (args != null && args.length > 0) { - cmd = args[0]; - start = 1; - } else { - cmd = null; - start = 0; - } - init(target, in, out, err, args, callback, start); - mCmd = cmd; + mShellCallback = callback; mResultReceiver = resultReceiver; + final int result = super.exec(target, in, out, err, args); - if (DEBUG) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget, here); - Slog.d(TAG, "Calling uid=" + Binder.getCallingUid() - + " pid=" + Binder.getCallingPid() + " ShellCallback=" + getShellCallback()); + if (mResultReceiver != null) { + mResultReceiver.send(result, null); } - int res = -1; - try { - res = onCommand(mCmd); - if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget); - } catch (SecurityException e) { - PrintWriter eout = getErrPrintWriter(); - eout.println("Security exception: " + e.getMessage()); - eout.println(); - e.printStackTrace(eout); - } catch (Throwable e) { - // Unlike usual calls, in this case if an exception gets thrown - // back to us we want to print it back in to the dump data, since - // that is where the caller expects all interesting information to - // go. - PrintWriter eout = getErrPrintWriter(); - eout.println(); - eout.println("Exception occurred while executing:"); - e.printStackTrace(eout); - } finally { - if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget); - if (mOutPrintWriter != null) { - mOutPrintWriter.flush(); - } - if (mErrPrintWriter != null) { - mErrPrintWriter.flush(); - } - if (DEBUG) Slog.d(TAG, "Sending command result on " + mTarget); - if (mResultReceiver != null) { - mResultReceiver.send(res, null); - } - } - if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget); - return res; + + return result; } /** @@ -146,90 +62,6 @@ public abstract class ShellCommand { } /** - * Return the raw FileDescriptor for the output stream. - */ - public FileDescriptor getOutFileDescriptor() { - return mOut; - } - - /** - * Return direct raw access (not buffered) to the command's output data stream. - */ - public OutputStream getRawOutputStream() { - if (mFileOut == null) { - mFileOut = new FileOutputStream(mOut); - } - return mFileOut; - } - - /** - * Return a PrintWriter for formatting output to {@link #getRawOutputStream()}. - */ - public PrintWriter getOutPrintWriter() { - if (mOutPrintWriter == null) { - mOutPrintWriter = new FastPrintWriter(getRawOutputStream()); - } - return mOutPrintWriter; - } - - /** - * Return the raw FileDescriptor for the error stream. - */ - public FileDescriptor getErrFileDescriptor() { - return mErr; - } - - /** - * Return direct raw access (not buffered) to the command's error output data stream. - */ - public OutputStream getRawErrorStream() { - if (mFileErr == null) { - mFileErr = new FileOutputStream(mErr); - } - return mFileErr; - } - - /** - * Return a PrintWriter for formatting output to {@link #getRawErrorStream()}. - */ - public PrintWriter getErrPrintWriter() { - if (mErr == null) { - return getOutPrintWriter(); - } - if (mErrPrintWriter == null) { - mErrPrintWriter = new FastPrintWriter(getRawErrorStream()); - } - return mErrPrintWriter; - } - - /** - * Return the raw FileDescriptor for the input stream. - */ - public FileDescriptor getInFileDescriptor() { - return mIn; - } - - /** - * Return direct raw access (not buffered) to the command's input data stream. - */ - public InputStream getRawInputStream() { - if (mFileIn == null) { - mFileIn = new FileInputStream(mIn); - } - return mFileIn; - } - - /** - * Return buffered access to the command's {@link #getRawInputStream()}. - */ - public InputStream getBufferedInputStream() { - if (mInputStream == null) { - mInputStream = new BufferedInputStream(getRawInputStream()); - } - return mInputStream; - } - - /** * Helper for just system services to ask the shell to open an output file. * @hide */ @@ -256,77 +88,19 @@ public abstract class ShellCommand { return null; } - /** - * Return the next option on the command line -- that is an argument that - * starts with '-'. If the next argument is not an option, null is returned. - */ - public String getNextOption() { - if (mCurArgData != null) { - String prev = mArgs[mArgPos - 1]; - throw new IllegalArgumentException("No argument expected after \"" + prev + "\""); - } - if (mArgPos >= mArgs.length) { - return null; - } - String arg = mArgs[mArgPos]; - if (!arg.startsWith("-")) { - return null; - } - mArgPos++; - if (arg.equals("--")) { - return null; - } - if (arg.length() > 1 && arg.charAt(1) != '-') { - if (arg.length() > 2) { - mCurArgData = arg.substring(2); - return arg.substring(0, 2); - } else { - mCurArgData = null; - return arg; - } - } - mCurArgData = null; - return arg; - } - - /** - * Return the next argument on the command line, whatever it is; if there are - * no arguments left, return null. - */ - public String getNextArg() { - if (mCurArgData != null) { - String arg = mCurArgData; - mCurArgData = null; - return arg; - } else if (mArgPos < mArgs.length) { - return mArgs[mArgPos++]; - } else { - return null; + public int handleDefaultCommands(String cmd) { + if ("dump".equals(cmd)) { + String[] newArgs = new String[getAllArgs().length-1]; + System.arraycopy(getAllArgs(), 1, newArgs, 0, getAllArgs().length-1); + getTarget().doDump(getOutFileDescriptor(), getOutPrintWriter(), newArgs); + return 0; } + return super.handleDefaultCommands(cmd); } @UnsupportedAppUsage public String peekNextArg() { - if (mCurArgData != null) { - return mCurArgData; - } else if (mArgPos < mArgs.length) { - return mArgs[mArgPos]; - } else { - return null; - } - } - - /** - * Return the next argument on the command line, whatever it is; if there are - * no arguments left, throws an IllegalArgumentException to report this to the user. - */ - public String getNextArgRequired() { - String arg = getNextArg(); - if (arg == null) { - String prev = mArgs[mArgPos - 1]; - throw new IllegalArgumentException("Argument expected after \"" + prev + "\""); - } - return arg; + return super.peekNextArg(); } /** @@ -335,43 +109,4 @@ public abstract class ShellCommand { public ShellCallback getShellCallback() { return mShellCallback; } - - public int handleDefaultCommands(String cmd) { - if ("dump".equals(cmd)) { - String[] newArgs = new String[mArgs.length-1]; - System.arraycopy(mArgs, 1, newArgs, 0, mArgs.length-1); - mTarget.doDump(mOut, getOutPrintWriter(), newArgs); - return 0; - } else if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) { - onHelp(); - } else { - getOutPrintWriter().println("Unknown command: " + cmd); - } - return -1; - } - - /** - * Implement parsing and execution of a command. If it isn't a command you understand, - * call {@link #handleDefaultCommands(String)} and return its result as a last resort. - * Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()} - * to process additional command line arguments. Command output can be written to - * {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}. - * - * <p class="caution">Note that no permission checking has been done before entering this function, - * so you need to be sure to do your own security verification for any commands you - * are executing. The easiest way to do this is to have the ShellCommand contain - * only a reference to your service's aidl interface, and do all of your command - * implementations on top of that -- that way you can rely entirely on your executing security - * code behind that interface.</p> - * - * @param cmd The first command line argument representing the name of the command to execute. - * @return Return the command result; generally 0 or positive indicates success and - * negative values indicate error. - */ - public abstract int onCommand(String cmd); - - /** - * Implement this to print help text about your command to {@link #getOutPrintWriter()}. - */ - public abstract void onHelp(); } diff --git a/core/java/android/os/connectivity/CellularBatteryStats.java b/core/java/android/os/connectivity/CellularBatteryStats.java index 2e0904048d40..caa406899161 100644 --- a/core/java/android/os/connectivity/CellularBatteryStats.java +++ b/core/java/android/os/connectivity/CellularBatteryStats.java @@ -15,241 +15,367 @@ */ package android.os.connectivity; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.BatteryStats; import android.os.Parcel; import android.os.Parcelable; - +import android.telephony.Annotation.NetworkType; import android.telephony.ModemActivityInfo; import android.telephony.SignalStrength; import java.util.Arrays; +import java.util.Objects; /** * API for Cellular power stats * * @hide */ +@SystemApi public final class CellularBatteryStats implements Parcelable { - private long mLoggingDurationMs; - private long mKernelActiveTimeMs; - private long mNumPacketsTx; - private long mNumBytesTx; - private long mNumPacketsRx; - private long mNumBytesRx; - private long mSleepTimeMs; - private long mIdleTimeMs; - private long mRxTimeMs; - private long mEnergyConsumedMaMs; - private long[] mTimeInRatMs; - private long[] mTimeInRxSignalStrengthLevelMs; - private long[] mTxTimeMs; - private long mMonitoredRailChargeConsumedMaMs; - - public static final @android.annotation.NonNull Parcelable.Creator<CellularBatteryStats> CREATOR = new - Parcelable.Creator<CellularBatteryStats>() { - public CellularBatteryStats createFromParcel(Parcel in) { - return new CellularBatteryStats(in); - } - - public CellularBatteryStats[] newArray(int size) { - return new CellularBatteryStats[size]; - } - }; - - public CellularBatteryStats() { - initialize(); - } - - public void writeToParcel(Parcel out, int flags) { - out.writeLong(mLoggingDurationMs); - out.writeLong(mKernelActiveTimeMs); - out.writeLong(mNumPacketsTx); - out.writeLong(mNumBytesTx); - out.writeLong(mNumPacketsRx); - out.writeLong(mNumBytesRx); - out.writeLong(mSleepTimeMs); - out.writeLong(mIdleTimeMs); - out.writeLong(mRxTimeMs); - out.writeLong(mEnergyConsumedMaMs); - out.writeLongArray(mTimeInRatMs); - out.writeLongArray(mTimeInRxSignalStrengthLevelMs); - out.writeLongArray(mTxTimeMs); - out.writeLong(mMonitoredRailChargeConsumedMaMs); - } - - public void readFromParcel(Parcel in) { - mLoggingDurationMs = in.readLong(); - mKernelActiveTimeMs = in.readLong(); - mNumPacketsTx = in.readLong(); - mNumBytesTx = in.readLong(); - mNumPacketsRx = in.readLong(); - mNumBytesRx = in.readLong(); - mSleepTimeMs = in.readLong(); - mIdleTimeMs = in.readLong(); - mRxTimeMs = in.readLong(); - mEnergyConsumedMaMs = in.readLong(); - in.readLongArray(mTimeInRatMs); - in.readLongArray(mTimeInRxSignalStrengthLevelMs); - in.readLongArray(mTxTimeMs); - mMonitoredRailChargeConsumedMaMs = in.readLong(); - } - - public long getLoggingDurationMs() { - return mLoggingDurationMs; - } - - public long getKernelActiveTimeMs() { - return mKernelActiveTimeMs; - } - - public long getNumPacketsTx() { - return mNumPacketsTx; - } - - public long getNumBytesTx() { - return mNumBytesTx; - } - - public long getNumPacketsRx() { - return mNumPacketsRx; - } - - public long getNumBytesRx() { - return mNumBytesRx; - } - - public long getSleepTimeMs() { - return mSleepTimeMs; - } - - public long getIdleTimeMs() { - return mIdleTimeMs; - } - - public long getRxTimeMs() { - return mRxTimeMs; - } - - public long getEnergyConsumedMaMs() { - return mEnergyConsumedMaMs; - } - - public long[] getTimeInRatMs() { - return mTimeInRatMs; - } - - public long[] getTimeInRxSignalStrengthLevelMs() { - return mTimeInRxSignalStrengthLevelMs; - } - - public long[] getTxTimeMs() { - return mTxTimeMs; - } - - public long getMonitoredRailChargeConsumedMaMs() { - return mMonitoredRailChargeConsumedMaMs; - } - - public void setLoggingDurationMs(long t) { - mLoggingDurationMs = t; - return; - } - - public void setKernelActiveTimeMs(long t) { - mKernelActiveTimeMs = t; - return; - } - - public void setNumPacketsTx(long n) { - mNumPacketsTx = n; - return; - } - - public void setNumBytesTx(long b) { - mNumBytesTx = b; - return; - } - - public void setNumPacketsRx(long n) { - mNumPacketsRx = n; - return; - } - - public void setNumBytesRx(long b) { - mNumBytesRx = b; - return; - } - - public void setSleepTimeMs(long t) { - mSleepTimeMs = t; - return; - } - - public void setIdleTimeMs(long t) { - mIdleTimeMs = t; - return; - } - - public void setRxTimeMs(long t) { - mRxTimeMs = t; - return; - } - - public void setEnergyConsumedMaMs(long e) { - mEnergyConsumedMaMs = e; - return; - } - - public void setTimeInRatMs(long[] t) { - mTimeInRatMs = Arrays.copyOfRange(t, 0, - Math.min(t.length, BatteryStats.NUM_DATA_CONNECTION_TYPES)); - return; - } - - public void setTimeInRxSignalStrengthLevelMs(long[] t) { - mTimeInRxSignalStrengthLevelMs = Arrays.copyOfRange(t, 0, - Math.min(t.length, SignalStrength.NUM_SIGNAL_STRENGTH_BINS)); - return; - } - - public void setTxTimeMs(long[] t) { - mTxTimeMs = Arrays.copyOfRange(t, 0, Math.min(t.length, ModemActivityInfo.TX_POWER_LEVELS)); - return; - } - - public void setMonitoredRailChargeConsumedMaMs(long monitoredRailEnergyConsumedMaMs) { - mMonitoredRailChargeConsumedMaMs = monitoredRailEnergyConsumedMaMs; - return; - } - - public int describeContents() { - return 0; - } - - private CellularBatteryStats(Parcel in) { - initialize(); - readFromParcel(in); - } - - private void initialize() { - mLoggingDurationMs = 0; - mKernelActiveTimeMs = 0; - mNumPacketsTx = 0; - mNumBytesTx = 0; - mNumPacketsRx = 0; - mNumBytesRx = 0; - mSleepTimeMs = 0; - mIdleTimeMs = 0; - mRxTimeMs = 0; - mEnergyConsumedMaMs = 0; - mTimeInRatMs = new long[BatteryStats.NUM_DATA_CONNECTION_TYPES]; - Arrays.fill(mTimeInRatMs, 0); - mTimeInRxSignalStrengthLevelMs = new long[SignalStrength.NUM_SIGNAL_STRENGTH_BINS]; - Arrays.fill(mTimeInRxSignalStrengthLevelMs, 0); - mTxTimeMs = new long[ModemActivityInfo.TX_POWER_LEVELS]; - Arrays.fill(mTxTimeMs, 0); - mMonitoredRailChargeConsumedMaMs = 0; - return; - } -}
\ No newline at end of file + private long mLoggingDurationMs = 0; + private long mKernelActiveTimeMs = 0; + private long mNumPacketsTx = 0; + private long mNumBytesTx = 0; + private long mNumPacketsRx = 0; + private long mNumBytesRx = 0; + private long mSleepTimeMs = 0; + private long mIdleTimeMs = 0; + private long mRxTimeMs = 0; + private long mEnergyConsumedMaMs = 0; + private long[] mTimeInRatMs = new long[BatteryStats.NUM_DATA_CONNECTION_TYPES]; + private long[] mTimeInRxSignalStrengthLevelMs = + new long[SignalStrength.NUM_SIGNAL_STRENGTH_BINS]; + private long[] mTxTimeMs = new long[ModemActivityInfo.TX_POWER_LEVELS]; + private long mMonitoredRailChargeConsumedMaMs = 0; + + public static final @NonNull Parcelable.Creator<CellularBatteryStats> CREATOR = + new Parcelable.Creator<CellularBatteryStats>() { + public CellularBatteryStats createFromParcel(Parcel in) { + return new CellularBatteryStats(in); + } + + public CellularBatteryStats[] newArray(int size) { + return new CellularBatteryStats[size]; + } + }; + + /** @hide **/ + public CellularBatteryStats() {} + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeLong(mLoggingDurationMs); + out.writeLong(mKernelActiveTimeMs); + out.writeLong(mNumPacketsTx); + out.writeLong(mNumBytesTx); + out.writeLong(mNumPacketsRx); + out.writeLong(mNumBytesRx); + out.writeLong(mSleepTimeMs); + out.writeLong(mIdleTimeMs); + out.writeLong(mRxTimeMs); + out.writeLong(mEnergyConsumedMaMs); + out.writeLongArray(mTimeInRatMs); + out.writeLongArray(mTimeInRxSignalStrengthLevelMs); + out.writeLongArray(mTxTimeMs); + out.writeLong(mMonitoredRailChargeConsumedMaMs); + } + + private void readFromParcel(Parcel in) { + mLoggingDurationMs = in.readLong(); + mKernelActiveTimeMs = in.readLong(); + mNumPacketsTx = in.readLong(); + mNumBytesTx = in.readLong(); + mNumPacketsRx = in.readLong(); + mNumBytesRx = in.readLong(); + mSleepTimeMs = in.readLong(); + mIdleTimeMs = in.readLong(); + mRxTimeMs = in.readLong(); + mEnergyConsumedMaMs = in.readLong(); + in.readLongArray(mTimeInRatMs); + in.readLongArray(mTimeInRxSignalStrengthLevelMs); + in.readLongArray(mTxTimeMs); + mMonitoredRailChargeConsumedMaMs = in.readLong(); + } + + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof CellularBatteryStats)) return false; + if (other == this) return true; + CellularBatteryStats otherStats = (CellularBatteryStats) other; + return this.mLoggingDurationMs == otherStats.mLoggingDurationMs + && this.mKernelActiveTimeMs == otherStats.mKernelActiveTimeMs + && this.mNumPacketsTx == otherStats.mNumPacketsTx + && this.mNumBytesTx == otherStats.mNumBytesTx + && this.mNumPacketsRx == otherStats.mNumPacketsRx + && this.mNumBytesRx == otherStats.mNumBytesRx + && this.mSleepTimeMs == otherStats.mSleepTimeMs + && this.mIdleTimeMs == otherStats.mIdleTimeMs + && this.mRxTimeMs == otherStats.mRxTimeMs + && this.mEnergyConsumedMaMs == otherStats.mEnergyConsumedMaMs + && Arrays.equals(this.mTimeInRatMs, otherStats.mTimeInRatMs) + && Arrays.equals(this.mTimeInRxSignalStrengthLevelMs, + otherStats.mTimeInRxSignalStrengthLevelMs) + && Arrays.equals(this.mTxTimeMs, otherStats.mTxTimeMs) + && this.mMonitoredRailChargeConsumedMaMs + == otherStats.mMonitoredRailChargeConsumedMaMs; + } + + @Override + public int hashCode() { + return Objects.hash(mLoggingDurationMs, mKernelActiveTimeMs, mNumPacketsTx, + mNumBytesTx, mNumPacketsRx, mNumBytesRx, mSleepTimeMs, mIdleTimeMs, + mRxTimeMs, mEnergyConsumedMaMs, Arrays.hashCode(mTimeInRatMs), + Arrays.hashCode(mTimeInRxSignalStrengthLevelMs), Arrays.hashCode(mTxTimeMs), + mMonitoredRailChargeConsumedMaMs); + } + + /** + * Returns the duration for which these cellular stats were collected. + * + * @return Duration of stats collection in milliseconds. + */ + public long getLoggingDurationMillis() { + return mLoggingDurationMs; + } + + /** + * Returns the duration for which the kernel was active within + * {@link #getLoggingDurationMillis()}. + * + * @return Duration of kernel active time in milliseconds. + */ + public long getKernelActiveTimeMillis() { + return mKernelActiveTimeMs; + } + + /** + * Returns the number of packets transmitted over cellular within + * {@link #getLoggingDurationMillis()}. + * + * @return Number of packets transmitted. + */ + public long getNumPacketsTx() { + return mNumPacketsTx; + } + + /** + * Returns the number of packets received over cellular within + * {@link #getLoggingDurationMillis()}. + * + * @return Number of packets received. + */ + public long getNumBytesTx() { + return mNumBytesTx; + } + + /** + * Returns the number of bytes transmitted over cellular within + * {@link #getLoggingDurationMillis()}. + * + * @return Number of bytes transmitted. + */ + public long getNumPacketsRx() { + return mNumPacketsRx; + } + + /** + * Returns the number of bytes received over cellular within + * {@link #getLoggingDurationMillis()}. + * + * @return Number of bytes received. + */ + public long getNumBytesRx() { + return mNumBytesRx; + } + + /** + * Returns the duration for which the device was sleeping within + * {@link #getLoggingDurationMillis()}. + * + * @return Duration of sleep time in milliseconds. + */ + public long getSleepTimeMillis() { + return mSleepTimeMs; + } + + /** + * Returns the duration for which the device was idle within + * {@link #getLoggingDurationMillis()}. + * + * @return Duration of idle time in milliseconds. + */ + public long getIdleTimeMillis() { + return mIdleTimeMs; + } + + /** + * Returns the duration for which the device was receiving over cellular within + * {@link #getLoggingDurationMillis()}. + * + * @return Duration of cellular reception time in milliseconds. + */ + public long getRxTimeMillis() { + return mRxTimeMs; + } + + /** + * Returns an estimation of energy consumed by cellular chip within + * {@link #getLoggingDurationMillis()}. + * + * @return Energy consumed in milli-ampere milliseconds (mAmS). + */ + public long getEnergyConsumedMaMillis() { + return mEnergyConsumedMaMs; + } + + /** + * Returns the time in microseconds that the phone has been running with + * the given data connection. + * + * @return Amount of time phone spends in various Radio Access Technologies in microseconds. + * The index is {@link NetworkType}. + */ + @NonNull + public long[] getTimeInRatMicros() { + return mTimeInRatMs; + } + + /** + * Returns the time in microseconds that the phone has been running with + * the given signal strength. + * + * @return Amount of time phone spends in various cellular rx signal strength levels + * in microseconds. The index is signal strength bin. + */ + @NonNull + public long[] getTimeInRxSignalStrengthLevelMicros() { + return mTimeInRxSignalStrengthLevelMs; + } + + /** + * Returns the duration for which the device was transmitting over cellular within + * {@link #getLoggingDurationMillis()}. + * + * @return Duration of cellular transmission time in milliseconds. + * Tx(transmit) power index below + * <ul> + * <li> index 0 = tx_power < 0dBm. </li> + * <li> index 1 = 0dBm < tx_power < 5dBm. </li> + * <li> index 2 = 5dBm < tx_power < 15dBm. </li> + * <li> index 3 = 15dBm < tx_power < 20dBm. </li> + * <li> index 4 = tx_power > 20dBm. </li> + * </ul> + */ + @NonNull + public long[] getTxTimeMillis() { + return mTxTimeMs; + } + + /** + * Returns the energy consumed by cellular chip within {@link #getLoggingDurationMillis()}. + * + * @return Energy consumed in milli-ampere milli-seconds (mAmS). + */ + public long getMonitoredRailChargeConsumedMaMillis() { + return mMonitoredRailChargeConsumedMaMs; + } + + /** @hide **/ + public void setLoggingDurationMillis(long t) { + mLoggingDurationMs = t; + return; + } + + /** @hide **/ + public void setKernelActiveTimeMillis(long t) { + mKernelActiveTimeMs = t; + return; + } + + /** @hide **/ + public void setNumPacketsTx(long n) { + mNumPacketsTx = n; + return; + } + + /** @hide **/ + public void setNumBytesTx(long b) { + mNumBytesTx = b; + return; + } + + /** @hide **/ + public void setNumPacketsRx(long n) { + mNumPacketsRx = n; + return; + } + + /** @hide **/ + public void setNumBytesRx(long b) { + mNumBytesRx = b; + return; + } + + /** @hide **/ + public void setSleepTimeMillis(long t) { + mSleepTimeMs = t; + return; + } + + /** @hide **/ + public void setIdleTimeMillis(long t) { + mIdleTimeMs = t; + return; + } + + /** @hide **/ + public void setRxTimeMillis(long t) { + mRxTimeMs = t; + return; + } + + /** @hide **/ + public void setEnergyConsumedMaMillis(long e) { + mEnergyConsumedMaMs = e; + return; + } + + /** @hide **/ + public void setTimeInRatMicros(@NonNull long[] t) { + mTimeInRatMs = Arrays.copyOfRange(t, 0, + Math.min(t.length, BatteryStats.NUM_DATA_CONNECTION_TYPES)); + return; + } + + /** @hide **/ + public void setTimeInRxSignalStrengthLevelMicros(@NonNull long[] t) { + mTimeInRxSignalStrengthLevelMs = Arrays.copyOfRange(t, 0, + Math.min(t.length, SignalStrength.NUM_SIGNAL_STRENGTH_BINS)); + return; + } + + /** @hide **/ + public void setTxTimeMillis(@NonNull long[] t) { + mTxTimeMs = Arrays.copyOfRange(t, 0, Math.min(t.length, ModemActivityInfo.TX_POWER_LEVELS)); + return; + } + + /** @hide **/ + public void setMonitoredRailChargeConsumedMaMillis(long monitoredRailEnergyConsumedMaMs) { + mMonitoredRailChargeConsumedMaMs = monitoredRailEnergyConsumedMaMs; + return; + } + + @Override + public int describeContents() { + return 0; + } + + private CellularBatteryStats(Parcel in) { + readFromParcel(in); + } +} diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index b1fd4e5e699e..af1a51f68d71 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -47,8 +47,6 @@ public class FeatureFlagUtils { static { DEFAULT_FLAGS = new HashMap<>(); DEFAULT_FLAGS.put("settings_audio_switcher", "true"); - DEFAULT_FLAGS.put("settings_mobile_network_v2", "true"); - DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true"); DEFAULT_FLAGS.put("settings_systemui_theme", "true"); DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false"); DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false"); diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java index 831e9ee43546..5d0d5bd79857 100644 --- a/core/java/android/view/InputChannel.java +++ b/core/java/android/view/InputChannel.java @@ -61,7 +61,6 @@ public final class InputChannel implements Parcelable { private native void nativeWriteToParcel(Parcel parcel); private native void nativeDup(InputChannel target); private native IBinder nativeGetToken(); - private native void nativeSetToken(IBinder token); private native String nativeGetName(); @@ -185,8 +184,4 @@ public final class InputChannel implements Parcelable { public IBinder getToken() { return nativeGetToken(); } - - public void setToken(IBinder token) { - nativeSetToken(token); - } } diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 0175ba201dd1..5876b03476ce 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.Context; @@ -139,7 +140,7 @@ public class TextureView extends View { * * @param context The context to associate this view with. */ - public TextureView(Context context) { + public TextureView(@NonNull Context context) { super(context); } @@ -149,7 +150,7 @@ public class TextureView extends View { * @param context The context to associate this view with. * @param attrs The attributes of the XML tag that is inflating the view. */ - public TextureView(Context context, AttributeSet attrs) { + public TextureView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } @@ -162,7 +163,7 @@ public class TextureView extends View { * reference to a style resource that supplies default values for * the view. Can be 0 to not look for defaults. */ - public TextureView(Context context, AttributeSet attrs, int defStyleAttr) { + public TextureView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @@ -179,7 +180,8 @@ public class TextureView extends View { * defStyleAttr is 0 or can not be found in the theme. Can be 0 * to not look for defaults. */ - public TextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + public TextureView(@NonNull Context context, @Nullable AttributeSet attrs, + int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @@ -484,13 +486,13 @@ public class TextureView extends View { * situations, make sure this texture view is not marked opaque.</p> * * @param transform The transform to apply to the content of - * this view. + * this view. If null the transform will be set to identity. * * @see #getTransform(android.graphics.Matrix) * @see #isOpaque() * @see #setOpaque(boolean) */ - public void setTransform(Matrix transform) { + public void setTransform(@Nullable Matrix transform) { mMatrix.set(transform); mMatrixChanged = true; invalidateParentIfNeeded(); @@ -507,7 +509,7 @@ public class TextureView extends View { * * @see #setTransform(android.graphics.Matrix) */ - public Matrix getTransform(Matrix transform) { + public @NonNull Matrix getTransform(@Nullable Matrix transform) { if (transform == null) { transform = new Matrix(); } @@ -544,7 +546,7 @@ public class TextureView extends View { * @see #getBitmap(android.graphics.Bitmap) * @see #getBitmap(int, int) */ - public Bitmap getBitmap() { + public @Nullable Bitmap getBitmap() { return getBitmap(getWidth(), getHeight()); } @@ -571,7 +573,7 @@ public class TextureView extends View { * @see #getBitmap(android.graphics.Bitmap) * @see #getBitmap() */ - public Bitmap getBitmap(int width, int height) { + public @Nullable Bitmap getBitmap(int width, int height) { if (isAvailable() && width > 0 && height > 0) { return getBitmap(Bitmap.createBitmap(getResources().getDisplayMetrics(), width, height, Bitmap.Config.ARGB_8888)); @@ -602,7 +604,7 @@ public class TextureView extends View { * @throws IllegalStateException if the hardware rendering context cannot be * acquired to capture the bitmap */ - public Bitmap getBitmap(Bitmap bitmap) { + public @NonNull Bitmap getBitmap(@NonNull Bitmap bitmap) { if (bitmap != null && isAvailable()) { applyUpdate(); applyTransformMatrix(); @@ -649,12 +651,13 @@ public class TextureView extends View { * owned by another producer. For instance, if the TextureView is being used * to render the camera's preview you cannot invoke this method.</p> * - * @return A Canvas used to draw into the surface. + * @return A Canvas used to draw into the surface, or null if the surface cannot be locked for + * drawing (see {@link #isAvailable()}). * * @see #lockCanvas(android.graphics.Rect) * @see #unlockCanvasAndPost(android.graphics.Canvas) */ - public Canvas lockCanvas() { + public @Nullable Canvas lockCanvas() { return lockCanvas(null); } @@ -669,15 +672,17 @@ public class TextureView extends View { * already connected to an image producer (for instance: the camera, * OpenGL, a media player, etc.) * - * @param dirty Area of the surface that will be modified. + * @param dirty Area of the surface that will be modified. If null the area of the entire + * surface is used. - * @return A Canvas used to draw into the surface. + * @return A Canvas used to draw into the surface, or null if the surface cannot be locked for + * drawing (see {@link #isAvailable()}). * * @see #lockCanvas() * @see #unlockCanvasAndPost(android.graphics.Canvas) * @see #isAvailable() */ - public Canvas lockCanvas(Rect dirty) { + public @Nullable Canvas lockCanvas(@Nullable Rect dirty) { if (!isAvailable()) return null; if (mCanvas == null) { @@ -705,7 +710,7 @@ public class TextureView extends View { * @see #lockCanvas() * @see #lockCanvas(android.graphics.Rect) */ - public void unlockCanvasAndPost(Canvas canvas) { + public void unlockCanvasAndPost(@NonNull Canvas canvas) { if (mCanvas != null && canvas == mCanvas) { canvas.restoreToCount(mSaveCount); mSaveCount = 0; @@ -723,7 +728,7 @@ public class TextureView extends View { * * @see #isAvailable() */ - public SurfaceTexture getSurfaceTexture() { + public @Nullable SurfaceTexture getSurfaceTexture() { return mSurface; } @@ -742,7 +747,7 @@ public class TextureView extends View { * @param surfaceTexture The {@link SurfaceTexture} that the view should use. * @see SurfaceTexture#detachFromGLContext() */ - public void setSurfaceTexture(SurfaceTexture surfaceTexture) { + public void setSurfaceTexture(@NonNull SurfaceTexture surfaceTexture) { if (surfaceTexture == null) { throw new NullPointerException("surfaceTexture must not be null"); } @@ -781,7 +786,7 @@ public class TextureView extends View { * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener) * @see SurfaceTextureListener */ - public SurfaceTextureListener getSurfaceTextureListener() { + public @Nullable SurfaceTextureListener getSurfaceTextureListener() { return mListener; } @@ -792,25 +797,22 @@ public class TextureView extends View { * @see #getSurfaceTextureListener() * @see SurfaceTextureListener */ - public void setSurfaceTextureListener(SurfaceTextureListener listener) { + public void setSurfaceTextureListener(@Nullable SurfaceTextureListener listener) { mListener = listener; } @UnsupportedAppUsage private final SurfaceTexture.OnFrameAvailableListener mUpdateListener = - new SurfaceTexture.OnFrameAvailableListener() { - @Override - public void onFrameAvailable(SurfaceTexture surfaceTexture) { - updateLayer(); - invalidate(); - } - }; + surfaceTexture -> { + updateLayer(); + invalidate(); + }; /** * This listener can be used to be notified when the surface texture * associated with this texture view is available. */ - public static interface SurfaceTextureListener { + public interface SurfaceTextureListener { /** * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use. * @@ -819,7 +821,7 @@ public class TextureView extends View { * @param width The width of the surface * @param height The height of the surface */ - public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height); + void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height); /** * Invoked when the {@link SurfaceTexture}'s buffers size changed. @@ -829,7 +831,7 @@ public class TextureView extends View { * @param width The new width of the surface * @param height The new height of the surface */ - public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height); + void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height); /** * Invoked when the specified {@link SurfaceTexture} is about to be destroyed. @@ -839,7 +841,7 @@ public class TextureView extends View { * * @param surface The surface about to be destroyed */ - public boolean onSurfaceTextureDestroyed(SurfaceTexture surface); + boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface); /** * Invoked when the specified {@link SurfaceTexture} is updated through @@ -847,7 +849,7 @@ public class TextureView extends View { * * @param surface The surface just updated */ - public void onSurfaceTextureUpdated(SurfaceTexture surface); + void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface); } @UnsupportedAppUsage diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 1599afb358e0..b90ce876aeb3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8727,7 +8727,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setContextClickable(true); } structure.setClassName(getAccessibilityClassName().toString()); - structure.setContentDescription(getContentDescription()); + structure.setContentDescription(mContentDescription); } /** @@ -9934,8 +9934,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, info.setImportantForAccessibility(isImportantForAccessibility()); info.setPackageName(mContext.getPackageName()); info.setClassName(getAccessibilityClassName()); - info.setStateDescription(getStateDescription()); - info.setContentDescription(getContentDescription()); + info.setStateDescription(mStateDescription); + info.setContentDescription(mContentDescription); info.setEnabled(isEnabled()); info.setClickable(isClickable()); @@ -10318,7 +10318,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #setStateDescription(CharSequence) */ @ViewDebug.ExportedProperty(category = "accessibility") - public final @Nullable CharSequence getStateDescription() { + public @Nullable CharSequence getStateDescription() { return mStateDescription; } @@ -13724,7 +13724,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @UnsupportedAppUsage public CharSequence getIterableTextForAccessibility() { - return getContentDescription(); + return mContentDescription; } /** @@ -29514,9 +29514,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, stream.addProperty("text:textAlignment", getTextAlignment()); // accessibility - CharSequence contentDescription = getContentDescription(); stream.addProperty("accessibility:contentDescription", - contentDescription == null ? "" : contentDescription.toString()); + mContentDescription == null ? "" : mContentDescription.toString()); + stream.addProperty("accessibility:stateDescription", + mStateDescription == null ? "" : mStateDescription.toString()); stream.addProperty("accessibility:labelFor", getLabelFor()); stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); } diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index f4f7d0b33fd1..6c6046f1876f 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -93,8 +93,9 @@ class WindowlessWindowManager implements IWindowSession { DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState) { final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession) - .setParent(mRootSurface) - .setName(attrs.getTitle().toString()); + .setParent(mRootSurface) + .setFormat(attrs.format) + .setName(attrs.getTitle().toString()); final SurfaceControl sc = b.build(); synchronized (this) { mStateForWindow.put(window.asBinder(), new State(sc, attrs)); diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 7ee53f26b1f8..e81db16f0743 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -92,7 +92,10 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; /** @@ -422,6 +425,13 @@ public final class InputMethodManager { int mCursorCandEnd; /** + * Initial startInput with {@link StartInputReason.WINDOW_FOCUS_GAIN} is executed + * in a background thread. Later, if there is an actual startInput it will wait on + * main thread till the background thread completes. + */ + private CompletableFuture<Void> mWindowFocusGainFuture; + + /** * The instance that has previously been sent to the input method. */ private CursorAnchorInfo mCursorAnchorInfo = null; @@ -1598,6 +1608,18 @@ public final class InputMethodManager { boolean startInputInner(@StartInputReason int startInputReason, @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags) { + if (startInputReason != StartInputReason.WINDOW_FOCUS_GAIN + && mWindowFocusGainFuture != null) { + try { + mWindowFocusGainFuture.get(); + } catch (ExecutionException | InterruptedException e) { + // do nothing + } catch (CancellationException e) { + // window no longer has focus. + return true; + } + } + final View view; synchronized (mH) { view = mServedView; @@ -1947,31 +1969,38 @@ public final class InputMethodManager { } } - if (checkFocusNoStartInput(forceNewFocus)) { - // We need to restart input on the current focus view. This - // should be done in conjunction with telling the system service - // about the window gaining focus, to help make the transition - // smooth. - if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(), - startInputFlags, softInputMode, windowFlags)) { - return; - } + final boolean forceNewFocus1 = forceNewFocus; + final int startInputFlags1 = startInputFlags; + if (mWindowFocusGainFuture != null) { + mWindowFocusGainFuture.cancel(false/* mayInterruptIfRunning */); } + mWindowFocusGainFuture = CompletableFuture.runAsync(() -> { + if (checkFocusNoStartInput(forceNewFocus1)) { + // We need to restart input on the current focus view. This + // should be done in conjunction with telling the system service + // about the window gaining focus, to help make the transition + // smooth. + if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(), + startInputFlags1, softInputMode, windowFlags)) { + return; + } + } - // For some reason we didn't do a startInput + windowFocusGain, so - // we'll just do a window focus gain and call it a day. - synchronized (mH) { - try { - if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); - mService.startInputOrWindowGainedFocus( - StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, - rootView.getWindowToken(), startInputFlags, softInputMode, windowFlags, - null, null, 0 /* missingMethodFlags */, - rootView.getContext().getApplicationInfo().targetSdkVersion); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + // For some reason we didn't do a startInput + windowFocusGain, so + // we'll just do a window focus gain and call it a day. + synchronized (mH) { + try { + if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); + mService.startInputOrWindowGainedFocus( + StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, + rootView.getWindowToken(), startInputFlags1, softInputMode, windowFlags, + null, null, 0 /* missingMethodFlags */, + rootView.getContext().getApplicationInfo().targetSdkVersion); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } - } + }); } /** @hide */ @@ -1986,6 +2015,10 @@ public final class InputMethodManager { // If the mCurRootView is losing window focus, release the strong reference to it // so as not to prevent it from being garbage-collected. mCurRootView = null; + if (mWindowFocusGainFuture != null) { + mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */); + mWindowFocusGainFuture = null; + } } else { if (DEBUG) { Log.v(TAG, "Ignoring onPreWindowFocus()." diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 7282008f7e3a..2895621f962a 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -328,6 +328,9 @@ public abstract class WebSettings { * <p> * The built-in mechanisms are the only currently supported zoom * mechanisms, so it is recommended that this setting is always enabled. + * However, on-screen zoom controls are deprecated in Android (see + * {@link android.widget.ZoomButtonsController}) so it's recommended to + * disable {@link #setDisplayZoomControls}. * * @param enabled whether the WebView should use its built-in zoom mechanisms */ @@ -347,7 +350,9 @@ public abstract class WebSettings { /** * Sets whether the WebView should display on-screen zoom controls when * using the built-in zoom mechanisms. See {@link #setBuiltInZoomControls}. - * The default is {@code true}. + * The default is {@code true}. However, on-screen zoom controls are deprecated + * in Android (see {@link android.widget.ZoomButtonsController}) so it's + * recommended to set this to {@code false}. * * @param enabled whether the WebView should display on-screen zoom controls */ diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java index 278f40660ee9..e1b8e6c2d7d1 100644 --- a/core/java/com/android/internal/os/BaseCommand.java +++ b/core/java/com/android/internal/os/BaseCommand.java @@ -18,14 +18,14 @@ package com.android.internal.os; import android.annotation.UnsupportedAppUsage; -import android.os.ShellCommand; +import android.os.BasicShellCommandHandler; import java.io.PrintStream; public abstract class BaseCommand { @UnsupportedAppUsage - final protected ShellCommand mArgs = new ShellCommand() { + final protected BasicShellCommandHandler mArgs = new BasicShellCommandHandler() { @Override public int onCommand(String cmd) { return 0; } @@ -50,7 +50,7 @@ public abstract class BaseCommand { } mRawArgs = args; - mArgs.init(null, null, null, null, args, null, 0); + mArgs.init(null, null, null, null, args, 0); try { onRun(); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index d6b32b58ce64..f5bfe5cfecaf 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -12618,20 +12618,20 @@ public class BatteryStatsImpl extends BatteryStats { txTimeMs[i] = counter.getTxTimeCounters()[i].getCountLocked(which); totalTxTimeMs += txTimeMs[i]; } - s.setLoggingDurationMs(computeBatteryRealtime(rawRealTime, which) / 1000); - s.setKernelActiveTimeMs(getMobileRadioActiveTime(rawRealTime, which) / 1000); + s.setLoggingDurationMillis(computeBatteryRealtime(rawRealTime, which) / 1000); + s.setKernelActiveTimeMillis(getMobileRadioActiveTime(rawRealTime, which) / 1000); s.setNumPacketsTx(getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which)); s.setNumBytesTx(getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which)); s.setNumPacketsRx(getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which)); s.setNumBytesRx(getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which)); - s.setSleepTimeMs(sleepTimeMs); - s.setIdleTimeMs(idleTimeMs); - s.setRxTimeMs(rxTimeMs); - s.setEnergyConsumedMaMs(energyConsumedMaMs); - s.setTimeInRatMs(timeInRatMs); - s.setTimeInRxSignalStrengthLevelMs(timeInRxSignalStrengthLevelMs); - s.setTxTimeMs(txTimeMs); - s.setMonitoredRailChargeConsumedMaMs(monitoredRailChargeConsumedMaMs); + s.setSleepTimeMillis(sleepTimeMs); + s.setIdleTimeMillis(idleTimeMs); + s.setRxTimeMillis(rxTimeMs); + s.setEnergyConsumedMaMillis(energyConsumedMaMs); + s.setTimeInRatMicros(timeInRatMs); + s.setTimeInRxSignalStrengthLevelMicros(timeInRxSignalStrengthLevelMs); + s.setTxTimeMillis(txTimeMs); + s.setMonitoredRailChargeConsumedMaMillis(monitoredRailChargeConsumedMaMs); return s; } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 317469e58245..73f549a31bac 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -38,25 +38,6 @@ oneway interface IStatusBar void showWirelessChargingAnimation(int batteryLevel); - /** - * Notifies System UI side of a visibility flag change on the specified display. - * - * @param displayId the id of the display to notify - * @param vis the visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will be reported - * separately in fullscreenStackVis and dockedStackVis - * @param fullscreenStackVis the flags which only apply in the region of the fullscreen stack, - * which is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR - * @param dockedStackVis the flags that only apply in the region of the docked stack, which is - * currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR - * @param mask which flags to change - * @param fullscreenBounds the current bounds of the fullscreen stack, in screen coordinates - * @param dockedBounds the current bounds of the docked stack, in screen coordinates - * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME. - */ - void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis, - int mask, in Rect fullscreenBounds, in Rect dockedBounds, - boolean navbarColorManagedByIme); - void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive); void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition, boolean showImeSwitcher, boolean isMultiClientImeEnabled); diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index d703b86d6c8d..3f08710bb17f 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -77,7 +77,6 @@ interface IStatusBarService void onNotificationSmartReplySent(in String key, in int replyIndex, in CharSequence reply, in int notificationLocation, boolean modifiedBeforeSending); void onNotificationSettingsViewed(String key); - void setSystemUiVisibility(int displayId, int vis, int mask, String cause); void onNotificationBubbleChanged(String key, boolean isBubble); void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName); void clearInlineReplyUriPermissions(String key); diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java index 4c3f04b10892..9095f05543da 100644 --- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java +++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java @@ -16,53 +16,50 @@ package com.android.internal.statusbar; -import android.graphics.Rect; +import android.annotation.NonNull; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; +import com.android.internal.view.AppearanceRegion; + /** * An immutable data object to return a set of values from StatusBarManagerService to its clients. */ public final class RegisterStatusBarResult implements Parcelable { public final ArrayMap<String, StatusBarIcon> mIcons; - public final int mDisabledFlags1; // switch[0] - public final int mSystemUiVisibility; // switch[1] - public final int mImeWindowVis; // switch[3] - public final int mImeBackDisposition; // switch[4] - public final boolean mShowImeSwitcher; // switch[5] - public final int mDisabledFlags2; // switch[6] - public final int mFullscreenStackSysUiVisibility; // switch[7] - public final int mDockedStackSysUiVisibility; // switch[8] + public final int mDisabledFlags1; // switch[0] + public final int mAppearance; // switch[1] + public final AppearanceRegion[] mAppearanceRegions; // switch[2] + public final int mImeWindowVis; // switch[3] + public final int mImeBackDisposition; // switch[4] + public final boolean mShowImeSwitcher; // switch[5] + public final int mDisabledFlags2; // switch[6] public final IBinder mImeToken; - public final Rect mFullscreenStackBounds; - public final Rect mDockedStackBounds; public final boolean mNavbarColorManagedByIme; public final boolean mAppFullscreen; public final boolean mAppImmersive; + public final int[] mTransientBarTypes; public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1, - int systemUiVisibility, int imeWindowVis, int imeBackDisposition, - boolean showImeSwitcher, int disabledFlags2, int fullscreenStackSysUiVisibility, - int dockedStackSysUiVisibility, IBinder imeToken, Rect fullscreenStackBounds, - Rect dockedStackBounds, boolean navbarColorManagedByIme, boolean appFullscreen, - boolean appImmersive) { + int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis, + int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken, + boolean navbarColorManagedByIme, boolean appFullscreen, boolean appImmersive, + @NonNull int[] transientBarTypes) { mIcons = new ArrayMap<>(icons); mDisabledFlags1 = disabledFlags1; - mSystemUiVisibility = systemUiVisibility; + mAppearance = appearance; + mAppearanceRegions = appearanceRegions; mImeWindowVis = imeWindowVis; mImeBackDisposition = imeBackDisposition; mShowImeSwitcher = showImeSwitcher; mDisabledFlags2 = disabledFlags2; - mFullscreenStackSysUiVisibility = fullscreenStackSysUiVisibility; - mDockedStackSysUiVisibility = dockedStackSysUiVisibility; mImeToken = imeToken; - mFullscreenStackBounds = fullscreenStackBounds; - mDockedStackBounds = dockedStackBounds; mNavbarColorManagedByIme = navbarColorManagedByIme; mAppFullscreen = appFullscreen; mAppImmersive = appImmersive; + mTransientBarTypes = transientBarTypes; } @Override @@ -74,19 +71,17 @@ public final class RegisterStatusBarResult implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeTypedArrayMap(mIcons, flags); dest.writeInt(mDisabledFlags1); - dest.writeInt(mSystemUiVisibility); + dest.writeInt(mAppearance); + dest.writeParcelableArray(mAppearanceRegions, 0); dest.writeInt(mImeWindowVis); dest.writeInt(mImeBackDisposition); dest.writeBoolean(mShowImeSwitcher); dest.writeInt(mDisabledFlags2); - dest.writeInt(mFullscreenStackSysUiVisibility); - dest.writeInt(mDockedStackSysUiVisibility); dest.writeStrongBinder(mImeToken); - dest.writeTypedObject(mFullscreenStackBounds, flags); - dest.writeTypedObject(mDockedStackBounds, flags); dest.writeBoolean(mNavbarColorManagedByIme); dest.writeBoolean(mAppFullscreen); dest.writeBoolean(mAppImmersive); + dest.writeIntArray(mTransientBarTypes); } /** @@ -99,24 +94,22 @@ public final class RegisterStatusBarResult implements Parcelable { final ArrayMap<String, StatusBarIcon> icons = source.createTypedArrayMap(StatusBarIcon.CREATOR); final int disabledFlags1 = source.readInt(); - final int systemUiVisibility = source.readInt(); + final int appearance = source.readInt(); + final AppearanceRegion[] appearanceRegions = + source.readParcelableArray(null, AppearanceRegion.class); final int imeWindowVis = source.readInt(); final int imeBackDisposition = source.readInt(); final boolean showImeSwitcher = source.readBoolean(); final int disabledFlags2 = source.readInt(); - final int fullscreenStackSysUiVisibility = source.readInt(); - final int dockedStackSysUiVisibility = source.readInt(); final IBinder imeToken = source.readStrongBinder(); - final Rect fullscreenStackBounds = source.readTypedObject(Rect.CREATOR); - final Rect dockedStackBounds = source.readTypedObject(Rect.CREATOR); final boolean navbarColorManagedByIme = source.readBoolean(); final boolean appFullscreen = source.readBoolean(); final boolean appImmersive = source.readBoolean(); - return new RegisterStatusBarResult(icons, disabledFlags1, systemUiVisibility, - imeWindowVis, imeBackDisposition, showImeSwitcher, disabledFlags2, - fullscreenStackSysUiVisibility, dockedStackSysUiVisibility, imeToken, - fullscreenStackBounds, dockedStackBounds, navbarColorManagedByIme, - appFullscreen, appImmersive); + final int[] transientBarTypes = source.createIntArray(); + return new RegisterStatusBarResult(icons, disabledFlags1, appearance, + appearanceRegions, imeWindowVis, imeBackDisposition, showImeSwitcher, + disabledFlags2, imeToken, navbarColorManagedByIme, appFullscreen, + appImmersive, transientBarTypes); } @Override diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index db91dc5a8bc3..ed7f5de83fd1 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -540,6 +540,7 @@ public class SystemConfig { Slog.w(TAG, "Couldn't find or open permissions file " + permFile); return; } + Slog.i(TAG, "Reading permissions from " + permFile); final boolean lowRam = ActivityManager.isLowRamDeviceStatic(); diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index bf1cea8cff2e..891520a34ce1 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -276,20 +276,12 @@ static jobject android_view_InputChannel_nativeGetToken(JNIEnv* env, jobject obj NativeInputChannel* nativeInputChannel = android_view_InputChannel_getNativeInputChannel(env, obj); if (nativeInputChannel) { - return javaObjectForIBinder(env, nativeInputChannel->getInputChannel()->getToken()); + return javaObjectForIBinder(env, + nativeInputChannel->getInputChannel()->getConnectionToken()); } return 0; } -static void android_view_InputChannel_nativeSetToken(JNIEnv* env, jobject obj, jobject tokenObj) { - NativeInputChannel* nativeInputChannel = - android_view_InputChannel_getNativeInputChannel(env, obj); - sp<IBinder> token = ibinderForJavaObject(env, tokenObj); - if (nativeInputChannel != nullptr) { - nativeInputChannel->getInputChannel()->setToken(token); - } -} - // ---------------------------------------------------------------------------- static const JNINativeMethod gInputChannelMethods[] = { @@ -312,8 +304,6 @@ static const JNINativeMethod gInputChannelMethods[] = { (void*)android_view_InputChannel_nativeDup }, { "nativeGetToken", "()Landroid/os/IBinder;", (void*)android_view_InputChannel_nativeGetToken }, - { "nativeSetToken", "(Landroid/os/IBinder;)V", - (void*)android_view_InputChannel_nativeSetToken } }; int register_android_view_InputChannel(JNIEnv* env) { diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 2f87debce978..b9d28e4ce8eb 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -100,7 +100,8 @@ message ActivityStackProto { message TaskRecordProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1; + // To be removed soon. + optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true]; optional int32 id = 2; repeated ActivityRecordProto activities = 3; optional int32 stack_id = 4; @@ -113,6 +114,7 @@ message TaskRecordProto { optional .android.graphics.RectProto bounds = 11; optional int32 min_width = 12; optional int32 min_height = 13; + optional .com.android.server.wm.TaskProto task = 14; } message ActivityRecordProto { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a15e1aea7a82..66e84dc16781 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2006,6 +2006,11 @@ <!-- =========================================== --> <eat-comment /> + <!-- @SystemApi Allows granting runtime permissions to telephony related components. + @hide Used internally. --> + <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" + android:protectionLevel="signature|telephony" /> + <!-- Allows modification of the telephony state - power on, mmi, etc. Does not include placing calls. <p>Not for use by third-party applications. --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index eaf93eb9e216..9ca98c570c89 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3705,7 +3705,7 @@ name is separated by comma. Example: "com.android.phone,com.android.stk,com.android.providers.telephony" --> - <string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons"</string> + <string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons,com.android.cellbroadcastservice"</string> <!-- The package name for the default system wifi app. This package must be trusted, as it has the permissions to control wifi diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java index 0be5009f85f0..9f68ef31c166 100644 --- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java +++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java @@ -18,7 +18,6 @@ package com.android.internal.statusbar; import static com.google.common.truth.Truth.assertThat; -import android.graphics.Rect; import android.os.Binder; import android.os.Parcel; import android.os.UserHandle; @@ -27,6 +26,8 @@ import android.util.ArrayMap; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import com.android.internal.view.AppearanceRegion; + import org.junit.Test; import org.junit.runner.RunWith; @@ -47,19 +48,17 @@ public class RegisterStatusBarResultTest { final RegisterStatusBarResult original = new RegisterStatusBarResult(iconMap, 0x2 /* disabledFlags1 */, - 0x4 /* systemUiVisibility */, + 0x4 /* appearance */, + new AppearanceRegion[0] /* appearanceRegions */, 0x8 /* imeWindowVis */, 0x10 /* imeBackDisposition */, false /* showImeSwitcher */, 0x20 /* disabledFlags2 */, - 0x40 /* fullscreenStackSysUiVisibility */, - 0x80 /* dockedStackSysUiVisibility */, new Binder() /* imeToken */, - new Rect(0x100, 0x200, 0x400, 0x800) /* fullscreenStackBounds */, - new Rect(0x1000, 0x2000, 0x4000, 0x8000) /* dockedStackBounds */, true /* navbarColorManagedByIme */, true /* appFullscreen */, - true /* appImmersive */); + true /* appImmersive */, + new int[0] /* transientBarTypes */); final RegisterStatusBarResult copy = clone(original); @@ -69,21 +68,17 @@ public class RegisterStatusBarResultTest { .isEqualTo(original.mIcons.get(dumyIconKey).user); assertThat(copy.mDisabledFlags1).isEqualTo(original.mDisabledFlags1); - assertThat(copy.mSystemUiVisibility).isEqualTo(original.mSystemUiVisibility); + assertThat(copy.mAppearance).isEqualTo(original.mAppearance); + assertThat(copy.mAppearanceRegions).isEqualTo(original.mAppearanceRegions); assertThat(copy.mImeWindowVis).isEqualTo(original.mImeWindowVis); assertThat(copy.mImeBackDisposition).isEqualTo(original.mImeBackDisposition); assertThat(copy.mShowImeSwitcher).isEqualTo(original.mShowImeSwitcher); assertThat(copy.mDisabledFlags2).isEqualTo(original.mDisabledFlags2); - assertThat(copy.mFullscreenStackSysUiVisibility) - .isEqualTo(original.mFullscreenStackSysUiVisibility); - assertThat(copy.mDockedStackSysUiVisibility) - .isEqualTo(original.mDockedStackSysUiVisibility); assertThat(copy.mImeToken).isSameAs(original.mImeToken); - assertThat(copy.mFullscreenStackBounds).isEqualTo(original.mFullscreenStackBounds); - assertThat(copy.mDockedStackBounds).isEqualTo(original.mDockedStackBounds); assertThat(copy.mNavbarColorManagedByIme).isEqualTo(original.mNavbarColorManagedByIme); assertThat(copy.mAppFullscreen).isEqualTo(original.mAppFullscreen); assertThat(copy.mAppImmersive).isEqualTo(original.mAppImmersive); + assertThat(copy.mTransientBarTypes).isEqualTo(original.mTransientBarTypes); } private RegisterStatusBarResult clone(RegisterStatusBarResult original) { diff --git a/data/keyboards/Vendor_1532_Product_0900.kl b/data/keyboards/Vendor_1532_Product_0900.kl index c2fc1b4f9365..4c6c4dda02b0 100644 --- a/data/keyboards/Vendor_1532_Product_0900.kl +++ b/data/keyboards/Vendor_1532_Product_0900.kl @@ -20,13 +20,19 @@ key 307 BUTTON_X key 308 BUTTON_Y key 310 BUTTON_L1 key 311 BUTTON_R1 -key 316 BUTTON_MODE key 317 BUTTON_THUMBL key 318 BUTTON_THUMBR key 158 BACK key 172 HOME +# Left arrow to the left of the "power" key +key 0x13a BUTTON_SELECT +# Right arrow to the right of the "power" key +key 0x13b BUTTON_START +# Power key +key 0x13c BUTTON_MODE + axis 0x00 X axis 0x01 Y axis 0x02 Z diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 4ca26c273c95..15e0c8d0a266 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -479,7 +479,8 @@ void CanvasContext::draw() { if (didDraw) { swap.damage = windowDirty; } else { - swap.damage = SkRect::MakeWH(INT_MAX, INT_MAX); + float max = static_cast<float>(INT_MAX); + swap.damage = SkRect::MakeWH(max, max); } swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC); swap.vsyncTime = mRenderThread.timeLord().latestVsync(); diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index 3abd2c2144e1..ca8f2ac82e94 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -505,6 +505,23 @@ public final class LocationRequest implements Parcelable { } /** + * Returns the realtime at which this request expires, taking into account both + * {@link #setExpireAt(long)} and {@link #setExpireIn(long)} relative to the given realtime. + * + * @hide + */ + public long getExpirationRealtimeMs(long startRealtimeMs) { + long expirationRealtimeMs; + // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0): + if (mExpireIn > Long.MAX_VALUE - startRealtimeMs) { + expirationRealtimeMs = Long.MAX_VALUE; + } else { + expirationRealtimeMs = startRealtimeMs + mExpireIn; + } + return Math.min(expirationRealtimeMs, mExpireAt); + } + + /** * Set the number of location updates. * * <p>By default locations are continuously updated until the request is explicitly diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 2257747c2c8b..4ed8f423d6c9 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -16,11 +16,11 @@ package android.media.tv.tuner; -import android.annotation.IntDef; -import android.hardware.tv.tuner.V1_0.Constants; +import android.annotation.Nullable; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.List; /** @@ -32,40 +32,16 @@ public final class Tuner implements AutoCloseable { private static final String TAG = "MediaTvTuner"; private static final boolean DEBUG = false; - @Retention(RetentionPolicy.SOURCE) - @IntDef({FRONTEND_TYPE_UNDEFINED, FRONTEND_TYPE_ANALOG, FRONTEND_TYPE_ATSC, FRONTEND_TYPE_ATSC3, - FRONTEND_TYPE_DVBC, FRONTEND_TYPE_DVBS, FRONTEND_TYPE_DVBT, FRONTEND_TYPE_ISDBS, - FRONTEND_TYPE_ISDBS3, FRONTEND_TYPE_ISDBT}) - public @interface FrontendType {} - - public static final int FRONTEND_TYPE_UNDEFINED = Constants.FrontendType.UNDEFINED; - public static final int FRONTEND_TYPE_ANALOG = Constants.FrontendType.ANALOG; - public static final int FRONTEND_TYPE_ATSC = Constants.FrontendType.ATSC; - public static final int FRONTEND_TYPE_ATSC3 = Constants.FrontendType.ATSC3; - public static final int FRONTEND_TYPE_DVBC = Constants.FrontendType.DVBC; - public static final int FRONTEND_TYPE_DVBS = Constants.FrontendType.DVBS; - public static final int FRONTEND_TYPE_DVBT = Constants.FrontendType.DVBT; - public static final int FRONTEND_TYPE_ISDBS = Constants.FrontendType.ISDBS; - public static final int FRONTEND_TYPE_ISDBS3 = Constants.FrontendType.ISDBS3; - public static final int FRONTEND_TYPE_ISDBT = Constants.FrontendType.ISDBT; - - - @Retention(RetentionPolicy.SOURCE) - @IntDef({FRONTEND_EVENT_TYPE_LOCKED, FRONTEND_EVENT_TYPE_NO_SIGNAL, - FRONTEND_EVENT_TYPE_LOST_LOCK}) - public @interface FrontendEventType {} - - public static final int FRONTEND_EVENT_TYPE_LOCKED = Constants.FrontendEventType.LOCKED; - public static final int FRONTEND_EVENT_TYPE_NO_SIGNAL = Constants.FrontendEventType.NO_SIGNAL; - public static final int FRONTEND_EVENT_TYPE_LOST_LOCK = Constants.FrontendEventType.LOST_LOCK; + private static final int MSG_ON_FRONTEND_EVENT = 1; static { System.loadLibrary("media_tv_tuner"); nativeInit(); } - private FrontendCallback mFrontendCallback; private List<Integer> mFrontendIds; + private Frontend mFrontend; + private EventHandler mHandler; public Tuner() { nativeSetup(); @@ -96,6 +72,8 @@ public final class Tuner implements AutoCloseable { */ private native Frontend nativeOpenFrontendById(int id); + private native Filter nativeOpenFilter(int type, int subType, int bufferSize); + /** * Frontend Callback. @@ -108,11 +86,66 @@ public final class Tuner implements AutoCloseable { void onEvent(int frontendEventType); } - protected static class Frontend { - int mId; + @Nullable + private EventHandler createEventHandler() { + Looper looper; + if ((looper = Looper.myLooper()) != null) { + return new EventHandler(looper); + } else if ((looper = Looper.getMainLooper()) != null) { + return new EventHandler(looper); + } + return null; + } + + private class EventHandler extends Handler { + private EventHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_ON_FRONTEND_EVENT: + if (mFrontend != null && mFrontend.mCallback != null) { + mFrontend.mCallback.onEvent(msg.arg1); + } + break; + default: + // fall through + } + } + } + + protected class Frontend { + private int mId; + private FrontendCallback mCallback; + private Frontend(int id) { mId = id; } + + public void setCallback(@Nullable FrontendCallback callback, @Nullable Handler handler) { + mCallback = callback; + + if (mCallback == null) { + return; + } + + if (handler == null) { + // use default looper if handler is null + if (mHandler == null) { + mHandler = createEventHandler(); + } + return; + } + + Looper looper = handler.getLooper(); + if (mHandler != null && mHandler.getLooper() == looper) { + // the same looper. reuse mHandler + return; + } + mHandler = new EventHandler(looper); + } } private List<Integer> getFrontendIds() { @@ -122,11 +155,29 @@ public final class Tuner implements AutoCloseable { private Frontend openFrontendById(int id) { if (mFrontendIds == null) { - getFrontendIds(); + mFrontendIds = getFrontendIds(); } if (!mFrontendIds.contains(id)) { return null; } - return nativeOpenFrontendById(id); + mFrontend = nativeOpenFrontendById(id); + return mFrontend; + } + + private void onFrontendEvent(int eventType) { + if (mHandler != null) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_FRONTEND_EVENT, eventType, 0)); + } + } + + protected class Filter { + int mId; + private Filter(int id) { + mId = id; + } + } + + private Filter openFilter(int type, int subType, int bufferSize) { + return nativeOpenFilter(type, subType, bufferSize); } } diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java new file mode 100644 index 000000000000..411882ed13bd --- /dev/null +++ b/media/java/android/media/tv/tuner/TunerConstants.java @@ -0,0 +1,72 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.tv.tuner; + +import android.annotation.IntDef; +import android.hardware.tv.tuner.V1_0.Constants; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @hide + */ +final class TunerConstants { + public static final int INVALID_TS_PID = Constants.Constant.INVALID_TS_PID; + public static final int INVALID_STREAM_ID = Constants.Constant.INVALID_STREAM_ID; + + + @Retention(RetentionPolicy.SOURCE) + @IntDef({FRONTEND_TYPE_UNDEFINED, FRONTEND_TYPE_ANALOG, FRONTEND_TYPE_ATSC, FRONTEND_TYPE_ATSC3, + FRONTEND_TYPE_DVBC, FRONTEND_TYPE_DVBS, FRONTEND_TYPE_DVBT, FRONTEND_TYPE_ISDBS, + FRONTEND_TYPE_ISDBS3, FRONTEND_TYPE_ISDBT}) + public @interface FrontendType {} + + public static final int FRONTEND_TYPE_UNDEFINED = Constants.FrontendType.UNDEFINED; + public static final int FRONTEND_TYPE_ANALOG = Constants.FrontendType.ANALOG; + public static final int FRONTEND_TYPE_ATSC = Constants.FrontendType.ATSC; + public static final int FRONTEND_TYPE_ATSC3 = Constants.FrontendType.ATSC3; + public static final int FRONTEND_TYPE_DVBC = Constants.FrontendType.DVBC; + public static final int FRONTEND_TYPE_DVBS = Constants.FrontendType.DVBS; + public static final int FRONTEND_TYPE_DVBT = Constants.FrontendType.DVBT; + public static final int FRONTEND_TYPE_ISDBS = Constants.FrontendType.ISDBS; + public static final int FRONTEND_TYPE_ISDBS3 = Constants.FrontendType.ISDBS3; + public static final int FRONTEND_TYPE_ISDBT = Constants.FrontendType.ISDBT; + + + @Retention(RetentionPolicy.SOURCE) + @IntDef({FRONTEND_EVENT_TYPE_LOCKED, FRONTEND_EVENT_TYPE_NO_SIGNAL, + FRONTEND_EVENT_TYPE_LOST_LOCK}) + public @interface FrontendEventType {} + + public static final int FRONTEND_EVENT_TYPE_LOCKED = Constants.FrontendEventType.LOCKED; + public static final int FRONTEND_EVENT_TYPE_NO_SIGNAL = Constants.FrontendEventType.NO_SIGNAL; + public static final int FRONTEND_EVENT_TYPE_LOST_LOCK = Constants.FrontendEventType.LOST_LOCK; + + + @Retention(RetentionPolicy.SOURCE) + @IntDef({DATA_FORMAT_TS, DATA_FORMAT_PES, DATA_FORMAT_ES, DATA_FORMAT_SHV_TLV}) + public @interface DataFormat {} + + public static final int DATA_FORMAT_TS = Constants.DataFormat.TS; + public static final int DATA_FORMAT_PES = Constants.DataFormat.PES; + public static final int DATA_FORMAT_ES = Constants.DataFormat.ES; + public static final int DATA_FORMAT_SHV_TLV = Constants.DataFormat.SHV_TLV; + + private TunerConstants() { + } +} diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp index 2d9051f5230d..517672ee6127 100644 --- a/media/jni/android_media_MediaCrypto.cpp +++ b/media/jni/android_media_MediaCrypto.cpp @@ -24,11 +24,10 @@ #include "jni.h" #include <nativehelper/JNIHelp.h> -#include <binder/IServiceManager.h> #include <cutils/properties.h> #include <media/stagefright/foundation/ADebug.h> +#include <mediadrm/DrmUtils.h> #include <mediadrm/ICrypto.h> -#include <mediadrm/IMediaDrmService.h> namespace android { @@ -64,20 +63,7 @@ JCrypto::~JCrypto() { // static sp<ICrypto> JCrypto::MakeCrypto() { - sp<IServiceManager> sm = defaultServiceManager(); - - sp<IBinder> binder = sm->getService(String16("media.drm")); - sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder); - if (service == NULL) { - return NULL; - } - - sp<ICrypto> crypto = service->makeCrypto(); - if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) { - return NULL; - } - - return crypto; + return DrmUtils::MakeCrypto(); } // static diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index f412161f418a..820fe98cafb6 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -27,14 +27,13 @@ #include "jni.h" #include <nativehelper/JNIHelp.h> -#include <binder/IServiceManager.h> #include <binder/Parcel.h> #include <binder/PersistableBundle.h> #include <cutils/properties.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/MediaErrors.h> +#include <mediadrm/DrmUtils.h> #include <mediadrm/IDrm.h> -#include <mediadrm/IMediaDrmService.h> using ::android::os::PersistableBundle; @@ -486,20 +485,7 @@ JDrm::~JDrm() { // static sp<IDrm> JDrm::MakeDrm() { - sp<IServiceManager> sm = defaultServiceManager(); - - sp<IBinder> binder = sm->getService(String16("media.drm")); - sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder); - if (service == NULL) { - return NULL; - } - - sp<IDrm> drm = service->makeDrm(); - if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) { - return NULL; - } - - return drm; + return DrmUtils::MakeDrm(); } // static diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index ba133fc44fb7..f8150972a413 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -25,18 +25,59 @@ #pragma GCC diagnostic ignored "-Wunused-function" +using ::android::hardware::Void; using ::android::hardware::hidl_vec; +using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType; using ::android::hardware::tv::tuner::V1_0::ITuner; using ::android::hardware::tv::tuner::V1_0::Result; struct fields_t { jfieldID context; jmethodID frontendInitID; + jmethodID filterInitID; + jmethodID onFrontendEventID; }; static fields_t gFields; namespace android { +/////////////// FilterCallback /////////////////////// +//TODO: implement filter callback +Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& /* filterEvent */) { + ALOGD("FilterCallback::onFilterEvent"); + return Void(); +} +Return<void> FilterCallback::onFilterStatus(const DemuxFilterStatus /*status*/) { + ALOGD("FilterCallback::onFilterStatu"); + return Void(); +} + +/////////////// FrontendCallback /////////////////////// + +FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {} + +Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) { + ALOGD("FrontendCallback::onEvent, type=%d", frontendEventType); + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod( + mObject, + gFields.onFrontendEventID, + (jint)frontendEventType); + return Void(); +} +Return<void> FrontendCallback::onDiseqcMessage(const hidl_vec<uint8_t>& /*diseqcMessage*/) { + ALOGD("FrontendCallback::onDiseqcMessage"); + return Void(); +} + +Return<void> FrontendCallback::onScanMessage( + FrontendScanMessageType type, const FrontendScanMessage& /*message*/) { + ALOGD("FrontendCallback::onScanMessage, type=%d", type); + return Void(); +} + +/////////////// Tuner /////////////////////// sp<ITuner> JTuner::mTuner; @@ -74,11 +115,10 @@ sp<ITuner> JTuner::getTunerService() { jobject JTuner::getFrontendIds() { ALOGD("JTuner::getFrontendIds()"); - hidl_vec<FrontendId> feIds; mTuner->getFrontendIds([&](Result, const hidl_vec<FrontendId>& frontendIds) { - feIds = frontendIds; + mFeIds = frontendIds; }); - if (feIds.size() == 0) { + if (mFeIds.size() == 0) { ALOGW("Frontend isn't available"); return NULL; } @@ -91,21 +131,25 @@ jobject JTuner::getFrontendIds() { jclass integerClazz = env->FindClass("java/lang/Integer"); jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V"); - for (int i=0; i < feIds.size(); i++) { - jobject idObj = env->NewObject(integerClazz, intInit, feIds[i]); + for (int i=0; i < mFeIds.size(); i++) { + jobject idObj = env->NewObject(integerClazz, intInit, mFeIds[i]); env->CallBooleanMethod(obj, arrayListAdd, idObj); } return obj; } jobject JTuner::openFrontendById(int id) { + sp<IFrontend> fe; mTuner->openFrontendById(id, [&](Result, const sp<IFrontend>& frontend) { - mFe = frontend; + fe = frontend; }); - if (mFe == nullptr) { + if (fe == nullptr) { ALOGE("Failed to open frontend"); return NULL; } + mFe = fe; + sp<FrontendCallback> feCb = new FrontendCallback(mObject, id); + fe->setCallback(feCb); jint jId = (jint) id; JNIEnv *env = AndroidRuntime::getJNIEnv(); @@ -113,9 +157,58 @@ jobject JTuner::openFrontendById(int id) { return env->NewObject( env->FindClass("android/media/tv/tuner/Tuner$Frontend"), gFields.frontendInitID, + mObject, (jint) jId); } +bool JTuner::openDemux() { + if (mTuner == nullptr) { + return false; + } + if (mDemux != nullptr) { + return true; + } + mTuner->openDemux([&](Result, uint32_t demuxId, const sp<IDemux>& demux) { + mDemux = demux; + mDemuxId = demuxId; + ALOGD("open demux, id = %d", demuxId); + }); + if (mDemux == nullptr) { + return false; + } + return true; +} + +jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { + if (mDemux == NULL) { + if (!openDemux()) { + return NULL; + } + } + + sp<IFilter> f; + mDemux->openFilter(type, bufferSize, new FilterCallback, + [&](Result, const sp<IFilter>& filter) { + f = filter; + }); + if (f == NULL) { + ALOGD("Failed to open filter, type = %d", type.mainType); + return NULL; + } + int fId; + f->getId([&](Result, uint32_t filterId) { + fId = filterId; + }); + mFilters[fId] = f; + + JNIEnv *env = AndroidRuntime::getJNIEnv(); + return env->NewObject( + env->FindClass("android/media/tv/tuner/Tuner$Filter"), + gFields.filterInitID, + mObject, + (jint) fId); +} + } // namespace android //////////////////////////////////////////////////////////////////////////////// @@ -147,8 +240,15 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { gFields.context = env->GetFieldID(clazz, "mNativeContext", "J"); CHECK(gFields.context != NULL); + gFields.onFrontendEventID = env->GetMethodID(clazz, "onFrontendEvent", "(I)V"); + jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend"); - gFields.frontendInitID = env->GetMethodID(frontendClazz, "<init>", "(I)V"); + gFields.frontendInitID = + env->GetMethodID(frontendClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V"); + + jclass filterClazz = env->FindClass("android/media/tv/tuner/Tuner$Filter"); + gFields.filterInitID = + env->GetMethodID(filterClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V"); } static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) { @@ -166,6 +266,19 @@ static jobject android_media_tv_Tuner_open_frontend_by_id(JNIEnv *env, jobject t return tuner->openFrontendById(id); } +static jobject android_media_tv_Tuner_open_filter( + JNIEnv *env, jobject thiz, jint type, jint subType, jint bufferSize) { + sp<JTuner> tuner = getTuner(env, thiz); + DemuxFilterType filterType { + .mainType = static_cast<DemuxFilterMainType>(type), + }; + + // TODO: other sub types + filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType)); + + return tuner->openFilter(filterType, bufferSize); +} + static const JNINativeMethod gMethods[] = { { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init }, { "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup }, @@ -173,6 +286,8 @@ static const JNINativeMethod gMethods[] = { (void *)android_media_tv_Tuner_get_frontend_ids }, { "nativeOpenFrontendById", "(I)Landroid/media/tv/tuner/Tuner$Frontend;", (void *)android_media_tv_Tuner_open_frontend_by_id }, + { "nativeOpenFilter", "(III)Landroid/media/tv/tuner/Tuner$Filter;", + (void *)android_media_tv_Tuner_open_filter }, }; static int register_android_media_tv_Tuner(JNIEnv *env) { diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 1425542aa648..7a889c3534da 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -18,29 +18,65 @@ #define _ANDROID_MEDIA_TV_TUNER_H_ #include <android/hardware/tv/tuner/1.0/ITuner.h> +#include <unordered_map> #include <utils/RefBase.h> #include "jni.h" +using ::android::hardware::Return; +using ::android::hardware::hidl_vec; +using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent; +using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus; +using ::android::hardware::tv::tuner::V1_0::DemuxFilterType; +using ::android::hardware::tv::tuner::V1_0::FrontendEventType; using ::android::hardware::tv::tuner::V1_0::FrontendId; +using ::android::hardware::tv::tuner::V1_0::FrontendScanMessage; +using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType; +using ::android::hardware::tv::tuner::V1_0::IDemux; +using ::android::hardware::tv::tuner::V1_0::IFilter; +using ::android::hardware::tv::tuner::V1_0::IFilterCallback; using ::android::hardware::tv::tuner::V1_0::IFrontend; +using ::android::hardware::tv::tuner::V1_0::IFrontendCallback; using ::android::hardware::tv::tuner::V1_0::ITuner; namespace android { +struct FilterCallback : public IFilterCallback { + virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent); + virtual Return<void> onFilterStatus(const DemuxFilterStatus status); +}; + +struct FrontendCallback : public IFrontendCallback { + FrontendCallback(jweak tunerObj, FrontendId id); + + virtual Return<void> onEvent(FrontendEventType frontendEventType); + virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage); + virtual Return<void> onScanMessage( + FrontendScanMessageType type, const FrontendScanMessage& message); + + jweak mObject; + FrontendId mId; +}; + struct JTuner : public RefBase { JTuner(JNIEnv *env, jobject thiz); sp<ITuner> getTunerService(); jobject getFrontendIds(); jobject openFrontendById(int id); + jobject openFilter(DemuxFilterType type, int bufferSize); protected: + bool openDemux(); virtual ~JTuner(); private: jclass mClass; jweak mObject; static sp<ITuner> mTuner; + hidl_vec<FrontendId> mFeIds; sp<IFrontend> mFe; + sp<IDemux> mDemux; + int mDemuxId; + std::unordered_map<int, sp<IFilter>> mFilters; }; } // namespace android diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types index 7a5299ff1b69..ce022a8b0f19 100644 --- a/mime/java-res/android.mime.types +++ b/mime/java-res/android.mime.types @@ -48,6 +48,9 @@ ?application/epub+zip epub ?application/pkix-cert cer ?application/rss+xml rss +?application/sdp sdp +?application/smil+xml smil +?application/ttml+xml ttml dfxp ?application/vnd.android.ota ota ?application/vnd.apple.mpegurl m3u8 ?application/vnd.ms-pki.stl stl @@ -67,12 +70,13 @@ ?application/x-x509-server-cert crt ?application/x-x509-user-cert crt -?audio/3gpp 3gpp +?audio/3gpp 3gpp 3ga ?audio/aac-adts aac +?audio/ac3 ac3 a52 ?audio/imelody imy ?audio/midi rtttl xmf ?audio/mobile-xmf mxmf -?audio/mp4 m4a +?audio/mp4 m4a m4b m4p f4a f4b f4p ?audio/mpegurl m3u ?audio/sp-midi smf ?audio/x-matroska mka @@ -101,10 +105,11 @@ ?text/xml xml ?text/x-vcard vcf -?video/3gpp2 3gpp2 3g2 +?video/3gpp2 3gpp2 3gp2 3g2 ?video/3gpp 3gpp ?video/avi avi ?video/m4v m4v +?video/mp4 m4v f4v mp4v mpeg4 ?video/mp2p mpeg ?video/mp2t m2ts mts ?video/mp2ts ts @@ -129,11 +134,11 @@ application/pgp-signature pgp application/x-x509-ca-cert crt -audio/aac aac +audio/aac aac adts adt audio/basic snd audio/flac flac audio/midi rtx -audio/mpeg mp3 m4a m4r +audio/mpeg mp3 mp2 mp1 mpa m4a m4r audio/x-mpegurl m3u m3u8 image/jpeg jpg image/x-ms-bmp bmp @@ -141,6 +146,6 @@ text/plain txt text/x-c++hdr hpp text/x-c++src cpp video/3gpp 3gpp -video/mpeg mpeg +video/mpeg mpeg mpeg2 mpv2 mp2v m2v m2t mpeg1 mpv1 mp1v m1v video/quicktime mov video/x-matroska mkv diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java index 706727bf050e..d3d9b286ded6 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java @@ -16,100 +16,30 @@ package com.android.systemui; -import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; - -import android.content.Context; -import android.os.PowerManager; -import android.util.DisplayMetrics; - -import com.android.internal.logging.MetricsLogger; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.appops.AppOpsController; -import com.android.systemui.assist.AssistManager; import com.android.systemui.biometrics.AuthController; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.doze.DozeLog; import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.navigationbar.car.CarNavigationBar; -import com.android.systemui.navigationbar.car.CarNavigationBarController; import com.android.systemui.pip.PipUI; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.power.PowerUI; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsModule; -import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.FeatureFlags; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationViewHierarchyManager; -import com.android.systemui.statusbar.PulseExpansionHandler; -import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.car.CarStatusBar; -import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.car.CarStatusBarModule; import com.android.systemui.statusbar.notification.InstantAppNotifier; -import com.android.systemui.statusbar.notification.NewNotifPipeline; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; -import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; -import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.logging.NotifLog; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.phone.AutoHideController; -import com.android.systemui.statusbar.phone.BiometricUnlockController; -import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.statusbar.phone.DozeScrimController; -import com.android.systemui.statusbar.phone.DozeServiceHost; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; -import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.LightBarController; -import com.android.systemui.statusbar.phone.LockscreenWallpaper; -import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; -import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.StatusBarIconController; -import com.android.systemui.statusbar.phone.StatusBarWindowController; -import com.android.systemui.statusbar.phone.StatusBarWindowViewController; -import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.RemoteInputUriController; -import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.tv.TvStatusBar; import com.android.systemui.theme.ThemeOverlayController; -import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.leak.GarbageMonitor; import com.android.systemui.volume.VolumeUI; -import javax.inject.Named; -import javax.inject.Singleton; - import dagger.Binds; -import dagger.Lazy; import dagger.Module; -import dagger.Provides; import dagger.multibindings.ClassKey; import dagger.multibindings.IntoMap; /** Binder for car specific {@link SystemUI} modules. */ -@Module(includes = {RecentsModule.class}) +@Module(includes = {RecentsModule.class, CarStatusBarModule.class}) public abstract class CarSystemUIBinder { /** Inject into AuthController. */ @Binds @@ -219,147 +149,4 @@ public abstract class CarSystemUIBinder { @IntoMap @ClassKey(VolumeUI.class) public abstract SystemUI bindVolumeUI(VolumeUI sysui); - - /** - * Provides our instance of StatusBar which is considered optional. - */ - @Provides - @Singleton - static CarStatusBar provideStatusBar( - Context context, - FeatureFlags featureFlags, - LightBarController lightBarController, - AutoHideController autoHideController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - StatusBarIconController statusBarIconController, - DozeLog dozeLog, - InjectionInflationController injectionInflationController, - PulseExpansionHandler pulseExpansionHandler, - NotificationWakeUpCoordinator notificationWakeUpCoordinator, - KeyguardBypassController keyguardBypassController, - KeyguardStateController keyguardStateController, - HeadsUpManagerPhone headsUpManagerPhone, - DynamicPrivacyController dynamicPrivacyController, - BypassHeadsUpNotifier bypassHeadsUpNotifier, - @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress, - Lazy<NewNotifPipeline> newNotifPipeline, - FalsingManager falsingManager, - BroadcastDispatcher broadcastDispatcher, - RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, - NotificationGutsManager notificationGutsManager, - NotificationLogger notificationLogger, - NotificationEntryManager notificationEntryManager, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, - NotificationViewHierarchyManager notificationViewHierarchyManager, - ForegroundServiceController foregroundServiceController, - AppOpsController appOpsController, - KeyguardViewMediator keyguardViewMediator, - ZenModeController zenModeController, - NotificationAlertingManager notificationAlertingManager, - DisplayMetrics displayMetrics, - MetricsLogger metricsLogger, - UiOffloadThread uiOffloadThread, - NotificationMediaManager notificationMediaManager, - NotificationLockscreenUserManager lockScreenUserManager, - NotificationRemoteInputManager remoteInputManager, - UserSwitcherController userSwitcherController, - NetworkController networkController, - BatteryController batteryController, - SysuiColorExtractor colorExtractor, - ScreenLifecycle screenLifecycle, - WakefulnessLifecycle wakefulnessLifecycle, - SysuiStatusBarStateController statusBarStateController, - VibratorHelper vibratorHelper, - BubbleController bubbleController, - NotificationGroupManager groupManager, - NotificationGroupAlertTransferHelper groupAlertTransferHelper, - VisualStabilityManager visualStabilityManager, - DeviceProvisionedController deviceProvisionedController, - NavigationBarController navigationBarController, - AssistManager assistManager, - NotificationListener notificationListener, - ConfigurationController configurationController, - StatusBarWindowController statusBarWindowController, - StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder, - NotifLog notifLog, - DozeParameters dozeParameters, - ScrimController scrimController, - Lazy<LockscreenWallpaper> lockscreenWallpaperLazy, - Lazy<BiometricUnlockController> biometricUnlockControllerLazy, - DozeServiceHost dozeServiceHost, - PowerManager powerManager, - DozeScrimController dozeScrimController, - CommandQueue commandQueue, - PluginManager pluginManager, - CarNavigationBarController carNavigationBarController, - RemoteInputUriController remoteInputUriController) { - return new CarStatusBar( - context, - featureFlags, - lightBarController, - autoHideController, - keyguardUpdateMonitor, - statusBarIconController, - dozeLog, - injectionInflationController, - pulseExpansionHandler, - notificationWakeUpCoordinator, - keyguardBypassController, - keyguardStateController, - headsUpManagerPhone, - dynamicPrivacyController, - bypassHeadsUpNotifier, - allowNotificationLongPress, - newNotifPipeline, - falsingManager, - broadcastDispatcher, - remoteInputQuickSettingsDisabler, - notificationGutsManager, - notificationLogger, - notificationEntryManager, - notificationInterruptionStateProvider, - notificationViewHierarchyManager, - foregroundServiceController, - appOpsController, - keyguardViewMediator, - zenModeController, - notificationAlertingManager, - displayMetrics, - metricsLogger, - uiOffloadThread, - notificationMediaManager, - lockScreenUserManager, - remoteInputManager, - userSwitcherController, - networkController, - batteryController, - colorExtractor, - screenLifecycle, - wakefulnessLifecycle, - statusBarStateController, - vibratorHelper, - bubbleController, - groupManager, - groupAlertTransferHelper, - visualStabilityManager, - deviceProvisionedController, - navigationBarController, - assistManager, - notificationListener, - configurationController, - statusBarWindowController, - statusBarWindowViewControllerBuilder, - notifLog, - dozeParameters, - scrimController, - lockscreenWallpaperLazy, - biometricUnlockControllerLazy, - dozeServiceHost, - powerManager, - dozeScrimController, - commandQueue, - pluginManager, - remoteInputUriController, - carNavigationBarController); - } } diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java index 98b91ebd8038..af92767efc49 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java @@ -53,13 +53,13 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private final CarNavigationBarController mCarNavigationBarController; private final WindowManager mWindowManager; private final DeviceProvisionedController mDeviceProvisionedController; + private final CommandQueue mCommandQueue; private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListener; private final Handler mMainHandler; private final Lazy<KeyguardStateController> mKeyguardStateController; private final Lazy<NavigationBarController> mNavigationBarController; private IStatusBarService mBarService; - private CommandQueue mCommandQueue; private ActivityManagerWrapper mActivityManagerWrapper; // If the nav bar should be hidden when the soft keyboard is visible. @@ -83,6 +83,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks CarNavigationBarController carNavigationBarController, WindowManager windowManager, DeviceProvisionedController deviceProvisionedController, + CommandQueue commandQueue, Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListener, @MainHandler Handler mainHandler, Lazy<KeyguardStateController> keyguardStateController, @@ -91,6 +92,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks mCarNavigationBarController = carNavigationBarController; mWindowManager = windowManager; mDeviceProvisionedController = deviceProvisionedController; + mCommandQueue = commandQueue; mFacetButtonTaskStackListener = facetButtonTaskStackListener; mMainHandler = mainHandler; mKeyguardStateController = keyguardStateController; @@ -109,7 +111,6 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks ServiceManager.getService(Context.STATUS_BAR_SERVICE)); // Connect into the status bar manager service - mCommandQueue = getComponent(CommandQueue.class); mCommandQueue.addCallback(this); RegisterStatusBarResult result = null; diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 110b32b57878..fc0b317d04ff 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -92,6 +92,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; @@ -131,7 +132,6 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; -import com.android.systemui.util.InjectionInflationController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -244,7 +244,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt KeyguardUpdateMonitor keyguardUpdateMonitor, StatusBarIconController statusBarIconController, DozeLog dozeLog, - InjectionInflationController injectionInflationController, PulseExpansionHandler pulseExpansionHandler, NotificationWakeUpCoordinator notificationWakeUpCoordinator, KeyguardBypassController keyguardBypassController, @@ -303,6 +302,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt CommandQueue commandQueue, PluginManager pluginManager, RemoteInputUriController remoteInputUriController, + SuperStatusBarViewFactory superStatusBarViewFactory, /* Car Settings injected components. */ CarNavigationBarController carNavigationBarController) { super( @@ -313,7 +313,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt keyguardUpdateMonitor, statusBarIconController, dozeLog, - injectionInflationController, pulseExpansionHandler, notificationWakeUpCoordinator, keyguardBypassController, @@ -372,7 +371,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt dozeScrimController, commandQueue, pluginManager, - remoteInputUriController); + remoteInputUriController, + superStatusBarViewFactory); mScrimController = scrimController; mCarNavigationBarController = carNavigationBarController; } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java new file mode 100644 index 000000000000..b19fae891a58 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2019 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.statusbar.car; + +import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; + +import android.content.Context; +import android.os.PowerManager; +import android.util.DisplayMetrics; + +import com.android.internal.logging.MetricsLogger; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.ForegroundServiceController; +import com.android.systemui.UiOffloadThread; +import com.android.systemui.appops.AppOpsController; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.doze.DozeLog; +import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.navigationbar.car.CarNavigationBarController; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.FeatureFlags; +import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationViewHierarchyManager; +import com.android.systemui.statusbar.PulseExpansionHandler; +import com.android.systemui.statusbar.StatusBarDependenciesModule; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; +import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.VibratorHelper; +import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.NewNotifPipeline; +import com.android.systemui.statusbar.notification.NotificationAlertingManager; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.logging.NotifLog; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.BiometricUnlockController; +import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.phone.DozeScrimController; +import com.android.systemui.statusbar.phone.DozeServiceHost; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.LockscreenWallpaper; +import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; +import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.phone.ScrimController; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.phone.StatusBarWindowController; +import com.android.systemui.statusbar.phone.StatusBarWindowViewController; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; +import com.android.systemui.statusbar.policy.RemoteInputUriController; +import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.statusbar.policy.ZenModeController; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Lazy; +import dagger.Module; +import dagger.Provides; + +/** + * Dagger Module providing {@link CarStatusBar}. + */ +@Module(includes = {StatusBarDependenciesModule.class}) +public class CarStatusBarModule { + /** + * Provides our instance of StatusBar which is considered optional. + */ + @Provides + @Singleton + static CarStatusBar provideStatusBar( + Context context, + FeatureFlags featureFlags, + LightBarController lightBarController, + AutoHideController autoHideController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + StatusBarIconController statusBarIconController, + DozeLog dozeLog, + PulseExpansionHandler pulseExpansionHandler, + NotificationWakeUpCoordinator notificationWakeUpCoordinator, + KeyguardBypassController keyguardBypassController, + KeyguardStateController keyguardStateController, + HeadsUpManagerPhone headsUpManagerPhone, + DynamicPrivacyController dynamicPrivacyController, + BypassHeadsUpNotifier bypassHeadsUpNotifier, + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress, + Lazy<NewNotifPipeline> newNotifPipeline, + FalsingManager falsingManager, + BroadcastDispatcher broadcastDispatcher, + RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, + NotificationGutsManager notificationGutsManager, + NotificationLogger notificationLogger, + NotificationEntryManager notificationEntryManager, + NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationViewHierarchyManager notificationViewHierarchyManager, + ForegroundServiceController foregroundServiceController, + AppOpsController appOpsController, + KeyguardViewMediator keyguardViewMediator, + ZenModeController zenModeController, + NotificationAlertingManager notificationAlertingManager, + DisplayMetrics displayMetrics, + MetricsLogger metricsLogger, + UiOffloadThread uiOffloadThread, + NotificationMediaManager notificationMediaManager, + NotificationLockscreenUserManager lockScreenUserManager, + NotificationRemoteInputManager remoteInputManager, + UserSwitcherController userSwitcherController, + NetworkController networkController, + BatteryController batteryController, + SysuiColorExtractor colorExtractor, + ScreenLifecycle screenLifecycle, + WakefulnessLifecycle wakefulnessLifecycle, + SysuiStatusBarStateController statusBarStateController, + VibratorHelper vibratorHelper, + BubbleController bubbleController, + NotificationGroupManager groupManager, + NotificationGroupAlertTransferHelper groupAlertTransferHelper, + VisualStabilityManager visualStabilityManager, + DeviceProvisionedController deviceProvisionedController, + NavigationBarController navigationBarController, + AssistManager assistManager, + NotificationListener notificationListener, + ConfigurationController configurationController, + StatusBarWindowController statusBarWindowController, + StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder, + NotifLog notifLog, + DozeParameters dozeParameters, + ScrimController scrimController, + Lazy<LockscreenWallpaper> lockscreenWallpaperLazy, + Lazy<BiometricUnlockController> biometricUnlockControllerLazy, + DozeServiceHost dozeServiceHost, + PowerManager powerManager, + DozeScrimController dozeScrimController, + CommandQueue commandQueue, + PluginManager pluginManager, + RemoteInputUriController remoteInputUriController, + SuperStatusBarViewFactory superStatusBarViewFactory, + CarNavigationBarController carNavigationBarController) { + return new CarStatusBar( + context, + featureFlags, + lightBarController, + autoHideController, + keyguardUpdateMonitor, + statusBarIconController, + dozeLog, + pulseExpansionHandler, + notificationWakeUpCoordinator, + keyguardBypassController, + keyguardStateController, + headsUpManagerPhone, + dynamicPrivacyController, + bypassHeadsUpNotifier, + allowNotificationLongPress, + newNotifPipeline, + falsingManager, + broadcastDispatcher, + remoteInputQuickSettingsDisabler, + notificationGutsManager, + notificationLogger, + notificationEntryManager, + notificationInterruptionStateProvider, + notificationViewHierarchyManager, + foregroundServiceController, + appOpsController, + keyguardViewMediator, + zenModeController, + notificationAlertingManager, + displayMetrics, + metricsLogger, + uiOffloadThread, + notificationMediaManager, + lockScreenUserManager, + remoteInputManager, + userSwitcherController, + networkController, + batteryController, + colorExtractor, + screenLifecycle, + wakefulnessLifecycle, + statusBarStateController, + vibratorHelper, + bubbleController, + groupManager, + groupAlertTransferHelper, + visualStabilityManager, + deviceProvisionedController, + navigationBarController, + assistManager, + notificationListener, + configurationController, + statusBarWindowController, + statusBarWindowViewControllerBuilder, + notifLog, + dozeParameters, + scrimController, + lockscreenWallpaperLazy, + biometricUnlockControllerLazy, + dozeServiceHost, + powerManager, + dozeScrimController, + commandQueue, + pluginManager, + remoteInputUriController, + superStatusBarViewFactory, + carNavigationBarController); + } +} diff --git a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java index 5dc9061a81a0..de45ea536e27 100644 --- a/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java +++ b/packages/SettingsLib/search/processor-src/com/android/settingslib/search/IndexableProcessor.java @@ -21,7 +21,6 @@ import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; -import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import java.io.IOException; @@ -73,10 +72,12 @@ public class IndexableProcessor extends AbstractProcessor { } mRanOnce = true; + final ClassName searchIndexableData = ClassName.get(PACKAGE, "SearchIndexableData"); + final FieldSpec providers = FieldSpec.builder( ParameterizedTypeName.get( ClassName.get(Set.class), - TypeName.get(Class.class)), + searchIndexableData), "mProviders", Modifier.PRIVATE, Modifier.FINAL) .initializer("new $T()", HashSet.class) @@ -84,7 +85,7 @@ public class IndexableProcessor extends AbstractProcessor { final MethodSpec addIndex = MethodSpec.methodBuilder("addIndex") .addModifiers(Modifier.PUBLIC) - .addParameter(ClassName.get(Class.class), "indexClass") + .addParameter(searchIndexableData, "indexClass") .addCode("$N.add(indexClass);\n", providers) .build(); @@ -113,19 +114,25 @@ public class IndexableProcessor extends AbstractProcessor { SearchIndexable searchIndexable = element.getAnnotation(SearchIndexable.class); int forTarget = searchIndexable.forTarget(); + MethodSpec.Builder builder = baseConstructorBuilder; + if (forTarget == SearchIndexable.ALL) { - baseConstructorBuilder.addCode("$N($L.class);\n", addIndex, className); + builder = baseConstructorBuilder; } else if ((forTarget & SearchIndexable.MOBILE) != 0) { - mobileConstructorBuilder.addCode("$N($L.class);\n", addIndex, className); + builder = mobileConstructorBuilder; } else if ((forTarget & SearchIndexable.TV) != 0) { - tvConstructorBuilder.addCode("$N($L.class);\n", addIndex, className); + builder = tvConstructorBuilder; } else if ((forTarget & SearchIndexable.WEAR) != 0) { - wearConstructorBuilder.addCode("$N($L.class);\n", addIndex, className); + builder = wearConstructorBuilder; } else if ((forTarget & SearchIndexable.AUTO) != 0) { - autoConstructorBuilder.addCode("$N($L.class);\n", addIndex, className); + builder = autoConstructorBuilder; } else if ((forTarget & SearchIndexable.ARC) != 0) { - arcConstructorBuilder.addCode("$N($L.class);\n", addIndex, className); + builder = arcConstructorBuilder; } + builder.addCode( + "$N(new SearchIndexableData($L.class, $L" + + ".SEARCH_INDEX_DATA_PROVIDER));\n", + addIndex, className, className); } else { throw new IllegalStateException("Null classname from " + element); } @@ -137,7 +144,7 @@ public class IndexableProcessor extends AbstractProcessor { .addModifiers(Modifier.PUBLIC) .returns(ParameterizedTypeName.get( ClassName.get(Collection.class), - TypeName.get(Class.class))) + searchIndexableData)) .addCode("return $N;\n", providers) .build(); diff --git a/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableData.java b/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableData.java new file mode 100644 index 000000000000..8b8f2688b93f --- /dev/null +++ b/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableData.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 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.settingslib.search; + +/** + * A Bundle class used in {@link SearchIndexableResources} to provide search Index data. + */ +public class SearchIndexableData { + private final Class mTargetClass; + private final Indexable.SearchIndexProvider mSearchIndexProvider; + + /** + * Constructs a SearchIndexableData + * + * @param targetClass The target opening class of the {@link Indexable.SearchIndexProvider}. It + * should be a {@link android.app.Activity} or fragment {@link + * androidx.fragment.app.Fragment}. + * But fragment is only supported in Android Settings. Other apps should use + * {@link android.app.Activity} + * @param provider provides searchable data for Android Settings + */ + public SearchIndexableData(Class targetClass, Indexable.SearchIndexProvider provider) { + mTargetClass = targetClass; + mSearchIndexProvider = provider; + } + + public Class getTargetClass() { + return mTargetClass; + } + + public Indexable.SearchIndexProvider getSearchIndexProvider() { + return mSearchIndexProvider; + } +} diff --git a/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableResources.java b/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableResources.java index 976647b3e88f..e00ca718ce1c 100644 --- a/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableResources.java +++ b/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableResources.java @@ -21,15 +21,12 @@ import java.util.Collection; public interface SearchIndexableResources { /** - * Returns a collection of classes that should be indexed for search. - * - * Each class should have the SEARCH_INDEX_DATA_PROVIDER public static member. + * Returns a Collection of {@link SearchIndexableData} that should be indexed for search. */ - Collection<Class> getProviderValues(); + Collection<SearchIndexableData> getProviderValues(); /** - * For testing. Can't use @VisibleForTesting here because this builds as a host binary as well - * as a device binary. + * Add {@link SearchIndexableData} for search in Android Settings. */ - void addIndex(Class indexClass); + void addIndex(SearchIndexableData indexBundle); }
\ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 14371fe4b41b..64b2892efc9a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1120,8 +1120,6 @@ <dimen name="bubble_touch_padding">12dp</dimen> <!-- Size of the circle around the bubbles when they're in the dismiss target. --> <dimen name="bubble_dismiss_encircle_size">52dp</dimen> - <!-- How much to inset the icon in the circle --> - <dimen name="bubble_icon_inset">16dp</dimen> <!-- Padding around the view displayed when the bubble is expanded --> <dimen name="bubble_expanded_view_padding">4dp</dimen> <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java index 074ef53aa57c..acce41cc942e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java @@ -56,7 +56,9 @@ public class TaskStackChangeListeners extends TaskStackListener { } public void addListener(IActivityManager am, TaskStackChangeListener listener) { - mTaskStackListeners.add(listener); + synchronized (mTaskStackListeners) { + mTaskStackListeners.add(listener); + } if (!mRegistered) { // Register mTaskStackListener to IActivityManager only once if needed. try { @@ -69,8 +71,12 @@ public class TaskStackChangeListeners extends TaskStackListener { } public void removeListener(TaskStackChangeListener listener) { - mTaskStackListeners.remove(listener); - if (mTaskStackListeners.isEmpty() && mRegistered) { + boolean isEmpty; + synchronized (mTaskStackListeners) { + mTaskStackListeners.remove(listener); + isEmpty = mTaskStackListeners.isEmpty(); + } + if (isEmpty && mRegistered) { // Unregister mTaskStackListener once we have no more listeners try { ActivityTaskManager.getService().unregisterTaskStackListener(this); @@ -83,14 +89,17 @@ public class TaskStackChangeListeners extends TaskStackListener { @Override public void onTaskStackChanged() throws RemoteException { - // Call the task changed callback for the non-ui thread listeners first + // Call the task changed callback for the non-ui thread listeners first. Copy to a set of + // temp listeners so that we don't lock on mTaskStackListeners while calling all the + // callbacks. This call is always on the same binder thread, so we can just synchronize + // on the copying of the listener list. synchronized (mTaskStackListeners) { - mTmpListeners.clear(); mTmpListeners.addAll(mTaskStackListeners); } for (int i = mTmpListeners.size() - 1; i >= 0; i--) { mTmpListeners.get(i).onTaskStackChangedBackground(); } + mTmpListeners.clear(); mHandler.removeMessages(H.ON_TASK_STACK_CHANGED); mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED); diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index 46b4c6b7d44c..21b52c1e5b57 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -169,12 +169,15 @@ public class CarrierTextController { mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mSeparator = separator; mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); - mSimSlotsNumber = ((TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE)).getSupportedModemCount(); + mSimSlotsNumber = getTelephonyManager().getSupportedModemCount(); mSimErrorState = new boolean[mSimSlotsNumber]; mMainHandler = Dependency.get(Dependency.MAIN_HANDLER); } + private TelephonyManager getTelephonyManager() { + return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + } + /** * Checks if there are faulty cards. Adds the text depending on the slot of the card * @@ -190,7 +193,7 @@ public class CarrierTextController { CharSequence carrierTextForSimIOError = getCarrierTextForSimState( IccCardConstants.State.CARD_IO_ERROR, carrier); // mSimErrorState has the state of each sim indexed by slotID. - for (int index = 0; index < mSimErrorState.length; index++) { + for (int index = 0; index < getTelephonyManager().getActiveModemCount(); index++) { if (!mSimErrorState[index]) { continue; } @@ -223,8 +226,7 @@ public class CarrierTextController { * @param callback Callback to provide text updates */ public void setListening(CarrierTextCallback callback) { - TelephonyManager telephonyManager = ((TelephonyManager) mContext - .getSystemService(Context.TELEPHONY_SERVICE)); + TelephonyManager telephonyManager = getTelephonyManager(); if (callback != null) { mCarrierTextCallback = callback; // TODO(b/140034799) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java index 9c0a71c1f81d..b1502b9a0d63 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java @@ -104,7 +104,12 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { private void setLockedSimMessage() { boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId); - int count = TelephonyManager.getDefault().getSimCount(); + int count = 1; + TelephonyManager telephonyManager = + (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + if (telephonyManager != null) { + count = telephonyManager.getActiveModemCount(); + } Resources rez = getResources(); String msg; TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor }); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java index fc888e11d3f5..70237a053e1e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java @@ -164,7 +164,12 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { } boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId); - int count = TelephonyManager.getDefault().getSimCount(); + int count = 1; + TelephonyManager telephonyManager = + (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + if (telephonyManager != null) { + count = telephonyManager.getActiveModemCount(); + } Resources rez = getResources(); String msg; TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor }); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 6685db130d4a..0b0922a7766f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2649,8 +2649,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // that don't return the complete set of values and have different types. In Keyguard we // need IccCardConstants, but TelephonyManager would only give us // TelephonyManager.SIM_STATE*, so we retrieve it manually. - final TelephonyManager tele = TelephonyManager.from(mContext); - int simState = tele.getSimState(slotId); + final TelephonyManager tele = + (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + int simState = (tele != null) ? + tele.getSimState(slotId) : TelephonyManager.SIM_STATE_UNKNOWN; State state; try { state = State.intToState(simState); diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java index a94952c5bc19..8e472f9c98a3 100644 --- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java +++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java @@ -47,6 +47,7 @@ public class CornerHandleView extends View { private int mLightColor; private int mDarkColor; private Path mPath; + private boolean mRequiresInvalidate; public CornerHandleView(Context context, AttributeSet attrs) { super(context, attrs); @@ -67,6 +68,15 @@ public class CornerHandleView extends View { updatePath(); } + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + if (alpha > 0f && mRequiresInvalidate) { + mRequiresInvalidate = false; + invalidate(); + } + } + private void updatePath() { mPath = new Path(); @@ -104,11 +114,16 @@ public class CornerHandleView extends View { * appropriately. Intention is to match the home handle color. */ public void updateDarkness(float darkIntensity) { - mPaint.setColor((int) ArgbEvaluator.getInstance().evaluate(darkIntensity, - mLightColor, - mDarkColor)); - if (getVisibility() == VISIBLE) { - invalidate(); + int color = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, + mLightColor, mDarkColor); + if (mPaint.getColor() != color) { + mPaint.setColor(color); + if (getVisibility() == VISIBLE && getAlpha() > 0) { + invalidate(); + } else { + // If we are currently invisible, then invalidate when we are next made visible + mRequiresInvalidate = true; + } } } diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java index 9a277e8fa77c..46ae84a95fad 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java @@ -249,7 +249,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController { public void onModeDeactivated() { mAssistHandleCallbacks = null; if (mContext != null) { - mContext.unregisterReceiver(mDefaultHomeBroadcastReceiver); + mBroadcastDispatcher.get().unregisterReceiver(mDefaultHomeBroadcastReceiver); Settings.Secure.putLong(mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, 0); Settings.Secure.putInt(mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, 0); Settings.Secure.putLong(mContext.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, 0); diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java b/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java index baa3a4a938c1..c641943278d4 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java @@ -67,8 +67,10 @@ public final class EdgeLight { } /** Sets the edge light color. */ - public void setColor(@ColorInt int color) { + public boolean setColor(@ColorInt int color) { + boolean changed = mColor != color; mColor = color; + return changed; } /** Returns the edge light length, in units of the total device perimeter. */ diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java index 570b911cd400..e5121a8ea35c 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java @@ -259,10 +259,13 @@ public class InvocationLightsView extends View if (mUseNavBarColor) { @ColorInt int invocationColor = (int) ArgbEvaluator.getInstance().evaluate( darkIntensity, mLightColor, mDarkColor); + boolean changed = true; for (EdgeLight light : mAssistInvocationLights) { - light.setColor(invocationColor); + changed &= light.setColor(invocationColor); + } + if (changed) { + invalidate(); } - invalidate(); } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java index f5f1fad71b14..84a592d68627 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java @@ -298,7 +298,10 @@ public abstract class AuthBiometricView extends LinearLayout { .getDimension(R.dimen.biometric_dialog_icon_padding); mIconView.setY(getHeight() - mIconView.getHeight() - iconPadding); - final int newHeight = mIconView.getHeight() + 2 * (int) iconPadding; + // Subtract the vertical padding from the new height since it's only used to create + // extra space between the other elements, and not part of the actual icon. + final int newHeight = mIconView.getHeight() + 2 * (int) iconPadding + - mIconView.getPaddingTop() - mIconView.getPaddingBottom(); mPanelController.updateForContentDimensions(mMediumWidth, newHeight, 0 /* animateDurationMs */); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 516de709c34f..6b0d3c807079 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -23,7 +23,10 @@ import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.IActivityTaskManager; import android.app.TaskStackListener; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.hardware.biometrics.Authenticator; @@ -85,6 +88,28 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } } + @VisibleForTesting + final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mCurrentDialog != null + && Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { + Log.w(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received"); + mCurrentDialog.dismissWithoutCallback(true /* animate */); + mCurrentDialog = null; + + try { + if (mReceiver != null) { + mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); + mReceiver = null; + } + } catch (RemoteException e) { + Log.e(TAG, "Remote exception", e); + } + } + } + }; + private final Runnable mTaskStackChangedRunnable = () -> { if (mCurrentDialog != null) { try { @@ -204,6 +229,11 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, super(context); mCommandQueue = commandQueue; mInjector = injector; + + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + + context.registerReceiver(mBroadcastReceiver, filter); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index 7600b2f3ed7a..f8e45d4c8b63 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java @@ -134,6 +134,10 @@ class Bubble { return mAppName; } + public Drawable getUserBadgedAppIcon() { + return mUserBadgedAppIcon; + } + boolean isInflated() { return mInflated; } @@ -165,7 +169,6 @@ class Bubble { mIconView = (BubbleView) inflater.inflate( R.layout.bubble_view, stackView, false /* attachToRoot */); mIconView.setBubble(this); - mIconView.setAppIcon(mUserBadgedAppIcon); mExpandedView = (BubbleExpandedView) inflater.inflate( R.layout.bubble_expanded_view, stackView, false /* attachToRoot */); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index e5af3897dff2..4a1bbe48efb0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -1459,7 +1459,7 @@ public class BubbleStackView extends FrameLayout { mFlyout.setupFlyoutStartingAsDot( updateMessage, mStackAnimationController.getStackPosition(), getWidth(), mStackAnimationController.isStackOnLeftSide(), - bubble.getIconView().getBadgeColor() /* dotColor */, + bubble.getIconView().getDotColor() /* dotColor */, expandFlyoutAfterDelay /* onLayoutComplete */, mFlyoutOnHide, bubble.getIconView().getDotCenter()); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java index fe4fa90a272d..35657d38df0c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java @@ -24,17 +24,16 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Path; -import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; -import android.graphics.drawable.InsetDrawable; import android.util.AttributeSet; import android.util.PathParser; import android.widget.FrameLayout; import com.android.internal.graphics.ColorUtils; +import com.android.launcher3.icons.BitmapInfo; +import com.android.launcher3.icons.ColorExtractor; import com.android.launcher3.icons.ShadowGenerator; import com.android.systemui.Interpolators; import com.android.systemui.R; @@ -45,17 +44,13 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; */ public class BubbleView extends FrameLayout { - private static final int DARK_ICON_ALPHA = 180; - private static final double ICON_MIN_CONTRAST = 4.1; - private static final int DEFAULT_BACKGROUND_COLOR = Color.LTGRAY; // Same value as Launcher3 badge code private static final float WHITE_SCRIM_ALPHA = 0.54f; private Context mContext; private BadgedImageView mBadgedImageView; - private int mBadgeColor; - private int mIconInset; - private Drawable mUserBadgedAppIcon; + private int mDotColor; + private ColorExtractor mColorExtractor; // mBubbleIconFactory cannot be static because it depends on Context. private BubbleIconFactory mBubbleIconFactory; @@ -79,13 +74,13 @@ public class BubbleView extends FrameLayout { public BubbleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mContext = context; - mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset); } @Override protected void onFinishInflate() { super.onFinishInflate(); mBadgedImageView = findViewById(R.id.bubble_image); + mColorExtractor = new ColorExtractor(); } @Override @@ -106,6 +101,13 @@ public class BubbleView extends FrameLayout { } /** + * @param factory Factory for creating normalized bubble icons. + */ + public void setBubbleIconFactory(BubbleIconFactory factory) { + mBubbleIconFactory = factory; + } + + /** * The {@link NotificationEntry} associated with this view, if one exists. */ @Nullable @@ -129,17 +131,6 @@ public class BubbleView extends FrameLayout { updateViews(); } - /** - * @param factory Factory for creating normalized bubble icons. - */ - public void setBubbleIconFactory(BubbleIconFactory factory) { - mBubbleIconFactory = factory; - } - - public void setAppIcon(Drawable appIcon) { - mUserBadgedAppIcon = appIcon; - } - /** Changes the dot's visibility to match the bubble view's state. */ void updateDotVisibility(boolean animate) { updateDotVisibility(animate, null /* after */); @@ -154,9 +145,17 @@ public class BubbleView extends FrameLayout { updateDotVisibility(animate); } + boolean isDotShowing() { + return mBubble.showBubbleDot() && !mSuppressDot; + } + + int getDotColor() { + return mDotColor; + } + /** Sets the position of the 'new' dot, animating it out and back in if requested. */ void setDotPosition(boolean onLeft, boolean animate) { - if (animate && onLeft != mBadgedImageView.getDotOnLeft() && shouldShowDot()) { + if (animate && onLeft != mBadgedImageView.getDotOnLeft() && isDotShowing()) { animateDot(false /* showDot */, () -> { mBadgedImageView.setDotOnLeft(onLeft); animateDot(true /* showDot */, null); @@ -180,7 +179,7 @@ public class BubbleView extends FrameLayout { * after animation if requested. */ private void updateDotVisibility(boolean animate, Runnable after) { - final boolean showDot = shouldShowDot(); + final boolean showDot = isDotShowing(); if (animate) { animateDot(showDot, after); } else { @@ -218,42 +217,21 @@ public class BubbleView extends FrameLayout { if (mBubble == null || mBubbleIconFactory == null) { return; } - // Update icon. - Notification.BubbleMetadata metadata = mBubble.getEntry().getBubbleMetadata(); - Notification n = mBubble.getEntry().getSbn().getNotification(); - Icon ic = metadata.getIcon(); - boolean needsTint = ic.getType() != Icon.TYPE_ADAPTIVE_BITMAP; - - Drawable iconDrawable = ic.loadDrawable(mContext); - if (needsTint) { - iconDrawable = buildIconWithTint(iconDrawable, n.color); - } - Bitmap bubbleIcon = mBubbleIconFactory.createBadgedIconBitmap(iconDrawable, - null /* user */, - true /* shrinkNonAdaptiveIcons */).icon; - - // Give it a shadow - Bitmap userBadgedBitmap = mBubbleIconFactory.createIconBitmap(mUserBadgedAppIcon, - 1f, mBubbleIconFactory.getBadgeSize()); - Canvas c = new Canvas(); - ShadowGenerator shadowGenerator = new ShadowGenerator(mBubbleIconFactory.getBadgeSize()); - c.setBitmap(userBadgedBitmap); - shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); - mBubbleIconFactory.badgeWithDrawable(bubbleIcon, - new BitmapDrawable(mContext.getResources(), userBadgedBitmap)); - mBadgedImageView.setImageBitmap(bubbleIcon); + Drawable bubbleDrawable = getBubbleDrawable(mContext); + BitmapInfo badgeBitmapInfo = getBadgedBitmap(); + BitmapInfo bubbleBitmapInfo = getBubbleBitmap(bubbleDrawable, badgeBitmapInfo); + mBadgedImageView.setImageBitmap(bubbleBitmapInfo.icon); // Update badge. - int badgeColor = determineDominateColor(iconDrawable, n.color); - mBadgeColor = badgeColor; - mBadgedImageView.setDotColor(badgeColor); + mDotColor = ColorUtils.blendARGB(badgeBitmapInfo.color, Color.WHITE, WHITE_SCRIM_ALPHA); + mBadgedImageView.setDotColor(mDotColor); // Update dot. Path iconPath = PathParser.createPathFromPathData( getResources().getString(com.android.internal.R.string.config_icon_mask)); Matrix matrix = new Matrix(); - float scale = mBubbleIconFactory.getNormalizer().getScale(iconDrawable, + float scale = mBubbleIconFactory.getNormalizer().getScale(bubbleDrawable, null /* outBounds */, null /* path */, null /* outMaskShape */); float radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f; matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */, @@ -261,41 +239,34 @@ public class BubbleView extends FrameLayout { iconPath.transform(matrix); mBadgedImageView.drawDot(iconPath); - animateDot(shouldShowDot(), null /* after */); + animateDot(isDotShowing(), null /* after */); } - boolean shouldShowDot() { - return mBubble.showBubbleDot() && !mSuppressDot; + Drawable getBubbleDrawable(Context context) { + Notification.BubbleMetadata metadata = getEntry().getBubbleMetadata(); + Icon ic = metadata.getIcon(); + return ic.loadDrawable(context); } - int getBadgeColor() { - return mBadgeColor; - } + BitmapInfo getBadgedBitmap() { + Bitmap userBadgedBitmap = mBubbleIconFactory.createIconBitmap( + mBubble.getUserBadgedAppIcon(), 1f, mBubbleIconFactory.getBadgeSize()); - private AdaptiveIconDrawable buildIconWithTint(Drawable iconDrawable, int backgroundColor) { - iconDrawable = checkTint(iconDrawable, backgroundColor); - InsetDrawable foreground = new InsetDrawable(iconDrawable, mIconInset); - ColorDrawable background = new ColorDrawable(backgroundColor); - return new AdaptiveIconDrawable(background, foreground); + Canvas c = new Canvas(); + ShadowGenerator shadowGenerator = new ShadowGenerator(mBubbleIconFactory.getBadgeSize()); + c.setBitmap(userBadgedBitmap); + shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); + BitmapInfo bitmapInfo = mBubbleIconFactory.createIconBitmap(userBadgedBitmap); + return bitmapInfo; } - private Drawable checkTint(Drawable iconDrawable, int backgroundColor) { - backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, 255 /* alpha */); - if (backgroundColor == Color.TRANSPARENT) { - // ColorUtils throws exception when background is translucent. - backgroundColor = DEFAULT_BACKGROUND_COLOR; - } - iconDrawable.setTint(Color.WHITE); - double contrastRatio = ColorUtils.calculateContrast(Color.WHITE, backgroundColor); - if (contrastRatio < ICON_MIN_CONTRAST) { - int dark = ColorUtils.setAlphaComponent(Color.BLACK, DARK_ICON_ALPHA); - iconDrawable.setTint(dark); - } - return iconDrawable; - } + BitmapInfo getBubbleBitmap(Drawable bubble, BitmapInfo badge) { + BitmapInfo bubbleIconInfo = mBubbleIconFactory.createBadgedIconBitmap(bubble, + null /* user */, + true /* shrinkNonAdaptiveIcons */); - private int determineDominateColor(Drawable d, int defaultTint) { - // XXX: should we pull from the drawable, app icon, notif tint? - return ColorUtils.blendARGB(defaultTint, Color.WHITE, WHITE_SCRIM_ALPHA); + mBubbleIconFactory.badgeWithDrawable(bubbleIconInfo.icon, + new BitmapDrawable(mContext.getResources(), badge.icon)); + return bubbleIconInfo; } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index 3b0c9aebfe08..9f5493720bef 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -16,109 +16,35 @@ package com.android.systemui.dagger; -import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; - -import android.content.Context; -import android.os.PowerManager; -import android.util.DisplayMetrics; - -import androidx.annotation.Nullable; - -import com.android.internal.logging.MetricsLogger; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.ForegroundServiceController; import com.android.systemui.LatencyTester; import com.android.systemui.ScreenDecorations; import com.android.systemui.SizeCompatModeActivityController; import com.android.systemui.SliceBroadcastRelayHandler; import com.android.systemui.SystemUI; -import com.android.systemui.UiOffloadThread; -import com.android.systemui.appops.AppOpsController; -import com.android.systemui.assist.AssistManager; import com.android.systemui.biometrics.AuthController; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.doze.DozeLog; import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.pip.PipUI; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.power.PowerUI; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsModule; -import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.FeatureFlags; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationViewHierarchyManager; -import com.android.systemui.statusbar.PulseExpansionHandler; -import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.InstantAppNotifier; -import com.android.systemui.statusbar.notification.NewNotifPipeline; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; -import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; -import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.logging.NotifLog; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.phone.AutoHideController; -import com.android.systemui.statusbar.phone.BiometricUnlockController; -import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.statusbar.phone.DozeScrimController; -import com.android.systemui.statusbar.phone.DozeServiceHost; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; -import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.KeyguardLiftController; -import com.android.systemui.statusbar.phone.LightBarController; -import com.android.systemui.statusbar.phone.LockscreenWallpaper; -import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; -import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.StatusBarIconController; -import com.android.systemui.statusbar.phone.StatusBarWindowController; -import com.android.systemui.statusbar.phone.StatusBarWindowViewController; -import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.RemoteInputUriController; -import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.statusbar.phone.StatusBarModule; import com.android.systemui.statusbar.tv.TvStatusBar; import com.android.systemui.theme.ThemeOverlayController; -import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.leak.GarbageMonitor; import com.android.systemui.volume.VolumeUI; -import javax.inject.Named; -import javax.inject.Singleton; - import dagger.Binds; -import dagger.Lazy; import dagger.Module; -import dagger.Provides; import dagger.multibindings.ClassKey; import dagger.multibindings.IntoMap; /** * SystemUI objects that are injectable should go here. */ -@Module(includes = {RecentsModule.class}) +@Module(includes = {RecentsModule.class, StatusBarModule.class}) public abstract class SystemUIBinder { /** Inject into AuthController. */ @Binds @@ -216,148 +142,4 @@ public abstract class SystemUIBinder { @IntoMap @ClassKey(VolumeUI.class) public abstract SystemUI bindVolumeUI(VolumeUI sysui); - - /** - * Provides our instance of StatusBar which is considered optional. - */ - @Provides - @Singleton - static StatusBar provideStatusBar( - Context context, - FeatureFlags featureFlags, - LightBarController lightBarController, - AutoHideController autoHideController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - StatusBarIconController statusBarIconController, - DozeLog dozeLog, - InjectionInflationController injectionInflationController, - PulseExpansionHandler pulseExpansionHandler, - NotificationWakeUpCoordinator notificationWakeUpCoordinator, - KeyguardBypassController keyguardBypassController, - KeyguardStateController keyguardStateController, - HeadsUpManagerPhone headsUpManagerPhone, - DynamicPrivacyController dynamicPrivacyController, - BypassHeadsUpNotifier bypassHeadsUpNotifier, - @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress, - Lazy<NewNotifPipeline> newNotifPipeline, - FalsingManager falsingManager, - BroadcastDispatcher broadcastDispatcher, - RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, - NotificationGutsManager notificationGutsManager, - NotificationLogger notificationLogger, - NotificationEntryManager notificationEntryManager, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, - NotificationViewHierarchyManager notificationViewHierarchyManager, - ForegroundServiceController foregroundServiceController, - AppOpsController appOpsController, - KeyguardViewMediator keyguardViewMediator, - ZenModeController zenModeController, - NotificationAlertingManager notificationAlertingManager, - DisplayMetrics displayMetrics, - MetricsLogger metricsLogger, - UiOffloadThread uiOffloadThread, - NotificationMediaManager notificationMediaManager, - NotificationLockscreenUserManager lockScreenUserManager, - NotificationRemoteInputManager remoteInputManager, - UserSwitcherController userSwitcherController, - NetworkController networkController, - BatteryController batteryController, - SysuiColorExtractor colorExtractor, - ScreenLifecycle screenLifecycle, - WakefulnessLifecycle wakefulnessLifecycle, - SysuiStatusBarStateController statusBarStateController, - VibratorHelper vibratorHelper, - BubbleController bubbleController, - NotificationGroupManager groupManager, - NotificationGroupAlertTransferHelper groupAlertTransferHelper, - VisualStabilityManager visualStabilityManager, - DeviceProvisionedController deviceProvisionedController, - NavigationBarController navigationBarController, - AssistManager assistManager, - NotificationListener notificationListener, - ConfigurationController configurationController, - StatusBarWindowController statusBarWindowController, - StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder, - NotifLog notifLog, - DozeParameters dozeParameters, - ScrimController scrimController, - @Nullable KeyguardLiftController keyguardLiftController, - Lazy<LockscreenWallpaper> lockscreenWallpaperLazy, - Lazy<BiometricUnlockController> biometricUnlockControllerLazy, - DozeServiceHost dozeServiceHost, - PowerManager powerManager, - DozeScrimController dozeScrimController, - CommandQueue commandQueue, - PluginManager pluginManager, - RemoteInputUriController remoteInputUriController) { - return new StatusBar( - context, - featureFlags, - lightBarController, - autoHideController, - keyguardUpdateMonitor, - statusBarIconController, - dozeLog, - injectionInflationController, - pulseExpansionHandler, - notificationWakeUpCoordinator, - keyguardBypassController, - keyguardStateController, - headsUpManagerPhone, - dynamicPrivacyController, - bypassHeadsUpNotifier, - allowNotificationLongPress, - newNotifPipeline, - falsingManager, - broadcastDispatcher, - remoteInputQuickSettingsDisabler, - notificationGutsManager, - notificationLogger, - notificationEntryManager, - notificationInterruptionStateProvider, - notificationViewHierarchyManager, - foregroundServiceController, - appOpsController, - keyguardViewMediator, - zenModeController, - notificationAlertingManager, - displayMetrics, - metricsLogger, - uiOffloadThread, - notificationMediaManager, - lockScreenUserManager, - remoteInputManager, - userSwitcherController, - networkController, - batteryController, - colorExtractor, - screenLifecycle, - wakefulnessLifecycle, - statusBarStateController, - vibratorHelper, - bubbleController, - groupManager, - groupAlertTransferHelper, - visualStabilityManager, - deviceProvisionedController, - navigationBarController, - assistManager, - notificationListener, - configurationController, - statusBarWindowController, - statusBarWindowViewControllerBuilder, - notifLog, - dozeParameters, - scrimController, - keyguardLiftController, - lockscreenWallpaperLazy, - biometricUnlockControllerLazy, - dozeServiceHost, - powerManager, - dozeScrimController, - commandQueue, - pluginManager, - remoteInputUriController); - } - } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 9e7f6c683bbe..b3a5181d1ca5 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -25,6 +25,7 @@ import com.android.systemui.DumpController; import com.android.systemui.assist.AssistModule; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.notification.people.PeopleHubModule; import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.StatusBar; @@ -71,5 +72,8 @@ public abstract class SystemUIModule { } @BindsOptionalOf + abstract CommandQueue optionalCommandQueue(); + + @BindsOptionalOf abstract StatusBar optionalStatusBar(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java index 86c532cdb773..ca04633b316a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java @@ -117,9 +117,14 @@ public class WorkLockActivity extends Activity { } } + @VisibleForTesting + protected void unregisterBroadcastReceiver() { + mBroadcastDispatcher.unregisterReceiver(mLockEventReceiver); + } + @Override public void onDestroy() { - unregisterReceiver(mLockEventReceiver); + unregisterBroadcastReceiver(); super.onDestroy(); } @@ -170,7 +175,12 @@ public class WorkLockActivity extends Activity { credential.putExtra(EXTRA_FROM_WORK_LOCK_ACTIVITY, true); } - startActivityForResult(credential, REQUEST_CODE_CONFIRM_CREDENTIALS); + final ActivityOptions launchOptions = ActivityOptions.makeBasic(); + launchOptions.setLaunchTaskId(getTaskId()); + launchOptions.setTaskOverlay(true /* taskOverlay */, true /* canResume */); + + startActivityForResult(credential, REQUEST_CODE_CONFIRM_CREDENTIALS, + launchOptions.toBundle()); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 264d644f9057..68a2417f90b8 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -21,9 +21,6 @@ import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_CORNER_FLOW; -import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_INTENT; -import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_CANCEL_NOTIFICATION; -import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP; import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; import android.animation.Animator; @@ -101,6 +98,7 @@ import java.io.OutputStream; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -109,372 +107,381 @@ import java.util.function.Function; import javax.inject.Inject; import javax.inject.Singleton; +import dagger.Lazy; /** - * POD used in the AsyncTask which saves an image in the background. + * Class for handling device screen shots */ -class SaveImageInBackgroundData { - Context context; - Bitmap image; - Uri imageUri; - Runnable finisher; - Function<PendingIntent, Void> onEditReady; - int iconSize; - int previewWidth; - int previewheight; - int errorMsgResId; - - void clearImage() { - image = null; - imageUri = null; - iconSize = 0; - } - void clearContext() { - context = null; - } -} - -/** - * An AsyncTask that saves an image to the media store in the background. - */ -class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { - private static final String TAG = "SaveImageInBackgroundTask"; - - private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png"; - private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)"; - - private final SaveImageInBackgroundData mParams; - private final NotificationManager mNotificationManager; - private final Notification.Builder mNotificationBuilder, mPublicNotificationBuilder; - private final String mImageFileName; - private final long mImageTime; - private final BigPictureStyle mNotificationStyle; - private final int mImageWidth; - private final int mImageHeight; - - SaveImageInBackgroundTask(Context context, SaveImageInBackgroundData data, - NotificationManager nManager) { - Resources r = context.getResources(); - - // Prepare all the output metadata - mParams = data; - mImageTime = System.currentTimeMillis(); - String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime)); - mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate); - - // Create the large notification icon - mImageWidth = data.image.getWidth(); - mImageHeight = data.image.getHeight(); - int iconSize = data.iconSize; - int previewWidth = data.previewWidth; - int previewHeight = data.previewheight; - - Paint paint = new Paint(); - ColorMatrix desat = new ColorMatrix(); - desat.setSaturation(0.25f); - paint.setColorFilter(new ColorMatrixColorFilter(desat)); - Matrix matrix = new Matrix(); - int overlayColor = 0x40FFFFFF; - - matrix.setTranslate((previewWidth - mImageWidth) / 2, (previewHeight - mImageHeight) / 2); - Bitmap picture = generateAdjustedHwBitmap(data.image, previewWidth, previewHeight, matrix, - paint, overlayColor); - - // Note, we can't use the preview for the small icon, since it is non-square - float scale = (float) iconSize / Math.min(mImageWidth, mImageHeight); - matrix.setScale(scale, scale); - matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2, - (iconSize - (scale * mImageHeight)) / 2); - Bitmap icon = generateAdjustedHwBitmap(data.image, iconSize, iconSize, matrix, paint, - overlayColor); - - mNotificationManager = nManager; - final long now = System.currentTimeMillis(); - - // Setup the notification - mNotificationStyle = new Notification.BigPictureStyle() - .bigPicture(picture.createAshmemBitmap()); - - // The public notification will show similar info but with the actual screenshot omitted - mPublicNotificationBuilder = - new Notification.Builder(context, NotificationChannels.SCREENSHOTS_HEADSUP) - .setContentTitle(r.getString(R.string.screenshot_saving_title)) - .setSmallIcon(R.drawable.stat_notify_image) - .setCategory(Notification.CATEGORY_PROGRESS) - .setWhen(now) - .setShowWhen(true) - .setColor(r.getColor( - com.android.internal.R.color.system_notification_accent_color)); - SystemUI.overrideNotificationAppName(context, mPublicNotificationBuilder, true); - - mNotificationBuilder = new Notification.Builder(context, - NotificationChannels.SCREENSHOTS_HEADSUP) - .setContentTitle(r.getString(R.string.screenshot_saving_title)) - .setSmallIcon(R.drawable.stat_notify_image) - .setWhen(now) - .setShowWhen(true) - .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color)) - .setStyle(mNotificationStyle) - .setPublicVersion(mPublicNotificationBuilder.build()); - mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true); - SystemUI.overrideNotificationAppName(context, mNotificationBuilder, true); - - mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT, - mNotificationBuilder.build()); - - /** - * NOTE: The following code prepares the notification builder for updating the notification - * after the screenshot has been written to disk. - */ +@Singleton +public class GlobalScreenshot { - // On the tablet, the large icon makes the notification appear as if it is clickable (and - // on small devices, the large icon is not shown) so defer showing the large icon until - // we compose the final post-save notification below. - mNotificationBuilder.setLargeIcon(icon.createAshmemBitmap()); - // But we still don't set it for the expanded view, allowing the smallIcon to show here. - mNotificationStyle.bigLargeIcon((Bitmap) null); + /** + * POD used in the AsyncTask which saves an image in the background. + */ + private static class SaveImageInBackgroundData { + public Context context; + public Bitmap image; + public Uri imageUri; + public Runnable finisher; + public Function<PendingIntent, Void> onEditReady; + public int iconSize; + public int previewWidth; + public int previewheight; + public int errorMsgResId; + + void clearImage() { + image = null; + imageUri = null; + iconSize = 0; + } + void clearContext() { + context = null; + } } /** - * Generates a new hardware bitmap with specified values, copying the content from the passed - * in bitmap. + * An AsyncTask that saves an image to the media store in the background. */ - private Bitmap generateAdjustedHwBitmap(Bitmap bitmap, int width, int height, Matrix matrix, - Paint paint, int color) { - Picture picture = new Picture(); - Canvas canvas = picture.beginRecording(width, height); - canvas.drawColor(color); - canvas.drawBitmap(bitmap, matrix, paint); - picture.endRecording(); - return Bitmap.createBitmap(picture); - } + private static class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { + private static final String TAG = "SaveImageInBackgroundTask"; + + private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png"; + private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)"; + + private final SaveImageInBackgroundData mParams; + private final NotificationManager mNotificationManager; + private final Notification.Builder mNotificationBuilder, mPublicNotificationBuilder; + private final String mImageFileName; + private final long mImageTime; + private final BigPictureStyle mNotificationStyle; + private final int mImageWidth; + private final int mImageHeight; + + SaveImageInBackgroundTask(Context context, SaveImageInBackgroundData data, + NotificationManager nManager) { + Resources r = context.getResources(); + + // Prepare all the output metadata + mParams = data; + mImageTime = System.currentTimeMillis(); + String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime)); + mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate); + + // Create the large notification icon + mImageWidth = data.image.getWidth(); + mImageHeight = data.image.getHeight(); + int iconSize = data.iconSize; + int previewWidth = data.previewWidth; + int previewHeight = data.previewheight; + + Paint paint = new Paint(); + ColorMatrix desat = new ColorMatrix(); + desat.setSaturation(0.25f); + paint.setColorFilter(new ColorMatrixColorFilter(desat)); + Matrix matrix = new Matrix(); + int overlayColor = 0x40FFFFFF; + + matrix.setTranslate((previewWidth - mImageWidth) / 2, + (previewHeight - mImageHeight) / 2); + Bitmap picture = generateAdjustedHwBitmap(data.image, previewWidth, previewHeight, + matrix, paint, overlayColor); + + // Note, we can't use the preview for the small icon, since it is non-square + float scale = (float) iconSize / Math.min(mImageWidth, mImageHeight); + matrix.setScale(scale, scale); + matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2, + (iconSize - (scale * mImageHeight)) / 2); + Bitmap icon = generateAdjustedHwBitmap(data.image, iconSize, iconSize, matrix, paint, + overlayColor); + + mNotificationManager = nManager; + final long now = System.currentTimeMillis(); + + // Setup the notification + mNotificationStyle = new Notification.BigPictureStyle() + .bigPicture(picture.createAshmemBitmap()); + + // The public notification will show similar info but with the actual screenshot omitted + mPublicNotificationBuilder = + new Notification.Builder(context, NotificationChannels.SCREENSHOTS_HEADSUP) + .setContentTitle(r.getString(R.string.screenshot_saving_title)) + .setSmallIcon(R.drawable.stat_notify_image) + .setCategory(Notification.CATEGORY_PROGRESS) + .setWhen(now) + .setShowWhen(true) + .setColor(r.getColor( + com.android.internal.R.color.system_notification_accent_color)); + SystemUI.overrideNotificationAppName(context, mPublicNotificationBuilder, true); + + mNotificationBuilder = new Notification.Builder(context, + NotificationChannels.SCREENSHOTS_HEADSUP) + .setContentTitle(r.getString(R.string.screenshot_saving_title)) + .setSmallIcon(R.drawable.stat_notify_image) + .setWhen(now) + .setShowWhen(true) + .setColor(r.getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setStyle(mNotificationStyle) + .setPublicVersion(mPublicNotificationBuilder.build()); + mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true); + SystemUI.overrideNotificationAppName(context, mNotificationBuilder, true); + + mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT, + mNotificationBuilder.build()); + + /** + * NOTE: The following code prepares the notification builder for updating the + * notification after the screenshot has been written to disk. + */ + + // On the tablet, the large icon makes the notification appear as if it is clickable + // (and on small devices, the large icon is not shown) so defer showing the large icon + // until we compose the final post-save notification below. + mNotificationBuilder.setLargeIcon(icon.createAshmemBitmap()); + // But we still don't set it for the expanded view, allowing the smallIcon to show here. + mNotificationStyle.bigLargeIcon((Bitmap) null); + } - @Override - protected Void doInBackground(Void... paramsUnused) { - if (isCancelled()) { - return null; + /** + * Generates a new hardware bitmap with specified values, copying the content from the + * passed in bitmap. + */ + private Bitmap generateAdjustedHwBitmap(Bitmap bitmap, int width, int height, Matrix matrix, + Paint paint, int color) { + Picture picture = new Picture(); + Canvas canvas = picture.beginRecording(width, height); + canvas.drawColor(color); + canvas.drawBitmap(bitmap, matrix, paint); + picture.endRecording(); + return Bitmap.createBitmap(picture); } - // By default, AsyncTask sets the worker thread to have background thread priority, so bump - // it back up so that we save a little quicker. - Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); + @Override + protected Void doInBackground(Void... paramsUnused) { + if (isCancelled()) { + return null; + } - Context context = mParams.context; - Bitmap image = mParams.image; - Resources r = context.getResources(); + // By default, AsyncTask sets the worker thread to have background thread priority, + // so bump it back up so that we save a little quicker. + Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); + + Context context = mParams.context; + Bitmap image = mParams.image; + Resources r = context.getResources(); - try { - // Save the screenshot to the MediaStore - final MediaStore.PendingParams params = new MediaStore.PendingParams( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mImageFileName, "image/png"); - params.setRelativePath(Environment.DIRECTORY_PICTURES + File.separator - + Environment.DIRECTORY_SCREENSHOTS); - - final Uri uri = MediaStore.createPending(context, params); - final MediaStore.PendingSession session = MediaStore.openPending(context, uri); try { - try (OutputStream out = session.openOutputStream()) { - if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) { - throw new IOException("Failed to compress"); + // Save the screenshot to the MediaStore + final MediaStore.PendingParams params = new MediaStore.PendingParams( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mImageFileName, "image/png"); + params.setRelativePath(Environment.DIRECTORY_PICTURES + File.separator + + Environment.DIRECTORY_SCREENSHOTS); + + final Uri uri = MediaStore.createPending(context, params); + final MediaStore.PendingSession session = MediaStore.openPending(context, uri); + try { + try (OutputStream out = session.openOutputStream()) { + if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) { + throw new IOException("Failed to compress"); + } } + session.publish(); + } catch (Exception e) { + session.abandon(); + throw e; + } finally { + IoUtils.closeQuietly(session); } - session.publish(); + + // Note: Both the share and edit actions are proxied through ActionProxyReceiver in + // order to do some common work like dismissing the keyguard and sending + // closeSystemWindows + + // Create a share intent, this will always go through the chooser activity first + // which should not trigger auto-enter PiP + String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime)); + String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate); + Intent sharingIntent = new Intent(Intent.ACTION_SEND); + sharingIntent.setType("image/png"); + sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); + // Include URI in ClipData also, so that grantPermission picks it up. + // We don't use setData here because some apps interpret this as "to:". + ClipData clipdata = new ClipData(new ClipDescription("content", + new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}), + new ClipData.Item(uri)); + sharingIntent.setClipData(clipdata); + sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject); + sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + // Make sure pending intents for the system user are still unique across users + // by setting the (otherwise unused) request code to the current user id. + int requestCode = context.getUserId(); + + PendingIntent chooserAction = PendingIntent.getBroadcast(context, requestCode, + new Intent(context, GlobalScreenshot.TargetChosenReceiver.class), + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); + Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null, + chooserAction.getIntentSender()) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + // Create a share action for the notification + PendingIntent shareAction = PendingIntent.getBroadcastAsUser(context, requestCode, + new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) + .putExtra(EXTRA_ACTION_INTENT, sharingChooserIntent) + .putExtra(EXTRA_DISALLOW_ENTER_PIP, true) + .setAction(Intent.ACTION_SEND), + PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); + Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder( + R.drawable.ic_screenshot_share, + r.getString(com.android.internal.R.string.share), shareAction); + mNotificationBuilder.addAction(shareActionBuilder.build()); + + // Create an edit intent, if a specific package is provided as the editor, then + // launch that directly + String editorPackage = context.getString(R.string.config_screenshotEditor); + Intent editIntent = new Intent(Intent.ACTION_EDIT); + if (!TextUtils.isEmpty(editorPackage)) { + editIntent.setComponent(ComponentName.unflattenFromString(editorPackage)); + } + editIntent.setType("image/png"); + editIntent.setData(uri); + editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + + // Create a edit action + PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode, + new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) + .putExtra(EXTRA_ACTION_INTENT, editIntent) + .putExtra(EXTRA_CANCEL_NOTIFICATION, + editIntent.getComponent() != null) + .setAction(Intent.ACTION_EDIT), + PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); + Notification.Action.Builder editActionBuilder = new Notification.Action.Builder( + R.drawable.ic_screenshot_edit, + r.getString(com.android.internal.R.string.screenshot_edit), editAction); + mNotificationBuilder.addAction(editActionBuilder.build()); + if (editAction != null && mParams.onEditReady != null) { + mParams.onEditReady.apply(editAction); + } + + // Create a delete action for the notification + PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode, + new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class) + .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()), + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); + Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder( + R.drawable.ic_screenshot_delete, + r.getString(com.android.internal.R.string.delete), deleteAction); + mNotificationBuilder.addAction(deleteActionBuilder.build()); + + mParams.imageUri = uri; + mParams.image = null; + mParams.errorMsgResId = 0; } catch (Exception e) { - session.abandon(); - throw e; - } finally { - IoUtils.closeQuietly(session); + // IOException/UnsupportedOperationException may be thrown if external storage is + // not mounted + Slog.e(TAG, "unable to save screenshot", e); + mParams.clearImage(); + mParams.errorMsgResId = R.string.screenshot_failed_to_save_text; } - // Note: Both the share and edit actions are proxied through ActionProxyReceiver in - // order to do some common work like dismissing the keyguard and sending - // closeSystemWindows - - // Create a share intent, this will always go through the chooser activity first which - // should not trigger auto-enter PiP - String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime)); - String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate); - Intent sharingIntent = new Intent(Intent.ACTION_SEND); - sharingIntent.setType("image/png"); - sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); - // Include URI in ClipData also, so that grantPermission picks it up. - // We don't use setData here because some apps interpret this as "to:". - ClipData clipdata = new ClipData(new ClipDescription("content", - new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}), - new ClipData.Item(uri)); - sharingIntent.setClipData(clipdata); - sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject); - sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - // Make sure pending intents for the system user are still unique across users - // by setting the (otherwise unused) request code to the current user id. - int requestCode = context.getUserId(); - - PendingIntent chooserAction = PendingIntent.getBroadcast(context, requestCode, - new Intent(context, GlobalScreenshot.TargetChosenReceiver.class), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); - Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null, - chooserAction.getIntentSender()) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - // Create a share action for the notification - PendingIntent shareAction = PendingIntent.getBroadcastAsUser(context, requestCode, - new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) - .putExtra(EXTRA_ACTION_INTENT, sharingChooserIntent) - .putExtra(EXTRA_DISALLOW_ENTER_PIP, true) - .setAction(Intent.ACTION_SEND), - PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); - Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder( - R.drawable.ic_screenshot_share, - r.getString(com.android.internal.R.string.share), shareAction); - mNotificationBuilder.addAction(shareActionBuilder.build()); - - // Create an edit intent, if a specific package is provided as the editor, then launch - // that directly - String editorPackage = context.getString(R.string.config_screenshotEditor); - Intent editIntent = new Intent(Intent.ACTION_EDIT); - if (!TextUtils.isEmpty(editorPackage)) { - editIntent.setComponent(ComponentName.unflattenFromString(editorPackage)); - } - editIntent.setType("image/png"); - editIntent.setData(uri); - editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - - // Create a edit action - PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode, - new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) - .putExtra(EXTRA_ACTION_INTENT, editIntent) - .putExtra(EXTRA_CANCEL_NOTIFICATION, editIntent.getComponent() != null) - .setAction(Intent.ACTION_EDIT), - PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); - Notification.Action.Builder editActionBuilder = new Notification.Action.Builder( - R.drawable.ic_screenshot_edit, - r.getString(com.android.internal.R.string.screenshot_edit), editAction); - mNotificationBuilder.addAction(editActionBuilder.build()); - if (editAction != null && mParams.onEditReady != null) { - mParams.onEditReady.apply(editAction); + // Recycle the bitmap data + if (image != null) { + image.recycle(); } - // Create a delete action for the notification - PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode, - new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class) - .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); - Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder( - R.drawable.ic_screenshot_delete, - r.getString(com.android.internal.R.string.delete), deleteAction); - mNotificationBuilder.addAction(deleteActionBuilder.build()); - - mParams.imageUri = uri; - mParams.image = null; - mParams.errorMsgResId = 0; - } catch (Exception e) { - // IOException/UnsupportedOperationException may be thrown if external storage is not - // mounted - Slog.e(TAG, "unable to save screenshot", e); - mParams.clearImage(); - mParams.errorMsgResId = R.string.screenshot_failed_to_save_text; + return null; } - // Recycle the bitmap data - if (image != null) { - image.recycle(); + @Override + protected void onPostExecute(Void params) { + if (mParams.errorMsgResId != 0) { + // Show a message that we've failed to save the image to disk + GlobalScreenshot.notifyScreenshotError(mParams.context, mNotificationManager, + mParams.errorMsgResId); + } else { + if (mParams.onEditReady != null) { + // Cancel the "saving screenshot" notification + mNotificationManager.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT); + } else { + // Show the final notification to indicate screenshot saved + Context context = mParams.context; + Resources r = context.getResources(); + + // Create the intent to show the screenshot in gallery + Intent launchIntent = new Intent(Intent.ACTION_VIEW); + launchIntent.setDataAndType(mParams.imageUri, "image/png"); + launchIntent.setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); + + final long now = System.currentTimeMillis(); + + // Update the text and the icon for the existing notification + mPublicNotificationBuilder + .setContentTitle(r.getString(R.string.screenshot_saved_title)) + .setContentText(r.getString(R.string.screenshot_saved_text)) + .setContentIntent( + PendingIntent.getActivity(mParams.context, 0, launchIntent, 0)) + .setWhen(now) + .setAutoCancel(true) + .setColor(context.getColor( + com.android.internal.R.color.system_notification_accent_color)); + mNotificationBuilder + .setContentTitle(r.getString(R.string.screenshot_saved_title)) + .setContentText(r.getString(R.string.screenshot_saved_text)) + .setContentIntent(PendingIntent.getActivity(mParams.context, 0, + launchIntent, 0)) + .setWhen(now) + .setAutoCancel(true) + .setColor(context.getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setPublicVersion(mPublicNotificationBuilder.build()) + .setFlag(Notification.FLAG_NO_CLEAR, false); + + mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT, + mNotificationBuilder.build()); + } + } + mParams.finisher.run(); + mParams.clearContext(); } - return null; - } - - @Override - protected void onPostExecute(Void params) { - if (mParams.errorMsgResId != 0) { - // Show a message that we've failed to save the image to disk - GlobalScreenshot.notifyScreenshotError(mParams.context, mNotificationManager, - mParams.errorMsgResId); - } else { - if (mParams.onEditReady != null) { - // Cancel the "saving screenshot" notification - mNotificationManager.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT); - } else { - // Show the final notification to indicate screenshot saved - Context context = mParams.context; - Resources r = context.getResources(); - - // Create the intent to show the screenshot in gallery - Intent launchIntent = new Intent(Intent.ACTION_VIEW); - launchIntent.setDataAndType(mParams.imageUri, "image/png"); - launchIntent.setFlags( - Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); - - final long now = System.currentTimeMillis(); - - // Update the text and the icon for the existing notification - mPublicNotificationBuilder - .setContentTitle(r.getString(R.string.screenshot_saved_title)) - .setContentText(r.getString(R.string.screenshot_saved_text)) - .setContentIntent( - PendingIntent.getActivity(mParams.context, 0, launchIntent, 0)) - .setWhen(now) - .setAutoCancel(true) - .setColor(context.getColor( - com.android.internal.R.color.system_notification_accent_color)); - mNotificationBuilder - .setContentTitle(r.getString(R.string.screenshot_saved_title)) - .setContentText(r.getString(R.string.screenshot_saved_text)) - .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, 0)) - .setWhen(now) - .setAutoCancel(true) - .setColor(context.getColor( - com.android.internal.R.color.system_notification_accent_color)) - .setPublicVersion(mPublicNotificationBuilder.build()) - .setFlag(Notification.FLAG_NO_CLEAR, false); + @Override + protected void onCancelled(Void params) { + // If we are cancelled while the task is running in the background, we may get null + // params. The finisher is expected to always be called back, so just use the baked-in + // params from the ctor in any case. + mParams.finisher.run(); + mParams.clearImage(); + mParams.clearContext(); - mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT, - mNotificationBuilder.build()); - } + // Cancel the posted notification + mNotificationManager.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT); } - mParams.finisher.run(); - mParams.clearContext(); } - @Override - protected void onCancelled(Void params) { - // If we are cancelled while the task is running in the background, we may get null params. - // The finisher is expected to always be called back, so just use the baked-in params from - // the ctor in any case. - mParams.finisher.run(); - mParams.clearImage(); - mParams.clearContext(); - - // Cancel the posted notification - mNotificationManager.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT); - } -} - -/** - * An AsyncTask that deletes an image from the media store in the background. - */ -class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> { - private Context mContext; + /** + * An AsyncTask that deletes an image from the media store in the background. + */ + private static class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> { + private Context mContext; - DeleteImageInBackgroundTask(Context context) { - mContext = context; - } + DeleteImageInBackgroundTask(Context context) { + mContext = context; + } - @Override - protected Void doInBackground(Uri... params) { - if (params.length != 1) return null; + @Override + protected Void doInBackground(Uri... params) { + if (params.length != 1) return null; - Uri screenshotUri = params[0]; - ContentResolver resolver = mContext.getContentResolver(); - resolver.delete(screenshotUri, null, null); - return null; + Uri screenshotUri = params[0]; + ContentResolver resolver = mContext.getContentResolver(); + resolver.delete(screenshotUri, null, null); + return null; + } } -} -@Singleton -public class GlobalScreenshot { static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id"; static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent"; static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification"; @@ -1041,8 +1048,9 @@ public class GlobalScreenshot { private final StatusBar mStatusBar; @Inject - public ActionProxyReceiver(StatusBar statusBar) { - mStatusBar = statusBar; + public ActionProxyReceiver(Optional<Lazy<StatusBar>> statusBarLazy) { + Lazy<StatusBar> statusBar = statusBarLazy.orElse(null); + mStatusBar = statusBar != null ? statusBar.get() : null; } @Override @@ -1067,8 +1075,13 @@ public class GlobalScreenshot { context.startActivityAsUser(actionIntent, opts.toBundle(), UserHandle.CURRENT); }; - mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, - true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */); + if (mStatusBar != null) { + mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, + true /* dismissShade */, true /* afterKeyguardGone */, + true /* deferred */); + } else { + startActivityRunnable.run(); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index eb6ea13a6690..621f101cd8af 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -22,8 +22,6 @@ import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEF import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static android.view.InsetsState.TYPE_NAVIGATION_BAR; -import static android.view.InsetsState.TYPE_TOP_BAR; import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS; @@ -34,7 +32,6 @@ import android.app.StatusBarManager.WindowType; import android.app.StatusBarManager.WindowVisibleState; import android.content.ComponentName; import android.content.Context; -import android.graphics.Rect; import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.hardware.display.DisplayManager; import android.inputmethodservice.InputMethodService.BackDispositionMode; @@ -45,13 +42,9 @@ import android.os.Looper; import android.os.Message; import android.util.Pair; import android.util.SparseArray; -import android.view.InsetsFlags; import android.view.InsetsState.InternalInsetType; -import android.view.View; import android.view.WindowInsetsController.Appearance; -import androidx.annotation.VisibleForTesting; - import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.StatusBarIcon; @@ -61,9 +54,6 @@ import com.android.systemui.statusbar.policy.CallbackController; import java.util.ArrayList; -import javax.inject.Inject; -import javax.inject.Singleton; - /** * This class takes the functions from IStatusBar that come in on * binder pool threads and posts messages to get them onto the main @@ -71,7 +61,6 @@ import javax.inject.Singleton; * coalescing these calls so they don't stack up. For the calls * are coalesced, note that they are all idempotent. */ -@Singleton public class CommandQueue extends IStatusBar.Stub implements CallbackController<Callbacks>, DisplayManager.DisplayListener { private static final int INDEX_MASK = 0xffff; @@ -307,8 +296,6 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } } - @VisibleForTesting - @Inject public CommandQueue(Context context) { context.getSystemService(DisplayManager.class).registerDisplayListener(this, mHandler); // We always have default display. @@ -470,42 +457,6 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } } - // TODO(b/118118435): Remove this function after migration - @Override - public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, - boolean navbarColorManagedByIme) { - synchronized (mLock) { - final boolean hasDockedStack = !dockedStackBounds.isEmpty(); - final boolean transientStatus = (vis & View.STATUS_BAR_TRANSIENT) != 0; - final boolean transientNavigation = (vis & View.NAVIGATION_BAR_TRANSIENT) != 0; - if (transientStatus && transientNavigation) { - showTransient(displayId, new int[]{TYPE_TOP_BAR, TYPE_NAVIGATION_BAR}); - } else if (transientStatus) { - showTransient(displayId, new int[]{TYPE_TOP_BAR}); - abortTransient(displayId, new int[]{TYPE_NAVIGATION_BAR}); - } else if (transientNavigation) { - showTransient(displayId, new int[]{TYPE_NAVIGATION_BAR}); - abortTransient(displayId, new int[]{TYPE_TOP_BAR}); - } else { - abortTransient(displayId, new int[]{TYPE_TOP_BAR, TYPE_NAVIGATION_BAR}); - } - SomeArgs args = SomeArgs.obtain(); - args.argi1 = displayId; - args.argi2 = InsetsFlags.getAppearance(vis); - args.argi3 = navbarColorManagedByIme ? 1 : 0; - final int fullscreenAppearance = InsetsFlags.getAppearance(fullscreenStackVis); - final int dockedAppearance = InsetsFlags.getAppearance(dockedStackVis); - args.arg1 = hasDockedStack - ? new AppearanceRegion[]{ - new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds), - new AppearanceRegion(dockedAppearance, dockedStackBounds)} - : new AppearanceRegion[]{ - new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds)}; - mHandler.obtainMessage(MSG_SYSTEM_BAR_APPEARANCE_CHANGED, args).sendToTarget(); - } - } - @Override public void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) { synchronized (mLock) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java new file mode 100644 index 000000000000..d1f6ebf3826d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarDependenciesModule.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 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.statusbar; + +import android.content.Context; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +/** + * Dagger Module providing common dependencies of StatusBar. + */ +@Module +public class StatusBarDependenciesModule { + /** + * Provides our instance of CommandQueue which is considered optional. + */ + @Provides + @Singleton + public CommandQueue provideCommandQueue(Context context) { + return new CommandQueue(context); + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java b/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java new file mode 100644 index 000000000000..bc7c22d65a44 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2019 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.statusbar; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.StatusBarWindowView; +import com.android.systemui.util.InjectionInflationController; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Creates a single instance of super_status_bar that can be shared across various system ui + * objects. + */ +@Singleton +public class SuperStatusBarViewFactory { + + private final Context mContext; + private final InjectionInflationController mInjectionInflationController; + + private StatusBarWindowView mStatusBarWindowView; + private NotificationShelf mNotificationShelf; + + @Inject + public SuperStatusBarViewFactory(Context context, + InjectionInflationController injectionInflationController) { + mContext = context; + mInjectionInflationController = injectionInflationController; + } + + /** + * Gets the inflated {@link StatusBarWindowView} from {@link R.layout#super_status_bar}. Returns + * a cached instance, if it has already been inflated. + */ + public StatusBarWindowView getStatusBarWindowView() { + if (mStatusBarWindowView != null) { + return mStatusBarWindowView; + } + + mStatusBarWindowView = (StatusBarWindowView) mInjectionInflationController.injectable( + LayoutInflater.from(mContext)).inflate(R.layout.super_status_bar, + /* root= */ null); + if (mStatusBarWindowView == null) { + throw new IllegalStateException( + "R.layout.super_status_bar could not be properly inflated"); + } + return mStatusBarWindowView; + } + + /** + * Gets the inflated {@link NotificationShelf} from + * {@link R.layout#status_bar_notification_shelf}. + * Returns a cached instance, if it has already been inflated. + * + * @param container the expected container to hold the {@link NotificationShelf}. The view + * isn't immediately attached, but the layout params of this view is used + * during inflation. + */ + public NotificationShelf getNotificationShelf(ViewGroup container) { + if (mNotificationShelf != null) { + return mNotificationShelf; + } + + mNotificationShelf = (NotificationShelf) mInjectionInflationController.injectable( + LayoutInflater.from(mContext)).inflate(R.layout.status_bar_notification_shelf, + container, /* attachToRoot= */ false); + if (mNotificationShelf == null) { + throw new IllegalStateException( + "R.layout.status_bar_notification_shelf could not be properly inflated"); + } + return mNotificationShelf; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java index 9981c93431e7..a0229d16d6eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java @@ -68,7 +68,6 @@ public class NotificationData { private final ArrayMap<String, NotificationEntry> mEntries = new ArrayMap<>(); private final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>(); - private final ArrayList<NotificationEntry> mFilteredForUser = new ArrayList<>(); private final NotificationGroupManager mGroupManager = Dependency.get(NotificationGroupManager.class); @@ -166,20 +165,20 @@ public class NotificationData { } public ArrayList<NotificationEntry> getNotificationsForCurrentUser() { - mFilteredForUser.clear(); - synchronized (mEntries) { final int len = mEntries.size(); + ArrayList<NotificationEntry> filteredForUser = new ArrayList<>(len); + for (int i = 0; i < len; i++) { NotificationEntry entry = mEntries.valueAt(i); final StatusBarNotification sbn = entry.getSbn(); if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) { continue; } - mFilteredForUser.add(entry); + filteredForUser.add(entry); } + return filteredForUser; } - return mFilteredForUser; } public NotificationEntry get(String key) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java index 396c5fefd8b7..0ef75165f54f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java @@ -142,6 +142,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { entry.updateIcons(mContext, sbn); entry.reset(); updateNotification(entry, pmUser, sbn, entry.getRow()); + entry.getRow().setOnDismissRunnable(onDismissRunnable); } else { entry.createIcons(mContext, sbn); new RowInflaterTask().inflate(mContext, parent, entry, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index a817f54e77ca..50a20374fee5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -159,6 +159,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private int mHeadsUpAddStartLocation; private float mHeadsUpLocation; private boolean mIsAppearing; + private boolean mDismissed; + private boolean mRefocusOnDismiss; public ActivatableNotificationView(Context context, AttributeSet attrs) { super(context, attrs); @@ -1048,6 +1050,27 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView return getHeight(); } + /** Mark that this view has been dismissed. */ + public void dismiss(boolean refocusOnDismiss) { + mDismissed = true; + mRefocusOnDismiss = refocusOnDismiss; + } + + /** Mark that this view is no longer dismissed. */ + public void unDismiss() { + mDismissed = false; + } + + /** Is this view marked as dismissed? */ + public boolean isDismissed() { + return mDismissed; + } + + /** Should a re-focus occur upon dismissing this view? */ + public boolean shouldRefocusOnDismiss() { + return mRefocusOnDismiss || isAccessibilityFocused(); + } + public interface OnActivatedListener { void onActivated(ActivatableNotificationView view); void onActivationReset(ActivatableNotificationView view); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 536db67a8795..f0d07a7ed0bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -95,6 +95,7 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.SwipeableView; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; @@ -114,7 +115,7 @@ import java.util.function.Consumer; * the group summary (which contains 1 or more child notifications). */ public class ExpandableNotificationRow extends ActivatableNotificationView - implements PluginListener<NotificationMenuRowPlugin> { + implements PluginListener<NotificationMenuRowPlugin>, SwipeableView { private static final boolean DEBUG = false; private static final int DEFAULT_DIVIDER_ALPHA = 0x29; @@ -288,7 +289,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } }; private boolean mForceUnlocked; - private boolean mDismissed; private boolean mKeepInParent; private boolean mRemoved; private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT = @@ -307,7 +307,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private boolean mHeadsupDisappearRunning; private View mChildAfterViewWhenDismissed; private View mGroupParentWhenDismissed; - private boolean mRefocusOnDismiss; private float mContentTransformationAmount; private boolean mIconsVisible = true; private boolean mAboveShelf; @@ -1164,6 +1163,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } } + @Override + public boolean hasFinishedInitialization() { + return getEntry().hasFinishedInitialization(); + } + /** * Get a handle to a NotificationMenuRowPlugin whose menu view has been added to our hierarchy, * or null if there is no menu row @@ -1323,11 +1327,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } } - public void setDismissed(boolean fromAccessibility) { + @Override + public void dismiss(boolean refocusOnDismiss) { + super.dismiss(refocusOnDismiss); setLongPressListener(null); - mDismissed = true; mGroupParentWhenDismissed = mNotificationParent; - mRefocusOnDismiss = fromAccessibility; mChildAfterViewWhenDismissed = null; mEntry.icon.setDismissed(); if (isChildInGroup()) { @@ -1340,10 +1344,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } } - public boolean isDismissed() { - return mDismissed; - } - public boolean keepInParent() { return mKeepInParent; } @@ -1445,7 +1445,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView groupSummary.getRow().performDismiss(fromAccessibility); } } - setDismissed(fromAccessibility); + dismiss(fromAccessibility); if (mEntry.isClearable()) { // TODO: beverlyt, log dismissal // TODO: track dismiss sentiment @@ -3021,10 +3021,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return false; } - public boolean shouldRefocusOnDismiss() { - return mRefocusOnDismiss || isAccessibilityFocused(); - } - public interface OnExpandClickListener { void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java index 54d406615ae0..fdd51e9e7790 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java @@ -23,7 +23,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.PendingIntent; import android.content.Intent; import android.provider.Settings; import android.view.LayoutInflater; @@ -310,6 +309,8 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section mParent.removeView(mPeopleHubView); } } else { + mPeopleHubView.unDismiss(); + mPeopleHubView.resetTranslation(); if (!currentlyVisible) { if (mPeopleHubView.getTransientContainer() != null) { mPeopleHubView.getTransientContainer().removeTransientView(mPeopleHubView); @@ -419,8 +420,9 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section } } - private void handlePeopleHubClick(PendingIntent pendingIntent) { - mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent, null, mPeopleHubView); + void hidePeopleRow() { + mPeopleHubVisible = false; + updateSectionBoundaries(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 6dca7ee9e872..2b9912ce055d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -4920,7 +4920,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } else { child.setMinClipTopAmount(0); } - previousChildWillBeDismissed = StackScrollAlgorithm.canChildBeDismissed(child); + previousChildWillBeDismissed = canChildBeDismissed(child); } } @@ -5523,7 +5523,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd performDismissAllAnimations(viewsToHide, closeShade, () -> { for (ExpandableNotificationRow rowToRemove : viewsToRemove) { - if (StackScrollAlgorithm.canChildBeDismissed(rowToRemove)) { + if (canChildBeDismissed(rowToRemove)) { if (selection == ROWS_ALL) { // TODO: This is a listener method; we shouldn't be calling it. Can we just // call performRemoveNotification as below? @@ -5552,7 +5552,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private boolean includeChildInDismissAll( ExpandableNotificationRow row, @SelectedRows int selection) { - return StackScrollAlgorithm.canChildBeDismissed(row) && matchesSelection(row, selection); + return canChildBeDismissed(row) && matchesSelection(row, selection); } /** @@ -6223,7 +6223,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd */ @Override public void onChildDismissed(View view) { - ExpandableNotificationRow row = (ExpandableNotificationRow) view; + if (!(view instanceof ActivatableNotificationView)) { + return; + } + ActivatableNotificationView row = (ActivatableNotificationView) view; if (!row.isDismissed()) { handleChildViewDismissed(view); } @@ -6261,6 +6264,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd row.performDismissWithBlockingHelper(false /* fromAccessibility */); } + if (view instanceof PeopleHubView) { + PeopleHubView row = (PeopleHubView) view; + row.dismiss(false); + mSectionsManager.hidePeopleRow(); + } + if (!isBlockingHelperShown) { mSwipedOutViews.add(view); } @@ -6349,9 +6358,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return 0; } - @Override + @Override public boolean canChildBeDismissed(View v) { - return StackScrollAlgorithm.canChildBeDismissed(v); + return NotificationStackScrollLayout.canChildBeDismissed(v); } @Override @@ -6361,6 +6370,23 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } }; + private static boolean canChildBeDismissed(View v) { + if (v instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) v; + if (row.isBlockingHelperShowingAndTranslationFinished()) { + return true; + } + if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) { + return false; + } + return row.canViewBeDismissed(); + } + if (v instanceof PeopleHubView) { + return true; + } + return false; + } + // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ @ShadeViewRefactor(RefactorComponent.INPUT) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java index 0968674d31cc..6d0fcc386281 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java @@ -31,11 +31,10 @@ import com.android.systemui.SwipeHelper; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; -class NotificationSwipeHelper extends SwipeHelper - implements NotificationSwipeActionHelper { +class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeActionHelper { + @VisibleForTesting protected static final long COVER_MENU_DELAY = 4000; private static final String TAG = "NotificationSwipeHelper"; @@ -58,12 +57,7 @@ class NotificationSwipeHelper extends SwipeHelper super(swipeDirection, callback, context, falsingManager); mMenuListener = menuListener; mCallback = callback; - mFalsingCheck = new Runnable() { - @Override - public void run() { - resetExposedMenuView(true /* animate */, true /* force */); - } - }; + mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */); } public View getTranslatingParentView() { @@ -126,14 +120,14 @@ class NotificationSwipeHelper extends SwipeHelper // Slide back any notifications that might be showing a menu resetExposedMenuView(true /* animate */, false /* force */); - if (currView instanceof ExpandableNotificationRow) { - initializeRow((ExpandableNotificationRow) currView); + if (currView instanceof SwipeableView) { + initializeRow((SwipeableView) currView); } } @VisibleForTesting - protected void initializeRow(ExpandableNotificationRow row) { - if (row.getEntry().hasFinishedInitialization()) { + protected void initializeRow(SwipeableView row) { + if (row.hasFinishedInitialization()) { mCurrMenuRow = row.createMenu(); if (mCurrMenuRow != null) { mCurrMenuRow.setMenuClickListener(mMenuListener); @@ -304,8 +298,8 @@ class NotificationSwipeHelper extends SwipeHelper @Override public Animator getViewTranslationAnimator(View v, float target, ValueAnimator.AnimatorUpdateListener listener) { - if (v instanceof ExpandableNotificationRow) { - return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener); + if (v instanceof SwipeableView) { + return ((SwipeableView) v).getTranslateViewAnimator(target, listener); } else { return superGetViewTranslationAnimator(v, target, listener); } @@ -313,15 +307,15 @@ class NotificationSwipeHelper extends SwipeHelper @Override public void setTranslation(View v, float translate) { - if (v instanceof ExpandableNotificationRow) { - ((ExpandableNotificationRow) v).setTranslation(translate); + if (v instanceof SwipeableView) { + ((SwipeableView) v).setTranslation(translate); } } @Override public float getTranslation(View v) { - if (v instanceof ExpandableNotificationRow) { - return ((ExpandableNotificationRow) v).getTranslation(); + if (v instanceof SwipeableView) { + return ((SwipeableView) v).getTranslation(); } else { return 0f; @@ -410,8 +404,8 @@ class NotificationSwipeHelper extends SwipeHelper if (anim != null) { anim.start(); } - } else if (prevMenuExposedView instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) prevMenuExposedView; + } else if (prevMenuExposedView instanceof SwipeableView) { + SwipeableView row = (SwipeableView) prevMenuExposedView; if (!row.isRemoved()) { row.resetTranslation(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt index e31ee024fa36..a0796060e9d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt @@ -16,23 +16,39 @@ package com.android.systemui.statusbar.notification.stack +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ObjectAnimator +import android.animation.ValueAnimator import android.content.Context import android.util.AttributeSet +import android.util.FloatProperty import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import com.android.systemui.R -import com.android.systemui.statusbar.notification.people.PersonViewModel +import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin import com.android.systemui.statusbar.notification.people.DataListener +import com.android.systemui.statusbar.notification.people.PersonViewModel import com.android.systemui.statusbar.notification.row.ActivatableNotificationView +private val TRANSLATE_CONTENT = object : FloatProperty<PeopleHubView>("translate") { + override fun setValue(view: PeopleHubView, value: Float) { + view.translation = value + } + + override fun get(view: PeopleHubView) = view.translation +} + class PeopleHubView(context: Context, attrs: AttributeSet) : - ActivatableNotificationView(context, attrs) { + ActivatableNotificationView(context, attrs), SwipeableView { private lateinit var contents: ViewGroup private lateinit var personControllers: List<PersonDataListenerImpl> + private var translateAnim: ObjectAnimator? = null + val personViewAdapters: Sequence<DataListener<PersonViewModel?>> get() = personControllers.asSequence() @@ -49,6 +65,34 @@ class PeopleHubView(context: Context, attrs: AttributeSet) : override fun getContentView(): View = contents + override fun hasFinishedInitialization(): Boolean = true + + override fun createMenu(): NotificationMenuRowPlugin? = null + + override fun getTranslateViewAnimator( + leftTarget: Float, + listener: ValueAnimator.AnimatorUpdateListener? + ): Animator = + ObjectAnimator + .ofFloat(this, TRANSLATE_CONTENT, leftTarget) + .apply { + listener?.let { addUpdateListener(listener) } + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(anim: Animator) { + translateAnim = null + } + }) + } + .also { + translateAnim?.cancel() + translateAnim = it + } + + override fun resetTranslation() { + translateAnim?.cancel() + translationX = 0f + } + private inner class PersonDataListenerImpl(val viewGroup: ViewGroup) : DataListener<PersonViewModel?> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 4b61064f4a54..9646c01c8c41 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -195,20 +195,6 @@ public class StackScrollAlgorithm { } } - public static boolean canChildBeDismissed(View v) { - if (!(v instanceof ExpandableNotificationRow)) { - return false; - } - ExpandableNotificationRow row = (ExpandableNotificationRow) v; - if (row.isBlockingHelperShowingAndTranslationFinished()) { - return true; - } - if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) { - return false; - } - return row.canViewBeDismissed(); - } - /** * Updates the dimmed, activated and hiding sensitive states of the children. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java new file mode 100644 index 000000000000..6c6ef61cfdaf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SwipeableView.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 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.statusbar.notification.stack; + +import android.animation.Animator; +import android.animation.ValueAnimator; + +import androidx.annotation.Nullable; + +import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; + +/** A View that is swipeable inside of the notification shade. */ +public interface SwipeableView { + + /** Has this view finished initializing? */ + boolean hasFinishedInitialization(); + + /** Optionally creates a menu for this view. */ + @Nullable NotificationMenuRowPlugin createMenu(); + + /** Animator for translating the view, simulating a swipe. */ + Animator getTranslateViewAnimator( + float leftTarget, ValueAnimator.AnimatorUpdateListener listener); + + /** Sets the translation amount for an in-progress swipe. */ + void setTranslation(float translate); + + /** Gets the current translation amount. */ + float getTranslation(); + + /** Has this view been removed? */ + boolean isRemoved(); + + /** Resets the swipe translation back to zero state. */ + void resetTranslation(); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java index fce1dcc998fe..c2731089132c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java @@ -203,10 +203,16 @@ public class ButtonDispatcher { mFadeAnimator.addUpdateListener(mAlphaListener); mFadeAnimator.start(); } else { - mAlpha = alpha; - final int N = mViews.size(); - for (int i = 0; i < N; i++) { - mViews.get(i).setAlpha(alpha); + // Discretize the alpha updates to prevent too frequent updates when there is a long + // alpha animation + int prevAlpha = (int) (getAlpha() * 255); + int nextAlpha = (int) (alpha * 255); + if (prevAlpha != nextAlpha) { + mAlpha = nextAlpha / 255f; + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + mViews.get(i).setAlpha(mAlpha); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index 2e776e39b54c..1532c4f977e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -247,7 +247,7 @@ public class LightBarController implements BatteryController.BatteryStateChangeC @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("LightBarController: "); - pw.print(" mAppearance=0x"); pw.println(ViewDebug.flagsToString( + pw.print(" mAppearance="); pw.println(ViewDebug.flagsToString( InsetsFlags.class, "appearance", mAppearance)); final int numStacks = mAppearanceRegions.length; for (int i = 0; i < numStacks; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java index 4f7af58094ec..abceb11b36e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java @@ -31,13 +31,13 @@ import com.android.settingslib.Utils; import com.android.systemui.R; public class NavigationHandle extends View implements ButtonInterface { - private float mDarkIntensity = -1; private final Paint mPaint = new Paint(); private @ColorInt final int mLightColor; private @ColorInt final int mDarkColor; private final int mRadius; private final int mBottom; + private boolean mRequiresInvalidate; public NavigationHandle(Context context) { this(context, null); @@ -60,6 +60,15 @@ public class NavigationHandle extends View implements ButtonInterface { } @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + if (alpha > 0f && mRequiresInvalidate) { + mRequiresInvalidate = false; + invalidate(); + } + } + + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -85,11 +94,15 @@ public class NavigationHandle extends View implements ButtonInterface { @Override public void setDarkIntensity(float intensity) { - if (mDarkIntensity != intensity) { - mPaint.setColor((int) ArgbEvaluator.getInstance().evaluate(intensity, mLightColor, - mDarkColor)); - mDarkIntensity = intensity; - invalidate(); + int color = (int) ArgbEvaluator.getInstance().evaluate(intensity, mLightColor, mDarkColor); + if (mPaint.getColor() != color) { + mPaint.setColor(color); + if (getVisibility() == VISIBLE && getAlpha() > 0) { + invalidate(); + } else { + // If we are currently invisible, then invalidate when we are next made visible + mRequiresInvalidate = true; + } } } 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 4148a73e579c..cff282472074 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -24,7 +24,6 @@ import static android.app.StatusBarManager.WindowType; import static android.app.StatusBarManager.WindowVisibleState; import static android.app.StatusBarManager.windowStateToString; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; -import static android.view.InsetsFlags.getAppearance; import static android.view.InsetsState.TYPE_TOP_BAR; import static android.view.InsetsState.containsType; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; @@ -75,7 +74,6 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; -import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; import android.media.AudioAttributes; @@ -109,7 +107,6 @@ import android.view.Display; import android.view.IWindowManager; import android.view.InsetsState.InternalInsetType; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.RemoteAnimationAdapter; import android.view.ThreadedRenderer; @@ -157,7 +154,6 @@ import com.android.systemui.bubbles.BubbleController; import com.android.systemui.charging.WirelessChargingAnimation; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.SystemUIBinder; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.fragments.ExtensionFragmentListener; @@ -202,6 +198,7 @@ import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; @@ -243,7 +240,6 @@ import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; -import com.android.systemui.util.InjectionInflationController; import com.android.systemui.volume.VolumeComponent; import java.io.FileDescriptor; @@ -364,8 +360,6 @@ public class StatusBar extends SystemUI implements DemoMode, @Nullable private final KeyguardLiftController mKeyguardLiftController; - private int mNaturalBarHeight = -1; - private final Point mCurrentDisplaySize = new Point(); protected StatusBarWindowViewController mStatusBarWindowViewController; @@ -384,7 +378,6 @@ public class StatusBar extends SystemUI implements DemoMode, private final FeatureFlags mFeatureFlags; private final StatusBarIconController mIconController; private final DozeLog mDozeLog; - private final InjectionInflationController mInjectionInflater; private final PulseExpansionHandler mPulseExpansionHandler; private final NotificationWakeUpCoordinator mWakeUpCoordinator; private final KeyguardBypassController mKeyguardBypassController; @@ -403,6 +396,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; private final PluginManager mPluginManager; private final RemoteInputUriController mRemoteInputUriController; + private final SuperStatusBarViewFactory mSuperStatusBarViewFactory; // expanded notifications protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window @@ -637,7 +631,7 @@ public class StatusBar extends SystemUI implements DemoMode, * Public constructor for StatusBar. * * StatusBar is considered optional, and therefore can not be marked as @Inject directly. - * Instead, an @Provide method is included in {@link SystemUIBinder}. + * Instead, an @Provide method is included. */ public StatusBar( Context context, @@ -647,7 +641,6 @@ public class StatusBar extends SystemUI implements DemoMode, KeyguardUpdateMonitor keyguardUpdateMonitor, StatusBarIconController statusBarIconController, DozeLog dozeLog, - InjectionInflationController injectionInflationController, PulseExpansionHandler pulseExpansionHandler, NotificationWakeUpCoordinator notificationWakeUpCoordinator, KeyguardBypassController keyguardBypassController, @@ -706,7 +699,8 @@ public class StatusBar extends SystemUI implements DemoMode, DozeScrimController dozeScrimController, CommandQueue commandQueue, PluginManager pluginManager, - RemoteInputUriController remoteInputUriController) { + RemoteInputUriController remoteInputUriController, + SuperStatusBarViewFactory superStatusBarViewFactory) { super(context); mFeatureFlags = featureFlags; mLightBarController = lightBarController; @@ -714,7 +708,6 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardUpdateMonitor = keyguardUpdateMonitor; mIconController = statusBarIconController; mDozeLog = dozeLog; - mInjectionInflater = injectionInflationController; mPulseExpansionHandler = pulseExpansionHandler; mWakeUpCoordinator = notificationWakeUpCoordinator; mKeyguardBypassController = keyguardBypassController; @@ -774,6 +767,8 @@ public class StatusBar extends SystemUI implements DemoMode, mCommandQueue = commandQueue; mPluginManager = pluginManager; mRemoteInputUriController = remoteInputUriController; + mSuperStatusBarViewFactory = superStatusBarViewFactory; + mBubbleExpandListener = (isExpanding, key) -> { mEntryManager.updateNotifications("onBubbleExpandChanged"); @@ -860,19 +855,11 @@ public class StatusBar extends SystemUI implements DemoMode, // Set up the initial notification state. This needs to happen before CommandQueue.disable() setUpPresenter(); - if ((result.mSystemUiVisibility & View.STATUS_BAR_TRANSIENT) != 0) { + if (containsType(result.mTransientBarTypes, TYPE_TOP_BAR)) { showTransientUnchecked(); } - final int fullscreenAppearance = getAppearance(result.mFullscreenStackSysUiVisibility); - final int dockedAppearance = getAppearance(result.mDockedStackSysUiVisibility); - final AppearanceRegion[] appearanceRegions = result.mDockedStackBounds.isEmpty() - ? new AppearanceRegion[]{ - new AppearanceRegion(fullscreenAppearance, result.mFullscreenStackBounds)} - : new AppearanceRegion[]{ - new AppearanceRegion(fullscreenAppearance, result.mFullscreenStackBounds), - new AppearanceRegion(dockedAppearance, result.mDockedStackBounds)}; - onSystemBarAppearanceChanged(mDisplayId, getAppearance(result.mSystemUiVisibility), - appearanceRegions, result.mNavbarColorManagedByIme); + onSystemBarAppearanceChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions, + result.mNavbarColorManagedByIme); mAppFullscreen = result.mAppFullscreen; mAppImmersive = result.mAppImmersive; @@ -892,7 +879,7 @@ public class StatusBar extends SystemUI implements DemoMode, "init: icons=%d disabled=0x%08x lights=0x%08x imeButton=0x%08x", numIcons, result.mDisabledFlags1, - result.mSystemUiVisibility, + result.mAppearance, result.mImeWindowVis)); } @@ -1368,10 +1355,7 @@ public class StatusBar extends SystemUI implements DemoMode, } private void inflateShelf() { - mNotificationShelf = - (NotificationShelf) mInjectionInflater.injectable( - LayoutInflater.from(mContext)).inflate( - R.layout.status_bar_notification_shelf, mStackScroller, false); + mNotificationShelf = mSuperStatusBarViewFactory.getNotificationShelf(mStackScroller); mNotificationShelf.setOnClickListener(mGoToLockedShadeListener); } @@ -1429,10 +1413,8 @@ public class StatusBar extends SystemUI implements DemoMode, } protected void inflateStatusBarWindow(Context context) { - mStatusBarWindow = (StatusBarWindowView) mInjectionInflater.injectable( - LayoutInflater.from(context)).inflate(R.layout.super_status_bar, null); + mStatusBarWindow = mSuperStatusBarViewFactory.getStatusBarWindowView(); mStatusBarWindowViewController = mStatusBarWindowViewControllerBuilder - .setStatusBarWindowView(mStatusBarWindow) .setShadeController(this) .build(); } @@ -1470,12 +1452,7 @@ public class StatusBar extends SystemUI implements DemoMode, } public int getStatusBarHeight() { - if (mNaturalBarHeight < 0) { - final Resources res = mContext.getResources(); - mNaturalBarHeight = - res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); - } - return mNaturalBarHeight; + return mStatusBarWindowController.getStatusBarHeight(); } protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { @@ -2649,7 +2626,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void createAndAddWindows(@Nullable RegisterStatusBarResult result) { makeStatusBarView(result); - mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight()); + mStatusBarWindowController.attach(); } // called by makeStatusbar and also by PhoneStatusBarView @@ -2927,7 +2904,7 @@ public class StatusBar extends SystemUI implements DemoMode, mQSPanel.updateResources(); } - loadDimens(); + mStatusBarWindowController.refreshStatusBarHeight(); if (mStatusBarView != null) { mStatusBarView.updateResources(); @@ -2940,19 +2917,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - protected void loadDimens() { - final Resources res = mContext.getResources(); - - int oldBarHeight = mNaturalBarHeight; - mNaturalBarHeight = res.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); - if (mStatusBarWindowController != null && mNaturalBarHeight != oldBarHeight) { - mStatusBarWindowController.setBarHeight(mNaturalBarHeight); - } - - if (DEBUG) Log.v(TAG, "defineSlots"); - } - // Visibility reporting protected void handleVisibleToUserChanged(boolean visibleToUser) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java new file mode 100644 index 000000000000..67f6a0ca6b72 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2019 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.statusbar.phone; + +import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; + +import android.content.Context; +import android.os.PowerManager; +import android.util.DisplayMetrics; + +import androidx.annotation.Nullable; + +import com.android.internal.logging.MetricsLogger; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.ForegroundServiceController; +import com.android.systemui.UiOffloadThread; +import com.android.systemui.appops.AppOpsController; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.doze.DozeLog; +import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.FeatureFlags; +import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationViewHierarchyManager; +import com.android.systemui.statusbar.PulseExpansionHandler; +import com.android.systemui.statusbar.StatusBarDependenciesModule; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; +import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.VibratorHelper; +import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.NewNotifPipeline; +import com.android.systemui.statusbar.notification.NotificationAlertingManager; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.logging.NotifLog; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; +import com.android.systemui.statusbar.policy.RemoteInputUriController; +import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.statusbar.policy.ZenModeController; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Lazy; +import dagger.Module; +import dagger.Provides; + +/** + * Dagger Module providing {@link StatusBar}. + */ +@Module(includes = {StatusBarDependenciesModule.class}) +public class StatusBarModule { + /** + * Provides our instance of StatusBar which is considered optional. + */ + @Provides + @Singleton + static StatusBar provideStatusBar( + Context context, + FeatureFlags featureFlags, + LightBarController lightBarController, + AutoHideController autoHideController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + StatusBarIconController statusBarIconController, + DozeLog dozeLog, + PulseExpansionHandler pulseExpansionHandler, + NotificationWakeUpCoordinator notificationWakeUpCoordinator, + KeyguardBypassController keyguardBypassController, + KeyguardStateController keyguardStateController, + HeadsUpManagerPhone headsUpManagerPhone, + DynamicPrivacyController dynamicPrivacyController, + BypassHeadsUpNotifier bypassHeadsUpNotifier, + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress, + Lazy<NewNotifPipeline> newNotifPipeline, + FalsingManager falsingManager, + BroadcastDispatcher broadcastDispatcher, + RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, + NotificationGutsManager notificationGutsManager, + NotificationLogger notificationLogger, + NotificationEntryManager notificationEntryManager, + NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationViewHierarchyManager notificationViewHierarchyManager, + ForegroundServiceController foregroundServiceController, + AppOpsController appOpsController, + KeyguardViewMediator keyguardViewMediator, + ZenModeController zenModeController, + NotificationAlertingManager notificationAlertingManager, + DisplayMetrics displayMetrics, + MetricsLogger metricsLogger, + UiOffloadThread uiOffloadThread, + NotificationMediaManager notificationMediaManager, + NotificationLockscreenUserManager lockScreenUserManager, + NotificationRemoteInputManager remoteInputManager, + UserSwitcherController userSwitcherController, + NetworkController networkController, + BatteryController batteryController, + SysuiColorExtractor colorExtractor, + ScreenLifecycle screenLifecycle, + WakefulnessLifecycle wakefulnessLifecycle, + SysuiStatusBarStateController statusBarStateController, + VibratorHelper vibratorHelper, + BubbleController bubbleController, + NotificationGroupManager groupManager, + NotificationGroupAlertTransferHelper groupAlertTransferHelper, + VisualStabilityManager visualStabilityManager, + DeviceProvisionedController deviceProvisionedController, + NavigationBarController navigationBarController, + AssistManager assistManager, + NotificationListener notificationListener, + ConfigurationController configurationController, + StatusBarWindowController statusBarWindowController, + StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder, + NotifLog notifLog, + DozeParameters dozeParameters, + ScrimController scrimController, + @Nullable KeyguardLiftController keyguardLiftController, + Lazy<LockscreenWallpaper> lockscreenWallpaperLazy, + Lazy<BiometricUnlockController> biometricUnlockControllerLazy, + DozeServiceHost dozeServiceHost, + PowerManager powerManager, + DozeScrimController dozeScrimController, + CommandQueue commandQueue, + PluginManager pluginManager, + RemoteInputUriController remoteInputUriController, + SuperStatusBarViewFactory superStatusBarViewFactory) { + return new StatusBar( + context, + featureFlags, + lightBarController, + autoHideController, + keyguardUpdateMonitor, + statusBarIconController, + dozeLog, + pulseExpansionHandler, + notificationWakeUpCoordinator, + keyguardBypassController, + keyguardStateController, + headsUpManagerPhone, + dynamicPrivacyController, + bypassHeadsUpNotifier, + allowNotificationLongPress, + newNotifPipeline, + falsingManager, + broadcastDispatcher, + remoteInputQuickSettingsDisabler, + notificationGutsManager, + notificationLogger, + notificationEntryManager, + notificationInterruptionStateProvider, + notificationViewHierarchyManager, + foregroundServiceController, + appOpsController, + keyguardViewMediator, + zenModeController, + notificationAlertingManager, + displayMetrics, + metricsLogger, + uiOffloadThread, + notificationMediaManager, + lockScreenUserManager, + remoteInputManager, + userSwitcherController, + networkController, + batteryController, + colorExtractor, + screenLifecycle, + wakefulnessLifecycle, + statusBarStateController, + vibratorHelper, + bubbleController, + groupManager, + groupAlertTransferHelper, + visualStabilityManager, + deviceProvisionedController, + navigationBarController, + assistManager, + notificationListener, + configurationController, + statusBarWindowController, + statusBarWindowViewControllerBuilder, + notifLog, + dozeParameters, + scrimController, + keyguardLiftController, + lockscreenWallpaperLazy, + biometricUnlockControllerLazy, + dozeServiceHost, + powerManager, + dozeScrimController, + commandQueue, + pluginManager, + remoteInputUriController, + superStatusBarViewFactory); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java index ca7a936d58f7..2ecceba2116a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java @@ -41,11 +41,13 @@ import android.view.WindowManager.LayoutParams; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.dagger.qualifiers.MainResources; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.RemoteInputController.Callback; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -69,6 +71,7 @@ import javax.inject.Singleton; public class StatusBarWindowController implements Callback, Dumpable, ConfigurationListener { private static final String TAG = "StatusBarWindowController"; + private static final boolean DEBUG = false; private final Context mContext; private final WindowManager mWindowManager; @@ -83,7 +86,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat private LayoutParams mLp; private boolean mHasTopUi; private boolean mHasTopUiChanged; - private int mBarHeight; + private int mBarHeight = -1; private float mScreenBrightnessDoze; private final State mCurrentState = new State(); private OtherwisedCollapsedListener mListener; @@ -92,13 +95,17 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat mCallbacks = Lists.newArrayList(); private final SysuiColorExtractor mColorExtractor; + private final SuperStatusBarViewFactory mSuperStatusBarViewFactory; + private final Resources mResources; @Inject public StatusBarWindowController(Context context, WindowManager windowManager, IActivityManager activityManager, DozeParameters dozeParameters, StatusBarStateController statusBarStateController, ConfigurationController configurationController, - KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor) { + KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor, + SuperStatusBarViewFactory superStatusBarViewFactory, + @MainResources Resources resources) { mContext = context; mWindowManager = windowManager; mActivityManager = activityManager; @@ -108,6 +115,15 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat mLpChanged = new LayoutParams(); mKeyguardBypassController = keyguardBypassController; mColorExtractor = colorExtractor; + mSuperStatusBarViewFactory = superStatusBarViewFactory; + mStatusBarView = mSuperStatusBarViewFactory.getStatusBarWindowView(); + mResources = resources; + + if (mBarHeight < 0) { + mBarHeight = mResources.getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_height); + } + mLockScreenDisplayTimeout = context.getResources() .getInteger(R.integer.config_lockScreenDisplayTimeout); ((SysuiStatusBarStateController) statusBarStateController) @@ -149,20 +165,36 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat || res.getBoolean(R.bool.config_enableLockScreenRotation); } + public int getStatusBarHeight() { + return mBarHeight; + } + /** - * Adds the status bar view to the window manager. - * - * @param statusBarView The view to add. - * @param barHeight The height of the status bar in collapsed state. + * Rereads the status_bar_height from configuration and reapplys the current state if the height + * is different. */ - public void add(ViewGroup statusBarView, int barHeight) { + public void refreshStatusBarHeight() { + int heightFromConfig = mResources.getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_height); + + if (mBarHeight != heightFromConfig) { + mBarHeight = heightFromConfig; + apply(mCurrentState); + } + if (DEBUG) Log.v(TAG, "defineSlots"); + } + + /** + * Adds the status bar view to the window manager. + */ + public void attach() { // Now that the status bar window encompasses the sliding panel and its // translucent backdrop, the entire thing is made TRANSLUCENT and is // hardware-accelerated. mLp = new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, - barHeight, + mBarHeight, LayoutParams.TYPE_STATUS_BAR, LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING @@ -176,8 +208,6 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat mLp.setTitle("StatusBar"); mLp.packageName = mContext.getPackageName(); mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - mStatusBarView = statusBarView; - mBarHeight = barHeight; mWindowManager.addView(mStatusBarView, mLp); mLpChanged.copyFrom(mLp); onThemeChanged(); @@ -534,11 +564,6 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat apply(mCurrentState); } - public void setBarHeight(int barHeight) { - mBarHeight = barHeight; - apply(mCurrentState); - } - public void setForcePluginOpen(boolean forcePluginOpen) { mCurrentState.forcePluginOpen = forcePluginOpen; apply(mCurrentState); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java index b7ada5d35a08..f716443cbfe1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.PulseExpansionHandler; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -492,7 +493,8 @@ public class StatusBarWindowViewController { private final DozeLog mDozeLog; private final DozeParameters mDozeParameters; private final CommandQueue mCommandQueue; - private StatusBarWindowView mView; + private final SuperStatusBarViewFactory mSuperStatusBarViewFactory; + private final StatusBarWindowView mView; @Inject public Builder( @@ -510,7 +512,8 @@ public class StatusBarWindowViewController { StatusBarStateController statusBarStateController, DozeLog dozeLog, DozeParameters dozeParameters, - CommandQueue commandQueue) { + CommandQueue commandQueue, + SuperStatusBarViewFactory superStatusBarViewFactory) { mInjectionInflationController = injectionInflationController; mCoordinator = coordinator; mPulseExpansionHandler = pulseExpansionHandler; @@ -526,14 +529,9 @@ public class StatusBarWindowViewController { mDozeLog = dozeLog; mDozeParameters = dozeParameters; mCommandQueue = commandQueue; - } + mSuperStatusBarViewFactory = superStatusBarViewFactory; - /** - * Provide {@link StatusBarWindowView} to attach this controller to. - */ - public Builder setStatusBarWindowView(StatusBarWindowView view) { - mView = view; - return this; + mView = mSuperStatusBarViewFactory.getStatusBarWindowView(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 5da726749580..bae51b6ebd9e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -48,6 +48,7 @@ import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionD import java.io.PrintWriter; import java.util.BitSet; +import java.util.concurrent.Executor; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -103,7 +104,7 @@ public class MobileSignalController extends SignalController< mPhone = phone; mDefaults = defaults; mSubscriptionInfo = info; - mPhoneStateListener = new MobilePhoneStateListener(receiverLooper); + mPhoneStateListener = new MobilePhoneStateListener((new Handler(receiverLooper))::post); mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator); mNetworkNameDefault = getStringIfExists( com.android.internal.R.string.lockscreen_carrier_default); @@ -665,8 +666,8 @@ public class MobileSignalController extends SignalController< } class MobilePhoneStateListener extends PhoneStateListener { - public MobilePhoneStateListener(Looper looper) { - super(looper); + public MobilePhoneStateListener(Executor executor) { + super(executor); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index e5898eded11e..12d357731560 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -282,7 +282,7 @@ public class NetworkControllerImpl extends BroadcastReceiver // exclusively for status bar icons. mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler); // Register the listener on our bg looper - mPhoneStateListener = new PhoneStateListener(bgLooper) { + mPhoneStateListener = new PhoneStateListener(mReceiverHandler::post) { @Override public void onActiveDataSubscriptionIdChanged(int subId) { mActiveMobileDataSubscription = subId; @@ -649,7 +649,7 @@ public class NetworkControllerImpl extends BroadcastReceiver } private boolean hasAnySim() { - int simCount = mPhone.getSimCount(); + int simCount = mPhone.getActiveModemCount(); for (int i = 0; i < simCount; i++) { int state = mPhone.getSimState(i); if (state != TelephonyManager.SIM_STATE_ABSENT diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java index 65bb28ffbe39..949ac4df88ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -22,6 +22,7 @@ import android.text.TextPaint; import android.text.method.TransformationMethod; import android.util.AttributeSet; import android.util.Log; +import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -238,13 +239,15 @@ public class SmartReplyView extends ViewGroup { public List<Button> inflateSmartActions(Context packageContext, @NonNull SmartActions smartActions, SmartReplyController smartReplyController, NotificationEntry entry, HeadsUpManager headsUpManager, boolean delayOnClickListener) { + Context themedPackageContext = new ContextThemeWrapper(packageContext, mContext.getTheme()); List<Button> buttons = new ArrayList<>(); int numSmartActions = smartActions.actions.size(); for (int n = 0; n < numSmartActions; n++) { Notification.Action action = smartActions.actions.get(n); if (action.actionIntent != null) { buttons.add(inflateActionButton( - this, getContext(), packageContext, n, smartActions, smartReplyController, + this, getContext(), themedPackageContext, n, smartActions, + smartReplyController, entry, headsUpManager, delayOnClickListener)); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 075c6d40ca31..13c0db938ca0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -463,8 +463,11 @@ public class UserSwitcherController implements Dumpable { } private void listenForCallState() { - TelephonyManager.from(mContext).listen(mPhoneStateListener, - PhoneStateListener.LISTEN_CALL_STATE); + final TelephonyManager tele = + (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + if (tele != null) { + tele.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); + } } private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index 1dd48634615b..d8eaaa182722 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -145,6 +145,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("", new CharSequence[]{}, false, new int[]{}); when(mTelephonyManager.getSupportedModemCount()).thenReturn(3); + when(mTelephonyManager.getActiveModemCount()).thenReturn(3); mCarrierTextController = new CarrierTextController(mContext, SEPARATOR, true, true); // This should not start listening on any of the real dependencies but will test that @@ -216,6 +217,15 @@ public class CarrierTextControllerTest extends SysuiTestCase { // There's only one subscription in the list assertEquals(1, captor.getValue().listOfCarriers.length); assertEquals(TEST_CARRIER, captor.getValue().listOfCarriers[0]); + + // Now it becomes single SIM active mode. + reset(mCarrierTextCallback); + when(mTelephonyManager.getActiveModemCount()).thenReturn(1); + // Update carrier text. It should ignore error state of subId 3 in inactive slotId. + mCarrierTextController.updateCarrierText(); + mTestableLooper.processAllMessages(); + verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); + assertEquals("TEST_CARRIER", captor.getValue().carrierText); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index c215a43e0f3e..486fa12e0577 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -35,6 +35,7 @@ import android.app.ActivityManager; import android.app.IActivityTaskManager; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.hardware.biometrics.Authenticator; @@ -403,6 +404,19 @@ public class AuthControllerTest extends SysuiTestCase { mAuthController.onDeviceCredentialPressed(); } + @Test + public void testActionCloseSystemDialogs_dismissesDialogIfShowing() throws Exception { + showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE); + Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + mAuthController.mBroadcastReceiver.onReceive(mContext, intent); + waitForIdleSync(); + + assertNull(mAuthController.mCurrentDialog); + assertNull(mAuthController.mReceiver); + verify(mDialog1).dismissWithoutCallback(true /* animate */); + verify(mReceiver).onDialogDismissed(eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL)); + } + // Helpers private void showDialog(int authenticators, int biometricModality) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 00681130074b..b1a6bc6d41fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -46,18 +46,19 @@ import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.graphics.drawable.Icon; import android.hardware.face.FaceManager; import android.service.notification.ZenModeConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.WindowManager; -import android.widget.FrameLayout; import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; import com.android.systemui.R; +import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -65,6 +66,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoveInterceptor; import com.android.systemui.statusbar.NotificationTestHelper; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -81,6 +83,7 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Test; @@ -119,7 +122,6 @@ public class BubbleControllerTest extends SysuiTestCase { @Mock private KeyguardBypassController mKeyguardBypassController; - private FrameLayout mStatusBarView; @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor; @Captor @@ -147,22 +149,28 @@ public class BubbleControllerTest extends SysuiTestCase { private SysuiColorExtractor mColorExtractor; @Mock ColorExtractor.GradientColors mGradientColors; + @Mock + private Resources mResources; + private SuperStatusBarViewFactory mSuperStatusBarViewFactory; private BubbleData mBubbleData; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mStatusBarView = new FrameLayout(mContext); mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager); mContext.addMockSystemService(FaceManager.class, mFaceManager); when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); + mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext, + new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent())); + // Bubbles get added to status bar window view mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, - mConfigurationController, mKeyguardBypassController, mColorExtractor); - mStatusBarWindowController.add(mStatusBarView, 120 /* height */); + mConfigurationController, mKeyguardBypassController, mColorExtractor, + mSuperStatusBarViewFactory, mResources); + mStatusBarWindowController.attach(); // Need notifications for bubbles mNotificationTestHelper = new NotificationTestHelper(mContext, mDependency); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java index 187c72a065a7..e4c387a26fd5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java @@ -19,7 +19,10 @@ package com.android.systemui.keyguard; import static android.app.ActivityManager.TaskDescription; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.ColorInt; @@ -36,7 +39,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.keyguard.WorkLockActivity; import org.junit.Before; import org.junit.Test; @@ -112,4 +114,11 @@ public class WorkLockActivityTest extends SysuiTestCase { .putExtra(Intent.EXTRA_USER_ID, USER_ID)); assertEquals(orgColor, mActivity.getPrimaryColor()); } + + @Test + public void testUnregisteredFromDispatcher() { + mActivity.unregisterBroadcastReceiver(); + verify(mBroadcastDispatcher).unregisterReceiver(any()); + verify(mContext, never()).unregisterReceiver(any()); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 5e6c96313d36..d17c573515f5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -226,7 +226,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { any(NotificationMenuRowPlugin.MenuItem.class)); reset(listener); - mGroupRow.setDismissed(true); + mGroupRow.dismiss(true); mGroupRow.doLongClickCallback(0,0); verify(listener, times(0)).onLongPress(eq(mGroupRow), eq(0), eq(0), any(NotificationMenuRowPlugin.MenuItem.class)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index c21e3ab079ff..ecb2d8190cfc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -107,6 +107,7 @@ import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateControllerImpl; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; @@ -134,7 +135,6 @@ import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; -import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Test; @@ -208,7 +208,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private PulseExpansionHandler mPulseExpansionHandler; @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator; @Mock private KeyguardBypassController mKeyguardBypassController; - @Mock private InjectionInflationController mInjectionInflationController; @Mock private DynamicPrivacyController mDynamicPrivacyController; @Mock private NewNotifPipeline mNewNotifPipeline; @Mock private ZenModeController mZenModeController; @@ -234,6 +233,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private KeyguardLiftController mKeyguardLiftController; @Mock private CommandQueue mCommandQueue; @Mock private PluginManager mPluginManager; + @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory; @Before public void setup() throws Exception { @@ -309,7 +309,6 @@ public class StatusBarTest extends SysuiTestCase { mKeyguardUpdateMonitor, mStatusBarIconController, mDozeLog, - mInjectionInflationController, mPulseExpansionHandler, mNotificationWakeUpCoordinator, mKeyguardBypassController, @@ -372,7 +371,8 @@ public class StatusBarTest extends SysuiTestCase { mDozeScrimController, mCommandQueue, mPluginManager, - mRemoteInputUriController); + mRemoteInputUriController, + mSuperStatusBarViewFactory); when(mStatusBarWindowView.findViewById(R.id.lock_icon_container)).thenReturn( mLockIconContainer); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java index a21a658348c4..147edf6589e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java @@ -25,9 +25,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.IActivityManager; +import android.content.res.Resources; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; -import android.view.ViewGroup; import android.view.WindowManager; import androidx.test.filters.SmallTest; @@ -35,6 +35,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -52,13 +53,15 @@ public class StatusBarWindowControllerTest extends SysuiTestCase { @Mock private WindowManager mWindowManager; @Mock private DozeParameters mDozeParameters; - @Mock private ViewGroup mStatusBarView; + @Mock private StatusBarWindowView mStatusBarView; @Mock private IActivityManager mActivityManager; @Mock private SysuiStatusBarStateController mStatusBarStateController; @Mock private ConfigurationController mConfigurationController; @Mock private KeyguardBypassController mKeyguardBypassController; @Mock private SysuiColorExtractor mColorExtractor; @Mock ColorExtractor.GradientColors mGradientColors; + @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory; + @Mock private Resources mResources; private StatusBarWindowController mStatusBarWindowController; @@ -67,11 +70,14 @@ public class StatusBarWindowControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); when(mDozeParameters.getAlwaysOn()).thenReturn(true); when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); + when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(mStatusBarView); mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, - mConfigurationController, mKeyguardBypassController, mColorExtractor); - mStatusBarWindowController.add(mStatusBarView, 100 /* height */); + mConfigurationController, mKeyguardBypassController, mColorExtractor, + mSuperStatusBarViewFactory, mResources); + + mStatusBarWindowController.attach(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java index 20fb6599f66e..bf81325eb6f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.PulseExpansionHandler; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -72,6 +73,7 @@ public class StatusBarWindowViewTest extends SysuiTestCase { @Mock private StatusBar mStatusBar; @Mock private DozeLog mDozeLog; @Mock private DozeParameters mDozeParameters; + @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory; @Before public void setUp() { @@ -82,6 +84,8 @@ public class StatusBarWindowViewTest extends SysuiTestCase { when(mStatusBar.isDozing()).thenReturn(false); mDependency.injectTestDependency(ShadeController.class, mShadeController); + when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(mView); + mController = new StatusBarWindowViewController.Builder( new InjectionInflationController( SystemUIFactory.getInstance().getRootComponent()), @@ -98,9 +102,9 @@ public class StatusBarWindowViewTest extends SysuiTestCase { mStatusBarStateController, mDozeLog, mDozeParameters, - new CommandQueue(mContext)) + new CommandQueue(mContext), + mSuperStatusBarViewFactory) .setShadeController(mShadeController) - .setStatusBarWindowView(mView) .build(); mController.setService(mStatusBar); mController.setDragDownHelper(mDragDownHelper); diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 998572fc5679..61bfb92363bd 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -27,6 +27,7 @@ java_defaults { "androidx.annotation_annotation", "netd_aidl_interface-java", "networkstack-aidl-interfaces-java", + "android.hardware.tetheroffload.control-V1.0-java", "tethering-client", ], manifest: "AndroidManifestBase.xml", @@ -38,11 +39,39 @@ android_library { defaults: ["TetheringAndroidLibraryDefaults"], } +cc_library_shared { + name: "libtetheroffloadjni", + srcs: [ + "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp", + ], + shared_libs: [ + "libnativehelper", + "libcutils", + "android.hardware.tetheroffload.config@1.0", + ], + static_libs: [ + "liblog", + "libbase", + "libhidlbase", + "libutils", + ], + + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + "-Wthread-safety", + ], +} + // Common defaults for compiling the actual APK. java_defaults { name: "TetheringAppDefaults", platform_apis: true, privileged: true, + jni_libs: [ + "libtetheroffloadjni", + ], resource_dirs: [ "res", ], @@ -71,6 +100,8 @@ filegroup { name: "tethering-servicescore-srcs", srcs: [ "src/com/android/server/connectivity/tethering/EntitlementManager.java", + "src/com/android/server/connectivity/tethering/OffloadController.java", + "src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java", "src/com/android/server/connectivity/tethering/TetheringConfiguration.java", "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java", ], @@ -88,3 +119,11 @@ filegroup { "src/android/net/util/PrefixUtils.java", ], } + +// This group would be removed when tethering migration is done. +filegroup { + name: "tethering-jni-srcs", + srcs: [ + "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp", + ], +} diff --git a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp index 3eaf48845a2f..3eaf48845a2f 100644 --- a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp +++ b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java index a3c299814a7a..16734d83e3aa 100644 --- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java @@ -36,8 +36,8 @@ import android.net.netlink.NetlinkSocket; import android.net.util.IpUtils; import android.net.util.SharedLog; import android.os.Handler; -import android.os.Looper; import android.os.INetworkManagementService; +import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; @@ -60,7 +60,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; /** * A class to encapsulate the business logic of programming the tethering @@ -74,7 +73,7 @@ public class OffloadController { private static final String ANYIP = "0.0.0.0"; private static final ForwardedStats EMPTY_STATS = new ForwardedStats(); - private static enum UpdateType { IF_NEEDED, FORCE }; + private enum UpdateType { IF_NEEDED, FORCE }; private final Handler mHandler; private final OffloadHardwareInterface mHwInterface; @@ -128,6 +127,7 @@ public class OffloadController { } } + /** Start hardware offload. */ public boolean start() { if (started()) return true; @@ -235,6 +235,7 @@ public class OffloadController { return isStarted; } + /** Stop hardware offload. */ public void stop() { // Completely stops tethering offload. After this method is called, it is no longer safe to // call any HAL method, no callbacks from the hardware will be delivered, and any in-flight @@ -258,7 +259,9 @@ public class OffloadController { // getTetherStats() is the only function in OffloadController that can be called from // a different thread. Do not attempt to update stats by querying the offload HAL // synchronously from a different thread than our Handler thread. http://b/64771555. - Runnable updateStats = () -> { updateStatsForCurrentUpstream(); }; + Runnable updateStats = () -> { + updateStatsForCurrentUpstream(); + }; if (Looper.myLooper() == mHandler.getLooper()) { updateStats.run(); } else { @@ -358,6 +361,7 @@ public class OffloadController { } } + /** Set current tethering upstream LinkProperties. */ public void setUpstreamLinkProperties(LinkProperties lp) { if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return; @@ -376,6 +380,7 @@ public class OffloadController { pushUpstreamParameters(prevUpstream); } + /** Set local prefixes. */ public void setLocalPrefixes(Set<IpPrefix> localPrefixes) { mExemptPrefixes = localPrefixes; @@ -383,6 +388,7 @@ public class OffloadController { computeAndPushLocalPrefixes(UpdateType.IF_NEEDED); } + /** Update current downstream LinkProperties. */ public void notifyDownstreamLinkProperties(LinkProperties lp) { final String ifname = lp.getInterfaceName(); final LinkProperties oldLp = mDownstreams.put(ifname, new LinkProperties(lp)); @@ -421,6 +427,7 @@ public class OffloadController { } } + /** Remove downstream interface from offload hardware. */ public void removeDownstreamInterface(String ifname) { final LinkProperties lp = mDownstreams.remove(ifname); if (lp == null) return; @@ -481,7 +488,7 @@ public class OffloadController { iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways)); if (!success) { - return success; + return success; } // Update stats after we've told the hardware to change routing so we don't miss packets. @@ -545,6 +552,7 @@ public class OffloadController { return false; } + /** Dump information. */ public void dump(IndentingPrintWriter pw) { if (isOffloadDisabled()) { pw.println("Offload disabled"); @@ -630,7 +638,7 @@ public class OffloadController { if (ip instanceof Inet4Address) { return (Inet4Address) ip; } - } catch (IllegalArgumentException iae) {} + } catch (IllegalArgumentException iae) { } return null; } diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java index 207f86762b95..01339a4a2c33 100644 --- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java @@ -23,9 +23,9 @@ import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; +import android.net.util.SharedLog; import android.os.Handler; import android.os.RemoteException; -import android.net.util.SharedLog; import android.system.OsConstants; import java.util.ArrayList; @@ -55,18 +55,34 @@ public class OffloadHardwareInterface { private TetheringOffloadCallback mTetheringOffloadCallback; private ControlCallback mControlCallback; + /** The callback to notify status of offload management process. */ public static class ControlCallback { + /** Offload started. */ public void onStarted() {} + /** + * Offload stopped because an error has occurred in lower layer. + */ public void onStoppedError() {} + /** + * Offload stopped because the device has moved to a bearer on which hardware offload is + * not supported. Subsequent calls to setUpstreamParameters and add/removeDownstream will + * likely fail and cannot be presumed to be saved inside of the hardware management process. + * Upon receiving #onSupportAvailable(), the caller should reprogram the hardware to begin + * offload again. + */ public void onStoppedUnsupported() {} + /** Indicate that offload is able to proivde support for this time. */ public void onSupportAvailable() {} + /** Offload stopped because of usage limit reached. */ public void onStoppedLimitReached() {} + /** Indicate to update NAT timeout. */ public void onNatTimeoutUpdate(int proto, String srcAddr, int srcPort, String dstAddr, int dstPort) {} } + /** The object which records Tx/Rx forwarded bytes. */ public static class ForwardedStats { public long rxBytes; public long txBytes; @@ -76,11 +92,13 @@ public class OffloadHardwareInterface { txBytes = 0; } + /** Add Tx/Rx bytes. */ public void add(ForwardedStats other) { rxBytes += other.rxBytes; txBytes += other.txBytes; } + /** Returns the string representation of this object. */ public String toString() { return String.format("rx:%s tx:%s", rxBytes, txBytes); } @@ -91,14 +109,17 @@ public class OffloadHardwareInterface { mLog = log.forSubComponent(TAG); } + /** Get default value indicating whether offload is supported. */ public int getDefaultTetherOffloadDisabled() { return DEFAULT_TETHER_OFFLOAD_DISABLED; } + /** Configure offload management process. */ public boolean initOffloadConfig() { return configOffload(); } + /** Initialize the tethering offload HAL. */ public boolean initOffloadControl(ControlCallback controlCb) { mControlCallback = controlCb; @@ -125,8 +146,8 @@ public class OffloadHardwareInterface { mOffloadControl.initOffload( mTetheringOffloadCallback, (boolean success, String errMsg) -> { - results.success = success; - results.errMsg = errMsg; + results.mSuccess = success; + results.mErrMsg = errMsg; }); } catch (RemoteException e) { record(logmsg, e); @@ -134,9 +155,10 @@ public class OffloadHardwareInterface { } record(logmsg, results); - return results.success; + return results.mSuccess; } + /** Stop IOffloadControl. */ public void stopOffloadControl() { if (mOffloadControl != null) { try { @@ -154,6 +176,7 @@ public class OffloadHardwareInterface { mLog.log("stopOffloadControl()"); } + /** Get Tx/Rx usage from last query. */ public ForwardedStats getForwardedStats(String upstream) { final String logmsg = String.format("getForwardedStats(%s)", upstream); @@ -174,6 +197,7 @@ public class OffloadHardwareInterface { return stats; } + /** Set local prefixes to offload management process. */ public boolean setLocalPrefixes(ArrayList<String> localPrefixes) { final String logmsg = String.format("setLocalPrefixes([%s])", String.join(",", localPrefixes)); @@ -182,8 +206,8 @@ public class OffloadHardwareInterface { try { mOffloadControl.setLocalPrefixes(localPrefixes, (boolean success, String errMsg) -> { - results.success = success; - results.errMsg = errMsg; + results.mSuccess = success; + results.mErrMsg = errMsg; }); } catch (RemoteException e) { record(logmsg, e); @@ -191,9 +215,10 @@ public class OffloadHardwareInterface { } record(logmsg, results); - return results.success; + return results.mSuccess; } + /** Set data limit value to offload management process. */ public boolean setDataLimit(String iface, long limit) { final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit); @@ -203,8 +228,8 @@ public class OffloadHardwareInterface { mOffloadControl.setDataLimit( iface, limit, (boolean success, String errMsg) -> { - results.success = success; - results.errMsg = errMsg; + results.mSuccess = success; + results.mErrMsg = errMsg; }); } catch (RemoteException e) { record(logmsg, e); @@ -212,9 +237,10 @@ public class OffloadHardwareInterface { } record(logmsg, results); - return results.success; + return results.mSuccess; } + /** Set upstream parameters to offload management process. */ public boolean setUpstreamParameters( String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) { iface = (iface != null) ? iface : NO_INTERFACE_NAME; @@ -230,8 +256,8 @@ public class OffloadHardwareInterface { mOffloadControl.setUpstreamParameters( iface, v4addr, v4gateway, v6gws, (boolean success, String errMsg) -> { - results.success = success; - results.errMsg = errMsg; + results.mSuccess = success; + results.mErrMsg = errMsg; }); } catch (RemoteException e) { record(logmsg, e); @@ -239,9 +265,10 @@ public class OffloadHardwareInterface { } record(logmsg, results); - return results.success; + return results.mSuccess; } + /** Add downstream prefix to offload management process. */ public boolean addDownstreamPrefix(String ifname, String prefix) { final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix); @@ -249,8 +276,8 @@ public class OffloadHardwareInterface { try { mOffloadControl.addDownstream(ifname, prefix, (boolean success, String errMsg) -> { - results.success = success; - results.errMsg = errMsg; + results.mSuccess = success; + results.mErrMsg = errMsg; }); } catch (RemoteException e) { record(logmsg, e); @@ -258,9 +285,10 @@ public class OffloadHardwareInterface { } record(logmsg, results); - return results.success; + return results.mSuccess; } + /** Remove downstream prefix from offload management process. */ public boolean removeDownstreamPrefix(String ifname, String prefix) { final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix); @@ -268,8 +296,8 @@ public class OffloadHardwareInterface { try { mOffloadControl.removeDownstream(ifname, prefix, (boolean success, String errMsg) -> { - results.success = success; - results.errMsg = errMsg; + results.mSuccess = success; + results.mErrMsg = errMsg; }); } catch (RemoteException e) { record(logmsg, e); @@ -277,7 +305,7 @@ public class OffloadHardwareInterface { } record(logmsg, results); - return results.success; + return results.mSuccess; } private void record(String msg, Throwable t) { @@ -286,7 +314,7 @@ public class OffloadHardwareInterface { private void record(String msg, CbResults results) { final String logmsg = msg + YIELDS + results; - if (!results.success) { + if (!results.mSuccess) { mLog.e(logmsg); } else { mLog.log(logmsg); @@ -298,7 +326,7 @@ public class OffloadHardwareInterface { public final ControlCallback controlCb; public final SharedLog log; - public TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) { + TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) { handler = h; controlCb = cb; log = sharedLog; @@ -332,7 +360,7 @@ public class OffloadHardwareInterface { @Override public void updateTimeout(NatTimeoutUpdate params) { handler.post(() -> { - controlCb.onNatTimeoutUpdate( + controlCb.onNatTimeoutUpdate( networkProtocolToOsConstant(params.proto), params.src.addr, uint16(params.src.port), params.dst.addr, uint16(params.dst.port)); @@ -352,15 +380,15 @@ public class OffloadHardwareInterface { } private static class CbResults { - boolean success; - String errMsg; + boolean mSuccess; + String mErrMsg; @Override public String toString() { - if (success) { + if (mSuccess) { return "ok"; } else { - return "fail: " + errMsg; + return "fail: " + mErrMsg; } } } diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp index 7c06e5f0d7ce..363be18a73bc 100644 --- a/packages/Tethering/tests/unit/Android.bp +++ b/packages/Tethering/tests/unit/Android.bp @@ -25,6 +25,7 @@ android_test { static_libs: [ "androidx.test.rules", "frameworks-base-testutils", + "net-tests-utils", "mockito-target-extended-minus-junit4", "TetheringApiCurrentLib", "testables", @@ -46,6 +47,7 @@ filegroup { name: "tethering-tests-src", srcs: [ "src/com/android/server/connectivity/tethering/EntitlementManagerTest.java", + "src/com/android/server/connectivity/tethering/OffloadControllerTest.java", "src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java", "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java", "src/android/net/dhcp/DhcpServingParamsParcelExtTest.java", diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java index 9931aec01487..8574f5401496 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java @@ -26,10 +26,10 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; import static com.android.testutils.MiscAssertsKt.assertContainsAll; +import static com.android.testutils.MiscAssertsKt.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyObject; @@ -148,10 +148,8 @@ public class OffloadControllerTest { public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception { setupFunctioningHardwareInterface(); when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1); - try { - Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED); - fail(); - } catch (SettingNotFoundException expected) {} + assertThrows(SettingNotFoundException.class, () -> + Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED)); final OffloadController offload = makeOffloadController(); offload.start(); @@ -168,10 +166,8 @@ public class OffloadControllerTest { public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception { setupFunctioningHardwareInterface(); when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0); - try { - Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED); - fail(); - } catch (SettingNotFoundException expected) {} + assertThrows(SettingNotFoundException.class, () -> + Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED)); final OffloadController offload = makeOffloadController(); offload.start(); diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java index 5b0de5e2aae0..0a735029eead 100644 --- a/services/core/java/com/android/server/AlarmManagerInternal.java +++ b/services/core/java/com/android/server/AlarmManagerInternal.java @@ -16,6 +16,8 @@ package com.android.server; +import android.app.PendingIntent; + public interface AlarmManagerInternal { // Some other components in the system server need to know about // broadcast alarms currently in flight @@ -30,4 +32,10 @@ public interface AlarmManagerInternal { boolean isIdling(); public void removeAlarmsForUid(int uid); public void registerInFlightListener(InFlightListener callback); + + /** + * Removes any alarm with the given pending intent with equality determined using + * {@link android.app.PendingIntent#equals(java.lang.Object) PendingIntent.equals} + */ + void remove(PendingIntent rec); } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index e757b4e1a070..e4d477a03afc 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -213,7 +213,6 @@ class AlarmManagerService extends SystemService { IAlarmListener mTimeTickTrigger; PendingIntent mDateChangeSender; Random mRandom; - PendingIntent.CancelListener mOperationCancelListener; boolean mInteractive = true; long mNonInteractiveStartTime; long mNonInteractiveTime; @@ -1460,7 +1459,6 @@ class AlarmManagerService extends SystemService { synchronized (mLock) { mHandler = new AlarmHandler(); - mOperationCancelListener = (intent) -> removeImpl(intent, null); mConstants = new Constants(mHandler); mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW); @@ -1715,9 +1713,6 @@ class AlarmManagerService extends SystemService { } else { maxElapsed = triggerElapsed + windowLength; } - if (operation != null) { - operation.registerCancelListener(mOperationCancelListener); - } synchronized (mLock) { if (DEBUG_BATCH) { Slog.v(TAG, "set(" + operation + ") : type=" + type @@ -1730,8 +1725,6 @@ class AlarmManagerService extends SystemService { "Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID + " reached for uid: " + UserHandle.formatUid(callingUid) + ", callingPackage: " + callingPackage; - mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER, - operation).sendToTarget(); Slog.w(TAG, errorMsg); throw new IllegalStateException(errorMsg); } @@ -1752,8 +1745,6 @@ class AlarmManagerService extends SystemService { if (ActivityManager.getService().isAppStartModeDisabled(callingUid, callingPackage)) { Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a + " -- package not allowed to start"); - mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER, - operation).sendToTarget(); return; } } catch (RemoteException e) { @@ -1970,6 +1961,11 @@ class AlarmManagerService extends SystemService { } @Override + public void remove(PendingIntent pi) { + mHandler.obtainMessage(AlarmHandler.REMOVE_FOR_CANCELED, pi).sendToTarget(); + } + + @Override public void registerInFlightListener(InFlightListener callback) { synchronized (mLock) { mInFlightListeners.add(callback); @@ -2074,8 +2070,6 @@ class AlarmManagerService extends SystemService { synchronized (mLock) { removeLocked(operation, listener); } - mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER, - operation).sendToTarget(); } @Override @@ -4078,7 +4072,7 @@ class AlarmManagerService extends SystemService { public static final int APP_STANDBY_BUCKET_CHANGED = 5; public static final int CHARGING_STATUS_CHANGED = 6; public static final int REMOVE_FOR_STOPPED = 7; - public static final int UNREGISTER_CANCEL_LISTENER = 8; + public static final int REMOVE_FOR_CANCELED = 8; AlarmHandler() { super(Looper.myLooper()); @@ -4161,10 +4155,10 @@ class AlarmManagerService extends SystemService { } break; - case UNREGISTER_CANCEL_LISTENER: - final PendingIntent pi = (PendingIntent) msg.obj; - if (pi != null) { - pi.unregisterCancelListener(mOperationCancelListener); + case REMOVE_FOR_CANCELED: + final PendingIntent operation = (PendingIntent) msg.obj; + synchronized (mLock) { + removeLocked(operation, null); } break; @@ -4644,11 +4638,6 @@ class AlarmManagerService extends SystemService { Intent.EXTRA_ALARM_COUNT, alarm.count), mDeliveryTracker, mHandler, null, allowWhileIdle ? mIdleOptions : null); - if (alarm.repeatInterval == 0) { - // Keep the listener for repeating alarms until they get cancelled - mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER, - alarm.operation).sendToTarget(); - } } catch (PendingIntent.CanceledException e) { if (alarm.repeatInterval > 0) { // This IntentSender is no longer valid, but this diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 39f039af330c..e1f65979bec3 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -43,7 +43,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; import android.content.res.Resources; -import android.database.ContentObserver; import android.hardware.location.ActivityRecognitionHardware; import android.location.Address; import android.location.Criteria; @@ -79,7 +78,6 @@ import android.os.WorkSource.WorkChain; import android.provider.Settings; import android.stats.location.LocationStatsEnums; import android.text.TextUtils; -import android.util.ArraySet; import android.util.EventLog; import android.util.Log; import android.util.Slog; @@ -99,12 +97,12 @@ import com.android.server.location.CallerIdentity; import com.android.server.location.GeocoderProxy; import com.android.server.location.GeofenceManager; import com.android.server.location.GeofenceProxy; -import com.android.server.location.LocationBlacklist; import com.android.server.location.LocationFudger; import com.android.server.location.LocationProviderProxy; import com.android.server.location.LocationRequestStatistics; import com.android.server.location.LocationRequestStatistics.PackageProviderKey; import com.android.server.location.LocationRequestStatistics.PackageStatistics; +import com.android.server.location.LocationSettingsStore; import com.android.server.location.MockProvider; import com.android.server.location.PassiveProvider; import com.android.server.pm.permission.PermissionManagerServiceInternal; @@ -183,13 +181,6 @@ public class LocationManagerService extends ILocationManager.Stub { private static final int FOREGROUND_IMPORTANCE_CUTOFF = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; - // default background throttling interval if not overriden in settings - private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000; - - // Default value for maximum age of last location returned to applications with foreground-only - // location permissions. - private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000; - // Location Providers may sometimes deliver location updates // slightly faster that requested - provide grace period so // we don't unnecessarily filter events that are otherwise on @@ -208,13 +199,14 @@ public class LocationManagerService extends ILocationManager.Stub { private ActivityManager mActivityManager; private UserManager mUserManager; + private LocationSettingsStore mSettingsStore; + private GeofenceManager mGeofenceManager; private LocationFudger mLocationFudger; private GeocoderProxy mGeocodeProvider; @Nullable private GnssManagerService mGnssManagerService; private PassiveProvider mPassiveProvider; // track passive provider for special cases - private LocationBlacklist mBlacklist; @GuardedBy("mLock") private String mExtraLocationControllerPackage; private boolean mExtraLocationControllerPackageEnabled; @@ -245,10 +237,6 @@ public class LocationManagerService extends ILocationManager.Stub { private final HashMap<String, Location> mLastLocationCoarseInterval = new HashMap<>(); - private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>(); - - private final ArraySet<String> mIgnoreSettingsPackageWhitelist = new ArraySet<>(); - // current active user on the device - other users are denied location data private int mCurrentUserId = UserHandle.USER_SYSTEM; private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM}; @@ -287,16 +275,19 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") private void initializeLocked() { - mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mPackageManager = mContext.getPackageManager(); - mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); - mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + mAppOps = mContext.getSystemService(AppOpsManager.class); + mPowerManager = mContext.getSystemService(PowerManager.class); + mActivityManager = mContext.getSystemService(ActivityManager.class); + mUserManager = mContext.getSystemService(UserManager.class); + + mSettingsStore = new LocationSettingsStore(mContext, mHandler); mLocationFudger = new LocationFudger(mContext, mHandler); - mBlacklist = new LocationBlacklist(mContext, mHandler); - mBlacklist.init(); - mGeofenceManager = new GeofenceManager(mContext, mBlacklist); + mGeofenceManager = new GeofenceManager(mContext, mSettingsStore); + + PowerManagerInternal localPowerManager = + LocalServices.getService(PowerManagerInternal.class); // prepare providers initializeProvidersLocked(); @@ -327,7 +318,6 @@ public class LocationManagerService extends ILocationManager.Stub { } }); }); - mActivityManager.addOnUidImportanceListener( (uid, importance) -> { // listener invoked on ui thread, move to our thread to reduce risk of blocking @@ -339,63 +329,7 @@ public class LocationManagerService extends ILocationManager.Stub { }); }, FOREGROUND_IMPORTANCE_CUTOFF); - mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), true, - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - synchronized (mLock) { - onLocationModeChangedLocked(true); - } - } - }, UserHandle.USER_ALL); - mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true, - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - synchronized (mLock) { - onProviderAllowedChangedLocked(); - } - } - }, UserHandle.USER_ALL); - mContext.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS), - true, - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - synchronized (mLock) { - onBackgroundThrottleIntervalChangedLocked(); - } - } - }, UserHandle.USER_ALL); - mContext.getContentResolver().registerContentObserver( - Settings.Global.getUriFor( - Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST), - true, - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - synchronized (mLock) { - onBackgroundThrottleWhitelistChangedLocked(); - } - } - }, UserHandle.USER_ALL); - mContext.getContentResolver().registerContentObserver( - Settings.Global.getUriFor( - Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST), - true, - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - synchronized (mLock) { - onIgnoreSettingsWhitelistChangedLocked(); - } - } - }, UserHandle.USER_ALL); - PowerManagerInternal localPowerManager = - LocalServices.getService(PowerManagerInternal.class); + localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION, state -> { // listener invoked on ui thread, move to our thread to reduce risk of blocking @@ -406,6 +340,33 @@ public class LocationManagerService extends ILocationManager.Stub { } }); }); + mBatterySaverMode = mPowerManager.getLocationPowerSaveMode(); + + mSettingsStore.addOnLocationEnabledChangedListener(() -> { + synchronized (mLock) { + onLocationModeChangedLocked(true); + } + }); + mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> { + synchronized (mLock) { + onProviderAllowedChangedLocked(); + } + }); + mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> { + synchronized (mLock) { + onBackgroundThrottleIntervalChangedLocked(); + } + }); + mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> { + synchronized (mLock) { + onBackgroundThrottleWhitelistChangedLocked(); + } + }); + mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> { + synchronized (mLock) { + onIgnoreSettingsWhitelistChangedLocked(); + } + }); new PackageMonitor() { @Override @@ -453,11 +414,6 @@ public class LocationManagerService extends ILocationManager.Stub { // provider initialization, and propagates changes until a steady state is reached mCurrentUserId = UserHandle.USER_NULL; onUserChangedLocked(ActivityManager.getCurrentUser()); - - // initialize in-memory settings values - onBackgroundThrottleWhitelistChangedLocked(); - onIgnoreSettingsWhitelistChangedLocked(); - onBatterySaverModeChangedLocked(mPowerManager.getLocationPowerSaveMode()); } @GuardedBy("mLock") @@ -479,6 +435,10 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") private void onBatterySaverModeChangedLocked(int newLocationMode) { + if (mBatterySaverMode == newLocationMode) { + return; + } + if (D) { Slog.d(TAG, "Battery Saver location mode changed from " @@ -486,11 +446,8 @@ public class LocationManagerService extends ILocationManager.Stub { + locationPowerSaveModeToString(newLocationMode)); } - if (mBatterySaverMode == newLocationMode) { - return; - } - mBatterySaverMode = newLocationMode; + for (LocationProvider p : mProviders) { applyRequirementsLocked(p); } @@ -588,17 +545,6 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") private void onBackgroundThrottleWhitelistChangedLocked() { - mBackgroundThrottlePackageWhitelist.clear(); - mBackgroundThrottlePackageWhitelist.addAll( - SystemConfig.getInstance().getAllowUnthrottledLocation()); - - String setting = Settings.Global.getString( - mContext.getContentResolver(), - Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST); - if (!TextUtils.isEmpty(setting)) { - mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(","))); - } - for (LocationProvider p : mProviders) { applyRequirementsLocked(p); } @@ -606,17 +552,6 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("lock") private void onIgnoreSettingsWhitelistChangedLocked() { - mIgnoreSettingsPackageWhitelist.clear(); - mIgnoreSettingsPackageWhitelist.addAll( - SystemConfig.getInstance().getAllowIgnoreLocationSettings()); - - String setting = Settings.Global.getString( - mContext.getContentResolver(), - Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST); - if (!TextUtils.isEmpty(setting)) { - mIgnoreSettingsPackageWhitelist.addAll(Arrays.asList(setting.split(","))); - } - for (LocationProvider p : mProviders) { applyRequirementsLocked(p); } @@ -859,8 +794,6 @@ public class LocationManagerService extends ILocationManager.Stub { mCurrentUserId = userId; onUserProfilesChangedLocked(); - mBlacklist.switchUser(userId); - // if the user changes, per-user settings may also have changed onLocationModeChangedLocked(false); onProviderAllowedChangedLocked(); @@ -1083,11 +1016,8 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") public void onAllowedChangedLocked() { if (mIsManagedBySettings) { - String allowedProviders = Settings.Secure.getStringForUser( - mContext.getContentResolver(), - Settings.Secure.LOCATION_PROVIDERS_ALLOWED, - mCurrentUserId); - boolean allowed = TextUtils.delimitedStringContains(allowedProviders, ',', mName); + boolean allowed = mSettingsStore.getLocationProvidersAllowed( + mCurrentUserId).contains(mName); if (allowed == mAllowed) { return; @@ -1909,10 +1839,7 @@ public class LocationManagerService extends ILocationManager.Stub { long identity = Binder.clearCallingIdentity(); try { - backgroundThrottleInterval = Settings.Global.getLong( - mContext.getContentResolver(), - Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS, - DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS); + backgroundThrottleInterval = mSettingsStore.getBackgroundThrottleIntervalMs(); } finally { Binder.restoreCallingIdentity(identity); } @@ -2032,16 +1959,12 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public String[] getBackgroundThrottlingWhitelist() { - synchronized (mLock) { - return mBackgroundThrottlePackageWhitelist.toArray(new String[0]); - } + return mSettingsStore.getBackgroundThrottlePackageWhitelist().toArray(new String[0]); } @Override public String[] getIgnoreSettingsWhitelist() { - synchronized (mLock) { - return mIgnoreSettingsPackageWhitelist.toArray(new String[0]); - } + return mSettingsStore.getIgnoreSettingsPackageWhitelist().toArray(new String[0]); } @GuardedBy("mLock") @@ -2050,7 +1973,8 @@ public class LocationManagerService extends ILocationManager.Stub { return true; } - if (mBackgroundThrottlePackageWhitelist.contains(callerIdentity.mPackageName)) { + if (mSettingsStore.getBackgroundThrottlePackageWhitelist().contains( + callerIdentity.mPackageName)) { return true; } @@ -2064,7 +1988,7 @@ public class LocationManagerService extends ILocationManager.Stub { return false; } - if (mIgnoreSettingsPackageWhitelist.contains( + if (mSettingsStore.getIgnoreSettingsPackageWhitelist().contains( record.mReceiver.mCallerIdentity.mPackageName)) { return true; } @@ -2081,23 +2005,13 @@ public class LocationManagerService extends ILocationManager.Stub { private boolean mIsForegroundUid; private Location mLastFixBroadcast; private Throwable mStackTrace; // for debugging only + private long mExpirationRealtimeMs; /** * Note: must be constructed with lock held. */ private UpdateRecord(String provider, LocationRequest request, Receiver receiver) { - // translate expireIn value into expireAt - long elapsedRealtime = SystemClock.elapsedRealtime(); - long expireAt; - // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0): - if (request.getExpireIn() > Long.MAX_VALUE - elapsedRealtime) { - expireAt = Long.MAX_VALUE; - } else { - expireAt = Math.max(request.getExpireIn() + elapsedRealtime, 0); - } - request.setExpireAt(Math.min(request.getExpireAt(), expireAt)); - request.setExpireIn(Long.MAX_VALUE); - + mExpirationRealtimeMs = request.getExpirationRealtimeMs(SystemClock.elapsedRealtime()); mProvider = provider; mRealRequest = request; mRequest = request; @@ -2472,7 +2386,8 @@ public class LocationManagerService extends ILocationManager.Stub { final int uid = Binder.getCallingUid(); final long identity = Binder.clearCallingIdentity(); try { - if (mBlacklist.isBlacklisted(packageName)) { + if (mSettingsStore.isLocationPackageBlacklisted(UserHandle.getUserId(uid), + packageName)) { if (D) { Log.d(TAG, "not returning last loc for blacklisted app: " + packageName); @@ -2513,10 +2428,7 @@ public class LocationManagerService extends ILocationManager.Stub { String op = resolutionLevelToOpStr(allowedResolutionLevel); long locationAgeMs = TimeUnit.NANOSECONDS.toMillis( SystemClock.elapsedRealtime() - location.getElapsedRealtimeNanos()); - if ((locationAgeMs > Settings.Global.getLong( - mContext.getContentResolver(), - Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS, - DEFAULT_LAST_LOCATION_MAX_AGE_MS)) + if (locationAgeMs > mSettingsStore.getMaxLastLocationAgeMs() && (mAppOps.unsafeCheckOp(op, uid, packageName) == AppOpsManager.MODE_FOREGROUND)) { return null; @@ -2575,11 +2487,7 @@ public class LocationManagerService extends ILocationManager.Stub { boolean foreground = LocationManagerServiceUtils.isImportanceForeground( mActivityManager.getPackageImportance(packageName)); if (!foreground) { - long backgroundThrottleIntervalMs = Settings.Global.getLong( - mContext.getContentResolver(), - Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS, - DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS); - if (locationAgeMs < backgroundThrottleIntervalMs) { + if (locationAgeMs < mSettingsStore.getBackgroundThrottleIntervalMs()) { // not allowed to request new locations, so we can't return anything return false; } @@ -2910,11 +2818,7 @@ public class LocationManagerService extends ILocationManager.Stub { long identity = Binder.clearCallingIdentity(); try { - return Settings.Secure.getIntForUser( - mContext.getContentResolver(), - Settings.Secure.LOCATION_MODE, - Settings.Secure.LOCATION_MODE_OFF, - userId) != Settings.Secure.LOCATION_MODE_OFF; + return mSettingsStore.isLocationEnabled(userId); } finally { Binder.restoreCallingIdentity(identity); } @@ -2969,7 +2873,7 @@ public class LocationManagerService extends ILocationManager.Stub { } // Check whether the expiry date has passed - return record.mRealRequest.getExpireAt() >= now; + return record.mExpirationRealtimeMs >= now; } @GuardedBy("mLock") @@ -3050,7 +2954,8 @@ public class LocationManagerService extends ILocationManager.Stub { continue; } - if (mBlacklist.isBlacklisted(receiver.mCallerIdentity.mPackageName)) { + if (mSettingsStore.isLocationPackageBlacklisted(receiverUserId, + receiver.mCallerIdentity.mPackageName)) { if (D) { Log.d(TAG, "skipping loc update for blacklisted app: " + receiver.mCallerIdentity.mPackageName); @@ -3100,7 +3005,7 @@ public class LocationManagerService extends ILocationManager.Stub { } // track expired records - if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) { + if (r.mRealRequest.getNumUpdates() <= 0 || r.mExpirationRealtimeMs < now) { // notify the client it can remove this listener r.mReceiver.callRemovedLocked(); if (deadUpdateRecords == null) { @@ -3392,33 +3297,11 @@ public class LocationManagerService extends ILocationManager.Stub { ipw.decreaseIndent(); } - if (mBlacklist != null) { - mBlacklist.dump(ipw); - } - if (mExtraLocationControllerPackage != null) { ipw.println("Location Controller Extra Package: " + mExtraLocationControllerPackage + (mExtraLocationControllerPackageEnabled ? " [enabled]" : "[disabled]")); } - if (!mBackgroundThrottlePackageWhitelist.isEmpty()) { - ipw.println("Throttling Whitelisted Packages:"); - ipw.increaseIndent(); - for (String packageName : mBackgroundThrottlePackageWhitelist) { - ipw.println(packageName); - } - ipw.decreaseIndent(); - } - - if (!mIgnoreSettingsPackageWhitelist.isEmpty()) { - ipw.println("Bypass Whitelisted Packages:"); - ipw.increaseIndent(); - for (String packageName : mIgnoreSettingsPackageWhitelist) { - ipw.println(packageName); - } - ipw.decreaseIndent(); - } - if (mLocationFudger != null) { ipw.println("Location Fudger:"); ipw.increaseIndent(); @@ -3426,6 +3309,8 @@ public class LocationManagerService extends ILocationManager.Stub { ipw.decreaseIndent(); } + mSettingsStore.dump(fd, pw, args); + ipw.println("Location Providers:"); ipw.increaseIndent(); for (LocationProvider provider : mProviders) { diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java index d75591cc7432..df76713d58a6 100644 --- a/services/core/java/com/android/server/am/PendingIntentController.java +++ b/services/core/java/com/android/server/am/PendingIntentController.java @@ -43,6 +43,7 @@ import android.util.Slog; import com.android.internal.os.IResultReceiver; import com.android.internal.util.function.pooled.PooledLambda; +import com.android.server.AlarmManagerInternal; import com.android.server.LocalServices; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.SafeActivityOptions; @@ -293,6 +294,8 @@ public class PendingIntentController { PendingIntentController::handlePendingIntentCancelled, this, callbacks); mH.sendMessage(m); } + final AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class); + ami.remove(new PendingIntent(rec)); } private void handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks) { diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index f2f1e0286a58..8be31a6e07c2 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -1323,7 +1323,7 @@ public final class ProcessList { final int procCount = procs.size(); for (int i = 0; i < procCount; i++) { final int procUid = procs.keyAt(i); - if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) { + if (!UserHandle.isCore(procUid) || !UserHandle.isSameUser(procUid, uid)) { // Don't use an app process or different user process for system component. continue; } diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 67d358910de1..232bc08e5b5c 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -21,6 +21,7 @@ import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCE import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN; import android.Manifest; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.attention.AttentionManagerInternal; @@ -85,6 +86,10 @@ public class AttentionManagerService extends SystemService { /** If the check attention called within that period - cached value will be returned. */ private static final long STALE_AFTER_MILLIS = 5_000; + /** The size of the buffer that stores recent attention check results. */ + @VisibleForTesting + protected static final int ATTENTION_CACHE_BUFFER_SIZE = 5; + /** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */ private static final String SERVICE_ENABLED = "service_enabled"; private static String sTestAttentionServicePackage; @@ -192,7 +197,8 @@ public class AttentionManagerService extends SystemService { userState.bindLocked(); // throttle frequent requests - final AttentionCheckCache cache = userState.mAttentionCheckCache; + final AttentionCheckCache cache = userState.mAttentionCheckCacheBuffer == null ? null + : userState.mAttentionCheckCacheBuffer.getLast(); if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) { callbackInternal.onSuccess(cache.mResult, cache.mTimestamp); return true; @@ -236,9 +242,11 @@ public class AttentionManagerService extends SystemService { } synchronized (mLock) { - userState.mAttentionCheckCache = new AttentionCheckCache( - SystemClock.uptimeMillis(), result, - timestamp); + if (userState.mAttentionCheckCacheBuffer == null) { + userState.mAttentionCheckCacheBuffer = new AttentionCheckCacheBuffer(); + } + userState.mAttentionCheckCacheBuffer.add( + new AttentionCheckCache(SystemClock.uptimeMillis(), result, timestamp)); } StatsLog.write( StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED, @@ -421,7 +429,41 @@ public class AttentionManagerService extends SystemService { } } - private static final class AttentionCheckCache { + @VisibleForTesting + protected static final class AttentionCheckCacheBuffer { + private final AttentionCheckCache[] mQueue; + private int mStartIndex; + private int mSize; + + AttentionCheckCacheBuffer() { + mQueue = new AttentionCheckCache[ATTENTION_CACHE_BUFFER_SIZE]; + mStartIndex = 0; + mSize = 0; + } + + public AttentionCheckCache getLast() { + int lastIdx = (mStartIndex + mSize - 1) % ATTENTION_CACHE_BUFFER_SIZE; + return mSize == 0 ? null : mQueue[lastIdx]; + } + + public void add(@NonNull AttentionCheckCache cache) { + int nextIndex = (mStartIndex + mSize) % ATTENTION_CACHE_BUFFER_SIZE; + mQueue[nextIndex] = cache; + if (mSize == ATTENTION_CACHE_BUFFER_SIZE) { + mStartIndex++; + } else { + mSize++; + } + } + + public AttentionCheckCache get(int offset) { + return offset >= mSize ? null + : mQueue[(mStartIndex + offset) % ATTENTION_CACHE_BUFFER_SIZE]; + } + } + + @VisibleForTesting + protected static final class AttentionCheckCache { private final long mLastComputed; private final int mResult; private final long mTimestamp; @@ -463,7 +505,7 @@ public class AttentionManagerService extends SystemService { @GuardedBy("mLock") AttentionCheck mCurrentAttentionCheck; @GuardedBy("mLock") - AttentionCheckCache mAttentionCheckCache; + AttentionCheckCacheBuffer mAttentionCheckCacheBuffer; @GuardedBy("mLock") private boolean mBinding; @@ -532,13 +574,14 @@ public class AttentionManagerService extends SystemService { pw.println("is fulfilled:=" + mCurrentAttentionCheck.mIsFulfilled); pw.decreaseIndent(); } - pw.println("attention check cache:"); - if (mAttentionCheckCache != null) { - pw.increaseIndent(); - pw.println("last computed=" + mAttentionCheckCache.mLastComputed); - pw.println("timestamp=" + mAttentionCheckCache.mTimestamp); - pw.println("result=" + mAttentionCheckCache.mResult); - pw.decreaseIndent(); + if (mAttentionCheckCacheBuffer != null) { + pw.println("attention check cache:"); + for (int i = 0; i < mAttentionCheckCacheBuffer.mSize; i++) { + pw.increaseIndent(); + pw.println("timestamp=" + mAttentionCheckCacheBuffer.get(i).mTimestamp); + pw.println("result=" + mAttentionCheckCacheBuffer.get(i).mResult); + pw.decreaseIndent(); + } } } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index e285bfdcdf4c..6355af6e0b2d 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1583,12 +1583,13 @@ public class AudioService extends IAudioService.Stub setMicrophoneMuteNoCallerCheck(currentUser); } - private int rescaleIndex(int index, int srcStream, int dstStream) { - int srcRange = - mStreamStates[srcStream].getMaxIndex() - mStreamStates[srcStream].getMinIndex(); - int dstRange = - mStreamStates[dstStream].getMaxIndex() - mStreamStates[dstStream].getMinIndex(); + private int getIndexRange(int streamType) { + return (mStreamStates[streamType].getMaxIndex() - mStreamStates[streamType].getMinIndex()); + } + private int rescaleIndex(int index, int srcStream, int dstStream) { + int srcRange = getIndexRange(srcStream); + int dstRange = getIndexRange(dstStream); if (srcRange == 0) { Log.e(TAG, "rescaleIndex : index range should not be zero"); return mStreamStates[dstStream].getMinIndex(); @@ -1599,6 +1600,17 @@ public class AudioService extends IAudioService.Stub / srcRange; } + private int rescaleStep(int step, int srcStream, int dstStream) { + int srcRange = getIndexRange(srcStream); + int dstRange = getIndexRange(dstStream); + if (srcRange == 0) { + Log.e(TAG, "rescaleStep : index range should not be zero"); + return 0; + } + + return ((step * dstRange + srcRange / 2) / srcRange); + } + /////////////////////////////////////////////////////////////////////////// // IPC methods /////////////////////////////////////////////////////////////////////////// @@ -1775,7 +1787,7 @@ public class AudioService extends IAudioService.Stub } } else { // convert one UI step (+/-1) into a number of internal units on the stream alias - step = rescaleIndex(10, streamType, streamTypeAlias); + step = rescaleStep(10, streamType, streamTypeAlias); } // If either the client forces allowing ringer modes for this adjustment, diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 2c23c51216a8..67a23dd73854 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -496,8 +496,6 @@ public class InputManagerService extends IInputManager.Stub } InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); - // Give the output channel a token just for identity purposes. - inputChannels[0].setToken(new Binder()); nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId, false /*isGestureMonitor*/); inputChannels[0].dispose(); // don't need to retain the Java object reference return inputChannels[1]; @@ -528,7 +526,6 @@ public class InputManagerService extends IInputManager.Stub try { InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); InputMonitorHost host = new InputMonitorHost(inputChannels[0]); - inputChannels[0].setToken(host.asBinder()); nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId, true /*isGestureMonitor*/); return new InputMonitor(inputChannels[1], host); @@ -547,7 +544,6 @@ public class InputManagerService extends IInputManager.Stub if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); } - inputChannel.setToken(new Binder()); nativeRegisterInputChannel(mPtr, inputChannel); } @@ -2188,7 +2184,7 @@ public class InputManagerService extends IInputManager.Stub @Override public void pilferPointers() { - nativePilferPointers(mPtr, asBinder()); + nativePilferPointers(mPtr, mInputChannel.getToken()); } @Override diff --git a/services/core/java/com/android/server/location/GeofenceManager.java b/services/core/java/com/android/server/location/GeofenceManager.java index 17a21694e725..81c06d7125f9 100644 --- a/services/core/java/com/android/server/location/GeofenceManager.java +++ b/services/core/java/com/android/server/location/GeofenceManager.java @@ -18,12 +18,11 @@ package com.android.server.location; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.PendingIntent; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.database.ContentObserver; import android.location.Geofence; import android.location.Location; import android.location.LocationListener; @@ -31,13 +30,14 @@ import android.location.LocationManager; import android.location.LocationRequest; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; -import android.os.UserHandle; -import android.provider.Settings; +import android.util.Log; import android.util.Slog; +import com.android.server.FgThread; import com.android.server.LocationManagerService; import com.android.server.PendingIntentUtils; @@ -48,7 +48,7 @@ import java.util.List; public class GeofenceManager implements LocationListener, PendingIntent.OnFinished { private static final String TAG = "GeofenceManager"; - private static final boolean D = LocationManagerService.D; + private static final boolean D = Log.isLoggable(TAG, Log.DEBUG); private static final int MSG_UPDATE_FENCES = 1; @@ -64,10 +64,6 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish */ private static final long MAX_AGE_NANOS = 5 * 60 * 1000000000L; // five minutes - /** - * The default value of most frequent update interval allowed. - */ - private static final long DEFAULT_MIN_INTERVAL_MS = 30 * 60 * 1000; // 30 minutes /** * Least frequent update interval allowed. @@ -75,11 +71,13 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish private static final long MAX_INTERVAL_MS = 2 * 60 * 60 * 1000; // two hours private final Context mContext; + private final GeofenceHandler mHandler; + private final LocationManager mLocationManager; private final AppOpsManager mAppOps; private final PowerManager.WakeLock mWakeLock; - private final GeofenceHandler mHandler; - private final LocationBlacklist mBlacklist; + + private final LocationSettingsStore mSettingsStore; private final Object mLock = new Object(); @@ -113,43 +111,17 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish */ private boolean mPendingUpdate; - /** - * The actual value of most frequent update interval allowed. - */ - private long mEffectiveMinIntervalMs; - private ContentResolver mResolver; - - public GeofenceManager(Context context, LocationBlacklist blacklist) { + public GeofenceManager(Context context, LocationSettingsStore settingsStore) { mContext = context; - mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); - mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE); - PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mHandler = new GeofenceHandler(); - mBlacklist = blacklist; - mResolver = mContext.getContentResolver(); - updateMinInterval(); - mResolver.registerContentObserver( - Settings.Global.getUriFor( - Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS), - true, - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - synchronized (mLock) { - updateMinInterval(); - } - } - }, UserHandle.USER_ALL); - } + mHandler = new GeofenceHandler(FgThread.getHandler().getLooper()); - /** - * Updates the minimal location request frequency. - */ - private void updateMinInterval() { - mEffectiveMinIntervalMs = Settings.Global.getLong(mResolver, - Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS, - DEFAULT_MIN_INTERVAL_MS); + mLocationManager = mContext.getSystemService(LocationManager.class); + mAppOps = mContext.getSystemService(AppOpsManager.class); + + mWakeLock = mContext.getSystemService(PowerManager.class).newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, TAG); + + mSettingsStore = settingsStore; } public void addFence(LocationRequest request, Geofence geofence, PendingIntent intent, @@ -161,8 +133,8 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish } GeofenceState state = new GeofenceState(geofence, - request.getExpireAt(), allowedResolutionLevel, uid, packageName, featureId, - listenerIdentifier, intent); + request.getExpirationRealtimeMs(SystemClock.elapsedRealtime()), + allowedResolutionLevel, uid, packageName, featureId, listenerIdentifier, intent); synchronized (mLock) { // first make sure it doesn't already exist for (int i = mFences.size() - 1; i >= 0; i--) { @@ -294,7 +266,8 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish double minFenceDistance = Double.MAX_VALUE; boolean needUpdates = false; for (GeofenceState state : mFences) { - if (mBlacklist.isBlacklisted(state.mPackageName)) { + if (mSettingsStore.isLocationPackageBlacklisted(ActivityManager.getCurrentUser(), + state.mPackageName)) { if (D) { Slog.d(TAG, "skipping geofence processing for blacklisted app: " + state.mPackageName); @@ -340,10 +313,11 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish // Compute a location update interval based on the distance to the nearest fence. long intervalMs; if (location != null && Double.compare(minFenceDistance, Double.MAX_VALUE) != 0) { - intervalMs = (long)Math.min(MAX_INTERVAL_MS, Math.max(mEffectiveMinIntervalMs, + intervalMs = (long) Math.min(MAX_INTERVAL_MS, Math.max( + mSettingsStore.getBackgroundThrottleProximityAlertIntervalMs(), minFenceDistance * 1000 / MAX_SPEED_M_S)); } else { - intervalMs = mEffectiveMinIntervalMs; + intervalMs = mSettingsStore.getBackgroundThrottleProximityAlertIntervalMs(); } if (!mReceivingLocationUpdates || mLocationUpdateInterval != intervalMs) { mReceivingLocationUpdates = true; @@ -436,13 +410,16 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish } @Override - public void onStatusChanged(String provider, int status, Bundle extras) { } + public void onStatusChanged(String provider, int status, Bundle extras) { + } @Override - public void onProviderEnabled(String provider) { } + public void onProviderEnabled(String provider) { + } @Override - public void onProviderDisabled(String provider) { } + public void onProviderDisabled(String provider) { + } @Override public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, @@ -457,17 +434,14 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish } private final class GeofenceHandler extends Handler { - public GeofenceHandler() { - super(true /*async*/); + private GeofenceHandler(Looper looper) { + super(looper); } @Override public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_UPDATE_FENCES: { - updateFences(); - break; - } + if (msg.what == MSG_UPDATE_FENCES) { + updateFences(); } } } diff --git a/services/core/java/com/android/server/location/LocationBlacklist.java b/services/core/java/com/android/server/location/LocationBlacklist.java deleted file mode 100644 index 3f3f82871c0f..000000000000 --- a/services/core/java/com/android/server/location/LocationBlacklist.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2012 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.server.location; - -import android.content.Context; -import android.database.ContentObserver; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; -import android.util.Log; -import android.util.Slog; - -import com.android.server.LocationManagerService; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Allows applications to be blacklisted from location updates at run-time. - * - * This is a silent blacklist. Applications can still call Location Manager - * API's, but they just won't receive any locations. - */ -public final class LocationBlacklist extends ContentObserver { - private static final String TAG = "LocationBlacklist"; - private static final boolean D = LocationManagerService.D; - private static final String BLACKLIST_CONFIG_NAME = "locationPackagePrefixBlacklist"; - private static final String WHITELIST_CONFIG_NAME = "locationPackagePrefixWhitelist"; - - private final Context mContext; - private final Object mLock = new Object(); - - // all fields below synchronized on mLock - private String[] mWhitelist = new String[0]; - private String[] mBlacklist = new String[0]; - - private int mCurrentUserId = UserHandle.USER_SYSTEM; - - public LocationBlacklist(Context context, Handler handler) { - super(handler); - mContext = context; - } - - public void init() { - mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( - BLACKLIST_CONFIG_NAME), false, this, UserHandle.USER_ALL); -// mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( -// WHITELIST_CONFIG_NAME), false, this, UserHandle.USER_ALL); - reloadBlacklist(); - } - - private void reloadBlacklistLocked() { - mWhitelist = getStringArrayLocked(WHITELIST_CONFIG_NAME); - if (D) Slog.d(TAG, "whitelist: " + Arrays.toString(mWhitelist)); - mBlacklist = getStringArrayLocked(BLACKLIST_CONFIG_NAME); - if (D) Slog.d(TAG, "blacklist: " + Arrays.toString(mBlacklist)); - } - - private void reloadBlacklist() { - synchronized (mLock) { - reloadBlacklistLocked(); - } - } - - /** - * Return true if in blacklist - * (package name matches blacklist, and does not match whitelist) - */ - public boolean isBlacklisted(String packageName) { - synchronized (mLock) { - for (String black : mBlacklist) { - if (packageName.startsWith(black)) { - if (inWhitelist(packageName)) { - continue; - } else { - if (D) Log.d(TAG, "dropping location (blacklisted): " - + packageName + " matches " + black); - return true; - } - } - } - } - return false; - } - - /** - * Return true if any of packages are in whitelist - */ - private boolean inWhitelist(String pkg) { - synchronized (mLock) { - for (String white : mWhitelist) { - if (pkg.startsWith(white)) return true; - } - } - return false; - } - - @Override - public void onChange(boolean selfChange) { - reloadBlacklist(); - } - - public void switchUser(int userId) { - synchronized(mLock) { - mCurrentUserId = userId; - reloadBlacklistLocked(); - } - } - - private String[] getStringArrayLocked(String key) { - String flatString; - synchronized(mLock) { - flatString = Settings.Secure.getStringForUser(mContext.getContentResolver(), key, - mCurrentUserId); - } - if (flatString == null) { - return new String[0]; - } - String[] splitStrings = flatString.split(","); - ArrayList<String> result = new ArrayList<String>(); - for (String pkg : splitStrings) { - pkg = pkg.trim(); - if (pkg.isEmpty()) { - continue; - } - result.add(pkg); - } - return result.toArray(new String[result.size()]); - } - - public void dump(PrintWriter pw) { - pw.println("mWhitelist=" + Arrays.toString(mWhitelist) + " mBlacklist=" + - Arrays.toString(mBlacklist)); - } -} diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java new file mode 100644 index 000000000000..a4b6d97e9471 --- /dev/null +++ b/services/core/java/com/android/server/location/LocationSettingsStore.java @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2019 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.server.location; + +import static android.provider.Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS; +import static android.provider.Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST; +import static android.provider.Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS; +import static android.provider.Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST; +import static android.provider.Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS; +import static android.provider.Settings.Secure.LOCATION_MODE; +import static android.provider.Settings.Secure.LOCATION_MODE_OFF; +import static android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED; + +import android.app.ActivityManager; +import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.text.TextUtils; + +import com.android.internal.util.IndentingPrintWriter; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Provides accessors and listeners for all location related settings. + */ +public class LocationSettingsStore { + + private static final String LOCATION_PACKAGE_BLACKLIST = "locationPackagePrefixBlacklist"; + private static final String LOCATION_PACKAGE_WHITELIST = "locationPackagePrefixWhitelist"; + + private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000; + private static final long DEFAULT_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS = + 30 * 60 * 1000; + private static final long DEFAULT_MAX_LAST_LOCATION_AGE_MS = 20 * 60 * 1000; + + private final Context mContext; + + private final IntegerSecureSetting mLocationMode; + private final StringListCachedSecureSetting mLocationProvidersAllowed; + private final LongGlobalSetting mBackgroundThrottleIntervalMs; + private final StringListCachedSecureSetting mLocationPackageBlacklist; + private final StringListCachedSecureSetting mLocationPackageWhitelist; + private final StringListCachedGlobalSetting mBackgroundThrottlePackageWhitelist; + private final StringListCachedGlobalSetting mIgnoreSettingsPackageWhitelist; + + public LocationSettingsStore(Context context, Handler handler) { + mContext = context; + + mLocationMode = new IntegerSecureSetting(context, LOCATION_MODE, handler); + mLocationProvidersAllowed = new StringListCachedSecureSetting(context, + LOCATION_PROVIDERS_ALLOWED, handler); + mBackgroundThrottleIntervalMs = new LongGlobalSetting(context, + LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS, handler); + mLocationPackageBlacklist = new StringListCachedSecureSetting(context, + LOCATION_PACKAGE_BLACKLIST, handler); + mLocationPackageWhitelist = new StringListCachedSecureSetting(context, + LOCATION_PACKAGE_WHITELIST, handler); + mBackgroundThrottlePackageWhitelist = new StringListCachedGlobalSetting(context, + LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST, handler); + mIgnoreSettingsPackageWhitelist = new StringListCachedGlobalSetting(context, + LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST, handler); + } + + /** + * Retrieve if location is enabled or not. + */ + public boolean isLocationEnabled(int userId) { + return mLocationMode.getValueForUser(LOCATION_MODE_OFF, userId) != LOCATION_MODE_OFF; + } + + /** + * Add a listener for changes to the location enabled setting. + */ + public void addOnLocationEnabledChangedListener(Runnable listener) { + mLocationMode.addListener(listener); + } + + /** + * Remove a listener for changes to the location enabled setting. + */ + public void removeOnLocationEnabledChangedListener(Runnable listener) { + mLocationMode.addListener(listener); + } + + /** + * Retrieve the currently allowed location providers. + */ + public List<String> getLocationProvidersAllowed(int userId) { + return mLocationProvidersAllowed.getValueForUser(userId); + } + + /** + * Add a listener for changes to the currently allowed location providers. + */ + public void addOnLocationProvidersAllowedChangedListener(Runnable runnable) { + mLocationProvidersAllowed.addListener(runnable); + } + + /** + * Remove a listener for changes to the currently allowed location providers. + */ + public void removeOnLocationProvidersAllowedChangedListener(Runnable runnable) { + mLocationProvidersAllowed.removeListener(runnable); + } + + /** + * Retrieve the background throttle interval. + */ + public long getBackgroundThrottleIntervalMs() { + return mBackgroundThrottleIntervalMs.getValue(DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS); + } + + /** + * Add a listener for changes to the background throttle interval. + */ + public void addOnBackgroundThrottleIntervalChangedListener(Runnable listener) { + mBackgroundThrottleIntervalMs.addListener(listener); + } + + /** + * Remove a listener for changes to the background throttle interval. + */ + public void removeOnBackgroundThrottleIntervalChangedListener(Runnable listener) { + mBackgroundThrottleIntervalMs.removeListener(listener); + } + + /** + * Check if the given package is blacklisted for location access. + */ + public boolean isLocationPackageBlacklisted(int userId, String packageName) { + List<String> locationPackageBlacklist = mLocationPackageBlacklist.getValueForUser(userId); + if (locationPackageBlacklist.isEmpty()) { + return false; + } + + List<String> locationPackageWhitelist = mLocationPackageWhitelist.getValueForUser(userId); + for (String locationWhitelistPackage : locationPackageWhitelist) { + if (packageName.startsWith(locationWhitelistPackage)) { + return false; + } + } + + for (String locationBlacklistPackage : locationPackageBlacklist) { + if (packageName.startsWith(locationBlacklistPackage)) { + return true; + } + } + + return false; + } + + /** + * Retrieve the background throttle package whitelist. + */ + public List<String> getBackgroundThrottlePackageWhitelist() { + return mBackgroundThrottlePackageWhitelist.getValue(); + } + + /** + * Add a listener for changes to the background throttle package whitelist. + */ + public void addOnBackgroundThrottlePackageWhitelistChangedListener(Runnable listener) { + mBackgroundThrottlePackageWhitelist.addListener(listener); + } + + /** + * Remove a listener for changes to the background throttle package whitelist. + */ + public void removeOnBackgroundThrottlePackageWhitelistChangedListener(Runnable listener) { + mBackgroundThrottlePackageWhitelist.removeListener(listener); + } + + /** + * Retrieve the ignore settings package whitelist. + */ + public List<String> getIgnoreSettingsPackageWhitelist() { + return mIgnoreSettingsPackageWhitelist.getValue(); + } + + /** + * Add a listener for changes to the ignore settings package whitelist. + */ + public void addOnIgnoreSettingsPackageWhitelistChangedListener(Runnable listener) { + mIgnoreSettingsPackageWhitelist.addListener(listener); + } + + /** + * Remove a listener for changes to the ignore settings package whitelist. + */ + public void removeOnIgnoreSettingsPackageWhitelistChangedListener(Runnable listener) { + mIgnoreSettingsPackageWhitelist.removeListener(listener); + } + + /** + * Retrieve the background throttling proximity alert interval. + */ + public long getBackgroundThrottleProximityAlertIntervalMs() { + return Settings.Global.getLong(mContext.getContentResolver(), + LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS, + DEFAULT_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS); + } + + public long getMaxLastLocationAgeMs() { + return Settings.Global.getLong( + mContext.getContentResolver(), + LOCATION_LAST_LOCATION_MAX_AGE_MILLIS, + DEFAULT_MAX_LAST_LOCATION_AGE_MS); + } + + /** + * Dump info for debugging. + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + int userId = ActivityManager.getCurrentUser(); + + ipw.println("--Location Settings--"); + ipw.increaseIndent(); + + ipw.print("Location Enabled: "); + ipw.println(isLocationEnabled(userId)); + + ipw.print("Location Providers Allowed: "); + ipw.println(getLocationProvidersAllowed(userId)); + + List<String> locationPackageBlacklist = mLocationPackageBlacklist.getValueForUser(userId); + if (!locationPackageBlacklist.isEmpty()) { + ipw.println("Location Blacklisted Packages:"); + ipw.increaseIndent(); + for (String packageName : locationPackageBlacklist) { + ipw.println(packageName); + } + ipw.decreaseIndent(); + + List<String> locationPackageWhitelist = mLocationPackageWhitelist.getValueForUser( + userId); + if (!locationPackageWhitelist.isEmpty()) { + ipw.println("Location Whitelisted Packages:"); + ipw.increaseIndent(); + for (String packageName : locationPackageWhitelist) { + ipw.println(packageName); + } + ipw.decreaseIndent(); + } + } + + List<String> backgroundThrottlePackageWhitelist = + mBackgroundThrottlePackageWhitelist.getValue(); + if (!backgroundThrottlePackageWhitelist.isEmpty()) { + ipw.println("Throttling Whitelisted Packages:"); + ipw.increaseIndent(); + for (String packageName : backgroundThrottlePackageWhitelist) { + ipw.println(packageName); + } + ipw.decreaseIndent(); + } + + List<String> ignoreSettingsPackageWhitelist = mIgnoreSettingsPackageWhitelist.getValue(); + if (!ignoreSettingsPackageWhitelist.isEmpty()) { + ipw.println("Bypass Whitelisted Packages:"); + ipw.increaseIndent(); + for (String packageName : ignoreSettingsPackageWhitelist) { + ipw.println(packageName); + } + ipw.decreaseIndent(); + } + } + + private abstract static class ObservingSetting extends ContentObserver { + + private final CopyOnWriteArrayList<Runnable> mListeners; + + private ObservingSetting(Context context, String settingName, Handler handler) { + super(handler); + mListeners = new CopyOnWriteArrayList<>(); + + context.getContentResolver().registerContentObserver( + getUriFor(settingName), false, this, UserHandle.USER_ALL); + } + + public void addListener(Runnable listener) { + mListeners.add(listener); + } + + public void removeListener(Runnable listener) { + mListeners.remove(listener); + } + + protected abstract Uri getUriFor(String settingName); + + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + for (Runnable listener : mListeners) { + listener.run(); + } + } + } + + private static class IntegerSecureSetting extends ObservingSetting { + + private final Context mContext; + private final String mSettingName; + + private IntegerSecureSetting(Context context, String settingName, Handler handler) { + super(context, settingName, handler); + mContext = context; + mSettingName = settingName; + } + + public int getValueForUser(int defaultValue, int userId) { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSettingName, + defaultValue, userId); + } + + @Override + protected Uri getUriFor(String settingName) { + return Settings.Secure.getUriFor(settingName); + } + } + + private static class StringListCachedSecureSetting extends ObservingSetting { + + private final Context mContext; + private final String mSettingName; + + private int mCachedUserId = UserHandle.USER_NULL; + private List<String> mCachedValue; + + private StringListCachedSecureSetting(Context context, String settingName, + Handler handler) { + super(context, settingName, handler); + mContext = context; + mSettingName = settingName; + } + + public synchronized List<String> getValueForUser(int userId) { + if (userId != mCachedUserId) { + String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(), + mSettingName, userId); + if (TextUtils.isEmpty(setting)) { + mCachedValue = Collections.emptyList(); + } else { + mCachedValue = Arrays.asList(setting.split(",")); + } + mCachedUserId = userId; + } + + return mCachedValue; + } + + public synchronized void invalidateForUser(int userId) { + if (mCachedUserId == userId) { + mCachedUserId = UserHandle.USER_NULL; + mCachedValue = null; + } + } + + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + invalidateForUser(userId); + super.onChange(selfChange, uri, userId); + } + + @Override + protected Uri getUriFor(String settingName) { + return Settings.Secure.getUriFor(settingName); + } + } + + private static class LongGlobalSetting extends ObservingSetting { + + private final Context mContext; + private final String mSettingName; + + private LongGlobalSetting(Context context, String settingName, Handler handler) { + super(context, settingName, handler); + mContext = context; + mSettingName = settingName; + } + + public long getValue(long defaultValue) { + return Settings.Global.getLong(mContext.getContentResolver(), mSettingName, + defaultValue); + } + + @Override + protected Uri getUriFor(String settingName) { + return Settings.Global.getUriFor(settingName); + } + } + + private static class StringListCachedGlobalSetting extends ObservingSetting { + + private final Context mContext; + private final String mSettingName; + + private boolean mValid; + private List<String> mCachedValue; + + private StringListCachedGlobalSetting(Context context, String settingName, + Handler handler) { + super(context, settingName, handler); + mContext = context; + mSettingName = settingName; + } + + public synchronized List<String> getValue() { + if (!mValid) { + String setting = Settings.Global.getString(mContext.getContentResolver(), + mSettingName); + if (TextUtils.isEmpty(setting)) { + mCachedValue = Collections.emptyList(); + } else { + mCachedValue = Arrays.asList(setting.split(",")); + } + mValid = true; + } + + return mCachedValue; + } + + public synchronized void invalidate() { + mValid = false; + mCachedValue = null; + } + + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + invalidate(); + super.onChange(selfChange, uri, userId); + } + + @Override + protected Uri getUriFor(String settingName) { + return Settings.Global.getUriFor(settingName); + } + } +} diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 193e0afc529e..c25e206d9104 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -1316,7 +1316,6 @@ public class MediaSessionService extends SystemService implements Monitor { * pressed. * * @param packageName The caller's package name, obtained by Context#getPackageName() - * @param opPackageName The caller's op package name, obtained by Context#getOpPackageName() * @param sessionToken token for the session that the controller is pointing to * @param keyEvent media key event * @see #dispatchVolumeKeyEvent @@ -1330,15 +1329,15 @@ public class MediaSessionService extends SystemService implements Monitor { try { synchronized (mLock) { MediaSessionRecord record = getMediaSessionRecordLocked(sessionToken); - if (record == null) { - Log.w(TAG, "Failed to find session to dispatch key event."); - return false; - } - if (DEBUG) { + if (DEBUG_KEY_EVENT) { Log.d(TAG, "dispatchMediaKeyEventToSessionAsSystemService, pkg=" + packageName + ", pid=" + pid + ", uid=" + uid + ", sessionToken=" + sessionToken + ", event=" + keyEvent + ", session=" + record); } + if (record == null) { + Log.w(TAG, "Failed to find session to dispatch key event."); + return false; + } return record.sendMediaButton(packageName, pid, uid, true /* asSystemService */, keyEvent, 0, null); } @@ -1688,6 +1687,12 @@ public class MediaSessionService extends SystemService implements Monitor { try { synchronized (mLock) { MediaSessionRecord record = getMediaSessionRecordLocked(sessionToken); + if (DEBUG_KEY_EVENT) { + Log.d(TAG, "dispatchVolumeKeyEventToSessionAsSystemService, pkg=" + + packageName + ", opPkg=" + opPackageName + ", pid=" + pid + + ", uid=" + uid + ", sessionToken=" + sessionToken + ", event=" + + keyEvent + ", session=" + record); + } if (record == null) { Log.w(TAG, "Failed to find session to dispatch key event, token=" + sessionToken + ". Fallbacks to the default handling."); @@ -1695,12 +1700,6 @@ public class MediaSessionService extends SystemService implements Monitor { keyEvent, AudioManager.USE_DEFAULT_STREAM_TYPE, false); return; } - if (DEBUG) { - Log.d(TAG, "dispatchVolumeKeyEventToSessionAsSystemService, pkg=" - + packageName + ", opPkg=" + opPackageName + ", pid=" + pid - + ", uid=" + uid + ", sessionToken=" + sessionToken + ", event=" - + keyEvent + ", session=" + record); - } switch (keyEvent.getAction()) { case KeyEvent.ACTION_DOWN: { int direction = 0; diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index dc0cd184c188..5195a521dd17 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -211,7 +211,7 @@ public class AppsFilter { final Uri data = intent.getData(); if ("content".equalsIgnoreCase(intent.getScheme()) && data != null - && providerInfo.authority.equalsIgnoreCase(data.getAuthority())) { + && Objects.equals(providerInfo.authority, data.getAuthority())) { return true; } } diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java index 91df33a8a16f..ef6b24cd198c 100644 --- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java +++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java @@ -116,13 +116,13 @@ class UserSystemPackageInstaller { * <p>Packages that are whitelisted, but then blacklisted so that they aren't to be installed on * any user, are purposefully still present in this list. */ - private final ArrayMap<String, Integer> mWhitelitsedPackagesForUserTypes; + private final ArrayMap<String, Integer> mWhitelistedPackagesForUserTypes; private final UserManagerService mUm; UserSystemPackageInstaller(UserManagerService ums) { mUm = ums; - mWhitelitsedPackagesForUserTypes = + mWhitelistedPackagesForUserTypes = determineWhitelistedPackagesForUserTypes(SystemConfig.getInstance()); } @@ -130,7 +130,7 @@ class UserSystemPackageInstaller { @VisibleForTesting UserSystemPackageInstaller(UserManagerService ums, ArrayMap<String, Integer> whitelist) { mUm = ums; - mWhitelitsedPackagesForUserTypes = whitelist; + mWhitelistedPackagesForUserTypes = whitelist; } /** @@ -249,7 +249,7 @@ class UserSystemPackageInstaller { return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST) != 0; } - /** Gets the PackageWhitelistMode for use of {@link #mWhitelitsedPackagesForUserTypes}. */ + /** Gets the PackageWhitelistMode for use of {@link #mWhitelistedPackagesForUserTypes}. */ private @PackageWhitelistMode int getWhitelistMode() { final int runtimeMode = SystemProperties.getInt( PACKAGE_WHITELIST_MODE_PROP, USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT); @@ -290,7 +290,7 @@ class UserSystemPackageInstaller { if (!pkg.isSystem()) { return; } - if (shouldInstallPackage(pkg, mWhitelitsedPackagesForUserTypes, + if (shouldInstallPackage(pkg, mWhitelistedPackagesForUserTypes, whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) { // Although the whitelist uses manifest names, this function returns packageNames. installPackages.add(pkg.packageName); @@ -340,10 +340,10 @@ class UserSystemPackageInstaller { */ @VisibleForTesting @NonNull Set<String> getWhitelistedPackagesForUserType(int flags) { - Set<String> installablePkgs = new ArraySet<>(mWhitelitsedPackagesForUserTypes.size()); - for (int i = 0; i < mWhitelitsedPackagesForUserTypes.size(); i++) { - String pkgName = mWhitelitsedPackagesForUserTypes.keyAt(i); - int whitelistedUserTypes = mWhitelitsedPackagesForUserTypes.valueAt(i); + Set<String> installablePkgs = new ArraySet<>(mWhitelistedPackagesForUserTypes.size()); + for (int i = 0; i < mWhitelistedPackagesForUserTypes.size(); i++) { + String pkgName = mWhitelistedPackagesForUserTypes.keyAt(i); + int whitelistedUserTypes = mWhitelistedPackagesForUserTypes.valueAt(i); if ((flags & whitelistedUserTypes) != 0) { installablePkgs.add(pkgName); } @@ -360,7 +360,7 @@ class UserSystemPackageInstaller { * completely blacklists an AOSP app). */ private Set<String> getWhitelistedSystemPackages() { - return mWhitelitsedPackagesForUserTypes.keySet(); + return mWhitelistedPackagesForUserTypes.keySet(); } /** @@ -456,18 +456,28 @@ class UserSystemPackageInstaller { } void dump(PrintWriter pw) { - pw.print("Whitelisted packages per user type"); - final int size = mWhitelitsedPackagesForUserTypes.size(); + final String prefix = " "; + final int mode = getWhitelistMode(); + pw.println("Whitelisted packages per user type"); + pw.print(prefix); pw.print("Mode: "); + pw.print(mode); + pw.print(isEnforceMode(mode) ? " (enforced)" : ""); + pw.print(isLogMode(mode) ? " (logged)" : ""); + pw.print(isImplicitWhitelistMode(mode) ? " (implicit)" : ""); + pw.println(); + + final int size = mWhitelistedPackagesForUserTypes.size(); if (size == 0) { - pw.println(": N/A"); + pw.print(prefix); pw.println("No packages"); return; } - pw.println(" (" + size + " packages)"); + final String prefix2 = prefix + prefix; + pw.print(prefix); pw.print(size); pw.println(" packages:"); for (int i = 0; i < size; i++) { - final String pkgName = mWhitelitsedPackagesForUserTypes.keyAt(i); + final String pkgName = mWhitelistedPackagesForUserTypes.keyAt(i); final String whitelistedUserTypes = - UserInfo.flagsToString(mWhitelitsedPackagesForUserTypes.valueAt(i)); - pw.println(" " + pkgName + ": " + whitelistedUserTypes); + UserInfo.flagsToString(mWhitelistedPackagesForUserTypes.valueAt(i)); + pw.print(prefix2); pw.print(pkgName); pw.print(": "); pw.println(whitelistedUserTypes); } } } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index ec64ee6d52de..b6934c9ce604 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -16,7 +16,6 @@ package com.android.server.statusbar; -import android.graphics.Rect; import android.os.Bundle; import android.view.InsetsState.InternalInsetType; import android.view.WindowInsetsController.Appearance; @@ -79,9 +78,7 @@ public interface StatusBarManagerInternal { void startAssist(Bundle args); void onCameraLaunchGestureDetected(int source); void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive); - void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis, - int mask, Rect fullscreenBounds, Rect dockedBounds, boolean isNavbarColorManagedByIme, - String cause); + void setDisableFlags(int displayId, int flags, String cause); void toggleSplitScreen(); void appTransitionFinished(int displayId); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index effeb80298b8..25c41f5cdd6b 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -25,7 +25,6 @@ import android.app.Notification; import android.app.StatusBarManager; import android.content.ComponentName; import android.content.Context; -import android.graphics.Rect; import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; @@ -43,10 +42,11 @@ import android.os.UserHandle; import android.service.notification.NotificationStats; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.Log; +import android.util.ArraySet; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.view.InsetsState.InternalInsetType; import android.view.WindowInsetsController.Appearance; import com.android.internal.R; @@ -263,12 +263,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, - boolean isNavbarColorManagedByIme, String cause) { - StatusBarManagerService.this.setSystemUiVisibility(displayId, vis, fullscreenStackVis, - dockedStackVis, mask, fullscreenBounds, dockedBounds, isNavbarColorManagedByIme, - cause); + public void setDisableFlags(int displayId, int flags, String cause) { + StatusBarManagerService.this.setDisableFlags(displayId, flags, cause); } @Override @@ -473,7 +469,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void onSystemBarAppearanceChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { - // TODO (b/118118435): save the information to UiState + final UiState state = getUiState(displayId); + if (!state.appearanceEquals(appearance, appearanceRegions, navbarColorManagedByIme)) { + state.setAppearance(appearance, appearanceRegions, navbarColorManagedByIme); + } if (mBar != null) { try { mBar.onSystemBarAppearanceChanged(displayId, appearance, appearanceRegions, @@ -483,7 +482,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public void showTransient(int displayId, int[] types) { + public void showTransient(int displayId, @InternalInsetType int[] types) { + getUiState(displayId).showTransient(types); if (mBar != null) { try { mBar.showTransient(displayId, types); @@ -492,7 +492,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public void abortTransient(int displayId, int[] types) { + public void abortTransient(int displayId, @InternalInsetType int[] types) { + getUiState(displayId).clearTransient(types); if (mBar != null) { try { mBar.abortTransient(displayId, types); @@ -896,54 +897,20 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } } - @Override - public void setSystemUiVisibility(int displayId, int vis, int mask, String cause) { - final UiState state = getUiState(displayId); - setSystemUiVisibility(displayId, vis, 0, 0, mask, - state.mFullscreenStackBounds, state.mDockedStackBounds, - state.mNavbarColorManagedByIme, cause); - } - - private void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, - int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, - boolean isNavbarColorManagedByIme, String cause) { + private void setDisableFlags(int displayId, int flags, String cause) { // also allows calls from window manager which is in this process. enforceStatusBarService(); - if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")"); - - synchronized (mLock) { - updateUiVisibilityLocked(displayId, vis, fullscreenStackVis, dockedStackVis, mask, - fullscreenBounds, dockedBounds, isNavbarColorManagedByIme); - disableLocked( - displayId, - mCurrentUserId, - vis & StatusBarManager.DISABLE_MASK, - mSysUiVisToken, - cause, 1); + final int unknownFlags = flags & ~StatusBarManager.DISABLE_MASK; + if (unknownFlags != 0) { + Slog.e(TAG, "Unknown disable flags: 0x" + Integer.toHexString(unknownFlags), + new RuntimeException()); } - } - private void updateUiVisibilityLocked(final int displayId, final int vis, - final int fullscreenStackVis, final int dockedStackVis, final int mask, - final Rect fullscreenBounds, final Rect dockedBounds, - final boolean isNavbarColorManagedByIme) { - final UiState state = getUiState(displayId); - if (!state.systemUiStateEquals(vis, fullscreenStackVis, dockedStackVis, - fullscreenBounds, dockedBounds, isNavbarColorManagedByIme)) { - state.setSystemUiState(vis, fullscreenStackVis, dockedStackVis, fullscreenBounds, - dockedBounds, isNavbarColorManagedByIme); - mHandler.post(() -> { - if (mBar != null) { - try { - mBar.setSystemUiVisibility(displayId, vis, fullscreenStackVis, - dockedStackVis, mask, fullscreenBounds, dockedBounds, - isNavbarColorManagedByIme); - } catch (RemoteException ex) { - Log.w(TAG, "Can not get StatusBar!"); - } - } - }); + if (SPEW) Slog.d(TAG, "setDisableFlags(0x" + Integer.toHexString(flags) + ")"); + + synchronized (mLock) { + disableLocked(displayId, mCurrentUserId, flags, mSysUiVisToken, cause, 1); } } @@ -965,11 +932,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } private class UiState { - private int mSystemUiVisibility = 0; - private int mFullscreenStackSysUiVisibility = 0; - private int mDockedStackSysUiVisibility = 0; - private final Rect mFullscreenStackBounds = new Rect(); - private final Rect mDockedStackBounds = new Rect(); + private @Appearance int mAppearance = 0; + private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0]; + private ArraySet<Integer> mTransientBarTypes = new ArraySet<>(); + private boolean mNavbarColorManagedByIme = false; private boolean mFullscreen = false; private boolean mImmersive = false; private int mDisabled1 = 0; @@ -978,53 +944,63 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D private int mImeBackDisposition = 0; private boolean mShowImeSwitcher = false; private IBinder mImeToken = null; - private boolean mNavbarColorManagedByIme = false; - private int getDisabled1() { - return mDisabled1; + private void setAppearance(@Appearance int appearance, + AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { + mAppearance = appearance; + mAppearanceRegions = appearanceRegions; + mNavbarColorManagedByIme = navbarColorManagedByIme; } - private int getDisabled2() { - return mDisabled2; + private boolean appearanceEquals(@Appearance int appearance, + AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme) { + if (mAppearance != appearance || mAppearanceRegions.length != appearanceRegions.length + || mNavbarColorManagedByIme != navbarColorManagedByIme) { + return false; + } + for (int i = appearanceRegions.length - 1; i >= 0; i--) { + if (!mAppearanceRegions[i].equals(appearanceRegions[i])) { + return false; + } + } + return true; } - private void setDisabled(int disabled1, int disabled2) { - mDisabled1 = disabled1; - mDisabled2 = disabled2; + private void showTransient(@InternalInsetType int[] types) { + for (int type : types) { + mTransientBarTypes.add(type); + } + } + + private void clearTransient(@InternalInsetType int[] types) { + for (int type : types) { + mTransientBarTypes.remove(type); + } } private void setFullscreen(boolean isFullscreen) { mFullscreen = isFullscreen; } - private void setImmersive(boolean immersive) { - mImmersive = immersive; + private void setImmersive(boolean isImmersive) { + mImmersive = isImmersive; } - private boolean disableEquals(int disabled1, int disabled2) { - return mDisabled1 == disabled1 && mDisabled2 == disabled2; + private int getDisabled1() { + return mDisabled1; } - private void setSystemUiState(final int vis, final int fullscreenStackVis, - final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds, - final boolean navbarColorManagedByIme) { - mSystemUiVisibility = vis; - mFullscreenStackSysUiVisibility = fullscreenStackVis; - mDockedStackSysUiVisibility = dockedStackVis; - mFullscreenStackBounds.set(fullscreenBounds); - mDockedStackBounds.set(dockedBounds); - mNavbarColorManagedByIme = navbarColorManagedByIme; + private int getDisabled2() { + return mDisabled2; } - private boolean systemUiStateEquals(final int vis, final int fullscreenStackVis, - final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds, - final boolean navbarColorManagedByIme) { - return mSystemUiVisibility == vis - && mFullscreenStackSysUiVisibility == fullscreenStackVis - && mDockedStackSysUiVisibility == dockedStackVis - && mFullscreenStackBounds.equals(fullscreenBounds) - && mDockedStackBounds.equals(dockedBounds) - && mNavbarColorManagedByIme == navbarColorManagedByIme; + private void setDisabled(int disabled1, int disabled2) { + mDisabled1 = disabled1; + mDisabled2 = disabled2; + } + + private boolean disableEquals(int disabled1, int disabled2) { + return mDisabled1 == disabled1 && mDisabled2 == disabled2; } private void setImeWindowState(final int vis, final int backDisposition, @@ -1084,13 +1060,16 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // TODO(b/118592525): Currently, status bar only works on the default display. // Make it aware of multi-display if needed. final UiState state = mDisplayUiState.get(DEFAULT_DISPLAY); + final int[] transientBarTypes = new int[state.mTransientBarTypes.size()]; + for (int i = 0; i < transientBarTypes.length; i++) { + transientBarTypes[i] = state.mTransientBarTypes.valueAt(i); + } return new RegisterStatusBarResult(icons, gatherDisableActionsLocked(mCurrentUserId, 1), - state.mSystemUiVisibility, state.mImeWindowVis, + state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis, state.mImeBackDisposition, state.mShowImeSwitcher, - gatherDisableActionsLocked(mCurrentUserId, 2), - state.mFullscreenStackSysUiVisibility, state.mDockedStackSysUiVisibility, - state.mImeToken, state.mFullscreenStackBounds, state.mDockedStackBounds, - state.mNavbarColorManagedByIme, state.mFullscreen, state.mImmersive); + gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken, + state.mNavbarColorManagedByIme, state.mFullscreen, state.mImmersive, + transientBarTypes); } } diff --git a/services/core/java/com/android/server/wallpaper/GLHelper.java b/services/core/java/com/android/server/wallpaper/GLHelper.java new file mode 100644 index 000000000000..1d733f53f055 --- /dev/null +++ b/services/core/java/com/android/server/wallpaper/GLHelper.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2019 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.server.wallpaper; + +import static android.opengl.EGL14.EGL_ALPHA_SIZE; +import static android.opengl.EGL14.EGL_BLUE_SIZE; +import static android.opengl.EGL14.EGL_CONFIG_CAVEAT; +import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION; +import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY; +import static android.opengl.EGL14.EGL_DEPTH_SIZE; +import static android.opengl.EGL14.EGL_GREEN_SIZE; +import static android.opengl.EGL14.EGL_HEIGHT; +import static android.opengl.EGL14.EGL_NONE; +import static android.opengl.EGL14.EGL_NO_CONTEXT; +import static android.opengl.EGL14.EGL_NO_DISPLAY; +import static android.opengl.EGL14.EGL_NO_SURFACE; +import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT; +import static android.opengl.EGL14.EGL_RED_SIZE; +import static android.opengl.EGL14.EGL_RENDERABLE_TYPE; +import static android.opengl.EGL14.EGL_STENCIL_SIZE; +import static android.opengl.EGL14.EGL_WIDTH; +import static android.opengl.EGL14.eglChooseConfig; +import static android.opengl.EGL14.eglCreateContext; +import static android.opengl.EGL14.eglCreatePbufferSurface; +import static android.opengl.EGL14.eglDestroyContext; +import static android.opengl.EGL14.eglDestroySurface; +import static android.opengl.EGL14.eglGetDisplay; +import static android.opengl.EGL14.eglGetError; +import static android.opengl.EGL14.eglInitialize; +import static android.opengl.EGL14.eglMakeCurrent; +import static android.opengl.EGL14.eglTerminate; +import static android.opengl.GLES20.GL_MAX_TEXTURE_SIZE; +import static android.opengl.GLES20.glGetIntegerv; + +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.EGLSurface; +import android.opengl.GLUtils; +import android.os.SystemProperties; +import android.util.Log; + +class GLHelper { + private static final String TAG = GLHelper.class.getSimpleName(); + private static final int sMaxTextureSize; + + static { + int maxTextureSize = SystemProperties.getInt("sys.max_texture_size", 0); + sMaxTextureSize = maxTextureSize > 0 ? maxTextureSize : retrieveTextureSizeFromGL(); + } + + private static int retrieveTextureSizeFromGL() { + try { + String err; + + // Before we can retrieve info from GL, + // we have to create EGLContext, EGLConfig and EGLDisplay first. + // We will fail at querying info from GL once one of above failed. + // When this happens, we will use defValue instead. + EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDisplay == null || eglDisplay == EGL_NO_DISPLAY) { + err = "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + if (!eglInitialize(eglDisplay, null, 0 /* majorOffset */, null, 1 /* minorOffset */)) { + err = "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + EGLConfig eglConfig = null; + int[] configsCount = new int[1]; + EGLConfig[] configs = new EGLConfig[1]; + int[] configSpec = new int[] { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 0, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_NONE + }; + + if (!eglChooseConfig(eglDisplay, configSpec, 0 /* attrib_listOffset */, + configs, 0 /* configOffset */, 1 /* config_size */, + configsCount, 0 /* num_configOffset */)) { + err = "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } else if (configsCount[0] > 0) { + eglConfig = configs[0]; + } + + if (eglConfig == null) { + throw new RuntimeException("eglConfig not initialized!"); + } + + int[] attr_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + EGLContext eglContext = eglCreateContext( + eglDisplay, eglConfig, EGL_NO_CONTEXT, attr_list, 0 /* offset */); + + if (eglContext == null || eglContext == EGL_NO_CONTEXT) { + err = "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + // We create a push buffer temporarily for querying info from GL. + int[] attrs = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + EGLSurface eglSurface = + eglCreatePbufferSurface(eglDisplay, eglConfig, attrs, 0 /* offset */); + eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); + + // Now, we are ready to query the info from GL. + int[] maxSize = new int[1]; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0 /* offset */); + + // We have got the info we want, release all egl resources. + eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(eglDisplay, eglSurface); + eglDestroyContext(eglDisplay, eglContext); + eglTerminate(eglDisplay); + return maxSize[0]; + } catch (RuntimeException e) { + Log.w(TAG, "Retrieve from GL failed", e); + return Integer.MAX_VALUE; + } + } + + static int getMaxTextureSize() { + return sMaxTextureSize; + } +} + diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 3663f4696a27..3cc6428c792b 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -134,6 +134,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub private static final boolean DEBUG = false; private static final boolean DEBUG_LIVE = true; + // This 100MB limitation is defined in RecordingCanvas. + private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; + public static class Lifecycle extends SystemService { private IWallpaperManagerService mService; @@ -572,7 +575,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Only generate crop for default display. final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY); - Rect cropHint = new Rect(wallpaper.cropHint); + final Rect cropHint = new Rect(wallpaper.cropHint); + final DisplayInfo displayInfo = new DisplayInfo(); + mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); if (DEBUG) { Slog.v(TAG, "Generating crop for new wallpaper(s): 0x" @@ -618,12 +623,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } // scale if the crop height winds up not matching the recommended metrics - needScale = (wpData.mHeight != cropHint.height()); + needScale = wpData.mHeight != cropHint.height() + || cropHint.height() > GLHelper.getMaxTextureSize() + || cropHint.width() > GLHelper.getMaxTextureSize(); //make sure screen aspect ratio is preserved if width is scaled under screen size if (needScale) { - final DisplayInfo displayInfo = new DisplayInfo(); - mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height(); final int newWidth = (int) (cropHint.width() * scaleByHeight); if (newWidth < displayInfo.logicalWidth) { @@ -644,14 +649,29 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (!needCrop && !needScale) { // Simple case: the nominal crop fits what we want, so we take // the whole thing and just copy the image file directly. - if (DEBUG) { - Slog.v(TAG, "Null crop of new wallpaper; copying"); + + // TODO: It is not accurate to estimate bitmap size without decoding it, + // may be we can try to remove this optimized way in the future, + // that means, we will always go into the 'else' block. + + // This is just a quick estimation, may be smaller than it is. + long estimateSize = options.outWidth * options.outHeight * 4; + + // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. + // Please see: RecordingCanvas#throwIfCannotDraw. + if (estimateSize < MAX_BITMAP_SIZE) { + success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); } - success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); + if (!success) { wallpaper.cropFile.delete(); // TODO: fall back to default wallpaper in this case } + + if (DEBUG) { + Slog.v(TAG, "Null crop of new wallpaper, estimate size=" + + estimateSize + ", success=" + success); + } } else { // Fancy case: crop and scale. First, we decode and scale down if appropriate. FileOutputStream f = null; @@ -665,49 +685,78 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // We calculate the largest power-of-two under the actual ratio rather than // just let the decode take care of it because we also want to remap where the // cropHint rectangle lies in the decoded [super]rect. - final BitmapFactory.Options scaler; final int actualScale = cropHint.height() / wpData.mHeight; int scale = 1; - while (2*scale < actualScale) { + while (2 * scale <= actualScale) { scale *= 2; } - if (scale > 1) { - scaler = new BitmapFactory.Options(); - scaler.inSampleSize = scale; + options.inSampleSize = scale; + options.inJustDecodeBounds = false; + + final Rect estimateCrop = new Rect(cropHint); + estimateCrop.scale(1f / options.inSampleSize); + final float hRatio = (float) wpData.mHeight / estimateCrop.height(); + final int destHeight = (int) (estimateCrop.height() * hRatio); + final int destWidth = (int) (estimateCrop.width() * hRatio); + + // We estimated an invalid crop, try to adjust the cropHint to get a valid one. + if (destWidth > GLHelper.getMaxTextureSize()) { + int newHeight = (int) (wpData.mHeight / hRatio); + int newWidth = (int) (wpData.mWidth / hRatio); + if (DEBUG) { - Slog.v(TAG, "Downsampling cropped rect with scale " + scale); + Slog.v(TAG, "Invalid crop dimensions, trying to adjust."); } - } else { - scaler = null; + + estimateCrop.set(cropHint); + estimateCrop.left += (cropHint.width() - newWidth) / 2; + estimateCrop.top += (cropHint.height() - newHeight) / 2; + estimateCrop.right = estimateCrop.left + newWidth; + estimateCrop.bottom = estimateCrop.top + newHeight; + cropHint.set(estimateCrop); + estimateCrop.scale(1f / options.inSampleSize); + } + + // We've got the safe cropHint; now we want to scale it properly to + // the desired rectangle. + // That's a height-biased operation: make it fit the hinted height. + final int safeHeight = (int) (estimateCrop.height() * hRatio); + final int safeWidth = (int) (estimateCrop.width() * hRatio); + + if (DEBUG) { + Slog.v(TAG, "Decode parameters:"); + Slog.v(TAG, " cropHint=" + cropHint + ", estimateCrop=" + estimateCrop); + Slog.v(TAG, " down sampling=" + options.inSampleSize + + ", hRatio=" + hRatio); + Slog.v(TAG, " dest=" + destWidth + "x" + destHeight); + Slog.v(TAG, " safe=" + safeWidth + "x" + safeHeight); + Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize()); } - Bitmap cropped = decoder.decodeRegion(cropHint, scaler); + + Bitmap cropped = decoder.decodeRegion(cropHint, options); decoder.recycle(); if (cropped == null) { Slog.e(TAG, "Could not decode new wallpaper"); } else { - // We've got the extracted crop; now we want to scale it properly to - // the desired rectangle. That's a height-biased operation: make it - // fit the hinted height, and accept whatever width we end up with. - cropHint.offsetTo(0, 0); - cropHint.right /= scale; // adjust by downsampling factor - cropHint.bottom /= scale; - final float heightR = - ((float) wpData.mHeight) / ((float) cropHint.height()); - if (DEBUG) { - Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint); - } - final int destWidth = (int)(cropHint.width() * heightR); + // We are safe to create final crop with safe dimensions now. final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped, - destWidth, wpData.mHeight, true); + safeWidth, safeHeight, true); if (DEBUG) { Slog.v(TAG, "Final extract:"); Slog.v(TAG, " dims: w=" + wpData.mWidth + " h=" + wpData.mHeight); - Slog.v(TAG, " out: w=" + finalCrop.getWidth() + Slog.v(TAG, " out: w=" + finalCrop.getWidth() + " h=" + finalCrop.getHeight()); } + // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. + // Please see: RecordingCanvas#throwIfCannotDraw. + if (finalCrop.getByteCount() > MAX_BITMAP_SIZE) { + throw new RuntimeException( + "Too large bitmap, limit=" + MAX_BITMAP_SIZE); + } + f = new FileOutputStream(wallpaper.cropFile); bos = new BufferedOutputStream(f, 32*1024); finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos); @@ -1997,6 +2046,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (!isWallpaperSupported(callingPackage)) { return; } + + // Make sure both width and height are not larger than max texture size. + width = Math.min(width, GLHelper.getMaxTextureSize()); + height = Math.min(height, GLHelper.getMaxTextureSize()); + synchronized (mLock) { int userId = UserHandle.getCallingUserId(); WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index 48a7b73a5fc1..12681133d9c4 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -41,7 +41,6 @@ import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY; import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE; import static com.android.server.am.ActivityDisplayProto.STACKS; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; @@ -1523,7 +1522,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { final ActivityStack stack = getChildAt(i); final ArrayList<TaskRecord> tasks = stack.getAllTasks(); for (int j = tasks.size() - 1; j >= 0; --j) { - stack.removeTask(tasks.get(j), "removeAllTasks", REMOVE_TASK_MODE_DESTROYING); + stack.removeChild(tasks.get(j), "removeAllTasks"); } } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d4dd033f38e6..d36004101b0e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1148,56 +1148,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } - // TODO(task-unify): Remove once TaskRecord and Task are unified. TaskRecord getTaskRecord() { return task; } /** - * Sets reference to the {@link TaskRecord} the {@link ActivityRecord} will treat as its parent. - * Note that this does not actually add the {@link ActivityRecord} as a {@link TaskRecord} - * children. However, this method will clean up references to this {@link ActivityRecord} in - * {@link ActivityStack}. - * @param task The new parent {@link TaskRecord}. - */ - // TODO(task-unify): Can be remove after task level unification. Callers can just use addChild - void setTask(TaskRecord task) { - // Do nothing if the {@link TaskRecord} is the same as the current {@link getTaskRecord}. - if (task != null && task == getTaskRecord()) { - return; - } - - final ActivityStack oldStack = getActivityStack(); - final ActivityStack newStack = task != null ? task.getStack() : null; - - // Inform old stack (if present) of activity removal and new stack (if set) of activity - // addition. - if (oldStack != newStack) { - if (oldStack != null) { - oldStack.onActivityRemovedFromStack(this); - } - - if (newStack != null) { - newStack.onActivityAddedToStack(this); - } - } - - final TaskRecord oldTask = this.task; - this.task = task; - - // This is attaching the activity to the task which we only want to do once. - // TODO(task-unify): Need to re-work after unifying the task level since it will already - // have a parent then. Just need to restructure the re-parent case not to do this. NOTE that - // the reparenting flag passed in can't be used directly for this as it isn't set in - // ActivityRecord#reparent() case that ends up calling this method. - if (task != null && getParent() == null) { - task.addChild(this); - } else { - onParentChanged(task, oldTask); - } - } - - /** * Sets the Task on this activity for the purposes of re-use during launch where we will * re-use another activity instead of this one for the launch. */ @@ -1220,8 +1175,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { - final TaskRecord oldTask = (oldParent != null) ? ((Task) oldParent).mTaskRecord : null; - final TaskRecord newTask = (newParent != null) ? ((Task) newParent).mTaskRecord : null; + final TaskRecord oldTask = oldParent != null ? (TaskRecord) oldParent : null; + final TaskRecord newTask = newParent != null ? (TaskRecord) newParent : null; this.task = newTask; super.onParentChanged(newParent, oldParent); @@ -1230,14 +1185,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (oldParent == null && newParent != null) { // First time we are adding the activity to the system. - // TODO(task-unify): See if mVoiceInteraction variable is really needed after task level - // unification. - mVoiceInteraction = task.mTaskRecord != null && task.mTaskRecord.voiceSession != null; + mVoiceInteraction = newTask.voiceSession != null; mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L; onDisplayChanged(task.getDisplayContent()); - if (task.mTaskRecord != null) { - task.mTaskRecord.updateOverrideConfigurationFromLaunchBounds(); - } + // TODO(b/36505427): Maybe this call should be moved inside + // updateOverrideConfiguration() + newTask.updateOverrideConfigurationFromLaunchBounds(); // Make sure override configuration is up-to-date before using to create window // controller. updateSizeCompatMode(); @@ -1279,8 +1232,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Inform old stack (if present) of activity removal and new stack (if set) of activity // addition. if (oldStack != newStack) { - // TODO(task-unify): Might be better to use onChildAdded and onChildRemoved signal for - // this once task level is unified. if (oldStack != null) { oldStack.onActivityRemovedFromStack(this); } @@ -1964,15 +1915,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s" + " to task=%d at %d", this, task.mTaskId, position); - - reparent(newTask.getTask(), position); - } - - // TODO(task-unify): Remove once Task level is unified. - void onParentChanged(TaskRecord newParent, TaskRecord oldParent) { - onParentChanged( - newParent != null ? newParent.mTask : null, - oldParent != null ? oldParent.mTask : null); + reparent(newTask, position); } private boolean isHomeIntent(Intent intent) { @@ -2051,7 +1994,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A /** * @return Stack value from current task, null if there is no task. */ - // TODO: Remove once ActivityStack and TaskStack are unified. + // TODO(stack-unify): Remove once ActivityStack and TaskStack are unified. <T extends ActivityStack> T getActivityStack() { return task != null ? (T) task.getStack() : null; } @@ -2339,7 +2282,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A /** Finish all activities in the task with the same affinity as this one. */ void finishActivityAffinity() { - final ArrayList<ActivityRecord> activities = getTaskRecord().mActivities; + final ArrayList<ActivityRecord> activities = getTaskRecord().mChildren; for (int index = activities.indexOf(this); index >= 0; --index) { final ActivityRecord cur = activities.get(index); if (!Objects.equals(cur.taskAffinity, taskAffinity)) { @@ -2451,7 +2394,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY, mUserId, System.identityHashCode(this), task.mTaskId, shortComponentName, reason); - final ArrayList<ActivityRecord> activities = task.mActivities; + final ArrayList<ActivityRecord> activities = task.mChildren; final int index = activities.indexOf(this); if (index < (task.getChildCount() - 1)) { if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { @@ -2505,7 +2448,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // When finishing the activity preemptively take the snapshot before the app window // is marked as hidden and any configuration changes take place if (mAtmService.mWindowManager.mTaskSnapshotController != null) { - final ArraySet<Task> tasks = Sets.newArraySet(task.mTask); + final ArraySet<Task> tasks = Sets.newArraySet(task); mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks); mAtmService.mWindowManager.mTaskSnapshotController .addSkipClosingAppSnapshotTasks(tasks); @@ -2547,7 +2490,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // In this case, we can set the visibility of all the task overlay activities when // we detect the last one is finishing to keep them in sync. if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) { - for (ActivityRecord taskOverlay : task.mActivities) { + for (int i = task.getChildCount() - 1; i >= 0 ; --i) { + final ActivityRecord taskOverlay = task.getChildAt(i); if (!taskOverlay.mTaskOverlay) { continue; } @@ -2819,8 +2763,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */ - // TODO(task-unify): Look into consolidating this with TaskRecord.removeChild once we unify - // task level. void removeFromHistory(String reason) { finishActivityResults(Activity.RESULT_CANCELED, null /* resultData */); makeFinishingLocked(); @@ -4612,16 +4554,25 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** - * Check if activity should be moved to RESUMED state. The activity: - * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)}) - * - should be focusable + * Check if activity should be moved to RESUMED state. + * See {@link #shouldBeResumed(ActivityRecord)} * @param activeActivity the activity that is active or just completed pause action. We won't * resume if this activity is active. */ @VisibleForTesting boolean shouldResumeActivity(ActivityRecord activeActivity) { - return shouldMakeActive(activeActivity) && isFocusable() && !isState(RESUMED) - && getActivityStack().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE; + return shouldBeResumed(activeActivity) && !isState(RESUMED); + } + + /** + * Check if activity should be RESUMED now. The activity: + * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)}) + * - should be focusable + */ + private boolean shouldBeResumed(ActivityRecord activeActivity) { + return shouldMakeActive(activeActivity) && isFocusable() + && getActivityStack().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE + && canResumeByCompat(); } /** @@ -4659,7 +4610,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // Check if position in task allows to become paused - final int positionInTask = task.mActivities.indexOf(this); + final int positionInTask = task.mChildren.indexOf(this); if (positionInTask == -1) { throw new IllegalStateException("Activity not found in its task"); } @@ -5387,7 +5338,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return INVALID_TASK_ID; } final TaskRecord task = r.task; - final int activityNdx = task.mActivities.indexOf(r); + final int activityNdx = task.mChildren.indexOf(r); if (activityNdx < 0 || (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) { return INVALID_TASK_ID; @@ -5751,7 +5702,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override boolean isWaitingForTransitionStart() { final DisplayContent dc = getDisplayContent(); - // TODO: Test for null can be removed once unification is done. + // TODO(display-unify): Test for null can be removed once unification is done. if (dc == null) return false; return dc.mAppTransition.isTransitionSet() && (dc.mOpeningApps.contains(this) @@ -6559,8 +6510,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If the changes come from change-listener, the incoming parent configuration is // still the old one. Make sure their orientations are the same to reduce computing // the compatibility bounds for the intermediate state. - && (task.mTaskRecord == null || task.mTaskRecord - .getConfiguration().orientation == newParentConfig.orientation)) { + && (task.getConfiguration().orientation == newParentConfig.orientation)) { final Rect taskBounds = task.getBounds(); // Since we only center the activity horizontally, if only the fixed height is smaller // than its container, the override bounds don't need to take effect. @@ -6878,8 +6828,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A preserveWindow &= isResizeOnlyChange(changes); final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged()); if (hasResizeChange) { - final boolean isDragResizing = - getTaskRecord().getTask().isDragResizing(); + final boolean isDragResizing = getTaskRecord().isDragResizing(); mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE : RELAUNCH_REASON_WINDOWING_MODE_RESIZE; } else { @@ -6897,23 +6846,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A deferRelaunchUntilPaused = true; preserveWindowOnDeferredRelaunch = preserveWindow; return true; - } else if (mState == RESUMED) { - // Try to optimize this case: the configuration is changing and we need to restart - // the top, resumed activity. Instead of doing the normal handshaking, just say - // "restart!". + } else { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Config is relaunching resumed " + this); - + "Config is relaunching " + this); if (DEBUG_STATES && !visible) { - Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + this + Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this + " called by " + Debug.getCallers(4)); } - - relaunchActivityLocked(true /* andResume */, preserveWindow); - } else { - if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, - "Config is relaunching non-resumed " + this); - relaunchActivityLocked(false /* andResume */, preserveWindow); + relaunchActivityLocked(preserveWindow); } // All done... tell the caller we weren't able to keep this activity around. @@ -7011,12 +6951,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A | CONFIG_SCREEN_LAYOUT)) != 0; } - void relaunchActivityLocked(boolean andResume, boolean preserveWindow) { + void relaunchActivityLocked(boolean preserveWindow) { if (mAtmService.mSuppressResizeConfigChanges && preserveWindow) { configChangeFlags = 0; return; } + final boolean andResume = shouldBeResumed(null /*activeActivity*/); List<ResultInfo> pendingResults = null; List<ReferrerIntent> pendingNewIntents = null; if (andResume) { diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 8e3995bfd872..593318de34e1 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -254,7 +254,11 @@ class ActivityStack extends ConfigurationContainer { @Override protected void onParentChanged( ConfigurationContainer newParent, ConfigurationContainer oldParent) { - ActivityDisplay display = getParent(); + if (oldParent != null) { + mPrevDisplayId = ((ActivityDisplay) oldParent).mDisplayId; + } + + final ActivityDisplay display = getParent(); if (display != null) { // Rotations are relative to the display. This means if there are 2 displays rotated // differently (eg. 2 monitors with one landscape and one portrait), moving a stack @@ -292,18 +296,6 @@ class ActivityStack extends ConfigurationContainer { RESTARTING_PROCESS } - @VisibleForTesting - /* The various modes for the method {@link #removeTask}. */ - // Task is being completely removed from all stacks in the system. - protected static final int REMOVE_TASK_MODE_DESTROYING = 0; - // Task is being removed from this stack so we can add it to another stack. In the case we are - // moving we don't want to perform some operations on the task like removing it from window - // manager or recents. - static final int REMOVE_TASK_MODE_MOVING = 1; - // Similar to {@link #REMOVE_TASK_MODE_MOVING} and the task will be added to the top of its new - // stack and the new stack will be on top of all stacks. - static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2; - final ActivityTaskManagerService mService; final WindowManagerService mWindowManager; @@ -381,6 +373,8 @@ class ActivityStack extends ConfigurationContainer { final int mStackId; /** The attached Display's unique identifier, or -1 if detached */ int mDisplayId; + // Id of the previous display the stack was on. + int mPrevDisplayId = INVALID_DISPLAY; /** Stores the override windowing-mode from before a transient mode change (eg. split) */ private int mRestoreOverrideWindowingMode = WINDOWING_MODE_UNDEFINED; @@ -962,7 +956,7 @@ class ActivityStack extends ConfigurationContainer { void positionChildWindowContainerAtTop(TaskRecord child) { if (mTaskStack != null) { // TODO: Remove after unification. This cannot be false after that. - mTaskStack.positionChildAtTop(child.getTask(), true /* includingParents */); + mTaskStack.positionChildAtTop(child, true /* includingParents */); } } @@ -974,7 +968,7 @@ class ActivityStack extends ConfigurationContainer { child.getStack(), true /* ignoreCurrent */); if (mTaskStack != null) { // TODO: Remove after unification. This cannot be false after that. - mTaskStack.positionChildAtBottom(child.getTask(), + mTaskStack.positionChildAtBottom(child, nextFocusableStack == null /* includingParents */); } } @@ -1168,7 +1162,7 @@ class ActivityStack extends ConfigurationContainer { } final TaskRecord task = r.getTaskRecord(); final ActivityStack stack = r.getActivityStack(); - if (stack != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) { + if (stack != null && task.mChildren.contains(r) && mTaskHistory.contains(task)) { if (stack != this) Slog.w(TAG, "Illegal state! task does not point to stack it is in."); return r; @@ -1183,7 +1177,8 @@ class ActivityStack extends ConfigurationContainer { /** Checks if there are tasks with specific UID in the stack. */ boolean isUidPresent(int uid) { for (TaskRecord task : mTaskHistory) { - for (ActivityRecord r : task.mActivities) { + for (int i = task.getChildCount() - 1; i >= 0 ; --i) { + final ActivityRecord r = task.getChildAt(i); if (r.getUid() == uid) { return true; } @@ -1195,7 +1190,8 @@ class ActivityStack extends ConfigurationContainer { /** Get all UIDs that are present in the stack. */ void getPresentUIDs(IntArray presentUIDs) { for (TaskRecord task : mTaskHistory) { - for (ActivityRecord r : task.mActivities) { + for (int i = task.getChildCount() - 1; i >= 0 ; --i) { + final ActivityRecord r = task.getChildAt(i); presentUIDs.add(r.getUid()); } } @@ -1207,12 +1203,6 @@ class ActivityStack extends ConfigurationContainer { return display != null && display.isSingleTaskInstance(); } - private void removeActivitiesFromLRUList(TaskRecord task) { - for (ActivityRecord r : task.mActivities) { - mLRUActivities.remove(r); - } - } - /** @return {@code true} if LRU list contained the specified activity. */ final boolean removeActivityFromLRUList(ActivityRecord activity) { return mLRUActivities.remove(activity); @@ -1792,8 +1782,7 @@ class ActivityStack extends ConfigurationContainer { if (prev.deferRelaunchUntilPaused) { // Complete the deferred relaunch that was waiting for pause to complete. if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev); - prev.relaunchActivityLocked(false /* andResume */, - prev.preserveWindowOnDeferredRelaunch); + prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch); } else if (wasStopping) { // We are also stopping, the stop request must have gone soon after the pause. // We can't clobber it, because the stop confirmation will not be handled. @@ -3016,19 +3005,19 @@ class ActivityStack extends ConfigurationContainer { mTaskHistory.remove(task); mTaskHistory.add(position, task); if (mTaskStack != null) { - // TODO: this could not be false after unification. - mTaskStack.positionChildAt(task.getTask(), position); + // TODO: this can not be false after unification Stack. + mTaskStack.positionChildAt(task, position); } - updateTaskMovement(task, true); + task.updateTaskMovement(true); } - private void insertTaskAtTop(TaskRecord task, ActivityRecord starting) { - // TODO: Better place to put all the code below...may be addTask... + void insertTaskAtTop(TaskRecord task, ActivityRecord starting) { + // TODO: Better place to put all the code below...may be addChild... mTaskHistory.remove(task); // Now put task at top. final int position = getAdjustedPositionForTask(task, mTaskHistory.size(), starting); mTaskHistory.add(position, task); - updateTaskMovement(task, true); + task.updateTaskMovement(true); positionChildWindowContainerAtTop(task); } @@ -3036,7 +3025,7 @@ class ActivityStack extends ConfigurationContainer { mTaskHistory.remove(task); final int position = getAdjustedPositionForTask(task, 0, null); mTaskHistory.add(position, task); - updateTaskMovement(task, true); + task.updateTaskMovement(true); positionChildWindowContainerAtBottom(task); } @@ -3070,7 +3059,7 @@ class ActivityStack extends ConfigurationContainer { if (!startIt) { if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task, new RuntimeException("here").fillInStackTrace()); - r.setTask(rTask); + rTask.positionChildAtTop(r); ActivityOptions.abort(options); return; } @@ -3097,7 +3086,7 @@ class ActivityStack extends ConfigurationContainer { // Slot the activity into the history stack and proceed if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task, new RuntimeException("here").fillInStackTrace()); - r.setTask(task); + task.positionChildAtTop(r); // The transition animation and starting window are not needed if {@code allowMoveToFront} // is false, because the activity won't be visible. @@ -3272,7 +3261,7 @@ class ActivityStack extends ConfigurationContainer { // with the same affinity is unlikely to be in the same stack. final TaskRecord targetTask; final ActivityRecord bottom = - !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ? + !mTaskHistory.isEmpty() && mTaskHistory.get(0).hasChild() ? mTaskHistory.get(0).getChildAt(0) : null; if (bottom != null && target.taskAffinity.equals(bottom.getTaskRecord().affinity)) { // If the activity currently at the bottom has the @@ -3483,7 +3472,7 @@ class ActivityStack extends ConfigurationContainer { // instance of the same activity? Then we drop the instance // below so it remains singleTop. if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) { - final ArrayList<ActivityRecord> taskActivities = task.mActivities; + final ArrayList<ActivityRecord> taskActivities = task.mChildren; final int targetNdx = taskActivities.indexOf(target); if (targetNdx > 0) { final ActivityRecord p = taskActivities.get(targetNdx - 1); @@ -3637,7 +3626,7 @@ class ActivityStack extends ConfigurationContainer { finishedTask = r.getTaskRecord(); int taskNdx = mTaskHistory.indexOf(finishedTask); final TaskRecord task = finishedTask; - int activityNdx = task.mActivities.indexOf(r); + int activityNdx = task.mChildren.indexOf(r); getDisplay().mDisplayContent.prepareAppTransition( TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); r.finishIfPossible(reason, false /* oomAdj */); @@ -3774,7 +3763,7 @@ class ActivityStack extends ConfigurationContainer { final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode, Intent resultData) { final TaskRecord task = srec.getTaskRecord(); - final ArrayList<ActivityRecord> activities = task.mActivities; + final ArrayList<ActivityRecord> activities = task.mChildren; final int start = activities.indexOf(srec); if (!mTaskHistory.contains(task) || (start < 0)) { return false; @@ -3868,8 +3857,16 @@ class ActivityStack extends ConfigurationContainer { * an activity moves away from the stack. */ void onActivityRemovedFromStack(ActivityRecord r) { + removeActivityFromLRUList(r); removeTimeoutsForActivity(r); + // TODO(stack-unify): null check will no longer be needed. + if (mTaskStack != null) { + mTaskStack.mExitingActivities.remove(r); + } + // TODO(stack-unify): Remove if no bugs showed up... + //r.mIsExiting = false; + if (mResumedActivity != null && mResumedActivity == r) { setResumedActivity(null, "onActivityRemovedFromStack"); } @@ -4062,7 +4059,7 @@ class ActivityStack extends ConfigurationContainer { if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Removing app " + app + " from history with " + i + " entries"); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; + final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mChildren; mTmpActivities.clear(); mTmpActivities.addAll(activities); @@ -4151,19 +4148,6 @@ class ActivityStack extends ConfigurationContainer { getDisplay().mDisplayContent.prepareAppTransition(transit, false); } - private void updateTaskMovement(TaskRecord task, boolean toFront) { - if (task.isPersistable) { - task.mLastTimeMoved = System.currentTimeMillis(); - // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most - // recently will be most negative, tasks sent to the bottom before that will be less - // negative. Similarly for recent tasks moved to the top which will be most positive. - if (!toFront) { - task.mLastTimeMoved *= -1; - } - } - mRootActivityContainer.invalidateTaskLayers(); - } - final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options, AppTimeTracker timeTracker, String reason) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); @@ -4296,7 +4280,7 @@ class ActivityStack extends ConfigurationContainer { mTaskHistory.remove(tr); mTaskHistory.add(0, tr); - updateTaskMovement(tr, false); + tr.updateTaskMovement(false); getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false); moveToBack("moveTaskToBackLocked", tr); @@ -4335,7 +4319,7 @@ class ActivityStack extends ConfigurationContainer { for (int taskIndex = mTaskHistory.indexOf(startTask); taskIndex >= 0; --taskIndex) { final TaskRecord task = mTaskHistory.get(taskIndex); - final ArrayList<ActivityRecord> activities = task.mActivities; + final ArrayList<ActivityRecord> activities = task.mChildren; int activityIndex = (start.getTaskRecord() == task) ? activities.indexOf(start) : activities.size() - 1; for (; activityIndex >= 0; --activityIndex) { @@ -4375,10 +4359,10 @@ class ActivityStack extends ConfigurationContainer { final TaskRecord task = mTaskHistory.get(i); if (task.isResizeable()) { if (tempTaskInsetBounds != null && !tempTaskInsetBounds.isEmpty()) { - task.setDisplayedBounds(taskBounds); + task.setOverrideDisplayedBounds(taskBounds); task.setBounds(tempTaskInsetBounds); } else { - task.setDisplayedBounds(null); + task.setOverrideDisplayedBounds(null); task.setBounds(taskBounds); } } @@ -4430,9 +4414,9 @@ class ActivityStack extends ConfigurationContainer { for (int i = mTaskHistory.size() - 1; i >= 0; i--) { final TaskRecord task = mTaskHistory.get(i); if (bounds == null || bounds.isEmpty()) { - task.setDisplayedBounds(null); + task.setOverrideDisplayedBounds(null); } else if (task.isResizeable()) { - task.setDisplayedBounds(bounds); + task.setOverrideDisplayedBounds(bounds); } } } @@ -4477,7 +4461,7 @@ class ActivityStack extends ConfigurationContainer { TaskRecord lastTask = null; ComponentName homeActivity = null; for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; + final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mChildren; mTmpActivities.clear(); mTmpActivities.addAll(activities); @@ -4675,7 +4659,7 @@ class ActivityStack extends ConfigurationContainer { pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds); pw.println(prefix + "* " + task); task.dump(pw, prefix + " "); - dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities, + dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mChildren, prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task); } return true; @@ -4686,15 +4670,15 @@ class ActivityStack extends ConfigurationContainer { if ("all".equals(name)) { for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - activities.addAll(mTaskHistory.get(taskNdx).mActivities); + activities.addAll(mTaskHistory.get(taskNdx).mChildren); } } else if ("top".equals(name)) { final int top = mTaskHistory.size() - 1; if (top >= 0) { - final ArrayList<ActivityRecord> list = mTaskHistory.get(top).mActivities; - int listTop = list.size() - 1; + final TaskRecord task = mTaskHistory.get(top); + int listTop = task.getChildCount() - 1; if (listTop >= 0) { - activities.add(list.get(listTop)); + activities.add(task.getChildAt(listTop)); } } } else { @@ -4702,7 +4686,9 @@ class ActivityStack extends ConfigurationContainer { matcher.build(name); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - for (ActivityRecord r1 : mTaskHistory.get(taskNdx).mActivities) { + final TaskRecord task = mTaskHistory.get(taskNdx); + for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r1 = task.getChildAt(activityNdx); if (matcher.match(r1, r1.intent.getComponent())) { activities.add(r1); } @@ -4734,58 +4720,51 @@ class ActivityStack extends ConfigurationContainer { return starting; } - /** - * Removes the input task from this stack. - * - * @param task to remove. - * @param reason for removal. - * @param mode task removal mode. Either {@link #REMOVE_TASK_MODE_DESTROYING}, - * {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}. - */ - void removeTask(TaskRecord task, String reason, int mode) { - if (!mTaskHistory.remove(task)) { - // Not really in this stack anymore... - return; + // TODO(stack-unify): Merge into removeChild method below. + void onChildRemoved(TaskRecord child, DisplayContent dc) { + mTaskHistory.remove(child); + EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, child.mTaskId, mStackId); + + ActivityDisplay display = getDisplay(); + if (display == null && dc != null) { + display = dc.mActivityDisplay; } - EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.mTaskId, getStackId()); + if (display.isSingleTaskInstance()) { + mService.notifySingleTaskDisplayEmpty(display.mDisplayId); + } - removeActivitiesFromLRUList(task); - updateTaskMovement(task, true); + display.mDisplayContent.setLayoutNeeded(); - if (mode == REMOVE_TASK_MODE_DESTROYING) { - task.cleanUpResourcesForDestroy(); + if (mTaskHistory.isEmpty()) { + // Stack is now empty... + remove(); } + } + /** + * Removes the input task from this stack. + * + * @param task to remove. + * @param reason for removal. + */ + void removeChild(TaskRecord task, String reason) { final ActivityDisplay display = getDisplay(); - if (mTaskHistory.isEmpty()) { - if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this); + final boolean topFocused = mRootActivityContainer.isTopDisplayFocusedStack(this); + mTaskStack.removeChild(task); + moveHomeStackToFrontIfNeeded(topFocused, display, reason); + } + + void moveHomeStackToFrontIfNeeded( + boolean wasTopFocusedStack, ActivityDisplay display, String reason) { + if (mTaskHistory.isEmpty() && wasTopFocusedStack) { // We only need to adjust focused stack if this stack is in focus and we are not in the // process of moving the task to the top of the stack that will be focused. - if (mode != REMOVE_TASK_MODE_MOVING_TO_TOP - && mRootActivityContainer.isTopDisplayFocusedStack(this)) { - String myReason = reason + " leftTaskHistoryEmpty"; - if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) { - display.moveHomeStackToFront(myReason); - } - } - if (isAttached()) { - display.positionChildAtBottom(this); - } - if (!isActivityTypeHome() || !isAttached()) { - remove(); + String myReason = reason + " leftTaskHistoryEmpty"; + if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) { + display.moveHomeStackToFront(myReason); } } - - task.setStack(null); - - // Notify if a task from the pinned stack is being removed (or moved depending on the mode) - if (inPinnedWindowingMode()) { - mService.getTaskChangeNotificationController().notifyActivityUnpinned(); - } - if (display != null && display.isSingleTaskInstance()) { - mService.notifySingleTaskDisplayEmpty(display.mDisplayId); - } } TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, @@ -4800,9 +4779,9 @@ class ActivityStack extends ConfigurationContainer { boolean toTop, ActivityRecord activity, ActivityRecord source, ActivityOptions options) { final TaskRecord task = TaskRecord.create( - mService, taskId, info, intent, voiceSession, voiceInteractor); + mService, taskId, info, intent, voiceSession, voiceInteractor, this); // add the task to stack first, mTaskPositioner might need the stack association - addTask(task, toTop, "createTaskRecord"); + addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY; final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController() .isKeyguardOrAodShowing(displayId); @@ -4811,7 +4790,6 @@ class ActivityStack extends ConfigurationContainer { && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) { task.setBounds(getRequestedOverrideBounds()); } - task.createTask(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); return task; } @@ -4819,34 +4797,31 @@ class ActivityStack extends ConfigurationContainer { return new ArrayList<>(mTaskHistory); } - void addTask(final TaskRecord task, final boolean toTop, String reason) { - addTask(task, toTop ? MAX_VALUE : 0, true /* schedulePictureInPictureModeChange */, reason); - if (toTop) { - // TODO: figure-out a way to remove this call. - positionChildWindowContainerAtTop(task); - } + // TODO(stack-unify): Merge with addChild below. + void onChildAdded(TaskRecord task, int position) { + final boolean toTop = position >= mTaskHistory.size(); + mTaskHistory.add(position, task); + + // TODO: Feels like this should go in TaskRecord#onParentChanged + task.updateTaskMovement(toTop); } - // TODO: This shouldn't allow automatic reparenting. Remove the call to preAddTask and deal - // with the fall-out... - void addTask(final TaskRecord task, int position, boolean schedulePictureInPictureModeChange, - String reason) { - // TODO: Is this remove really needed? Need to look into the call path for the other addTask - mTaskHistory.remove(task); + void addChild(final TaskRecord task, final boolean toTop, boolean showForAllUsers) { if (isSingleTaskInstance() && !mTaskHistory.isEmpty()) { throw new IllegalStateException("Can only have one child on stack=" + this); } - position = getAdjustedPositionForTask(task, position, null /* starting */); - final boolean toTop = position >= mTaskHistory.size(); - final ActivityStack prevStack = preAddTask(task, reason, toTop); - - mTaskHistory.add(position, task); - task.setStack(this); + final int position = + getAdjustedPositionForTask(task, toTop ? MAX_VALUE : 0, null /* starting */); - updateTaskMovement(task, toTop); + // We only want to move the parents to the parents if we are creating this task at the + // top of its stack. + mTaskStack.addChild(task, position, showForAllUsers, toTop /*moveParents*/); - postAddTask(task, prevStack, schedulePictureInPictureModeChange); + if (toTop) { + // TODO: figure-out a way to remove this call. + positionChildWindowContainerAtTop(task); + } } void positionChildAt(TaskRecord task, int index) { @@ -4861,8 +4836,14 @@ class ActivityStack extends ConfigurationContainer { final ActivityRecord topRunningActivity = task.topRunningActivityLocked(); final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity; insertTaskAtPosition(task, index); - task.setStack(this); - postAddTask(task, null /* prevStack */, true /* schedulePictureInPictureModeChange */); + + // TODO: Investigate if this random code is really needed. + if (task.voiceSession != null) { + try { + task.voiceSession.taskStarted(task.intent, task.mTaskId); + } catch (RemoteException e) { + } + } if (wasResumed) { if (mResumedActivity != null) { @@ -4879,32 +4860,6 @@ class ActivityStack extends ConfigurationContainer { mRootActivityContainer.resumeFocusedStacksTopActivities(); } - private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) { - final ActivityStack prevStack = task.getStack(); - if (prevStack != null && prevStack != this) { - prevStack.removeTask(task, reason, - toTop ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING); - } - return prevStack; - } - - /** - * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode - * change. Callers may set this to false if they are explicitly scheduling PiP mode - * changes themselves, like during the PiP animation - */ - private void postAddTask(TaskRecord task, ActivityStack prevStack, - boolean schedulePictureInPictureModeChange) { - if (schedulePictureInPictureModeChange && prevStack != null) { - mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, prevStack); - } else if (task.voiceSession != null) { - try { - task.voiceSession.taskStarted(task.intent, task.mTaskId); - } catch (RemoteException e) { - } - } - } - public void setAlwaysOnTop(boolean alwaysOnTop) { if (isAlwaysOnTop() == alwaysOnTop) { return; diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index dc3d2631a5d7..f8a7397f10df 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -52,7 +52,6 @@ import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; @@ -83,6 +82,7 @@ import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; +import static com.android.server.wm.WindowContainer.POSITION_TOP; import android.Manifest; import android.app.Activity; @@ -1420,7 +1420,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // WM resizeTask must be done after the task is moved to the correct stack, // because Task's setBounds() also updates dim layer's bounds, but that has // dependency on the stack. - task.resizeWindowContainer(); + task.resize(false /* relayout */, false /* forced */); } } @@ -1885,26 +1885,22 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { final ActivityStack stack = mRootActivityContainer.getLaunchStack(null, aOptions, task, onTop); final ActivityStack currentStack = task.getStack(); + + if (currentStack == stack) { + // Nothing else to do since it is already restored in the right stack. + return true; + } + if (currentStack != null) { - // Task has already been restored once. See if we need to do anything more - if (currentStack == stack) { - // Nothing else to do since it is already restored in the right stack. - return true; - } - // Remove current stack association, so we can re-associate the task with the - // right stack below. - currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING); + // Task has already been restored once. Just re-parent it to the new stack. + task.reparent(stack.mTaskStack, + POSITION_TOP, true /*moveParents*/, "restoreRecentTaskLocked"); + return true; } - stack.addTask(task, onTop, "restoreRecentTask"); - // TODO: move call for creation here and other place into Stack.addTask() - task.createTask(onTop, true /* showForAllUsers */); + stack.addChild(task, onTop, true /* showForAllUsers */); if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Added restored task=" + task + " to stack=" + stack); - for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) { - final ActivityRecord r = task.getChildAt(activityNdx); - r.setTask(task); - } return true; } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index d1bb2559e5be..6edcb0298938 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -50,6 +50,7 @@ import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS; +import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; @@ -1842,7 +1843,7 @@ class ActivityStarter { // {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The task // reference is needed in the call below to {@link setTargetStackAndMoveToFrontIfNeeded} if (targetTaskTop.getTaskRecord() == null) { - targetTaskTop.setTask(targetTask); + targetTask.addChild(targetTaskTop); } if (top != null) { @@ -1862,8 +1863,8 @@ class ActivityStarter { // Go ahead and reset it. mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */, mLaunchFlags, mOptions); - mTargetStack.addTask(targetTask, - !mLaunchTaskBehind /* toTop */, "complyActivityFlags"); + mTargetStack.addChild(targetTask, !mLaunchTaskBehind /* toTop */, + (mStartActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0); } } } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) == 0 && !mAddingToTask diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 222f26edaf5d..da7af5fdd369 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -85,7 +85,6 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.Scr import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE; import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; @@ -1996,7 +1995,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return false; } final TaskRecord task = r.getTaskRecord(); - int index = task.mActivities.lastIndexOf(r); + int index = task.mChildren.lastIndexOf(r); if (index > 0) { ActivityRecord under = task.getChildAt(index - 1); under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null; @@ -2221,18 +2220,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found"); return rect; } - if (task.getStack() != null) { - // Return the bounds from window manager since it will be adjusted for various - // things like the presense of a docked stack for tasks that aren't resizeable. - task.getWindowContainerBounds(rect); - } else { - // Task isn't in window manager yet since it isn't associated with a stack. - // Return the persist value from activity manager - if (!task.matchParentBounds()) { - rect.set(task.getBounds()); - } else if (task.mLastNonFullscreenBounds != null) { - rect.set(task.mLastNonFullscreenBounds); - } + if (task.getParent() != null) { + rect.set(task.getBounds()); + } else if (task.mLastNonFullscreenBounds != null) { + rect.set(task.mLastNonFullscreenBounds); } } } finally { @@ -2249,7 +2240,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final TaskRecord tr = mRootActivityContainer.anyTaskForId(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS); if (tr != null) { - return tr.mTaskDescription; + return tr.getTaskDescription(); } } return null; @@ -3168,10 +3159,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { null /* voiceSession */, null /* voiceInteractor */, !ON_TOP); if (!mRecentTasks.addToBottom(task)) { // The app has too many tasks already and we can't add any more - stack.removeTask(task, "addAppTask", REMOVE_TASK_MODE_DESTROYING); + stack.removeChild(task, "addAppTask"); return INVALID_TASK_ID; } - task.mTaskDescription.copyFrom(description); + task.getTaskDescription().copyFrom(description); // TODO: Send the thumbnail to WM to store it. @@ -4489,7 +4480,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found"); return; } - task.cancelWindowTransition(); + task.cancelTaskWindowTransition(); } } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 8b4f7cc571f8..30f3bc5e70fb 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -134,9 +134,9 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { onConfigurationChanged(newParentConfig, true /*forwardToChildren*/); } - // TODO: Consolidate with onConfigurationChanged() method above once unification is done. This - // is only currently need during the process of unification where we don't want configuration - // forwarded to a child from both parents. + // TODO(root-unify): Consolidate with onConfigurationChanged() method above once unification is + // done. This is only currently need during the process of unification where we don't want + // configuration forwarded to a child from both parents. public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) { mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration); resolveOverrideConfiguration(newParentConfig); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 89568ebf4277..d1d468b5ae3d 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2409,7 +2409,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo /** Returns true if a removal action is still being deferred. */ @Override boolean checkCompleteDeferredRemoval() { - final boolean stillDeferringRemoval = super.checkCompleteDeferredRemoval(); + boolean stillDeferringRemoval = false; + + for (int i = getChildCount() - 1; i >= 0; --i) { + final DisplayChildWindowContainer child = getChildAt(i); + stillDeferringRemoval |= child.checkCompleteDeferredRemoval(); + if (getChildCount() == 0) { + // If this display is pending to be removed because it contains an activity with + // {@link ActivityRecord#mIsExiting} is true, this display may be removed when + // completing the removal of the last activity from + // {@link ActivityRecord#checkCompleteDeferredRemoval}. + return false; + } + } if (!stillDeferringRemoval && mDeferredRemoval) { removeImmediately(); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 6e238b33d8dd..fcfd9ded9ad7 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -144,13 +144,16 @@ import android.view.InputChannel; import android.view.InputDevice; import android.view.InputEvent; import android.view.InputEventReceiver; +import android.view.InsetsFlags; import android.view.InsetsState; +import android.view.InsetsState.InternalInsetType; import android.view.MotionEvent; import android.view.PointerIcon; import android.view.Surface; import android.view.View; import android.view.ViewRootImpl; import android.view.WindowInsets; +import android.view.WindowInsetsController.Appearance; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; @@ -332,8 +335,6 @@ public class DisplayPolicy { private int mResettingSystemUiFlags = 0; // Bits that we are currently always keeping cleared. private int mForceClearedSystemUiFlags = 0; - private int mLastFullscreenStackSysUiFlags; - private int mLastDockedStackSysUiFlags; private int mLastAppearance; private int mLastFullscreenAppearance; private int mLastDockedAppearance; @@ -3172,11 +3173,6 @@ public class DisplayPolicy { &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS); } - final int appearance = win.mAttrs.insetsFlags.appearance; - final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */, - mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState); - final int dockedVisibility = updateLightStatusBarLw(0 /* vis */, - mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState); final int fullscreenAppearance = updateLightStatusBarAppearanceLw(0 /* vis */, mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState); final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */, @@ -3190,9 +3186,9 @@ public class DisplayPolicy { final Pair<Integer, Boolean> result = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility); final int visibility = result.first; + final int appearance = win.mAttrs.insetsFlags.appearance + | InsetsFlags.getAppearance(visibility); final int diff = visibility ^ mLastSystemUiFlags; - final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags; - final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags; final InsetsPolicy insetsPolicy = getInsetsPolicy(); final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) != 0 @@ -3205,7 +3201,7 @@ public class DisplayPolicy { | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)) != 0 || behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; - if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 + if (diff == 0 && mLastAppearance == appearance && mLastFullscreenAppearance == fullscreenAppearance && mLastDockedAppearance == dockedAppearance @@ -3216,9 +3212,12 @@ public class DisplayPolicy { && mLastDockedStackBounds.equals(mDockedStackBounds)) { return 0; } + + // Obtains which types should show transient and which types should abort transient. + // If there is no transient state change, this pair will contain two empty arrays. + final Pair<int[], int[]> transientState = getTransientState(visibility, mLastSystemUiFlags); + mLastSystemUiFlags = visibility; - mLastFullscreenStackSysUiFlags = fullscreenVisibility; - mLastDockedStackSysUiFlags = dockedVisibility; mLastAppearance = appearance; mLastFullscreenAppearance = fullscreenAppearance; mLastDockedAppearance = dockedAppearance; @@ -3240,14 +3239,16 @@ public class DisplayPolicy { StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); if (statusBar != null) { final int displayId = getDisplayId(); - // TODO(b/118118435): disabled flags only - statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility, - dockedVisibility, 0xffffffff, fullscreenStackBounds, - dockedStackBounds, isNavbarColorManagedByIme, win.toString()); - if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) { - statusBar.onSystemBarAppearanceChanged(displayId, appearance, - appearanceRegions, isNavbarColorManagedByIme); + statusBar.setDisableFlags(displayId, visibility & StatusBarManager.DISABLE_MASK, + win.toString()); + if (transientState.first.length > 0) { + statusBar.showTransient(displayId, transientState.first); } + if (transientState.second.length > 0) { + statusBar.abortTransient(displayId, transientState.second); + } + statusBar.onSystemBarAppearanceChanged(displayId, appearance, + appearanceRegions, isNavbarColorManagedByIme); statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive); // TODO(b/118118435): Remove this after removing system UI visibilities. @@ -3258,23 +3259,28 @@ public class DisplayPolicy { return diff; } - private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) { - final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded(); - final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming; - if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) { - // If the top fullscreen-or-dimming window is also the top fullscreen, respect - // its light flag. - vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null) - & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } else if (statusColorWin != null && statusColorWin.isDimming()) { - // Otherwise if it's dimming, clear the light flag. - vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + private static Pair<int[], int[]> getTransientState(int vis, int oldVis) { + final IntArray typesToShow = new IntArray(0); + final IntArray typesToAbort = new IntArray(0); + updateTransientState(vis, oldVis, View.STATUS_BAR_TRANSIENT, TYPE_TOP_BAR, typesToShow, + typesToAbort); + updateTransientState(vis, oldVis, View.NAVIGATION_BAR_TRANSIENT, + InsetsState.TYPE_NAVIGATION_BAR, typesToShow, typesToAbort); + return Pair.create(typesToShow.toArray(), typesToAbort.toArray()); + } + + private static void updateTransientState(int vis, int oldVis, int transientFlag, + @InternalInsetType int type, IntArray typesToShow, IntArray typesToAbort) { + final boolean wasTransient = (oldVis & transientFlag) != 0; + final boolean isTransient = (vis & transientFlag) != 0; + if (!wasTransient && isTransient) { + typesToShow.add(type); + } else if (wasTransient && !isTransient) { + typesToAbort.add(type); } - return vis; } - private int updateLightStatusBarAppearanceLw(int appearance, WindowState opaque, + private int updateLightStatusBarAppearanceLw(@Appearance int appearance, WindowState opaque, WindowState opaqueOrDimming) { final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded(); final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming; @@ -3282,7 +3288,10 @@ public class DisplayPolicy { // If the top fullscreen-or-dimming window is also the top fullscreen, respect // its light flag. appearance &= ~APPEARANCE_LIGHT_TOP_BAR; - appearance |= statusColorWin.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_TOP_BAR; + final int legacyAppearance = InsetsFlags.getAppearance( + PolicyControl.getSystemUiVisibility(statusColorWin, null)); + appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance) + & APPEARANCE_LIGHT_TOP_BAR; } else if (statusColorWin != null && statusColorWin.isDimming()) { // Otherwise if it's dimming, clear the light flag. appearance &= ~APPEARANCE_LIGHT_TOP_BAR; diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 2dae12642be3..01cbc5d1e880 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -211,9 +211,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // If there are multiple tasks in the target stack (ie. the home stack, with 3p // and default launchers coexisting), then move the task to the top as a part of // moving the stack to the front - if (targetStack.topTask() != targetActivity.getTaskRecord()) { - targetStack.addTask(targetActivity.getTaskRecord(), true /* toTop */, - "startRecentsActivity"); + final TaskRecord task = targetActivity.getTaskRecord(); + if (targetStack.topTask() != task) { + targetStack.insertTaskAtTop(task, targetActivity); } } else { // No recents activity, create the new recents activity bottom most diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index 51a3e7205489..dc78922ef4fc 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -1265,8 +1265,7 @@ class RootActivityContainer extends ConfigurationContainer : task.realActivity != null ? task.realActivity.flattenToString() : task.getTopActivity() != null ? task.getTopActivity().packageName : "unknown"; - taskBounds[i] = new Rect(); - task.getWindowContainerBounds(taskBounds[i]); + taskBounds[i] = mService.getTaskBounds(task.mTaskId); taskUserIds[i] = task.mUserId; } info.taskIds = taskIds; @@ -1876,7 +1875,12 @@ class RootActivityContainer extends ConfigurationContainer ActivityStack getNextFocusableStack(@NonNull ActivityStack currentFocus, boolean ignoreCurrent) { // First look for next focusable stack on the same display - final ActivityDisplay preferredDisplay = currentFocus.getDisplay(); + ActivityDisplay preferredDisplay = currentFocus.getDisplay(); + if (preferredDisplay == null) { + // Stack is currently detached because it is being removed. Use the previous display it + // was on. + preferredDisplay = getActivityDisplay(currentFocus.mPrevDisplayId); + } final ActivityStack preferredFocusableStack = preferredDisplay.getNextFocusableStack( currentFocus, ignoreCurrent); if (preferredFocusableStack != null) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index f5d3affa89ef..149bcfb991ea 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -206,7 +206,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } @Override - void onChildPositionChanged() { + void onChildPositionChanged(WindowContainer child) { mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, !mWmService.mPerDisplayFocusEnabled /* updateInputWindows */); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 634990b5fdf2..dce15bc8acf8 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; @@ -24,6 +25,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.res.Configuration.EMPTY; import static android.view.SurfaceControl.METADATA_TASK_ID; +import static com.android.server.EventLogTags.WM_TASK_CREATED; import static com.android.server.EventLogTags.WM_TASK_REMOVED; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS; @@ -63,17 +65,21 @@ import java.util.function.Consumer; class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener{ static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM; + final ActivityTaskManagerService mAtmService; + // TODO: Track parent marks like this in WindowContainer. TaskStack mStack; /* Unique identifier for this task. */ final int mTaskId; /* User for which this task was created. */ - final int mUserId; + // TODO: Make final + int mUserId; final Rect mPreparedFrozenBounds = new Rect(); final Configuration mPreparedFrozenMergedConfig = new Configuration(); // If non-empty, bounds used to display the task during animations/interactions. + // TODO(b/119687367): This member is temporary. private final Rect mOverrideDisplayedBounds = new Rect(); /** ID of the display which rotation {@link #mRotation} has. */ @@ -90,11 +96,12 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta private Rect mTmpRect2 = new Rect(); // Resize mode of the task. See {@link ActivityInfo#resizeMode} - private int mResizeMode; + // Based on the {@link ActivityInfo#resizeMode} of the root activity. + int mResizeMode; - // Whether the task supports picture-in-picture. - // See {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} - private boolean mSupportsPictureInPicture; + // Whether or not this task and its activities support PiP. Based on the + // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity. + boolean mSupportsPictureInPicture; // Whether the task is currently being drag-resized private boolean mDragResizing; @@ -116,40 +123,23 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta /** @see #setCanAffectSystemUiFlags */ private boolean mCanAffectSystemUiFlags = true; - // TODO: remove after unification - TaskRecord mTaskRecord; - - // TODO: Remove after unification. - @Override - public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) { - // Forward configuration changes in cases - // - children won't get it from TaskRecord - // - it's a pinned task - forwardToChildren &= (mTaskRecord == null) || inPinnedWindowingMode(); - super.onConfigurationChanged(newParentConfig, forwardToChildren); - } - - Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode, - boolean supportsPictureInPicture, TaskDescription taskDescription, - TaskRecord taskRecord) { - super(service); + Task(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture, + TaskDescription taskDescription, ActivityTaskManagerService atm) { + super(atm.mWindowManager); + mAtmService = atm; mTaskId = taskId; mStack = stack; mUserId = userId; mResizeMode = resizeMode; mSupportsPictureInPicture = supportsPictureInPicture; - mTaskRecord = taskRecord; mTaskDescription = taskDescription; + EventLog.writeEvent(WM_TASK_CREATED, mTaskId, + stack != null ? stack.mStackId : INVALID_STACK_ID); // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED). setOrientation(SCREEN_ORIENTATION_UNSET); - if (mTaskRecord != null) { - // This can be null when we call createTaskInStack in WindowTestUtils. Remove this after - // unification. - mTaskRecord.registerConfigurationChangeListener(this); - } else { - setBounds(getResolvedOverrideBounds()); - } + // TODO(task-merge): Is this really needed? + setBounds(getResolvedOverrideBounds()); } @Override @@ -157,37 +147,40 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta return mStack != null ? mStack.getDisplayContent() : null; } - private int getAdjustedAddPosition(int suggestedPosition) { - final int size = mChildren.size(); - if (suggestedPosition >= size) { - return Math.min(size, suggestedPosition); + int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) { + int maxPosition = mChildren.size(); + if (!r.mTaskOverlay) { + // We want to place all non-overlay activities below overlays. + while (maxPosition > 0) { + final ActivityRecord current = mChildren.get(maxPosition - 1); + if (current.mTaskOverlay && !current.removed) { + --maxPosition; + continue; + } + break; + } + if (maxPosition < 0) { + maxPosition = 0; + } } - for (int pos = 0; pos < size && pos < suggestedPosition; ++pos) { + if (suggestedPosition >= maxPosition) { + return Math.min(maxPosition, suggestedPosition); + } + + for (int pos = 0; pos < maxPosition && pos < suggestedPosition; ++pos) { // TODO: Confirm that this is the behavior we want long term. if (mChildren.get(pos).removed) { // suggestedPosition assumes removed tokens are actually gone. ++suggestedPosition; } } - return Math.min(size, suggestedPosition); - } - - @Override - void addChild(ActivityRecord child, int position) { - position = getAdjustedAddPosition(position); - super.addChild(child, position); - - // Inform the TaskRecord side of the child addition - // TODO(task-unify): Will be removed after task unification. - if (mTaskRecord != null) { - mTaskRecord.onChildAdded(child, position); - } + return Math.min(maxPosition, suggestedPosition); } @Override void positionChildAt(int position, ActivityRecord child, boolean includingParents) { - position = getAdjustedAddPosition(position); + position = getAdjustedAddPosition(child, position); super.positionChildAt(position, child, includingParents); } @@ -222,47 +215,34 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta void removeImmediately() { if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId); EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask"); - if (mTaskRecord != null) { - mTaskRecord.unregisterConfigurationChangeListener(this); - } - super.removeImmediately(); } - void reparent(TaskStack stack, int position, boolean moveParents) { - if (stack == mStack) { - throw new IllegalArgumentException( - "task=" + this + " already child of stack=" + mStack); - } - if (stack == null) { - throw new IllegalArgumentException("reparent: could not find stack."); - } + // TODO: Consolidate this with TaskRecord.reparent() + void reparent(TaskStack stack, int position, boolean moveParents, String reason) { if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId + " from stack=" + mStack); EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask"); - final DisplayContent prevDisplayContent = getDisplayContent(); - - // If we are moving from the fullscreen stack to the pinned stack - // then we want to preserve our insets so that there will not - // be a jump in the area covered by system decorations. We rely - // on the pinned animation to later unset this value. - if (stack.inPinnedWindowingMode()) { - mPreserveNonFloatingState = true; - } else { - mPreserveNonFloatingState = false; - } - getParent().removeChild(this); - stack.addTask(this, position, showForAllUsers(), moveParents); + final ActivityStack prevStack = mStack.mActivityStack; + final boolean wasTopFocusedStack = + mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack); + final ActivityDisplay prevStackDisplay = prevStack.getDisplay(); - // Relayout display(s). - final DisplayContent displayContent = stack.getDisplayContent(); - displayContent.setLayoutNeeded(); - if (prevDisplayContent != displayContent) { - onDisplayChanged(displayContent); - prevDisplayContent.setLayoutNeeded(); + reparent(stack, position); + + if (!moveParents) { + // Only move home stack forward if we are not going to move the new parent forward. + prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason); } - getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); + + mStack = stack; + stack.positionChildAt(position, this, moveParents); + + // If we are moving from the fullscreen stack to the pinned stack then we want to preserve + // our insets so that there will not be a jump in the area covered by system decorations. + // We rely on the pinned animation to later unset this value. + mPreserveNonFloatingState = stack.inPinnedWindowingMode(); } /** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */ @@ -270,46 +250,6 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta mStack.positionChildAt(position, this, false /* includingParents */); } - @Override - void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { - super.onParentChanged(newParent, oldParent); - - // Update task bounds if needed. - adjustBoundsForDisplayChangeIfNeeded(getDisplayContent()); - - if (getWindowConfiguration().windowsAreScaleable()) { - // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them - // while a resize is pending. - forceWindowsScaleable(true /* force */); - } else { - forceWindowsScaleable(false /* force */); - } - } - - @Override - void removeChild(ActivityRecord child) { - if (!mChildren.contains(child)) { - Slog.e(TAG, "removeChild: token=" + this + " not found."); - return; - } - - super.removeChild(child); - - // Inform the TaskRecord side of the child removal - // TODO(task-unify): Will be removed after task unification. - if (mTaskRecord != null) { - mTaskRecord.onChildRemoved(child); - } - - // TODO(task-unify): Need to make this account for what we are doing in - // ActivityRecord.removeFromHistory so that the task isn't removed in some situations when - // we unify task level. - if (mChildren.isEmpty()) { - EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeActivity: last activity"); - removeIfPossible(); - } - } - void setSendingToBottom(boolean toBottom) { for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) { mChildren.get(appTokenNdx).sendingToBottom = toBottom; @@ -331,7 +271,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta @Override public int setBounds(Rect bounds) { int rotation = Surface.ROTATION_0; - final DisplayContent displayContent = mStack.getDisplayContent(); + final DisplayContent displayContent = mStack != null ? mStack.getDisplayContent() : null; if (displayContent != null) { rotation = displayContent.getDisplayInfo().rotation; } else if (bounds == null) { @@ -355,9 +295,8 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill // it if possible. - // TODO: Move to TaskRecord after unification is done. - if (mTaskRecord != null && mTaskRecord.getParent() != null) { - mTaskRecord.onConfigurationChanged(mTaskRecord.getParent().getConfiguration()); + if (getParent() != null) { + onConfigurationChanged(getParent().getConfiguration()); return true; } return false; @@ -379,8 +318,9 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } /** - * Sets bounds that override where the task is displayed. Used during transient operations - * like animation / interaction. + * Displayed bounds are used to set where the task is drawn at any given time. This is + * separate from its actual bounds so that the app doesn't see any meaningful configuration + * changes during transitionary periods. */ void setOverrideDisplayedBounds(Rect overrideDisplayedBounds) { if (overrideDisplayedBounds != null) { @@ -399,13 +339,13 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta return mOverrideDisplayedBounds; } - void setResizeable(int resizeMode) { - mResizeMode = resizeMode; + boolean isResizeable(boolean checkSupportsPip) { + return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode) + || (checkSupportsPip && mSupportsPictureInPicture)); } boolean isResizeable() { - return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture - || mWmService.mAtmService.mForceResizableActivities; + return isResizeable(true /* checkSupportsPip */); } /** @@ -462,6 +402,10 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } } + /** + * Gets the current overridden displayed bounds. These will be empty if the task is not + * currently overriding where it is displayed. + */ @Override public Rect getDisplayedBounds() { if (mOverrideDisplayedBounds.isEmpty()) { @@ -577,7 +521,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER); } - private void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) { + void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) { if (displayContent == null) { return; } @@ -618,9 +562,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) { - if (mTaskRecord != null) { - mTaskRecord.requestResize(getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); - } + mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION); } } @@ -758,7 +700,8 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { - mTaskRecord.onSnapshotChanged(snapshot); + mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged( + mTaskId, snapshot); } TaskDescription getTaskDescription() { @@ -794,11 +737,6 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta mDimmer.dontAnimateExit(); } - @Override - public String toString() { - return "{taskId=" + mTaskId + " appTokens=" + mChildren + "}"; - } - String getName() { return toShortString(); } @@ -825,9 +763,8 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta } } - @CallSuper - @Override - public void writeToProto(ProtoOutputStream proto, long fieldId, + // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged. + void writeToProtoInnerTaskOnly(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { return; @@ -843,8 +780,10 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta proto.write(FILLS_PARENT, matchParentBounds()); getBounds().writeToProto(proto, BOUNDS); mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS); - proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); - proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); + if (mSurfaceControl != null) { + proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth()); + proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight()); + } proto.end(token); } diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index 6920d9d3a770..672827fbb5ee 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -52,11 +52,10 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.server.EventLogTags.WM_TASK_CREATED; +import static com.android.server.EventLogTags.WM_TASK_REMOVED; import static com.android.server.am.TaskRecordProto.ACTIVITIES; import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE; import static com.android.server.am.TaskRecordProto.BOUNDS; -import static com.android.server.am.TaskRecordProto.CONFIGURATION_CONTAINER; import static com.android.server.am.TaskRecordProto.FULLSCREEN; import static com.android.server.am.TaskRecordProto.ID; import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS; @@ -66,11 +65,9 @@ import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY; import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY; import static com.android.server.am.TaskRecordProto.RESIZE_MODE; import static com.android.server.am.TaskRecordProto.STACK_ID; +import static com.android.server.am.TaskRecordProto.TASK; import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; @@ -85,10 +82,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; -import static com.android.server.wm.WindowContainer.POSITION_TOP; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static java.lang.Integer.MAX_VALUE; @@ -143,7 +136,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; -class TaskRecord extends ConfigurationContainer { +class TaskRecord extends Task { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_ATM; private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; @@ -212,7 +205,6 @@ class TaskRecord extends ConfigurationContainer { */ private static TaskRecordFactory sTaskRecordFactory; - final int mTaskId; // Unique identifier for this task. String affinity; // The affinity name for this task, or null; may change identity. String rootAffinity; // Initial base affinity, or null; does not change from initial root. final IVoiceInteractionSession voiceSession; // Voice interaction session driving task @@ -238,17 +230,11 @@ class TaskRecord extends ConfigurationContainer { boolean hasBeenVisible; // Set if any activities in the task have been visible to the user. String stringName; // caching of toString() result. - int mUserId; // user for which this task was created boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity // was changed. int numFullscreen; // Number of fullscreen activities. - int mResizeMode; // The resize mode of this task and its activities. - // Based on the {@link ActivityInfo#resizeMode} of the root activity. - private boolean mSupportsPictureInPicture; // Whether or not this task and its activities - // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag - // of the root activity. /** Can't be put in lockTask mode. */ final static int LOCK_TASK_AUTH_DONT_LOCK = 0; /** Can enter app pinning with user approval. Can never start over existing lockTask task. */ @@ -264,13 +250,6 @@ class TaskRecord extends ConfigurationContainer { int mLockTaskUid = -1; // The uid of the application that called startLockTask(). - // This represents the last resolved activity values for this task - // NOTE: This value needs to be persisted with each task - TaskDescription mTaskDescription; - - /** List of all activities in the task arranged in history order */ - final ArrayList<ActivityRecord> mActivities; - /** Current stack. Setter must always be used to update the value. */ private ActivityStack mStack; @@ -308,8 +287,6 @@ class TaskRecord extends ConfigurationContainer { int mCallingUid; String mCallingPackage; - final ActivityTaskManagerService mAtmService; - private final Rect mTmpStableBounds = new Rect(); private final Rect mTmpNonDecorBounds = new Rect(); private final Rect mTmpBounds = new Rect(); @@ -328,17 +305,9 @@ class TaskRecord extends ConfigurationContainer { // This number will be assigned when we evaluate OOM scores for all visible tasks. int mLayerRank = -1; - // When non-empty, this represents the bounds this task will be drawn at. This gets set during - // transient operations such as split-divider dragging and animations. - // TODO(b/119687367): This member is temporary. - final Rect mDisplayedBounds = new Rect(); - /** Helper object used for updating override configuration. */ private Configuration mTmpConfig = new Configuration(); - // TODO: remove after unification - Task mTask; - /** Used by fillTaskInfo */ final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport(); @@ -346,21 +315,21 @@ class TaskRecord extends ConfigurationContainer { * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int, * ActivityInfo, Intent, TaskDescription)} instead. */ - TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, - Intent _intent, IVoiceInteractionSession _voiceSession, - IVoiceInteractor _voiceInteractor, TaskDescription _taskDescription) { + TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent, + IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, + TaskDescription _taskDescription, ActivityStack stack) { this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/, null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/, false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/, UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/, - null /*_lastDescription*/, new ArrayList<>(), System.currentTimeMillis(), + null /*_lastDescription*/, System.currentTimeMillis(), true /*neverRelinquishIdentity*/, _taskDescription != null ? _taskDescription : new TaskDescription(), _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/, info.applicationInfo.uid, info.packageName, info.resizeMode, info.supportsPictureInPicture(), false /*_realActivitySuspended*/, false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info, - _voiceSession, _voiceInteractor); + _voiceSession, _voiceInteractor, stack); } /** Don't use constructor directly. This is only used by XML parser. */ @@ -368,15 +337,16 @@ class TaskRecord extends ConfigurationContainer { Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, - int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, + int _effectiveUid, String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info, - IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) { - mAtmService = atmService; - mTaskId = _taskId; + IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, + ActivityStack stack) { + super(_taskId, stack != null ? stack.mTaskStack : null, _userId, resizeMode, + supportsPictureInPicture, _lastTaskDescription, atmService); mRemoteToken = new RemoteToken(this); affinityIntent = _affinityIntent; affinity = _affinity; @@ -390,15 +360,12 @@ class TaskRecord extends ConfigurationContainer { isAvailable = true; autoRemoveRecents = _autoRemoveRecents; askedCompatMode = _askedCompatMode; - mUserId = _userId; mUserSetupComplete = userSetupComplete; effectiveUid = _effectiveUid; touchActiveTime(); lastDescription = _lastDescription; - mActivities = activities; mLastTimeMoved = lastTimeMoved; mNeverRelinquishIdentity = neverRelinquishIdentity; - mTaskDescription = _lastTaskDescription; mAffiliatedTaskId = taskAffiliation; mAffiliatedTaskColor = taskAffiliationColor; mPrevAffiliateTaskId = prevTaskId; @@ -406,7 +373,6 @@ class TaskRecord extends ConfigurationContainer { mCallingUid = callingUid; mCallingPackage = callingPackage; mResizeMode = resizeMode; - mSupportsPictureInPicture = supportsPictureInPicture; if (info != null) { setIntent(_intent, info); setMinDimensions(info); @@ -418,39 +384,6 @@ class TaskRecord extends ConfigurationContainer { mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity); } - Task getTask() { - return mTask; - } - - void createTask(boolean onTop, boolean showForAllUsers) { - if (mTask != null) { - throw new IllegalArgumentException("mTask=" + mTask - + " already created for task=" + this); - } - - final Rect bounds = updateOverrideConfigurationFromLaunchBounds(); - final TaskStack stack = getStack().getTaskStack(); - - if (stack == null) { - throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack); - } - EventLog.writeEvent(WM_TASK_CREATED, mTaskId, stack.mStackId); - mTask = new Task(mTaskId, stack, mUserId, mAtmService.mWindowManager, mResizeMode, - mSupportsPictureInPicture, mTaskDescription, this); - final int position = onTop ? POSITION_TOP : POSITION_BOTTOM; - - if (!mDisplayedBounds.isEmpty()) { - mTask.setOverrideDisplayedBounds(mDisplayedBounds); - } - // We only want to move the parents to the parents if we are creating this task at the - // top of its stack. - stack.addTask(mTask, position, showForAllUsers, onTop /* moveParents */); - } - - void setTask(Task task) { - mTask = task; - } - void cleanUpResourcesForDestroy() { if (hasChild()) { return; @@ -473,60 +406,33 @@ class TaskRecord extends ConfigurationContainer { mAtmService.mStackSupervisor.mRecentTasks.remove(this); } - removeWindowContainer(); + removeIfPossible(); } @VisibleForTesting - void removeWindowContainer() { + @Override + void removeIfPossible() { mAtmService.getLockTaskController().clearLockedTask(this); - if (mTask == null) { - if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId); - return; - } - mTask.removeIfPossible(); - mTask = null; - if (!getWindowConfiguration().persistTaskBounds()) { - // Reset current bounds for task whose bounds shouldn't be persisted so it uses - // default configuration the next time it launches. - setBounds(null); - } + super.removeIfPossible(); mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId); } - void onSnapshotChanged(TaskSnapshot snapshot) { - mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(mTaskId, snapshot); - } - void setResizeMode(int resizeMode) { if (mResizeMode == resizeMode) { return; } mResizeMode = resizeMode; - mTask.setResizeable(resizeMode); mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities(); } - void setTaskDockedResizing(boolean resizing) { - if (mTask == null) { - Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found."); - return; - } - mTask.setTaskDockedResizing(resizing); - } - - // TODO: Consolidate this with the resize() method below. - public void requestResize(Rect bounds, int resizeMode) { - mAtmService.resizeTask(mTaskId, bounds, resizeMode); - } - boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) { mAtmService.deferWindowLayout(); try { final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; - if (mTask == null) { + if (getParent() == null) { // Task doesn't exist in window manager yet (e.g. was restored from recents). // All we can do for now is update the bounds so it can be used when the task is // added to window manager. @@ -577,7 +483,7 @@ class TaskRecord extends ConfigurationContainer { } } } - mTask.resize(kept, forced); + resize(kept, forced); saveLaunchingStateIfNeeded(); @@ -588,19 +494,6 @@ class TaskRecord extends ConfigurationContainer { } } - // TODO: Investigate combining with the resize() method above. - void resizeWindowContainer() { - mTask.resize(false /* relayout */, false /* forced */); - } - - void getWindowContainerBounds(Rect bounds) { - if (mTask != null) { - mTask.getBounds(bounds); - } else { - bounds.setEmpty(); - } - } - /** * Convenience method to reparent a task to the top or bottom position of the stack. */ @@ -708,32 +601,16 @@ class TaskRecord extends ConfigurationContainer { // Adjust the position for the new parent stack as needed. position = toStack.getAdjustedPositionForTask(this, position, null /* starting */); - // Must reparent first in window manager to avoid a situation where AM can delete the - // we are coming from in WM before we reparent because it became empty. - mTask.reparent(toStack.getTaskStack(), position, - moveStackMode == REPARENT_MOVE_STACK_TO_FRONT); - final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront)); - // Move the task - sourceStack.removeTask(this, reason, moveStackToFront - ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING); - toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason); + + reparent(toStack.getTaskStack(), position, moveStackToFront, reason); if (schedulePictureInPictureModeChange) { // Notify of picture-in-picture mode changes supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack); } - // TODO: Ensure that this is actually necessary here - // Notify the voice session if required - if (voiceSession != null) { - try { - voiceSession.taskStarted(intent, mTaskId); - } catch (RemoteException e) { - } - } - // If the task had focus before (or we're requested to move focus), move focus to the // new stack by moving the stack to the front. if (r != null) { @@ -809,14 +686,6 @@ class TaskRecord extends ConfigurationContainer { || targetWindowingMode == WINDOWING_MODE_FREEFORM; } - void cancelWindowTransition() { - if (mTask == null) { - Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found."); - return; - } - mTask.cancelTaskWindowTransition(); - } - /** * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD! */ @@ -970,65 +839,103 @@ class TaskRecord extends ConfigurationContainer { return (T) mStack; } - /** - * Must be used for setting parent stack because it performs configuration updates. - * Must be called after adding task as a child to the stack. - */ - // TODO(task-unify): Remove or rework after task level unification. - void setStack(ActivityStack stack) { - if (stack != null && !stack.isInStackLocked(this)) { - throw new IllegalStateException("Task must be added as a Stack child first."); - } - final ActivityStack oldStack = mStack; - mStack = stack; + // TODO(stack-unify): Can be removed on stack unified. + void onParentChanged(ActivityStack newParent, ActivityStack oldParent) { + onParentChanged( + newParent != null ? newParent.mTaskStack : null, + oldParent != null ? oldParent.mTaskStack : null); + } + + @Override + void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { + final ActivityStack oldStack = (oldParent != null) + ? ((TaskStack) oldParent).mActivityStack : null; + final ActivityStack newStack = (newParent != null) + ? ((TaskStack) newParent).mActivityStack : null; + + mStack = newStack; - // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this - // {@link ActivityRecord} from its current {@link ActivityStack}. + super.onParentChanged(newParent, oldParent); - if (oldStack != mStack) { + if (oldStack != null) { for (int i = getChildCount() - 1; i >= 0; --i) { final ActivityRecord activity = getChildAt(i); + oldStack.onActivityRemovedFromStack(activity); + } - if (oldStack != null) { - oldStack.onActivityRemovedFromStack(activity); - } + updateTaskMovement(true /*toFront*/); - if (mStack != null) { - stack.onActivityAddedToStack(activity); + if (oldStack.inPinnedWindowingMode() + && (newStack == null || !newStack.inPinnedWindowingMode())) { + // Notify if a task from the pinned stack is being removed + // (or moved depending on the mode). + mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned(); + } + } + + if (newStack != null) { + for (int i = getChildCount() - 1; i >= 0; --i) { + final ActivityRecord activity = getChildAt(i); + newStack.onActivityAddedToStack(activity); + } + + // TODO: Ensure that this is actually necessary here + // Notify the voice session if required + if (voiceSession != null) { + try { + voiceSession.taskStarted(intent, mTaskId); + } catch (RemoteException e) { } } } - onParentChanged(mStack, oldStack); - } + // First time we are adding the task to the system. + if (oldParent == null && newParent != null) { - /** - * @return Id of current stack, {@link INVALID_STACK_ID} if no stack is set. - */ - int getStackId() { - return mStack != null ? mStack.mStackId : INVALID_STACK_ID; - } + // TODO: Super random place to be doing this, but aligns with what used to be done + // before we unified Task level. Look into if this can be done in a better place. + updateOverrideConfigurationFromLaunchBounds(); + } - @Override - protected int getChildCount() { - return mActivities.size(); - } + // Task is being removed. + if (oldParent != null && newParent == null) { + cleanUpResourcesForDestroy(); + } - @Override - protected ActivityRecord getChildAt(int index) { - return mActivities.get(index); + + // Update task bounds if needed. + adjustBoundsForDisplayChangeIfNeeded(getDisplayContent()); + + if (getWindowConfiguration().windowsAreScaleable()) { + // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them + // while a resize is pending. + forceWindowsScaleable(true /* force */); + } else { + forceWindowsScaleable(false /* force */); + } + + mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay(); } - @Override - protected ConfigurationContainer getParent() { - return mStack; + /** TODO(task-merge): Consolidate into {@link TaskStack#onChildPositionChanged}. */ + void updateTaskMovement(boolean toFront) { + if (isPersistable) { + mLastTimeMoved = System.currentTimeMillis(); + // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most + // recently will be most negative, tasks sent to the bottom before that will be less + // negative. Similarly for recent tasks moved to the top which will be most positive. + if (!toFront) { + mLastTimeMoved *= -1; + } + } + mAtmService.mRootActivityContainer.invalidateTaskLayers(); } - @Override - protected void onParentChanged( - ConfigurationContainer newParent, ConfigurationContainer oldParent) { - super.onParentChanged(newParent, oldParent); - mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay(); + /** + * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set. + */ + int getStackId() { + return mStack != null ? mStack.mStackId : INVALID_STACK_ID; } // Close up recents linked list. @@ -1121,16 +1028,6 @@ class TaskRecord extends ConfigurationContainer { return null; } - boolean isVisible() { - for (int i = getChildCount() - 1; i >= 0; --i) { - final ActivityRecord r = getChildAt(i); - if (r.visible) { - return true; - } - } - return false; - } - /** * Return true if any activities in this task belongs to input uid. */ @@ -1210,15 +1107,10 @@ class TaskRecord extends ConfigurationContainer { * Reorder the history stack so that the passed activity is brought to the front. */ final void moveActivityToFrontLocked(ActivityRecord newTop) { - if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, - "Removing and adding activity " + newTop - + " to stack at top callers=" + Debug.getCallers(4)); - - mActivities.remove(newTop); - mActivities.add(newTop); + if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity " + + newTop + " to stack at top callers=" + Debug.getCallers(4)); - // Make sure window manager is aware of the position change. - mTask.positionChildAtTop(newTop); + positionChildAtTop(newTop); updateEffectiveIntent(); } @@ -1232,19 +1124,29 @@ class TaskRecord extends ConfigurationContainer { return getChildAt(0).getActivityType(); } - /** Called when a Task child is added from the Task.java side. */ - // TODO(task-unify): Just override addChild to do what is needed when someone calls to add a - // child. - void onChildAdded(ActivityRecord r, int index) { + @Override + void addChild(ActivityRecord r, int index) { + if (r.getParent() != null) { + // Shouldn't already have a parent since we are just adding to the task...Maybe you + // meant to use reparent? + throw new IllegalStateException( + "r=" + r + " parent=" + r.getParent() + " task=" + this); + } + + // If this task had any child before we added this one. + boolean hadChild = hasChild(); + + index = getAdjustedAddPosition(r, index); + super.addChild(r, index); + + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this); r.inHistory = true; - // Remove r first, and if it wasn't already in the list and it's fullscreen, count it. - if (!mActivities.remove(r) && r.occludesParent()) { - // Was not previously in list. + if (r.occludesParent()) { numFullscreen++; } // Only set this based on the first activity - if (!hasChild()) { + if (!hadChild) { if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) { // Normally non-standard activity type for the activity record will be set when the // object is created, however we delay setting the standard application type until @@ -1264,20 +1166,6 @@ class TaskRecord extends ConfigurationContainer { r.setActivityType(getActivityType()); } - final int size = getChildCount(); - - if (index == size && size > 0) { - final ActivityRecord top = getChildAt(size - 1); - if (top.mTaskOverlay) { - // Place below the task overlay activity since the overlay activity should always - // be on top. - index--; - } - } - - index = Math.min(size, index); - mActivities.add(index, r); - updateEffectiveIntent(); if (r.isPersistable()) { mAtmService.notifyTaskPersisterLocked(this, false); @@ -1288,31 +1176,23 @@ class TaskRecord extends ConfigurationContainer { mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay(); } - // TODO(task-unify): Merge onChildAdded method below into this since task will be a single - // object. void addChild(ActivityRecord r) { - if (r.getParent() != null) { - // Shouldn't already have a parent since we are just adding to the task... - throw new IllegalStateException( - "r=" + r + " parent=" + r.getParent() + " task=" + this); - } + addChild(r, Integer.MAX_VALUE /* add on top */); + } - ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this); - // This means the activity isn't attached to Task.java yet. Go ahead and do that. - // TODO(task-unify): Remove/call super once we unify task level. - if (mTask != null) { - mTask.addChild(r, Integer.MAX_VALUE /* add on top */); - } else { - onChildAdded(r, Integer.MAX_VALUE); - } + @Override + void removeChild(ActivityRecord r) { + removeChild(r, "removeChild"); } - /** Called when a Task child is removed from the Task.java side. */ - // TODO(task-unify): Just override removeChild to do what is needed when someone calls to remove - // a child. - void onChildRemoved(ActivityRecord r) { - if (mActivities.remove(r) && r.occludesParent()) { - // Was previously in list. + void removeChild(ActivityRecord r, String reason) { + if (!mChildren.contains(r)) { + Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this); + return; + } + + super.removeChild(r); + if (r.occludesParent()) { numFullscreen--; } if (r.isPersistable()) { @@ -1336,16 +1216,19 @@ class TaskRecord extends ConfigurationContainer { // When destroying a task, tell the supervisor to remove it so that any activity it // has can be cleaned up correctly. This is currently the only place where we remove // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays - // state into removeTask(), we just clear the task here before the other residual + // state into removeChild(), we just clear the task here before the other residual // work. - // TODO: If the callers to removeTask() changes such that we have multiple places - // where we are destroying the task, move this back into removeTask() + // TODO: If the callers to removeChild() changes such that we have multiple places + // where we are destroying the task, move this back into removeChild() mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */, - !REMOVE_FROM_RECENTS, "onChildRemoved"); + !REMOVE_FROM_RECENTS, reason); } } else if (!mReuseTask) { // Remove entire task if it doesn't have any activity left and it isn't marked for reuse - mStack.removeTask(this, "onChildRemoved", REMOVE_TASK_MODE_DESTROYING); + mStack.removeChild(this, reason); + EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, + "removeChild: last r=" + r + " in t=" + this); + removeIfPossible(); } } @@ -1380,7 +1263,7 @@ class TaskRecord extends ConfigurationContainer { * Completely remove all activities associated with an existing * task starting at a specified index. */ - final void performClearTaskAtIndexLocked(int activityNdx, String reason) { + private void performClearTaskAtIndexLocked(int activityNdx, String reason) { int numActivities = getChildCount(); for ( ; activityNdx < numActivities; ++activityNdx) { final ActivityRecord r = getChildAt(activityNdx); @@ -1390,7 +1273,7 @@ class TaskRecord extends ConfigurationContainer { if (mStack == null) { // Task was restored from persistent storage. r.takeFromHistory(); - mActivities.remove(activityNdx); + removeChild(r); --activityNdx; --numActivities; } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason, @@ -1526,20 +1409,13 @@ class TaskRecord extends ConfigurationContainer { " mLockTaskAuth=" + lockTaskAuthToString()); } - private boolean isResizeable(boolean checkSupportsPip) { - return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode) - || (checkSupportsPip && mSupportsPictureInPicture)); - } - - boolean isResizeable() { - return isResizeable(true /* checkSupportsPip */); - } - @Override public boolean supportsSplitScreenWindowingMode() { // A task can not be docked even if it is considered resizeable because it only supports // picture-in-picture mode but has a non-resizeable resizeMode return super.supportsSplitScreenWindowingMode() + // TODO(task-group): Probably makes sense to move this and associated code into + // WindowContainer so it affects every node. && mAtmService.mSupportsSplitScreenMultiWindow && (mAtmService.mForceResizableActivities || (isResizeable(false /* checkSupportsPip */) @@ -1672,15 +1548,13 @@ class TaskRecord extends ConfigurationContainer { } topActivity = false; } - mTaskDescription = new TaskDescription(label, null, iconResource, iconFilename, - colorPrimary, colorBackground, statusBarColor, navigationBarColor, + final TaskDescription taskDescription = new TaskDescription(label, null, iconResource, + iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor, statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent); - if (mTask != null) { - mTask.setTaskDescription(mTaskDescription); - } + setTaskDescription(taskDescription); // Update the task affiliation color if we are the parent of the group if (mTaskId == mAffiliatedTaskId) { - mAffiliatedTaskColor = mTaskDescription.getPrimaryColor(); + mAffiliatedTaskColor = taskDescription.getPrimaryColor(); } } } @@ -1903,38 +1777,6 @@ class TaskRecord extends ConfigurationContainer { } /** - * Displayed bounds are used to set where the task is drawn at any given time. This is - * separate from its actual bounds so that the app doesn't see any meaningful configuration - * changes during transitionary periods. - */ - void setDisplayedBounds(Rect bounds) { - if (bounds == null) { - mDisplayedBounds.setEmpty(); - } else { - mDisplayedBounds.set(bounds); - } - if (mTask != null) { - mTask.setOverrideDisplayedBounds( - mDisplayedBounds.isEmpty() ? null : mDisplayedBounds); - } - } - - /** - * Gets the current overridden displayed bounds. These will be empty if the task is not - * currently overriding where it is displayed. - */ - Rect getDisplayedBounds() { - return mDisplayedBounds; - } - - /** - * @return {@code true} if this has overridden displayed bounds. - */ - boolean hasDisplayedBounds() { - return !mDisplayedBounds.isEmpty(); - } - - /** * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than * intersectBounds on a side, then the respective side will not be intersected. * @@ -2190,16 +2032,10 @@ class TaskRecord extends ConfigurationContainer { computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); } - /** @see WindowContainer#handlesOrientationChangeFromDescendant */ - boolean handlesOrientationChangeFromDescendant() { - return mTask != null && mTask.getParent() != null - && mTask.getParent().handlesOrientationChangeFromDescendant(); - } - /** - * Compute bounds (letterbox or pillarbox) for {@link #WINDOWING_MODE_FULLSCREEN} when the - * parent doesn't handle the orientation change and the requested orientation is different from - * the parent. + * Compute bounds (letterbox or pillarbox) for + * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the + * orientation change and the requested orientation is different from the parent. */ void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity, @NonNull Rect parentBounds, int parentOrientation) { @@ -2345,7 +2181,7 @@ class TaskRecord extends ConfigurationContainer { info.realActivity = realActivity; info.numActivities = mReuseActivitiesReport.numActivities; info.lastActiveTime = lastActiveTime; - info.taskDescription = new ActivityManager.TaskDescription(mTaskDescription); + info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription()); info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode(); info.resizeMode = mResizeMode; info.configuration.setTo(getConfiguration()); @@ -2435,7 +2271,7 @@ class TaskRecord extends ConfigurationContainer { } pw.println(")"); } - pw.print(prefix); pw.print("Activities="); pw.println(mActivities); + pw.print(prefix); pw.print("Activities="); pw.println(mChildren); if (!askedCompatMode || !inRecents || !isAvailable) { pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); pw.print(" inRecents="); pw.print(inRecents); @@ -2490,6 +2326,7 @@ class TaskRecord extends ConfigurationContainer { return toString(); } + @Override public void writeToProto(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { @@ -2497,13 +2334,13 @@ class TaskRecord extends ConfigurationContainer { } final long token = proto.start(fieldId); - super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel); + writeToProtoInnerTaskOnly(proto, TASK, logLevel); proto.write(ID, mTaskId); for (int i = getChildCount() - 1; i >= 0; i--) { - ActivityRecord activity = getChildAt(i); + final ActivityRecord activity = getChildAt(i); activity.writeToProto(proto, ACTIVITIES); } - proto.write(STACK_ID, mStack.mStackId); + proto.write(STACK_ID, getStackId()); if (mLastNonFullscreenBounds != null) { mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS); } @@ -2579,8 +2416,8 @@ class TaskRecord extends ConfigurationContainer { if (lastDescription != null) { out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); } - if (mTaskDescription != null) { - mTaskDescription.saveToXml(out); + if (getTaskDescription() != null) { + getTaskDescription().saveToXml(out); } out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); @@ -2641,14 +2478,14 @@ class TaskRecord extends ConfigurationContainer { static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, - IVoiceInteractor voiceInteractor) { + IVoiceInteractor voiceInteractor, ActivityStack stack) { return getTaskRecordFactory().create( - service, taskId, info, intent, voiceSession, voiceInteractor); + service, taskId, info, intent, voiceSession, voiceInteractor, stack); } static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, - Intent intent, TaskDescription taskDescription) { - return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription); + Intent intent, TaskDescription taskDescription, ActivityStack stack) { + return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription, stack); } static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) @@ -2665,15 +2502,15 @@ class TaskRecord extends ConfigurationContainer { TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, - IVoiceInteractor voiceInteractor) { + IVoiceInteractor voiceInteractor, ActivityStack stack) { return new TaskRecord(service, taskId, info, intent, voiceSession, voiceInteractor, - null /*taskDescription*/); + null /*taskDescription*/, stack); } TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, - Intent intent, TaskDescription taskDescription) { + Intent intent, TaskDescription taskDescription, ActivityStack stack) { return new TaskRecord(service, taskId, info, intent, null /*voiceSession*/, - null /*voiceInteractor*/, taskDescription); + null /*voiceInteractor*/, taskDescription, stack); } /** @@ -2683,20 +2520,20 @@ class TaskRecord extends ConfigurationContainer { Intent affinityIntent, String affinity, String rootAffinity, ComponentName realActivity, ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents, boolean askedCompatMode, int userId, - int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities, + int effectiveUid, String lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended, - boolean userSetupComplete, int minWidth, int minHeight) { + boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) { return new TaskRecord(service, taskId, intent, affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents, - askedCompatMode, userId, effectiveUid, lastDescription, activities, + askedCompatMode, userId, effectiveUid, lastDescription, lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/, - null /*_voiceInteractor*/); + null /*_voiceInteractor*/, stack); } TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) @@ -2908,15 +2745,15 @@ class TaskRecord extends ConfigurationContainer { taskId, intent, affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription, - activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription, + lastTimeOnTop, neverRelinquishIdentity, taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended, - userSetupComplete, minWidth, minHeight); + userSetupComplete, minWidth, minHeight, null /*stack*/); task.mLastNonFullscreenBounds = lastNonFullscreenBounds; task.setBounds(lastNonFullscreenBounds); for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { - activities.get(activityNdx).setTask(task); + task.addChild(activities.get(activityNdx)); } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 56211e25f421..68b76fb14174 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -116,7 +116,6 @@ public class TaskStack extends WindowContainer<Task> implements /** ActivityRecords that are exiting, but still on screen for animations. */ final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>(); - final ArrayList<ActivityRecord> mTmpActivities = new ArrayList<>(); /** Detach this stack from its display when animation completes. */ // TODO: maybe tie this to WindowContainer#removeChild some how... @@ -330,7 +329,7 @@ public class TaskStack extends WindowContainer<Task> implements } /** Bounds of the stack with other system factors taken into consideration. */ - public void getDimBounds(Rect out) { + void getDimBounds(Rect out) { getBounds(out); } @@ -482,11 +481,6 @@ public class TaskStack extends WindowContainer<Task> implements dividerSize); } - // TODO: Checkout the call points of this method and the ones below to see how they can fit in WC. - void addTask(Task task, int position) { - addTask(task, position, task.showForAllUsers(), true /* moveParents */); - } - /** * Put a Task in this stack. Used for adding only. * When task is added to top of the stack, the entire branch of the hierarchy (including stack @@ -495,22 +489,21 @@ public class TaskStack extends WindowContainer<Task> implements * @param position Target position to add the task to. * @param showForAllUsers Whether to show the task regardless of the current user. */ - void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) { - final TaskStack currentStack = task.mStack; - // TODO: We pass stack to task's constructor, but we still need to call this method. - // This doesn't make sense, mStack will already be set equal to "this" at this point. - if (currentStack != null && currentStack.mStackId != mStackId) { - throw new IllegalStateException("Trying to add taskId=" + task.mTaskId - + " to stackId=" + mStackId - + ", but it is already attached to stackId=" + task.mStack.mStackId); - } - + void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) { // Add child task. task.mStack = this; addChild(task, null); // Move child to a proper position, as some restriction for position might apply. - positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers); + position = positionChildAt( + position, task, moveParents /* includingParents */, showForAllUsers); + // TODO(task-merge): Remove cast. + mActivityStack.onChildAdded((TaskRecord) task, position); + } + + @Override + void addChild(Task task, int position) { + addChild(task, position, task.showForAllUsers(), false /* includingParents */); } void positionChildAt(Task child, int position) { @@ -563,13 +556,12 @@ public class TaskStack extends WindowContainer<Task> implements /** * Overridden version of {@link TaskStack#positionChildAt(int, Task, boolean)}. Used in - * {@link TaskStack#addTask(Task, int, boolean showForAllUsers, boolean)}, as it can receive - * showForAllUsers param from {@link AppWindowToken} instead of {@link Task#showForAllUsers()}. + * {@link TaskStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it can receive + * showForAllUsers param from {@link ActivityRecord} instead of {@link Task#showForAllUsers()}. */ - private void positionChildAt(int position, Task child, boolean includingParents, + int positionChildAt(int position, Task child, boolean includingParents, boolean showForAllUsers) { - final int targetPosition = findPositionForTask(child, position, showForAllUsers, - false /* addingNew */); + final int targetPosition = findPositionForTask(child, position, showForAllUsers); super.positionChildAt(targetPosition, child, includingParents); // Log positioning. @@ -578,6 +570,14 @@ public class TaskStack extends WindowContainer<Task> implements final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0; EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition); + + return targetPosition; + } + + @Override + void onChildPositionChanged(WindowContainer child) { + // TODO(task-merge): Read comment on updateTaskMovement method. + //((TaskRecord) child).updateTaskMovement(true); } void reparent(int displayId, Rect outStackBounds, boolean onTop) { @@ -597,14 +597,13 @@ public class TaskStack extends WindowContainer<Task> implements // TODO: We should really have users as a window container in the hierarchy so that we don't // have to do complicated things like we are doing in this method. - private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers, - boolean addingNew) { + private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers) { final boolean canShowTask = showForAllUsers || mWmService.isCurrentProfileLocked(task.mUserId); final int stackSize = mChildren.size(); int minPosition = 0; - int maxPosition = addingNew ? stackSize : stackSize - 1; + int maxPosition = stackSize - 1; if (canShowTask) { minPosition = computeMinPosition(minPosition, stackSize); @@ -615,8 +614,7 @@ public class TaskStack extends WindowContainer<Task> implements // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid. if (targetPosition == POSITION_BOTTOM && minPosition == 0) { return POSITION_BOTTOM; - } else if (targetPosition == POSITION_TOP - && maxPosition == (addingNew ? stackSize : stackSize - 1)) { + } else if (targetPosition == POSITION_TOP && maxPosition == (stackSize - 1)) { return POSITION_TOP; } // Reset position based on minimum/maximum possible positions. @@ -669,24 +667,17 @@ public class TaskStack extends WindowContainer<Task> implements */ @Override void removeChild(Task task) { + if (!mChildren.contains(task)) { + // Not really in this stack anymore... + return; + } if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + task); super.removeChild(task); task.mStack = null; - if (mDisplayContent != null) { - if (mChildren.isEmpty()) { - getParent().positionChildAt(POSITION_BOTTOM, this, false /* includingParents */); - } - mDisplayContent.setLayoutNeeded(); - } - for (int appNdx = mExitingActivities.size() - 1; appNdx >= 0; --appNdx) { - final ActivityRecord activity = mExitingActivities.get(appNdx); - if (activity.getTask() == task) { - activity.mIsExiting = false; - mExitingActivities.remove(appNdx); - } - } + // TODO(task-merge): Remove cast. + mActivityStack.onChildRemoved((TaskRecord) task, mDisplayContent); } @Override @@ -1298,7 +1289,7 @@ public class TaskStack extends WindowContainer<Task> implements super.writeToProto(proto, WINDOW_CONTAINER, logLevel); proto.write(ID, mStackId); for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) { - mChildren.get(taskNdx).writeToProto(proto, TASKS, logLevel); + mChildren.get(taskNdx).writeToProtoInnerTaskOnly(proto, TASKS, logLevel); } proto.write(FILLS_PARENT, matchParentBounds()); getRawBounds().writeToProto(proto, BOUNDS); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 7ce2b5eb727b..a393ba65fbc9 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -428,7 +428,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< parent.mTreeWeight += child.mTreeWeight; parent = parent.getParent(); } - onChildPositionChanged(); + onChildPositionChanged(child); } /** @@ -454,7 +454,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< parent.mTreeWeight -= child.mTreeWeight; parent = parent.getParent(); } - onChildPositionChanged(); + onChildPositionChanged(child); } /** @@ -583,7 +583,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (mChildren.peekLast() != child) { mChildren.remove(child); mChildren.add(child); - onChildPositionChanged(); + onChildPositionChanged(child); } if (includingParents && getParent() != null) { getParent().positionChildAt(POSITION_TOP, this /* child */, @@ -594,7 +594,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (mChildren.peekFirst() != child) { mChildren.remove(child); mChildren.addFirst(child); - onChildPositionChanged(); + onChildPositionChanged(child); } if (includingParents && getParent() != null) { getParent().positionChildAt(POSITION_BOTTOM, this /* child */, @@ -608,14 +608,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // doing this adjustment here and remove any adjustments in the callers. mChildren.remove(child); mChildren.add(position, child); - onChildPositionChanged(); + onChildPositionChanged(child); } } /** * Notify that a child's position has changed. Possible changes are adding or removing a child. */ - void onChildPositionChanged() { } + void onChildPositionChanged(WindowContainer child) { } /** * Update override configuration and recalculate full config. diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 17e67ebf617f..344befad8fa9 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -638,7 +638,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private boolean mIsDimming = false; private @Nullable InsetsSourceProvider mControllableInsetProvider; - private InsetsState mClientInsetsState = new InsetsState(); + private InsetsState mClientInsetsState; private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f; private KeyInterceptionInfo mKeyInterceptionInfo; @@ -767,6 +767,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mSeq = seq; mPowerManagerWrapper = powerManagerWrapper; mForceSeamlesslyRotate = token.mRoundedCornerOverlay; + mClientInsetsState = + getDisplayContent().getInsetsStateController().getInsetsForDispatch(this); if (DEBUG) { Slog.v(TAG, "Window " + this + " client=" + c.asBinder() + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a); @@ -2207,7 +2209,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mInputChannel = inputChannels[0]; mClientChannel = inputChannels[1]; mWmService.mInputManager.registerInputChannel(mInputChannel); - mClientChannel.setToken(mInputChannel.getToken()); mInputWindowHandle.token = mInputChannel.getToken(); if (outInputChannel != null) { mClientChannel.transferTo(outInputChannel); diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index da355ea0ca3b..425b4b632971 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -23,7 +23,6 @@ cc_library_static { "com_android_server_AlarmManagerService.cpp", "com_android_server_am_BatteryStatsService.cpp", "com_android_server_connectivity_Vpn.cpp", - "com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp", "com_android_server_ConsumerIrService.cpp", "com_android_server_devicepolicy_CryptoTestHelper.cpp", "com_android_server_HardwarePropertiesManagerService.cpp", @@ -54,6 +53,7 @@ cc_library_static { "com_android_server_am_LowMemDetector.cpp", "onload.cpp", ":lib_networkStatsFactory_native", + ":tethering-jni-srcs", ], include_dirs: [ diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 35e2436817df..b546a1d9ef4e 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1596,8 +1596,8 @@ static jboolean nativeTransferTouchFocus(JNIEnv* env, return JNI_FALSE; } - if (im->getInputManager()->getDispatcher()-> - transferTouchFocus(fromChannel->getToken(), toChannel->getToken())) { + if (im->getInputManager()->getDispatcher()->transferTouchFocus( + fromChannel->getConnectionToken(), toChannel->getConnectionToken())) { return JNI_TRUE; } else { return JNI_FALSE; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 2009dbdca448..ef9e69df01df 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -439,7 +439,7 @@ public final class SystemServer { // In case the runtime switched since last boot (such as when // the old runtime was removed in an OTA), set the system - // property so that it is in sync. We can | xq oqi't do this in + // property so that it is in sync. We can't do this in // libnativehelper's JniInvocation::Init code where we already // had to fallback to a different runtime because it is // running as root and we need to be the system user to set diff --git a/services/net/Android.bp b/services/net/Android.bp index e24dec562a46..c56ecd6e19e7 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -29,6 +29,7 @@ filegroup { "java/android/net/ConnectivityModuleConnector.java", "java/android/net/NetworkStackClient.java", "java/android/net/ip/InterfaceController.java", + "java/android/net/netlink/*.java", "java/android/net/util/InterfaceParams.java", "java/android/net/util/NetdService.java", "java/android/net/util/NetworkConstants.java", diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java index 485f436f7f65..556f96ace5d2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java @@ -24,6 +24,7 @@ import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow; @@ -35,6 +36,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.AlarmManagerService.ACTIVE_INDEX; import static com.android.server.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED; import static com.android.server.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED; +import static com.android.server.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED; import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_LONG_TIME; import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_SHORT_TIME; import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION; @@ -80,9 +82,9 @@ import android.provider.Settings; import android.util.Log; import android.util.SparseArray; -import androidx.test.filters.FlakyTest; import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.MockedVoidMethod; import com.android.internal.annotations.GuardedBy; import com.android.server.usage.AppStandbyInternal; @@ -171,7 +173,6 @@ public class AlarmManagerServiceTest { } public class Injector extends AlarmManagerService.Injector { - boolean mIsAutomotiveOverride; Injector(Context context) { super(context); @@ -257,12 +258,13 @@ public class AlarmManagerServiceTest { .startMocking(); doReturn(mIActivityManager).when(ActivityManager::getService); doReturn(mAppStateTracker).when(() -> LocalServices.getService(AppStateTracker.class)); - doReturn(null) - .when(() -> LocalServices.getService(DeviceIdleInternal.class)); doReturn(mAppStandbyInternal).when( () -> LocalServices.getService(AppStandbyInternal.class)); doReturn(mUsageStatsManagerInternal).when( () -> LocalServices.getService(UsageStatsManagerInternal.class)); + doCallRealMethod().when((MockedVoidMethod) () -> + LocalServices.addService(eq(AlarmManagerInternal.class), any())); + doCallRealMethod().when(() -> LocalServices.getService(AlarmManagerInternal.class)); when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong())) .thenReturn(STANDBY_BUCKET_ACTIVE); @@ -455,7 +457,6 @@ public class AlarmManagerServiceTest { assertEquals(expectedTriggerTime, mTestTimer.getElapsed()); } - @FlakyTest(bugId = 130313408) @Test public void testEarliestAlarmSet() { final PendingIntent pi6 = getNewMockPendingIntent(); @@ -600,11 +601,15 @@ public class AlarmManagerServiceTest { anyLong())).thenReturn(bucket); mAppStandbyListener.onAppIdleStateChanged(TEST_CALLING_PACKAGE, UserHandle.getUserId(TEST_CALLING_UID), false, bucket, 0); + assertAndHandleMessageSync(APP_STANDBY_BUCKET_CHANGED); + } + + private void assertAndHandleMessageSync(int what) { final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture()); final Message lastMessage = messageCaptor.getValue(); assertEquals("Unexpected message send to handler", lastMessage.what, - APP_STANDBY_BUCKET_CHANGED); + what); mService.mHandler.handleMessage(lastMessage); } @@ -664,12 +669,7 @@ public class AlarmManagerServiceTest { mChargingReceiver.onReceive(mMockContext, new Intent(parole ? BatteryManager.ACTION_CHARGING : BatteryManager.ACTION_DISCHARGING)); - final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); - verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture()); - final Message lastMessage = messageCaptor.getValue(); - assertEquals("Unexpected message send to handler", lastMessage.what, - CHARGING_STATUS_CHANGED); - mService.mHandler.handleMessage(lastMessage); + assertAndHandleMessageSync(CHARGING_STATUS_CHANGED); } @Test @@ -971,12 +971,13 @@ public class AlarmManagerServiceTest { } @Test - public void alarmCountOnPendingIntentCancel() { + public void alarmCountOnRemoveForCanceled() { + final AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class); final PendingIntent pi = getNewMockPendingIntent(); - setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 123, pi); - verify(pi).registerCancelListener(mService.mOperationCancelListener); + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 12345, pi); assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); - mService.mOperationCancelListener.onCancelled(pi); + ami.remove(pi); + assertAndHandleMessageSync(REMOVE_FOR_CANCELED); assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); } @@ -985,5 +986,6 @@ public class AlarmManagerServiceTest { if (mMockingSession != null) { mMockingSession.finishMocking(); } + LocalServices.removeServiceForTest(AlarmManagerInternal.class); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java new file mode 100644 index 000000000000..3975f0baa22a --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019 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.server.am; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; +import android.app.ActivityManagerInternal; +import android.app.AppGlobals; +import android.app.PendingIntent; +import android.content.Intent; +import android.content.pm.IPackageManager; +import android.os.Looper; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.AlarmManagerInternal; +import com.android.server.LocalServices; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + +@RunWith(AndroidJUnit4.class) +public class PendingIntentControllerTest { + private static final String TEST_PACKAGE_NAME = "test-package-1"; + private static final int TEST_CALLING_UID = android.os.Process.myUid(); + private static final Intent[] TEST_INTENTS = new Intent[]{new Intent("com.test.intent")}; + + @Mock + private UserController mUserController; + @Mock + private AlarmManagerInternal mAlarmManagerInternal; + @Mock + private ActivityManagerInternal mActivityManagerInternal; + @Mock + private IPackageManager mIPackageManager; + + private MockitoSession mMockingSession; + private PendingIntentController mPendingIntentController; + + @Before + public void setUp() throws Exception { + mMockingSession = mockitoSession() + .initMocks(this) + .mockStatic(LocalServices.class) + .mockStatic(AppGlobals.class) + .strictness(Strictness.LENIENT) // Needed to stub LocalServices.getService twice + .startMocking(); + doReturn(mAlarmManagerInternal).when( + () -> LocalServices.getService(AlarmManagerInternal.class)); + doReturn(mActivityManagerInternal).when( + () -> LocalServices.getService(ActivityManagerInternal.class)); + doReturn(mIPackageManager).when(() -> AppGlobals.getPackageManager()); + when(mIPackageManager.getPackageUid(eq(TEST_PACKAGE_NAME), anyInt(), anyInt())).thenReturn( + TEST_CALLING_UID); + mPendingIntentController = new PendingIntentController(Looper.getMainLooper(), + mUserController); + mPendingIntentController.onActivityManagerInternalAdded(); + } + + private PendingIntentRecord createPendingIntentRecord(int flags) { + return mPendingIntentController.getIntentSender(ActivityManager.INTENT_SENDER_BROADCAST, + TEST_PACKAGE_NAME, TEST_CALLING_UID, 0, null, null, 0, TEST_INTENTS, null, flags, + null); + } + + @Test + public void alarmsRemovedOnCancel() { + final PendingIntentRecord pir = createPendingIntentRecord(0); + mPendingIntentController.cancelIntentSender(pir); + final ArgumentCaptor<PendingIntent> piCaptor = ArgumentCaptor.forClass(PendingIntent.class); + verify(mAlarmManagerInternal).remove(piCaptor.capture()); + assertEquals("Wrong target for pending intent passed to alarm manager", pir, + piCaptor.getValue().getTarget()); + } + + @Test + public void alarmsRemovedOnRecreateWithCancelCurrent() { + final PendingIntentRecord pir = createPendingIntentRecord(0); + createPendingIntentRecord(PendingIntent.FLAG_CANCEL_CURRENT); + final ArgumentCaptor<PendingIntent> piCaptor = ArgumentCaptor.forClass(PendingIntent.class); + verify(mAlarmManagerInternal).remove(piCaptor.capture()); + assertEquals("Wrong target for pending intent passed to alarm manager", pir, + piCaptor.getValue().getTarget()); + } + + @Test + public void alarmsRemovedOnSendingOneShot() { + final PendingIntentRecord pir = createPendingIntentRecord(PendingIntent.FLAG_ONE_SHOT); + pir.send(0, null, null, null, null, null, null); + final ArgumentCaptor<PendingIntent> piCaptor = ArgumentCaptor.forClass(PendingIntent.class); + verify(mAlarmManagerInternal).remove(piCaptor.capture()); + assertEquals("Wrong target for pending intent passed to alarm manager", pir, + piCaptor.getValue().getTarget()); + } + + @After + public void tearDown() { + if (mMockingSession != null) { + mMockingSession.finishMocking(); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java index 184dc3dfed62..a47a5671ccb3 100644 --- a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java @@ -16,6 +16,8 @@ package com.android.server.attention; +import static com.android.server.attention.AttentionManagerService.ATTENTION_CACHE_BUFFER_SIZE; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -39,6 +41,8 @@ import android.service.attention.IAttentionService; import androidx.test.filters.SmallTest; import com.android.server.attention.AttentionManagerService.AttentionCheck; +import com.android.server.attention.AttentionManagerService.AttentionCheckCache; +import com.android.server.attention.AttentionManagerService.AttentionCheckCacheBuffer; import com.android.server.attention.AttentionManagerService.AttentionHandler; import com.android.server.attention.AttentionManagerService.UserState; @@ -56,11 +60,16 @@ public class AttentionManagerServiceTest { private AttentionManagerService mSpyAttentionManager; private UserState mSpyUserState; private final int mTimeout = 1000; - @Mock private AttentionCallbackInternal mMockAttentionCallbackInternal; - @Mock private AttentionHandler mMockHandler; - @Mock private IAttentionCallback mMockIAttentionCallback; - @Mock private IPowerManager mMockIPowerManager; - @Mock Context mContext; + @Mock + private AttentionCallbackInternal mMockAttentionCallbackInternal; + @Mock + private AttentionHandler mMockHandler; + @Mock + private IAttentionCallback mMockIAttentionCallback; + @Mock + private IPowerManager mMockIPowerManager; + @Mock + Context mContext; @Before public void setUp() throws RemoteException { @@ -140,12 +149,45 @@ public class AttentionManagerServiceTest { mSpyAttentionManager.onSwitchUser(userId); } + @Test + public void testAttentionCheckCacheBuffer_getLast_returnTheLastElement() { + AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer(); + buffer.add(new AttentionCheckCache(0, 0, 1L)); + AttentionCheckCache cache = new AttentionCheckCache(0, 0, 2L); + buffer.add(cache); + assertThat(buffer.getLast()).isEqualTo(cache); + } + + @Test + public void testAttentionCheckCacheBuffer_get_returnNullWhenOutOfBoundary() { + AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer(); + assertThat(buffer.get(1)).isNull(); + } + + @Test + public void testAttentionCheckCacheBuffer_get_handleCircularIndexing() { + AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer(); + AttentionCheckCache cache = new AttentionCheckCache(0L, 0, 1L); + // Insert SIZE+1 elements. + for (int i = 0; i <= ATTENTION_CACHE_BUFFER_SIZE; i++) { + if (i == 1) { + buffer.add(cache); + } else { + buffer.add(new AttentionCheckCache(0L, 0, i)); + } + } + // The element that was at index 1 should be at index 0 after inserting SIZE + 1 elements. + assertThat(buffer.get(0)).isEqualTo(cache); + } + private class MockIAttentionService implements IAttentionService { public void checkAttention(IAttentionCallback callback) throws RemoteException { callback.onSuccess(0, 0); } + public void cancelAttentionCheck(IAttentionCallback callback) { } + public IBinder asBinder() { return null; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 38d6c9c1e4db..2ce37f1be4c5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -53,8 +53,6 @@ import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStack.ActivityState.STARTED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; @@ -136,13 +134,13 @@ public class ActivityRecordTests extends ActivityTestsBase { @Test public void testStackCleanupOnActivityRemoval() { - mTask.mTask.removeChild(mActivity); + mTask.removeChild(mActivity); verify(mStack, times(1)).onActivityRemovedFromStack(any()); } @Test public void testStackCleanupOnTaskRemoval() { - mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING); + mStack.removeChild(mTask, null /*reason*/); // Stack should be gone on task removal. assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId)); } @@ -325,7 +323,7 @@ public class ActivityRecordTests extends ActivityTestsBase { : ORIENTATION_PORTRAIT; mTask.onRequestedOverrideConfigurationChanged(newConfig); - doReturn(true).when(mTask.mTask).isDragResizing(); + doReturn(true).when(mTask).isDragResizing(); mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; @@ -382,7 +380,7 @@ public class ActivityRecordTests extends ActivityTestsBase { } // Mimic the behavior that display doesn't handle app's requested orientation. - final DisplayContent dc = mTask.mTask.getDisplayContent(); + final DisplayContent dc = mTask.getDisplayContent(); doReturn(false).when(dc).onDescendantOrientationChanged(any(), any()); doReturn(false).when(dc).handlesOrientationChangeFromDescendant(); @@ -1174,7 +1172,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Empty the home stack. final ActivityStack homeStack = mActivity.getDisplay().getHomeStack(); for (TaskRecord t : homeStack.getAllTasks()) { - homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING); + homeStack.removeChild(t, "test"); } mActivity.finishing = true; doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities(); @@ -1200,7 +1198,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // Empty the home stack. final ActivityStack homeStack = mActivity.getDisplay().getHomeStack(); for (TaskRecord t : homeStack.getAllTasks()) { - homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING); + homeStack.removeChild(t, "test"); } mActivity.finishing = true; spyOn(mStack); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index fcebb81fd658..cc0cc3f85d50 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -38,7 +38,6 @@ import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; @@ -93,21 +92,6 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testEmptyTaskCleanupOnRemove() { - assertNotNull(mTask.getTask()); - mStack.removeTask(mTask, "testEmptyTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); - assertNull(mTask.getTask()); - } - - @Test - public void testOccupiedTaskCleanupOnRemove() { - final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); - assertNotNull(mTask.getTask()); - mStack.removeTask(mTask, "testOccupiedTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); - assertNotNull(mTask.getTask()); - } - - @Test public void testResumedActivity() { final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); assertNull(mStack.getResumedActivity()); @@ -996,27 +980,6 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testAdjustFocusedStackToHomeWhenNoActivity() { - final ActivityStack homeStask = mDefaultDisplay.getHomeStack(); - TaskRecord homeTask = homeStask.topTask(); - if (homeTask == null) { - // Create home task if there isn't one. - homeTask = new TaskBuilder(mSupervisor).setStack(homeStask).build(); - } - - final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); - mStack.moveToFront("testAdjustFocusedStack"); - - // Simulate that home activity has not been started or is force-stopped. - homeStask.removeTask(homeTask, "testAdjustFocusedStack", REMOVE_TASK_MODE_DESTROYING); - - // Finish the only activity. - topActivity.finishIfPossible("testAdjustFocusedStack", false /* oomAdj */); - // Although home stack is empty, it should still be the focused stack. - assertEquals(homeStask, mDefaultDisplay.getFocusedStack()); - } - - @Test public void testWontFinishHomeStackImmediately() { final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index ace5d4efa39b..a28bbb60d70c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -715,7 +715,7 @@ public class ActivityStarterTests extends ActivityTestsBase { if (startedActivity != null && startedActivity.getTaskRecord() != null) { // Remove the activity so it doesn't interfere with with subsequent activity launch // tests from this method. - startedActivity.getTaskRecord().mTask.removeChild(startedActivity); + startedActivity.getTaskRecord().removeChild(startedActivity); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 78db6c92772f..1db8f1b1b596 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -269,7 +269,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { // fullscreen value is normally read from resources in ctor, so for testing we need // to set it somewhere else since we can't mock resources. doReturn(true).when(activity).occludesParent(); - activity.setTask(mTaskRecord); + mTaskRecord.addChild(activity); // Make visible by default... activity.setHidden(false); } @@ -376,15 +376,13 @@ class ActivityTestsBase extends SystemServiceTestsBase { final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo, intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/, - null /*taskDescription*/); + null /*taskDescription*/, mStack); spyOn(task); task.mUserId = mUserId; if (mStack != null) { mStack.moveToFront("test"); - mStack.addTask(task, true, "creating test task"); - task.createTask(true, true); - spyOn(task.mTask); + mStack.addChild(task, true, true); } return task; diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java index 1fb6a563aa40..c5301b8a8c6e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java @@ -165,7 +165,7 @@ public class AppChangeTransitionTests extends WindowTestsBase { // setup currently defaults to no snapshot. setUpOnDisplay(mDisplayContent); - mTask.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM); + mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); assertEquals(1, mDisplayContent.mChangingApps.size()); assertTrue(mActivity.isInChangeTransition()); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 2f0486d3e81b..d33dbd1dda7c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -48,7 +48,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import android.content.res.Configuration; @@ -63,7 +63,6 @@ import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; /** * Tests for the {@link ActivityRecord} class. @@ -209,9 +208,11 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testSizeCompatBounds() { + // TODO(task-merge): Move once Task is merged into TaskRecord + final TaskRecord tr = (TaskRecord) mTask; // Disable the real configuration resolving because we only simulate partial flow. // TODO: Have test use full flow. - doNothing().when(mTask.mTaskRecord).computeConfigResourceOverrides(any(), any()); + doNothing().when(tr).computeConfigResourceOverrides(any(), any()); final Rect fixedBounds = mActivity.getRequestedOverrideConfiguration().windowConfiguration .getBounds(); fixedBounds.set(0, 0, 1200, 1600); @@ -337,11 +338,9 @@ public class AppWindowTokenTests extends WindowTestsBase { mDisplayContent.getDisplayRotation().setFixedToUserRotation( DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED); - - mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS); + reset(mTask); mActivity.reportDescendantOrientationChangeIfNeeded(); - - verify(mTask.mTaskRecord).onConfigurationChanged(any(Configuration.class)); + verify(mTask).onConfigurationChanged(any(Configuration.class)); } @Test @@ -451,6 +450,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testTransitionAnimationBounds() { + removeGlobalMinSizeRestriction(); final Rect stackBounds = new Rect(0, 0, 1000, 600); final Rect taskBounds = new Rect(100, 400, 600, 800); mStack.setBounds(stackBounds); @@ -458,16 +458,16 @@ public class AppWindowTokenTests extends WindowTestsBase { // Check that anim bounds for freeform window match task bounds mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); - assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_NONE)); + assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_NONE)); // STACK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by // bounds animation layer. mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - assertEquals(taskBounds, mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM)); + assertEquals(mTask.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_AFTER_ANIM)); // STACK_CLIP_BEFORE_ANIM should use stack bounds since it won't be clipped later. mTask.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - assertEquals(stackBounds, mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM)); + assertEquals(mStack.getBounds(), mActivity.getAnimationBounds(STACK_CLIP_BEFORE_ANIM)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index 8c2ae5a7659a..55947ae9626f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -178,11 +178,14 @@ public class InsetsPolicyTest extends WindowTestsBase { @Test public void testShowTransientBars_topCanBeTransient_appGetsTopFakeControl() { + // Adding app window before setting source visibility is to prevent the visibility from + // being cleared by InsetsSourceProvider.updateVisibility. + final WindowState app = addWindow(TYPE_APPLICATION, "app"); + addWindow(TYPE_STATUS_BAR, "topBar") .getControllableInsetProvider().getSource().setVisible(false); addWindow(TYPE_NAVIGATION_BAR, "navBar") .getControllableInsetProvider().getSource().setVisible(true); - final WindowState app = addWindow(TYPE_APPLICATION, "app"); final InsetsPolicy policy = mDisplayContent.getInsetsPolicy(); policy.updateBarControlTarget(app); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index cc598ffa63bd..69091c61ec90 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -885,7 +885,7 @@ public class RecentTasksTest extends ActivityTestsBase { final int taskId = task.mTaskId; mRecentTasks.add(task); // Only keep the task in RecentTasks. - task.removeWindowContainer(); + task.removeIfPossible(); mStack.remove(); // The following APIs should not restore task from recents to the active list. diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index 839ddb2038ff..ca8f5351c73a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -196,9 +196,6 @@ public class RecentsAnimationTest extends ActivityTestsBase { doReturn(app).when(mService).getProcessController(eq(recentActivity.processName), anyInt()); ClientLifecycleManager lifecycleManager = mService.getLifecycleManager(); doNothing().when(lifecycleManager).scheduleTransaction(any()); - AppWarnings appWarnings = mService.getAppWarningsLocked(); - spyOn(appWarnings); - doNothing().when(appWarnings).onStartActivity(any()); startRecentsActivity(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index aa97de72e507..63f70c05f203 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -36,7 +36,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityDisplay.POSITION_TOP; -import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; @@ -272,8 +271,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { assertTrue(pinnedActivity.isFocusable()); // Without the overridding activity, stack should not be focusable. - pinnedStack.removeTask(pinnedActivity.getTaskRecord(), "testFocusability", - REMOVE_TASK_MODE_DESTROYING); + pinnedStack.removeChild(pinnedActivity.getTaskRecord(), "testFocusability"); assertFalse(pinnedStack.isFocusable()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index fa1f435a37c0..ad1d1afe7603 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -437,6 +437,10 @@ public class SystemServicesTestRule implements TestRule { spyOn(getLockTaskController()); spyOn(getTaskChangeNotificationController()); initRootActivityContainerMocks(); + + AppWarnings appWarnings = getAppWarningsLocked(); + spyOn(appWarnings); + doNothing().when(appWarnings).onStartActivity(any()); } void initRootActivityContainerMocks() { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java index df55b39b0817..012eb5252c50 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java @@ -79,8 +79,9 @@ public class TaskPositionerTests extends WindowTestsBase { // This should be the same calculation as the TaskPositioner uses. mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm); + removeGlobalMinSizeRestriction(); - mPositioner = new TaskPositioner(mWm, mock(IActivityTaskManager.class)); + mPositioner = new TaskPositioner(mWm, mWm.mAtmService); mPositioner.register(mDisplayContent); mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window"); @@ -493,10 +494,7 @@ public class TaskPositionerTests extends WindowTestsBase { + ") " + Log.getStackTraceString(new Throwable())); } } - assertEquals("left", expected.left, actual.left); - assertEquals("right", expected.right, actual.right); - assertEquals("top", expected.top, actual.top); - assertEquals("bottom", expected.bottom, actual.bottom); + assertEquals(expected, actual); } @FlakyTest(bugId = 129492888) diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java index f8d49ad18664..d2342f081fa1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -66,7 +66,8 @@ public class TaskPositioningControllerTests extends WindowTestsBase { any(InputChannel.class))).thenReturn(true); mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window"); - mWindow.getTask().setResizeable(RESIZE_MODE_RESIZEABLE); + // TODO(task-merge): Remove cast. + ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_RESIZEABLE); mWindow.mInputChannel = new InputChannel(); mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor(); @@ -142,7 +143,8 @@ public class TaskPositioningControllerTests extends WindowTestsBase { doReturn(mWindow.getTask()).when(content).findTaskForResizePoint(anyInt(), anyInt()); assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow()); - mWindow.getTask().setResizeable(RESIZE_MODE_UNRESIZEABLE); + // TODO(task-merge): Remove cast. + ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_UNRESIZEABLE); mTarget.handleTapOutsideTask(content, 0, 0); // Wait until the looper processes finishTaskPositioning. diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index a4e38f15e0e7..2cafc965e648 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -132,7 +132,7 @@ public class TaskRecordTests extends ActivityTestsBase { @Test public void testCopyBaseIntentForTaskInfo() { final TaskRecord task = createTaskRecord(1); - task.mTaskDescription = new ActivityManager.TaskDescription(); + task.setTaskDescription(new ActivityManager.TaskDescription()); final TaskInfo info = task.getTaskInfo(); // The intent of info should be a copy so assert that they are different instances. @@ -348,10 +348,12 @@ public class TaskRecordTests extends ActivityTestsBase { TaskRecord task = stack.getChildAt(0); ActivityRecord root = task.getTopActivity(); - final WindowContainer parentWindowContainer = mock(WindowContainer.class); - Mockito.doReturn(parentWindowContainer).when(task.mTask).getParent(); - Mockito.doReturn(true).when(parentWindowContainer) - .handlesOrientationChangeFromDescendant(); + final WindowContainer parentWindowContainer = + new WindowContainer(mSystemServicesTestRule.getWindowManagerService()); + spyOn(parentWindowContainer); + parentWindowContainer.setBounds(fullScreenBounds); + doReturn(parentWindowContainer).when(task).getParent(); + doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant(); // Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the // bounds because its parent says it will handle it at a later time. @@ -433,7 +435,7 @@ public class TaskRecordTests extends ActivityTestsBase { info.targetActivity = targetClassName; final TaskRecord task = TaskRecord.create(mService, 1 /* taskId */, info, intent, - null /* taskDescription */); + null /* taskDescription */, null /*stack*/); assertEquals("The alias activity component should be saved in task intent.", aliasClassName, task.intent.getComponent().getClassName()); @@ -834,8 +836,9 @@ public class TaskRecordTests extends ActivityTestsBase { private TaskRecord createTaskRecord(int taskId) { return new TaskRecord(mService, taskId, new Intent(), null, null, null, ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null, - new ArrayList<>(), 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0, - 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/); + 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0, + 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/, + null /*stack*/); } private static class TestTaskRecordFactory extends TaskRecordFactory { @@ -843,16 +846,16 @@ public class TaskRecordTests extends ActivityTestsBase { @Override TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, - Intent intent, - IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) { + Intent intent, IVoiceInteractionSession voiceSession, + IVoiceInteractor voiceInteractor, ActivityStack stack) { mCreated = true; return null; } @Override TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info, - Intent intent, - ActivityManager.TaskDescription taskDescription) { + Intent intent, ActivityManager.TaskDescription taskDescription, + ActivityStack stack) { mCreated = true; return null; } @@ -863,14 +866,14 @@ public class TaskRecordTests extends ActivityTestsBase { ComponentName realActivity, ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents, boolean askedCompatMode, int userId, int effectiveUid, String lastDescription, - ArrayList<ActivityRecord> activities, long lastTimeMoved, + long lastTimeMoved, boolean neverRelinquishIdentity, ActivityManager.TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended, boolean userSetupComplete, int minWidth, - int minHeight) { + int minHeight, ActivityStack stack) { mCreated = true; return null; } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 4dfa26644fa9..cb2e1e03a446 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; @@ -92,7 +94,7 @@ public class TaskTests extends WindowTestsBase { boolean gotException = false; try { - task.reparent(stackController1, 0, false/* moveParents */); + task.reparent(stackController1, 0, false/* moveParents */, "testReparent"); } catch (IllegalArgumentException e) { gotException = true; } @@ -100,14 +102,14 @@ public class TaskTests extends WindowTestsBase { gotException = false; try { - task.reparent(null, 0, false/* moveParents */); + task.reparent(null, 0, false/* moveParents */, "testReparent"); } catch (IllegalArgumentException e) { gotException = true; } assertTrue("Should not be able to reparent to a stack that doesn't exist", gotException); - task.reparent(stackController2, 0, false/* moveParents */); + task.reparent(stackController2, 0, false/* moveParents */, "testReparent"); assertEquals(stackController2, task.getParent()); assertEquals(0, task.getParent().mChildren.indexOf(task)); assertEquals(1, task2.getParent().mChildren.indexOf(task2)); @@ -125,7 +127,7 @@ public class TaskTests extends WindowTestsBase { final TaskStack stack2 = createTaskStackOnDisplay(dc); final Task task2 = createTaskInStack(stack2, 0 /* userId */); // Reparent and check state - task.reparent(stack2, 0, false /* moveParents */); + task.reparent(stack2, 0, false /* moveParents */, "testReparent_BetweenDisplays"); assertEquals(stack2, task.getParent()); assertEquals(0, task.getParent().mChildren.indexOf(task)); assertEquals(1, task2.getParent().mChildren.indexOf(task2)); @@ -138,6 +140,7 @@ public class TaskTests extends WindowTestsBase { final Task task = createTaskInStack(stack1, 0 /* userId */); // Check that setting bounds also updates surface position + task.setWindowingMode(WINDOWING_MODE_FREEFORM); Rect bounds = new Rect(10, 10, 100, 200); task.setBounds(bounds); assertEquals(new Point(bounds.left, bounds.top), task.getLastSurfacePosition()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java index 8cd97cb8a344..428d869fe3cd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java @@ -255,6 +255,7 @@ public class WindowFrameTests extends WindowTestsBase { @Test public void testLayoutNonfullscreenTask() { + removeGlobalMinSizeRestriction(); final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo(); final int logicalWidth = displayInfo.logicalWidth; final int logicalHeight = displayInfo.logicalHeight; @@ -264,8 +265,8 @@ public class WindowFrameTests extends WindowTestsBase { WindowState w = createWindow(); final Task task = w.getTask(); // Use split-screen because it is non-fullscreen, but also not floating - task.mTaskRecord.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - task.mTaskRecord.setBounds(taskBounds); + task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + task.setBounds(taskBounds); // The bounds we are requesting might be different from what the system resolved based on // other factors. final Rect resolvedTaskBounds = task.getBounds(); @@ -303,8 +304,8 @@ public class WindowFrameTests extends WindowTestsBase { final int insetTop = logicalHeight / 5; final int insetRight = insetLeft + (resolvedTaskBounds.right - resolvedTaskBounds.left); final int insetBottom = insetTop + (resolvedTaskBounds.bottom - resolvedTaskBounds.top); - task.mTaskRecord.setDisplayedBounds(resolvedTaskBounds); - task.mTaskRecord.setBounds(insetLeft, insetTop, insetRight, insetBottom); + task.setOverrideDisplayedBounds(resolvedTaskBounds); + task.setBounds(insetLeft, insetTop, insetRight, insetBottom); windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect); w.computeFrameLw(); assertEquals(resolvedTaskBounds, w.getFrameLw()); @@ -477,7 +478,7 @@ public class WindowFrameTests extends WindowTestsBase { WindowState w = createWindow(); final Task task = w.getTask(); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; - task.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM); + task.setWindowingMode(WINDOWING_MODE_FREEFORM); DisplayContent dc = mTestDisplayContent; dc.mInputMethodTarget = w; @@ -499,7 +500,7 @@ public class WindowFrameTests extends WindowTestsBase { // First check that it only gets moved up enough to show window. final Rect winRect = new Rect(200, 200, 300, 500); - task.mTaskRecord.setBounds(winRect); + task.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect); w.computeFrameLw(); @@ -511,7 +512,7 @@ public class WindowFrameTests extends WindowTestsBase { // Now check that it won't get moved beyond the top and then has appropriate insets winRect.bottom = 600; - task.mTaskRecord.setBounds(winRect); + task.setBounds(winRect); w.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect); w.computeFrameLw(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 51daf6567a47..3f32e33a76ec 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -42,7 +42,7 @@ class WindowTestUtils { .setUserId(userId) .setStack(stack.mActivityStack) .build(); - return task.mTask; + return task; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 780fed9805cb..c3f59eb75460 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -384,7 +384,7 @@ class WindowTestsBase extends SystemServiceTestsBase { } /** Sets the default minimum task size to 1 so that tests can use small task sizes */ - public void removeGlobalMinSizeRestriction() { + void removeGlobalMinSizeRestriction() { mWm.mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp = 1; } } diff --git a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java index 7d8e430e5416..b68e04f9b29f 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java +++ b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java @@ -448,10 +448,10 @@ final class UsageStatsProtoV2 { final long packagesToken = proto.start( IntervalStatsObfuscatedProto.PACKAGES); UsageStats usageStats = parseUsageStats(proto, stats.beginTime); + proto.end(packagesToken); if (usageStats.mPackageToken != PackagesTokenData.UNASSIGNED_TOKEN) { stats.packageStatsObfuscated.put(usageStats.mPackageToken, usageStats); } - proto.end(packagesToken); } catch (IOException e) { Slog.e(TAG, "Unable to read some usage stats from proto.", e); } @@ -484,6 +484,13 @@ final class UsageStatsProtoV2 { if (stats.endTime == 0) { stats.endTime = stats.beginTime; } + // update the begin and end time stamps for all usage stats + final int usageStatsSize = stats.packageStatsObfuscated.size(); + for (int i = 0; i < usageStatsSize; i++) { + final UsageStats usageStats = stats.packageStatsObfuscated.valueAt(i); + usageStats.mBeginTimeStamp = stats.beginTime; + usageStats.mEndTimeStamp = stats.endTime; + } return; } } diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp index c380d291d573..7cc233b2439e 100644 --- a/startop/view_compiler/Android.bp +++ b/startop/view_compiler/Android.bp @@ -16,7 +16,6 @@ cc_defaults { name: "viewcompiler_defaults", - defaults: ["libdexfile_static_defaults"], header_libs: [ "libbase_headers", ], @@ -30,6 +29,7 @@ cc_defaults { "liblog", "libutils", "libziparchive", + "libz", ], cppflags: ["-std=c++17"], target: { diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc index 48b44d0fc99b..50cf5a50d7a8 100644 --- a/startop/view_compiler/dex_builder.cc +++ b/startop/view_compiler/dex_builder.cc @@ -16,8 +16,6 @@ #include "dex_builder.h" -#include "dex/descriptors_names.h" - #include <fstream> #include <memory> @@ -30,8 +28,6 @@ using std::string; using ::dex::kAccPublic; using Op = Instruction::Op; -using Opcode = ::art::Instruction::Code; - const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; }; const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; }; @@ -43,20 +39,29 @@ constexpr uint8_t kDexFileMagic[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x38, 0x00 constexpr size_t kMaxEncodedStringLength{5}; // Converts invoke-* to invoke-*/range -constexpr Opcode InvokeToInvokeRange(Opcode opcode) { +constexpr ::dex::Opcode InvokeToInvokeRange(::dex::Opcode opcode) { switch (opcode) { - case ::art::Instruction::INVOKE_VIRTUAL: - return ::art::Instruction::INVOKE_VIRTUAL_RANGE; - case ::art::Instruction::INVOKE_DIRECT: - return ::art::Instruction::INVOKE_DIRECT_RANGE; - case ::art::Instruction::INVOKE_STATIC: - return ::art::Instruction::INVOKE_STATIC_RANGE; - case ::art::Instruction::INVOKE_INTERFACE: - return ::art::Instruction::INVOKE_INTERFACE_RANGE; + case ::dex::Opcode::OP_INVOKE_VIRTUAL: + return ::dex::Opcode::OP_INVOKE_VIRTUAL_RANGE; + case ::dex::Opcode::OP_INVOKE_DIRECT: + return ::dex::Opcode::OP_INVOKE_DIRECT_RANGE; + case ::dex::Opcode::OP_INVOKE_STATIC: + return ::dex::Opcode::OP_INVOKE_STATIC_RANGE; + case ::dex::Opcode::OP_INVOKE_INTERFACE: + return ::dex::Opcode::OP_INVOKE_INTERFACE_RANGE; default: LOG(FATAL) << opcode << " is not a recognized invoke opcode."; - UNREACHABLE(); + __builtin_unreachable(); + } +} + +std::string DotToDescriptor(const char* class_name) { + std::string descriptor(class_name); + std::replace(descriptor.begin(), descriptor.end(), '.', '/'); + if (descriptor.length() > 0 && descriptor[0] != '[') { + descriptor = "L" + descriptor + ";"; } + return descriptor; } } // namespace @@ -178,7 +183,7 @@ void WriteTestDexFile(const string& filename) { } TypeDescriptor TypeDescriptor::FromClassname(const std::string& name) { - return TypeDescriptor{art::DotToDescriptor(name.c_str())}; + return TypeDescriptor{DotToDescriptor(name.c_str())}; } DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} { @@ -219,11 +224,11 @@ ir::String* DexBuilder::GetOrAddString(const std::string& string) { ClassBuilder DexBuilder::MakeClass(const std::string& name) { auto* class_def = Alloc<ir::Class>(); - ir::Type* type_def = GetOrAddType(art::DotToDescriptor(name.c_str())); + ir::Type* type_def = GetOrAddType(DotToDescriptor(name.c_str())); type_def->class_def = class_def; class_def->type = type_def; - class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object")); + class_def->super_class = GetOrAddType(DotToDescriptor("java.lang.Object")); class_def->access_flags = kAccPublic; return ClassBuilder{this, name, class_def}; } @@ -378,26 +383,26 @@ void MethodBuilder::EncodeInstructions() { void MethodBuilder::EncodeInstruction(const Instruction& instruction) { switch (instruction.opcode()) { case Instruction::Op::kReturn: - return EncodeReturn(instruction, ::art::Instruction::RETURN); + return EncodeReturn(instruction, ::dex::Opcode::OP_RETURN); case Instruction::Op::kReturnObject: - return EncodeReturn(instruction, ::art::Instruction::RETURN_OBJECT); + return EncodeReturn(instruction, ::dex::Opcode::OP_RETURN_OBJECT); case Instruction::Op::kMove: case Instruction::Op::kMoveObject: return EncodeMove(instruction); case Instruction::Op::kInvokeVirtual: - return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL); + return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_VIRTUAL); case Instruction::Op::kInvokeDirect: - return EncodeInvoke(instruction, art::Instruction::INVOKE_DIRECT); + return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_DIRECT); case Instruction::Op::kInvokeStatic: - return EncodeInvoke(instruction, art::Instruction::INVOKE_STATIC); + return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_STATIC); case Instruction::Op::kInvokeInterface: - return EncodeInvoke(instruction, art::Instruction::INVOKE_INTERFACE); + return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_INTERFACE); case Instruction::Op::kBindLabel: return BindLabel(instruction.args()[0]); case Instruction::Op::kBranchEqz: - return EncodeBranch(art::Instruction::IF_EQZ, instruction); + return EncodeBranch(::dex::Opcode::OP_IF_EQZ, instruction); case Instruction::Op::kBranchNEqz: - return EncodeBranch(art::Instruction::IF_NEZ, instruction); + return EncodeBranch(::dex::Opcode::OP_IF_NEZ, instruction); case Instruction::Op::kNew: return EncodeNew(instruction); case Instruction::Op::kCheckCast: @@ -410,10 +415,10 @@ void MethodBuilder::EncodeInstruction(const Instruction& instruction) { } } -void MethodBuilder::EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode) { +void MethodBuilder::EncodeReturn(const Instruction& instruction, ::dex::Opcode opcode) { CHECK(!instruction.dest().has_value()); if (instruction.args().size() == 0) { - Encode10x(art::Instruction::RETURN_VOID); + Encode10x(::dex::Opcode::OP_RETURN_VOID); } else { CHECK_EQ(1, instruction.args().size()); size_t source = RegisterValue(instruction.args()[0]); @@ -433,27 +438,27 @@ void MethodBuilder::EncodeMove(const Instruction& instruction) { if (source.is_immediate()) { // TODO: support more registers CHECK_LT(RegisterValue(*instruction.dest()), 16); - Encode11n(art::Instruction::CONST_4, RegisterValue(*instruction.dest()), source.value()); + Encode11n(::dex::Opcode::OP_CONST_4, RegisterValue(*instruction.dest()), source.value()); } else if (source.is_string()) { constexpr size_t kMaxRegisters = 256; CHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters); CHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string - Encode21c(::art::Instruction::CONST_STRING, RegisterValue(*instruction.dest()), source.value()); + Encode21c(::dex::Opcode::OP_CONST_STRING, RegisterValue(*instruction.dest()), source.value()); } else if (source.is_variable()) { // For the moment, we only use this when we need to reshuffle registers for // an invoke instruction, meaning we are too big for the 4-bit version. // We'll err on the side of caution and always generate the 16-bit form of // the instruction. - Opcode opcode = instruction.opcode() == Instruction::Op::kMove - ? ::art::Instruction::MOVE_16 - : ::art::Instruction::MOVE_OBJECT_16; + auto opcode = instruction.opcode() == Instruction::Op::kMove + ? ::dex::Opcode::OP_MOVE_16 + : ::dex::Opcode::OP_MOVE_OBJECT_16; Encode32x(opcode, RegisterValue(*instruction.dest()), RegisterValue(source)); } else { UNIMPLEMENTED(FATAL); } } -void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode) { +void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::dex::Opcode opcode) { constexpr size_t kMaxArgs = 5; // Currently, we only support up to 5 arguments. @@ -480,8 +485,8 @@ void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruct for (size_t i = 0; i < instruction.args().size(); ++i) { Instruction::Op move_op; - if (opcode == ::art::Instruction::INVOKE_VIRTUAL || - opcode == ::art::Instruction::INVOKE_DIRECT) { + if (opcode == ::dex::Opcode::OP_INVOKE_VIRTUAL || + opcode == ::dex::Opcode::OP_INVOKE_DIRECT) { // In this case, there is an implicit `this` argument, which is always an object. if (i == 0) { move_op = Instruction::Op::kMoveObject; @@ -514,8 +519,8 @@ void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruct // If there is a return value, add a move-result instruction if (instruction.dest().has_value()) { - Encode11x(instruction.result_is_object() ? art::Instruction::MOVE_RESULT_OBJECT - : art::Instruction::MOVE_RESULT, + Encode11x(instruction.result_is_object() ? ::dex::Opcode::OP_MOVE_RESULT_OBJECT + : ::dex::Opcode::OP_MOVE_RESULT, RegisterValue(*instruction.dest())); } @@ -523,7 +528,7 @@ void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruct } // Encodes a conditional branch that tests a single argument. -void MethodBuilder::EncodeBranch(art::Instruction::Code op, const Instruction& instruction) { +void MethodBuilder::EncodeBranch(::dex::Opcode op, const Instruction& instruction) { const auto& args = instruction.args(); const auto& test_value = args[0]; const auto& branch_target = args[1]; @@ -546,7 +551,7 @@ void MethodBuilder::EncodeNew(const Instruction& instruction) { const Value& type = instruction.args()[0]; CHECK_LT(RegisterValue(*instruction.dest()), 256); CHECK(type.is_type()); - Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value()); + Encode21c(::dex::Opcode::OP_NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value()); } void MethodBuilder::EncodeCast(const Instruction& instruction) { @@ -558,7 +563,7 @@ void MethodBuilder::EncodeCast(const Instruction& instruction) { const Value& type = instruction.args()[0]; CHECK_LT(RegisterValue(*instruction.dest()), 256); CHECK(type.is_type()); - Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value()); + Encode21c(::dex::Opcode::OP_CHECK_CAST, RegisterValue(*instruction.dest()), type.value()); } void MethodBuilder::EncodeFieldOp(const Instruction& instruction) { @@ -569,7 +574,7 @@ void MethodBuilder::EncodeFieldOp(const Instruction& instruction) { CHECK(instruction.dest()->is_variable()); CHECK_EQ(0, instruction.args().size()); - Encode21c(::art::Instruction::SGET, + Encode21c(::dex::Opcode::OP_SGET, RegisterValue(*instruction.dest()), instruction.index_argument()); break; @@ -579,7 +584,7 @@ void MethodBuilder::EncodeFieldOp(const Instruction& instruction) { CHECK_EQ(1, args.size()); CHECK(args[0].is_variable()); - Encode21c(::art::Instruction::SPUT, RegisterValue(args[0]), instruction.index_argument()); + Encode21c(::dex::Opcode::OP_SPUT, RegisterValue(args[0]), instruction.index_argument()); break; } case Instruction::Op::kGetInstanceField: { @@ -587,7 +592,7 @@ void MethodBuilder::EncodeFieldOp(const Instruction& instruction) { CHECK(instruction.dest()->is_variable()); CHECK_EQ(1, instruction.args().size()); - Encode22c(::art::Instruction::IGET, + Encode22c(::dex::Opcode::OP_IGET, RegisterValue(*instruction.dest()), RegisterValue(args[0]), instruction.index_argument()); @@ -599,7 +604,7 @@ void MethodBuilder::EncodeFieldOp(const Instruction& instruction) { CHECK(args[0].is_variable()); CHECK(args[1].is_variable()); - Encode22c(::art::Instruction::IPUT, + Encode22c(::dex::Opcode::OP_IPUT, RegisterValue(args[1]), RegisterValue(args[0]), instruction.index_argument()); diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h index 3924e77fab59..3ae37ce1f762 100644 --- a/startop/view_compiler/dex_builder.h +++ b/startop/view_compiler/dex_builder.h @@ -24,7 +24,9 @@ #include <unordered_map> #include <vector> -#include "dex/dex_instruction.h" +#include "android-base/logging.h" + +#include "slicer/dex_bytecode.h" #include "slicer/dex_ir.h" #include "slicer/writer.h" @@ -364,11 +366,11 @@ class MethodBuilder { // Encodes a return instruction. For instructions with no return value, the opcode field is // ignored. Otherwise, this specifies which return instruction will be used (return, // return-object, etc.) - void EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode); + void EncodeReturn(const Instruction& instruction, ::dex::Opcode opcode); void EncodeMove(const Instruction& instruction); - void EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode); - void EncodeBranch(art::Instruction::Code op, const Instruction& instruction); + void EncodeInvoke(const Instruction& instruction, ::dex::Opcode opcode); + void EncodeBranch(::dex::Opcode op, const Instruction& instruction); void EncodeNew(const Instruction& instruction); void EncodeCast(const Instruction& instruction); void EncodeFieldOp(const Instruction& instruction); @@ -377,17 +379,18 @@ class MethodBuilder { // https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of // formats. - inline void Encode10x(art::Instruction::Code opcode) { + inline void Encode10x(::dex::Opcode opcode) { // 00|op - buffer_.push_back(opcode); + static_assert(sizeof(uint8_t) == sizeof(::dex::Opcode)); + buffer_.push_back(static_cast<uint8_t>(opcode)); } - inline void Encode11x(art::Instruction::Code opcode, uint8_t a) { + inline void Encode11x(::dex::Opcode opcode, uint8_t a) { // aa|op buffer_.push_back((a << 8) | opcode); } - inline void Encode11n(art::Instruction::Code opcode, uint8_t a, int8_t b) { + inline void Encode11n(::dex::Opcode opcode, uint8_t a, int8_t b) { // b|a|op // Make sure the fields are in bounds (4 bits for a, 4 bits for b). @@ -398,13 +401,13 @@ class MethodBuilder { buffer_.push_back(((b & 0xf) << 12) | (a << 8) | opcode); } - inline void Encode21c(art::Instruction::Code opcode, uint8_t a, uint16_t b) { + inline void Encode21c(::dex::Opcode opcode, uint8_t a, uint16_t b) { // aa|op|bbbb buffer_.push_back((a << 8) | opcode); buffer_.push_back(b); } - inline void Encode22c(art::Instruction::Code opcode, uint8_t a, uint8_t b, uint16_t c) { + inline void Encode22c(::dex::Opcode opcode, uint8_t a, uint8_t b, uint16_t c) { // b|a|op|bbbb CHECK(IsShortRegister(a)); CHECK(IsShortRegister(b)); @@ -412,13 +415,13 @@ class MethodBuilder { buffer_.push_back(c); } - inline void Encode32x(art::Instruction::Code opcode, uint16_t a, uint16_t b) { + inline void Encode32x(::dex::Opcode opcode, uint16_t a, uint16_t b) { buffer_.push_back(opcode); buffer_.push_back(a); buffer_.push_back(b); } - inline void Encode35c(art::Instruction::Code opcode, size_t a, uint16_t b, uint8_t c, uint8_t d, + inline void Encode35c(::dex::Opcode opcode, size_t a, uint16_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f, uint8_t g) { // a|g|op|bbbb|f|e|d|c @@ -433,7 +436,7 @@ class MethodBuilder { buffer_.push_back((f << 12) | (e << 8) | (d << 4) | c); } - inline void Encode3rc(art::Instruction::Code opcode, size_t a, uint16_t b, uint16_t c) { + inline void Encode3rc(::dex::Opcode opcode, size_t a, uint16_t b, uint16_t c) { CHECK_LE(a, 255); buffer_.push_back((a << 8) | opcode); buffer_.push_back(b); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 010446492d16..dbada25f50a8 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -828,13 +828,6 @@ public class CarrierConfigManager { "disable_severe_when_extreme_disabled_bool"; /** - * The message expiration time in milliseconds for duplicate detection purposes. - * @hide - */ - public static final String KEY_MESSAGE_EXPIRATION_TIME_LONG = - "message_expiration_time_long"; - - /** * The data call retry configuration for different types of APN. * @hide */ @@ -3371,7 +3364,6 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false); sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false); sDefaults.putBoolean(KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true); - sDefaults.putLong(KEY_MESSAGE_EXPIRATION_TIME_LONG, 86400000L); sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{ "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000," + "320000:5000,640000:5000,1280000:5000,1800000:5000", diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index b5e91d0bad85..75e4fec97825 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2371,12 +2371,10 @@ public class SubscriptionManager { * @param plans the list of plans. The first plan is always the primary and * most important plan. Any additional plans are secondary and * may not be displayed or used by decision making logic. - * The list of all plans must meet the requirements defined in - * {@link SubscriptionPlan.Builder#setNetworkTypes(int[])}. * @throws SecurityException if the caller doesn't meet the requirements * outlined above. * @throws IllegalArgumentException if plans don't meet the requirements - * mentioned above. + * defined in {@link SubscriptionPlan}. */ public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) { try { diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/telephony/java/android/telephony/SubscriptionPlan.java index e24eb2696c6c..28a5c2086ede 100644 --- a/telephony/java/android/telephony/SubscriptionPlan.java +++ b/telephony/java/android/telephony/SubscriptionPlan.java @@ -44,6 +44,14 @@ import java.util.Objects; * as explaining how much mobile data they have remaining, and what will happen * when they run out. * + * If specifying network types, the developer must supply at least one plan + * that applies to all network types (default), and all additional plans + * may not include a particular network type more than once. + * This is enforced by {@link SubscriptionManager} when setting the plans. + * + * Plan selection will prefer plans that have specific network types defined + * over plans that apply to all network types. + * * @see SubscriptionManager#setSubscriptionPlans(int, java.util.List) * @see SubscriptionManager#getSubscriptionPlans(int) */ @@ -213,7 +221,7 @@ public final class SubscriptionPlan implements Parcelable { /** * Return an array containing all {@link NetworkType}s this SubscriptionPlan applies to. - * A null array means this SubscriptionPlan applies to all network types. + * A null value means this SubscriptionPlan applies to all network types. */ public @Nullable @NetworkType int[] getNetworkTypes() { return networkTypes; @@ -372,20 +380,13 @@ public final class SubscriptionPlan implements Parcelable { /** * Set the network types this SubscriptionPlan applies to. - * The developer must supply at least one plan that applies to all network types (default), - * and all additional plans may not include a particular network type more than once. - * Plan selection will prefer plans that have specific network types defined - * over plans that apply to all network types. * * @param networkTypes a set of all {@link NetworkType}s that apply to this plan. - * A null value or empty array means the plan applies to all network types. + * A null value means the plan applies to all network types, + * and an empty array means the plan applies to no network types. */ public @NonNull Builder setNetworkTypes(@Nullable @NetworkType int[] networkTypes) { - if (networkTypes == null || networkTypes.length == 0) { - plan.networkTypes = null; - } else { - plan.networkTypes = networkTypes; - } + plan.networkTypes = networkTypes; return this; } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 0c663f85b99c..4eb5a362efae 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -9567,18 +9567,37 @@ public class TelephonyManager { } /** - * Resets Telephony and IMS settings back to factory defaults. + * Resets telephony manager settings back to factory defaults. * * @hide */ - @SystemApi - @RequiresPermission(Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset(int subId) { try { Log.d(TAG, "factoryReset: subId=" + subId); ITelephony telephony = getITelephony(); - if (telephony != null) + if (telephony != null) { telephony.factoryReset(subId); + } + } catch (RemoteException e) { + } + } + + + /** + * Resets Telephony and IMS settings back to factory defaults only for the subscription + * associated with this instance. + * @see #createForSubscriptionId(int) + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.CONNECTIVITY_INTERNAL) + public void resetSettings() { + try { + Log.d(TAG, "resetSettings: subId=" + getSubId()); + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.factoryReset(getSubId()); + } } catch (RemoteException e) { } } diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 7cafa1ea068c..9fc8e7563a81 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -254,8 +254,8 @@ public class ImsMmTelManager implements RegistrationManager { * the {@link ImsService} associated with the subscription is not available. This can happen if * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed * reason. - * @deprecated Use {@link #registerImsRegistrationCallback( - * RegistrationManager.RegistrationCallback, Executor)} instead. + * @deprecated Use {@link RegistrationManager#registerImsRegistrationCallback(Executor, + * RegistrationManager.RegistrationCallback)} instead. */ @Deprecated @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @@ -285,9 +285,8 @@ public class ImsMmTelManager implements RegistrationManager { /**{@inheritDoc}*/ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void registerImsRegistrationCallback( - @NonNull RegistrationManager.RegistrationCallback c, - @NonNull @CallbackExecutor Executor executor) throws ImsException { + public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull RegistrationManager.RegistrationCallback c) throws ImsException { if (c == null) { throw new IllegalArgumentException("Must include a non-null RegistrationCallback."); } @@ -348,8 +347,8 @@ public class ImsMmTelManager implements RegistrationManager { /**{@inheritDoc}*/ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback, - @NonNull @CallbackExecutor Executor executor) { + public void getRegistrationState(@NonNull @CallbackExecutor Executor executor, + @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) { if (stateCallback == null) { throw new IllegalArgumentException("Must include a non-null callback."); } @@ -371,9 +370,9 @@ public class ImsMmTelManager implements RegistrationManager { /**{@inheritDoc}*/ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void getRegistrationTransportType( - @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback, - @NonNull @CallbackExecutor Executor executor) { + public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor, + @NonNull @AccessNetworkConstants.TransportType + Consumer<Integer> transportTypeCallback) { if (transportTypeCallback == null) { throw new IllegalArgumentException("Must include a non-null callback."); } @@ -607,17 +606,17 @@ public class ImsMmTelManager implements RegistrationManager { * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} broadcast for this subscription. * @param capability The capability that is being queried for support on the carrier network. * @param transportType The transport type of the capability to check support for. + * @param executor The executor that the callback will be called with. * @param callback A consumer containing a Boolean result specifying whether or not the * capability is supported on this carrier network for the transport specified. - * @param executor The executor that the callback will be called with. * @throws ImsException if the subscription is no longer valid or the IMS service is not * available. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability, @AccessNetworkConstants.TransportType int transportType, - @NonNull Consumer<Boolean> callback, - @NonNull @CallbackExecutor Executor executor) throws ImsException { + @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Boolean> callback) throws ImsException { if (callback == null) { throw new IllegalArgumentException("Must include a non-null Consumer."); } diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java index 25bd1caea431..6432016ac2c3 100644 --- a/telephony/java/android/telephony/ims/ImsRcsManager.java +++ b/telephony/java/android/telephony/ims/ImsRcsManager.java @@ -141,8 +141,8 @@ public class ImsRcsManager implements RegistrationManager { /**{@inheritDoc}*/ @Override public void registerImsRegistrationCallback( - @NonNull RegistrationManager.RegistrationCallback c, - @NonNull @CallbackExecutor Executor executor) + @NonNull @CallbackExecutor Executor executor, + @NonNull RegistrationCallback c) throws ImsException { if (c == null) { throw new IllegalArgumentException("Must include a non-null RegistrationCallback."); @@ -168,8 +168,8 @@ public class ImsRcsManager implements RegistrationManager { /**{@inheritDoc}*/ @Override - public void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback, - @NonNull @CallbackExecutor Executor executor) { + public void getRegistrationState(@NonNull @CallbackExecutor Executor executor, + @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) { if (stateCallback == null) { throw new IllegalArgumentException("Must include a non-null stateCallback."); } @@ -182,9 +182,9 @@ public class ImsRcsManager implements RegistrationManager { /**{@inheritDoc}*/ @Override - public void getRegistrationTransportType( - @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback, - @NonNull @CallbackExecutor Executor executor) { + public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor, + @NonNull @AccessNetworkConstants.TransportType + Consumer<Integer> transportTypeCallback) { if (transportTypeCallback == null) { throw new IllegalArgumentException("Must include a non-null transportTypeCallback."); } diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index b4c11e3c32a1..23402b88f3b1 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -90,7 +90,7 @@ public interface RegistrationManager { /** * Callback class for receiving IMS network Registration callback events. - * @see #registerImsRegistrationCallback(RegistrationCallback, Executor) + * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) * @see #unregisterImsRegistrationCallback(RegistrationCallback) */ class RegistrationCallback { @@ -229,8 +229,8 @@ public interface RegistrationManager { * When the callback is registered, it will initiate the callback c to be called with the * current registration state. * - * @param c The {@link RegistrationCallback} to be added. * @param executor The executor the callback events should be run on. + * @param c The {@link RegistrationCallback} to be added. * @see #unregisterImsRegistrationCallback(RegistrationCallback) * @throws ImsException if the subscription associated with this callback is valid, but * the {@link ImsService} associated with the subscription is not available. This can happen if @@ -238,8 +238,8 @@ public interface RegistrationManager { * reason. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - void registerImsRegistrationCallback(@NonNull RegistrationCallback c, - @NonNull @CallbackExecutor Executor executor) throws ImsException; + void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull RegistrationCallback c) throws ImsException; /** * Removes an existing {@link RegistrationCallback}. @@ -250,36 +250,36 @@ public interface RegistrationManager { * * @param c The {@link RegistrationCallback} to be removed. * @see SubscriptionManager.OnSubscriptionsChangedListener - * @see #registerImsRegistrationCallback(RegistrationCallback, Executor) + * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c); /** * Gets the registration state of the IMS service. - * @param stateCallback A callback called on the supplied {@link Executor} that will contain the - * registration state of the IMS service, which will be one of the - * following: {@link #REGISTRATION_STATE_NOT_REGISTERED}, - * {@link #REGISTRATION_STATE_REGISTERING}, or - * {@link #REGISTRATION_STATE_REGISTERED}. * @param executor The {@link Executor} that will be used to call the IMS registration state * callback. + * @param stateCallback A callback called on the supplied {@link Executor} that will contain the + * registration state of the IMS service, which will be one of the + * following: {@link #REGISTRATION_STATE_NOT_REGISTERED}, + * {@link #REGISTRATION_STATE_REGISTERING}, or + * {@link #REGISTRATION_STATE_REGISTERED}. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback, - @NonNull @CallbackExecutor Executor executor); + void getRegistrationState(@NonNull @CallbackExecutor Executor executor, + @NonNull @ImsRegistrationState Consumer<Integer> stateCallback); /** * Gets the Transport Type associated with the current IMS registration. - * @param transportTypeCallback The transport type associated with the current IMS registration, - * which will be one of following: - * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}, - * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or - * {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID}. * @param executor The {@link Executor} that will be used to call the transportTypeCallback. + * @param transportTypeCallback The transport type associated with the current IMS registration, + * which will be one of following: + * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}, + * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or + * {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID}. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) void getRegistrationTransportType( - @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback, - @NonNull @CallbackExecutor Executor executor); + @NonNull @CallbackExecutor Executor executor, + @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback); } diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java index ead4a28beff4..74aaec1eee34 100644 --- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java +++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java @@ -108,13 +108,18 @@ public class BootImageProfileTest implements IDeviceTest { // Test the profile contents contain common methods for core-oj that would normally be AOT // compiled. res = mTestDevice.executeShellCommand("profman --dump-classes-and-methods --profile-file=" - + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar"); + + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar" + + " --apk=/system/framework/services.jar"); boolean sawObjectInit = false; + boolean sawPmInit = false; for (String line : res.split("\n")) { if (line.contains("Ljava/lang/Object;-><init>()V")) { sawObjectInit = true; + } else if (line.contains("Lcom/android/server/pm/PackageManagerService;-><init>")) { + sawPmInit = true; } } assertTrue("Did not see Object.<init> in " + res, sawObjectInit); + assertTrue("Did not see PackageManagerService.<init> in " + res, sawPmInit); } } diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java index 7d88161a2805..176c7a0ada7b 100644 --- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java +++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java @@ -32,7 +32,7 @@ public class HierrarchicalDataClassBase implements Parcelable { - // Code below generated by codegen v1.0.12. + // Code below generated by codegen v1.0.13. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -98,8 +98,8 @@ public class HierrarchicalDataClassBase implements Parcelable { }; @DataClass.Generated( - time = 1572655992854L, - codegenVersion = "1.0.12", + time = 1573006405823L, + codegenVersion = "1.0.13", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java", inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java index c930ce535ab6..e348c77c0ac6 100644 --- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java +++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java @@ -46,7 +46,7 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase { - // Code below generated by codegen v1.0.12. + // Code below generated by codegen v1.0.13. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -120,8 +120,8 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase { }; @DataClass.Generated( - time = 1572655993858L, - codegenVersion = "1.0.12", + time = 1573006406833L, + codegenVersion = "1.0.13", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java", inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java index 368a5c3a81e8..112d3df02280 100644 --- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java +++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import android.util.ArrayMap; import android.util.SparseArray; import android.util.SparseIntArray; @@ -52,7 +53,8 @@ public class ParcelAllTheThingsDataClass implements Parcelable { - // Code below generated by codegen v1.0.12. + + // Code below generated by codegen v1.0.13. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -410,8 +412,8 @@ public class ParcelAllTheThingsDataClass implements Parcelable { } @DataClass.Generated( - time = 1572655991821L, - codegenVersion = "1.0.12", + time = 1573006404728L, + codegenVersion = "1.0.13", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java", inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java index 9d52287d631e..0fdcf5918c81 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java +++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java @@ -342,7 +342,7 @@ public final class SampleDataClass implements Parcelable { - // Code below generated by codegen v1.0.12. + // Code below generated by codegen v1.0.13. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -1872,8 +1872,8 @@ public final class SampleDataClass implements Parcelable { } @DataClass.Generated( - time = 1572655989589L, - codegenVersion = "1.0.12", + time = 1573006402566L, + codegenVersion = "1.0.13", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java", inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java index cef32d1051df..cab477dafae9 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java +++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java @@ -85,7 +85,7 @@ public class SampleWithCustomBuilder implements Parcelable { - // Code below generated by codegen v1.0.12. + // Code below generated by codegen v1.0.13. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -253,8 +253,8 @@ public class SampleWithCustomBuilder implements Parcelable { } @DataClass.Generated( - time = 1572655990725L, - codegenVersion = "1.0.12", + time = 1573006403628L, + codegenVersion = "1.0.13", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java", inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java index 27055f6a4df8..6190085a4d82 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java +++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java @@ -36,7 +36,7 @@ public class SampleWithNestedDataClasses { - // Code below generated by codegen v1.0.12. + // Code below generated by codegen v1.0.13. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -135,8 +135,8 @@ public class SampleWithNestedDataClasses { }; @DataClass.Generated( - time = 1572655995915L, - codegenVersion = "1.0.12", + time = 1573006408903L, + codegenVersion = "1.0.13", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java", inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)") @Deprecated @@ -160,7 +160,7 @@ public class SampleWithNestedDataClasses { - // Code below generated by codegen v1.0.12. + // Code below generated by codegen v1.0.13. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -259,8 +259,8 @@ public class SampleWithNestedDataClasses { }; @DataClass.Generated( - time = 1572655995924L, - codegenVersion = "1.0.12", + time = 1573006408912L, + codegenVersion = "1.0.13", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java", inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)") @Deprecated @@ -274,7 +274,7 @@ public class SampleWithNestedDataClasses { - // Code below generated by codegen v1.0.12. + // Code below generated by codegen v1.0.13. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -373,8 +373,8 @@ public class SampleWithNestedDataClasses { }; @DataClass.Generated( - time = 1572655995930L, - codegenVersion = "1.0.12", + time = 1573006408917L, + codegenVersion = "1.0.13", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java", inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java index 4bfec895fdcb..5a960d7dd002 100644 --- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java +++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java @@ -51,7 +51,7 @@ public class StaleDataclassDetectorFalsePositivesTest { - // Code below generated by codegen v1.0.12. + // Code below generated by codegen v1.0.13. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -65,8 +65,8 @@ public class StaleDataclassDetectorFalsePositivesTest { @DataClass.Generated( - time = 1572655994865L, - codegenVersion = "1.0.12", + time = 1573006407900L, + codegenVersion = "1.0.13", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java", inputSignatures = "public @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)") @Deprecated diff --git a/tools/codegen/src/com/android/codegen/FieldInfo.kt b/tools/codegen/src/com/android/codegen/FieldInfo.kt index ed35a1dfc599..ebfbbd8163b5 100644 --- a/tools/codegen/src/com/android/codegen/FieldInfo.kt +++ b/tools/codegen/src/com/android/codegen/FieldInfo.kt @@ -93,6 +93,8 @@ data class FieldInfo( // Generic args val isArray = Type.endsWith("[]") val isList = FieldClass == "List" || FieldClass == "ArrayList" + val isMap = FieldClass == "Map" || FieldClass == "ArrayMap" + || FieldClass == "HashMap" || FieldClass == "LinkedHashMap" val fieldBit = bitAtExpr(index) var isLast = false val isFinal = fieldAst.isFinal @@ -197,7 +199,7 @@ data class FieldInfo( listOf("String", "CharSequence", "Exception", "Size", "SizeF", "Bundle", "FileDescriptor", "SparseBooleanArray", "SparseIntArray", "SparseArray") -> FieldClass - FieldClass == "Map" && fieldTypeGenegicArgs[0] == "String" -> "Map" + isMap && fieldTypeGenegicArgs[0] == "String" -> "Map" isArray -> when { FieldInnerType!! in (PRIMITIVE_TYPES + "String") -> FieldInnerType + "Array" isBinder(FieldInnerType) -> "BinderArray" diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt index c25d0c74f251..dc1f4c50abc4 100644 --- a/tools/codegen/src/com/android/codegen/Generators.kt +++ b/tools/codegen/src/com/android/codegen/Generators.kt @@ -343,7 +343,7 @@ private fun ClassPrinter.generateBuilderSetters(visibility: String) { } } - if (FieldClass.endsWith("Map") && FieldInnerType != null) { + if (isMap && FieldInnerType != null) { generateBuilderMethod( name = adderName, defVisibility = visibility, @@ -351,7 +351,7 @@ private fun ClassPrinter.generateBuilderSetters(visibility: String) { paramNames = listOf("key", "value"), genJavadoc = { +javadocSeeSetter }) { !singularNameCustomizationHint - +"if ($name == null) $setterName(new $LinkedHashMap());" + +"if ($name == null) $setterName(new ${if (FieldClass == "Map") LinkedHashMap else FieldClass}());" +"$name.put(key, value);" +"return$maybeCast this;" } @@ -507,7 +507,8 @@ fun ClassPrinter.generateParcelable() { // Create container if any val containerInitExpr = when { - FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()" + FieldClass == "Map" -> "new $LinkedHashMap<>()" + isMap -> "new $FieldClass()" FieldClass == "List" || FieldClass == "ArrayList" -> "new ${classRef("java.util.ArrayList")}<>()" else -> "" diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt index 339057f24833..85c832fcf34f 100644 --- a/tools/codegen/src/com/android/codegen/SharedConstants.kt +++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt @@ -1,7 +1,7 @@ package com.android.codegen const val CODEGEN_NAME = "codegen" -const val CODEGEN_VERSION = "1.0.12" +const val CODEGEN_VERSION = "1.0.13" const val CANONICAL_BUILDER_CLASS = "Builder" const val BASE_BUILDER_CLASS = "BaseBuilder" diff --git a/wifi/java/android/net/wifi/ISoftApCallback.aidl b/wifi/java/android/net/wifi/ISoftApCallback.aidl index 8a252dd1e447..452a655edc7b 100644 --- a/wifi/java/android/net/wifi/ISoftApCallback.aidl +++ b/wifi/java/android/net/wifi/ISoftApCallback.aidl @@ -15,6 +15,7 @@ */ package android.net.wifi; +import android.net.wifi.SoftApInfo; import android.net.wifi.WifiClient; @@ -43,4 +44,11 @@ oneway interface ISoftApCallback * @param clients the currently connected clients */ void onConnectedClientsChanged(in List<WifiClient> clients); + + /** + * Service to manager callback providing information of softap. + * + * @param softApInfo is the softap information. {@link SoftApInfo} + */ + void onInfoChanged(in SoftApInfo softApInfo); } diff --git a/wifi/java/android/net/wifi/SoftApInfo.aidl b/wifi/java/android/net/wifi/SoftApInfo.aidl new file mode 100644 index 000000000000..d4551cfac044 --- /dev/null +++ b/wifi/java/android/net/wifi/SoftApInfo.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +parcelable SoftApInfo; + diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java new file mode 100644 index 000000000000..375a9774f570 --- /dev/null +++ b/wifi/java/android/net/wifi/SoftApInfo.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * A class representing information about SoftAp. + * {@see WifiManager} + * + * @hide + */ +@SystemApi +public final class SoftApInfo implements Parcelable { + + /** + * AP Channel bandwidth is invalid. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_INVALID = 0; + + /** + * AP Channel bandwidth is 20 MHZ but no HT. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_20MHZ_NOHT = 1; + + /** + * AP Channel bandwidth is 20 MHZ. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_20MHZ = 2; + + /** + * AP Channel bandwidth is 40 MHZ. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_40MHZ = 3; + + /** + * AP Channel bandwidth is 80 MHZ. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_80MHZ = 4; + + /** + * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 5; + + /** + * AP Channel bandwidth is 160 MHZ. + * + * @see #getBandwidth() + */ + public static final int CHANNEL_WIDTH_160MHZ = 6; + + /** + * @hide + */ + @IntDef(prefix = { "CHANNEL_WIDTH_" }, value = { + CHANNEL_WIDTH_INVALID, + CHANNEL_WIDTH_20MHZ_NOHT, + CHANNEL_WIDTH_20MHZ, + CHANNEL_WIDTH_40MHZ, + CHANNEL_WIDTH_80MHZ, + CHANNEL_WIDTH_80MHZ_PLUS_MHZ, + CHANNEL_WIDTH_160MHZ, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Bandwidth {} + + + /** The frequency which AP resides on. */ + private int mFrequency = 0; + + @Bandwidth + private int mBandwidth = CHANNEL_WIDTH_INVALID; + + /** + * Get the frequency which AP resides on. + */ + public int getFrequency() { + return mFrequency; + } + + /** + * Set the frequency which AP resides on. + * @hide + */ + public void setFrequency(int freq) { + mFrequency = freq; + } + + /** + * Get AP Channel bandwidth. + * + * @return One of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ}, + * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}, + * {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ} or {@link #CHANNEL_WIDTH_UNKNOWN}. + */ + @Bandwidth + public int getBandwidth() { + return mBandwidth; + } + + /** + * Set AP Channel bandwidth. + * @hide + */ + public void setBandwidth(@Bandwidth int bandwidth) { + mBandwidth = bandwidth; + } + + /** + * @hide + */ + public SoftApInfo(@Nullable SoftApInfo source) { + if (source != null) { + mFrequency = source.mFrequency; + mBandwidth = source.mBandwidth; + } + } + + /** + * @hide + */ + public SoftApInfo() { + } + + @Override + /** Implement the Parcelable interface. */ + public int describeContents() { + return 0; + } + + @Override + /** Implement the Parcelable interface */ + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mFrequency); + dest.writeInt(mBandwidth); + } + + @NonNull + /** Implement the Parcelable interface */ + public static final Creator<SoftApInfo> CREATOR = new Creator<SoftApInfo>() { + public SoftApInfo createFromParcel(Parcel in) { + SoftApInfo info = new SoftApInfo(); + info.mFrequency = in.readInt(); + info.mBandwidth = in.readInt(); + return info; + } + + public SoftApInfo[] newArray(int size) { + return new SoftApInfo[size]; + } + }; + + @NonNull + @Override + public String toString() { + return "SoftApInfo{" + + "bandwidth= " + mBandwidth + + ",frequency= " + mFrequency + + '}'; + } + + @Override + public boolean equals(@NonNull Object o) { + if (this == o) return true; + if (!(o instanceof SoftApInfo)) return false; + SoftApInfo softApInfo = (SoftApInfo) o; + return mFrequency == softApInfo.mFrequency + && mBandwidth == softApInfo.mBandwidth; + } + + @Override + public int hashCode() { + return Objects.hash(mFrequency, mBandwidth); + } +} diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 07831c71b0d3..8108fef5d3ee 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -3315,6 +3315,15 @@ public class WifiManager { * @param clients the currently connected clients */ void onConnectedClientsChanged(@NonNull List<WifiClient> clients); + + /** + * Called when information of softap changes. + * + * @param softApInfo is the softap information. {@link SoftApInfo} + */ + default void onInfoChanged(@NonNull SoftApInfo softApInfo) { + // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI. + } } /** @@ -3354,6 +3363,16 @@ public class WifiManager { mCallback.onConnectedClientsChanged(clients); }); } + + @Override + public void onInfoChanged(SoftApInfo softApInfo) { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "SoftApCallbackProxy: onInfoChange: softApInfo=" + softApInfo); + } + mHandler.post(() -> { + mCallback.onInfoChanged(softApInfo); + }); + } } /** diff --git a/wifi/tests/src/android/net/wifi/SoftApInfoTest.java b/wifi/tests/src/android/net/wifi/SoftApInfoTest.java new file mode 100644 index 000000000000..929f3ab88fd8 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/SoftApInfoTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import android.os.Parcel; + +import static org.junit.Assert.assertEquals; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit tests for {@link android.net.wifi.SoftApInfo}. + */ +@SmallTest +public class SoftApInfoTest { + + /** + * Verifies copy constructor. + */ + @Test + public void testCopyOperator() throws Exception { + SoftApInfo info = new SoftApInfo(); + info.setFrequency(2412); + info.setBandwidth(SoftApInfo.CHANNEL_WIDTH_20MHZ); + + SoftApInfo copiedInfo = new SoftApInfo(info); + + assertEquals(info, copiedInfo); + assertEquals(info.hashCode(), copiedInfo.hashCode()); + } + + /** + * Verifies parcel serialization/deserialization. + */ + @Test + public void testParcelOperation() throws Exception { + SoftApInfo info = new SoftApInfo(); + info.setFrequency(2412); + info.setBandwidth(SoftApInfo.CHANNEL_WIDTH_20MHZ); + + Parcel parcelW = Parcel.obtain(); + info.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + SoftApInfo fromParcel = SoftApInfo.CREATOR.createFromParcel(parcelR); + + assertEquals(info, fromParcel); + assertEquals(info.hashCode(), fromParcel.hashCode()); + } + +} diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index d2516a33fead..14e994cf0f08 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -97,6 +97,8 @@ public class WifiManagerTest { private static final String TEST_PACKAGE_NAME = "TestPackage"; private static final String TEST_COUNTRY_CODE = "US"; private static final String[] TEST_MAC_ADDRESSES = {"da:a1:19:0:0:0"}; + private static final int TEST_AP_FREQUENCY = 2412; + private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ; @Mock Context mContext; @Mock android.net.wifi.IWifiManager mWifiService; @@ -122,7 +124,6 @@ public class WifiManagerTest { mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); when(mContext.getOpPackageName()).thenReturn(TEST_PACKAGE_NAME); - mWifiManager = new WifiManager(mContext, mWifiService, mLooper.getLooper()); verify(mWifiService).getVerboseLoggingLevel(); } @@ -776,11 +777,34 @@ public class WifiManagerTest { verify(mSoftApCallback).onConnectedClientsChanged(testClients); } + + /* + * Verify client-provided callback is being called through callback proxy + */ + @Test + public void softApCallbackProxyCallsOnSoftApInfoChanged() throws Exception { + SoftApInfo testSoftApInfo = new SoftApInfo(); + testSoftApInfo.setFrequency(TEST_AP_FREQUENCY); + testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH); + ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor = + ArgumentCaptor.forClass(ISoftApCallback.Stub.class); + mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler); + verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(), + anyInt()); + + callbackCaptor.getValue().onInfoChanged(testSoftApInfo); + mLooper.dispatchAll(); + verify(mSoftApCallback).onInfoChanged(testSoftApInfo); + } + /* * Verify client-provided callback is being called through callback proxy on multiple events */ @Test public void softApCallbackProxyCallsOnMultipleUpdates() throws Exception { + SoftApInfo testSoftApInfo = new SoftApInfo(); + testSoftApInfo.setFrequency(TEST_AP_FREQUENCY); + testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH); ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor = ArgumentCaptor.forClass(ISoftApCallback.Stub.class); mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler); @@ -790,11 +814,13 @@ public class WifiManagerTest { final List<WifiClient> testClients = new ArrayList(); callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLING, 0); callbackCaptor.getValue().onConnectedClientsChanged(testClients); + callbackCaptor.getValue().onInfoChanged(testSoftApInfo); callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL); mLooper.dispatchAll(); verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLING, 0); verify(mSoftApCallback).onConnectedClientsChanged(testClients); + verify(mSoftApCallback).onInfoChanged(testSoftApInfo); verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL); } |