diff options
140 files changed, 2735 insertions, 979 deletions
diff --git a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java index 28d40969aa21..ba072da8071e 100644 --- a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java @@ -69,7 +69,6 @@ public class BinderCallsStatsPerfTest { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); Binder b = new Binder(); mBinderCallsStats = new BinderCallsStats(false); - assertNull(mBinderCallsStats.callStarted(b, 0)); while (state.keepRunning()) { BinderCallsStats.CallSession s = mBinderCallsStats.callStarted(b, 0); mBinderCallsStats.callEnded(s); diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 2ba4bebd8df5..26334411d6ee 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -147,6 +147,7 @@ Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I Landroid/app/admin/SecurityLog$SecurityEvent;-><init>([B)V +Landroid/app/ActionBar;->setShowHideAnimationEnabled(Z)V Landroid/app/AlarmManager;->FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED:I Landroid/app/AlarmManager;->FLAG_IDLE_UNTIL:I Landroid/app/AlarmManager;->FLAG_STANDALONE:I @@ -249,7 +250,9 @@ Landroid/app/Dialog;->mListenersHandler:Landroid/os/Handler; Landroid/app/Dialog;->mOwnerActivity:Landroid/app/Activity; Landroid/app/Dialog;->mShowMessage:Landroid/os/Message; Landroid/app/DownloadManager$Request;->mUri:Landroid/net/Uri; +Landroid/app/DownloadManager;->setAccessFilename(Z)V Landroid/app/FragmentManagerImpl;->mAdded:Ljava/util/ArrayList; +Landroid/app/FragmentManagerImpl;->mStateSaved:Z Landroid/app/FragmentManagerImpl;->noteStateNotSaved()V Landroid/app/Fragment;->mChildFragmentManager:Landroid/app/FragmentManagerImpl; Landroid/app/Fragment;->mWho:Ljava/lang/String; @@ -373,6 +376,8 @@ Landroid/app/Service;->setForeground(Z)V Landroid/app/SharedPreferencesImpl;-><init>(Ljava/io/File;I)V Landroid/app/SharedPreferencesImpl;->mFile:Ljava/io/File; Landroid/app/SharedPreferencesImpl;->startReloadIfChangedUnexpectedly()V +Landroid/app/slice/Slice$Builder;-><init>(Landroid/net/Uri;)V +Landroid/app/slice/Slice$Builder;->setSpec(Landroid/app/slice/SliceSpec;)Landroid/app/slice/Slice$Builder; Landroid/app/slice/SliceItem;->getTimestamp()J Landroid/app/slice/SliceManager;->bindSlice(Landroid/net/Uri;Ljava/util/List;)Landroid/app/slice/Slice; Landroid/app/slice/SliceManager;->pinSlice(Landroid/net/Uri;Ljava/util/List;)V @@ -484,6 +489,7 @@ Landroid/bluetooth/BluetoothGattCharacteristic;->mService:Landroid/bluetooth/Blu Landroid/bluetooth/BluetoothGattDescriptor;->mCharacteristic:Landroid/bluetooth/BluetoothGattCharacteristic; Landroid/bluetooth/BluetoothGattDescriptor;->mInstance:I Landroid/bluetooth/BluetoothGatt;->mAuthRetryState:I +Landroid/bluetooth/BluetoothGatt;->mClientIf:I Landroid/bluetooth/BluetoothGatt;->refresh()Z Landroid/bluetooth/BluetoothHeadset;->ACTION_ACTIVE_DEVICE_CHANGED:Ljava/lang/String; Landroid/bluetooth/BluetoothHeadset;->close()V @@ -508,11 +514,13 @@ Landroid/bluetooth/BluetoothPan;->isValidDevice(Landroid/bluetooth/BluetoothDevi Landroid/bluetooth/BluetoothPan;->log(Ljava/lang/String;)V Landroid/bluetooth/BluetoothPan;->setBluetoothTethering(Z)V Landroid/bluetooth/BluetoothProfile;->PAN:I +Landroid/bluetooth/BluetoothSocket;->mPfd:Landroid/os/ParcelFileDescriptor; Landroid/bluetooth/BluetoothUuid;->RESERVED_UUIDS:[Landroid/os/ParcelUuid; Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String; Landroid/bluetooth/IBluetoothManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth; Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String; +Landroid/bluetooth/IBluetooth$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I Landroid/bluetooth/le/ScanRecord;->parseFromBytes([B)Landroid/bluetooth/le/ScanRecord; Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor; Landroid/content/BroadcastReceiver$PendingResult;-><init>(ILjava/lang/String;Landroid/os/Bundle;IZZLandroid/os/IBinder;II)V @@ -680,6 +688,7 @@ Landroid/content/res/AssetFileDescriptor;->mStartOffset:J Landroid/content/res/AssetManager;->addAssetPathAsSharedLibrary(Ljava/lang/String;)I Landroid/content/res/AssetManager;->addAssetPath(Ljava/lang/String;)I Landroid/content/res/AssetManager;->applyStyle(JIILandroid/content/res/XmlBlock$Parser;[IJJ)V +Landroid/content/res/AssetManager;->createTheme()J Landroid/content/res/AssetManager;->getAssignedPackageIdentifiers()Landroid/util/SparseArray; Landroid/content/res/AssetManager;->getResourceBagText(II)Ljava/lang/CharSequence; Landroid/content/res/AssetManager;->getResourceEntryName(I)Ljava/lang/String; @@ -709,6 +718,8 @@ Landroid/content/res/CompatibilityInfo;->DEFAULT_COMPATIBILITY_INFO:Landroid/con Landroid/content/res/DrawableCache;->getInstance(JLandroid/content/res/Resources;Landroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable; Landroid/content/res/DrawableCache;-><init>()V Landroid/content/res/ObbInfo;->salt:[B +Landroid/content/res/Resources;->mClassLoader:Ljava/lang/ClassLoader; +Landroid/content/res/Resources;->mDrawableInflater:Landroid/graphics/drawable/DrawableInflater; Landroid/content/res/Resources;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo; Landroid/content/res/ResourcesImpl;->getAssets()Landroid/content/res/AssetManager; Landroid/content/res/ResourcesImpl;->mAccessLock:Ljava/lang/Object; @@ -731,6 +742,7 @@ Landroid/content/res/Resources;->mResourcesImpl:Landroid/content/res/ResourcesIm Landroid/content/res/Resources;->mSystem:Landroid/content/res/Resources; Landroid/content/res/Resources;->mTmpValue:Landroid/util/TypedValue; Landroid/content/res/Resources;->mTypedArrayPool:Landroid/util/Pools$SynchronizedPool; +Landroid/content/res/Resources;->selectDefaultTheme(II)I Landroid/content/res/Resources;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V Landroid/content/res/StringBlock;-><init>(JZ)V @@ -815,12 +827,15 @@ Landroid/graphics/drawable/BitmapDrawable;->mTargetDensity:I Landroid/graphics/drawable/BitmapDrawable;->setBitmap(Landroid/graphics/Bitmap;)V Landroid/graphics/drawable/ColorDrawable$ColorState;->mUseColor:I Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;->mConstantPadding:Landroid/graphics/Rect; +Landroid/graphics/drawable/DrawableContainer$DrawableContainerState;->mDrawables:[Landroid/graphics/drawable/Drawable; Landroid/graphics/drawable/DrawableContainer;->getOpticalInsets()Landroid/graphics/Insets; Landroid/graphics/drawable/DrawableContainer;->mDrawableContainerState:Landroid/graphics/drawable/DrawableContainer$DrawableContainerState; Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; Landroid/graphics/drawable/Drawable;->inflateWithAttributes(Landroid/content/res/Resources;Lorg/xmlpull/v1/XmlPullParser;Landroid/content/res/TypedArray;I)V Landroid/graphics/drawable/Drawable;->mCallback:Ljava/lang/ref/WeakReference; Landroid/graphics/drawable/Drawable;->parseTintMode(ILandroid/graphics/PorterDuff$Mode;)Landroid/graphics/PorterDuff$Mode; +Landroid/graphics/drawable/DrawableInflater;->mClassLoader:Ljava/lang/ClassLoader; +Landroid/graphics/drawable/GradientDrawable;->getOpticalInsets()Landroid/graphics/Insets; Landroid/graphics/drawable/GradientDrawable$GradientState;->mAngle:I Landroid/graphics/drawable/GradientDrawable$GradientState;->mGradientColors:[I Landroid/graphics/drawable/GradientDrawable$GradientState;->mGradient:I @@ -864,6 +879,10 @@ Landroid/graphics/drawable/StateListDrawable;->getStateDrawableIndex([I)I Landroid/graphics/drawable/StateListDrawable;->getStateSet(I)[I Landroid/graphics/drawable/StateListDrawable;->mStateListState:Landroid/graphics/drawable/StateListDrawable$StateListState; Landroid/graphics/drawable/StateListDrawable;->updateStateFromTypedArray(Landroid/content/res/TypedArray;)V +Landroid/graphics/drawable/VectorDrawable;->getTargetByName(Ljava/lang/String;)Ljava/lang/Object; +Landroid/graphics/drawable/VectorDrawable;->mTintFilter:Landroid/graphics/PorterDuffColorFilter; +Landroid/graphics/drawable/VectorDrawable;->setAllowCaching(Z)V +Landroid/graphics/drawable/VectorDrawable$VGroup;->setRotation(F)V Landroid/graphics/FontFamily;->abortCreation()V Landroid/graphics/FontFamily;->addFontFromAssetManager(Landroid/content/res/AssetManager;Ljava/lang/String;IZIII[Landroid/graphics/fonts/FontVariationAxis;)Z Landroid/graphics/FontFamily;->addFontFromBuffer(Ljava/nio/ByteBuffer;I[Landroid/graphics/fonts/FontVariationAxis;II)Z @@ -886,6 +905,7 @@ Landroid/graphics/NinePatch$InsetStruct;-><init>(IIIIIIIIFIF)V Landroid/graphics/NinePatch;->mBitmap:Landroid/graphics/Bitmap; Landroid/graphics/Picture;->mNativePicture:J Landroid/graphics/PixelXorXfermode;-><init>(I)V +Landroid/graphics/PorterDuffColorFilter;->getColor()I Landroid/graphics/PorterDuffColorFilter;->setColor(I)V Landroid/graphics/PorterDuffColorFilter;->setMode(Landroid/graphics/PorterDuff$Mode;)V Landroid/graphics/Rect;->scale(F)V @@ -907,6 +927,8 @@ Landroid/hardware/camera2/CameraCharacteristics;->CONTROL_MAX_REGIONS:Landroid/h Landroid/hardware/camera2/CameraCharacteristics;->DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; Landroid/hardware/camera2/CameraCharacteristics;->DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; Landroid/hardware/camera2/CameraCharacteristics;->DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS:Landroid/hardware/camera2/CameraCharacteristics$Key; +Landroid/hardware/camera2/CameraCharacteristics$Key;->getNativeKey()Landroid/hardware/camera2/impl/CameraMetadataNative$Key; +Landroid/hardware/camera2/CameraCharacteristics$Key;-><init>(Ljava/lang/String;Landroid/hardware/camera2/utils/TypeReference;)V Landroid/hardware/camera2/CameraCharacteristics$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;J)V Landroid/hardware/camera2/CameraCharacteristics$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;)V Landroid/hardware/camera2/CameraCharacteristics;->LED_AVAILABLE_LEDS:Landroid/hardware/camera2/CameraCharacteristics$Key; @@ -931,6 +953,8 @@ Landroid/hardware/camera2/CameraCharacteristics;->SCALER_AVAILABLE_STREAM_CONFIG Landroid/hardware/camera2/CaptureRequest;->JPEG_GPS_COORDINATES:Landroid/hardware/camera2/CaptureRequest$Key; Landroid/hardware/camera2/CaptureRequest;->JPEG_GPS_PROCESSING_METHOD:Landroid/hardware/camera2/CaptureRequest$Key; Landroid/hardware/camera2/CaptureRequest;->JPEG_GPS_TIMESTAMP:Landroid/hardware/camera2/CaptureRequest$Key; +Landroid/hardware/camera2/CaptureRequest$Key;->getNativeKey()Landroid/hardware/camera2/impl/CameraMetadataNative$Key; +Landroid/hardware/camera2/CaptureRequest$Key;-><init>(Ljava/lang/String;Landroid/hardware/camera2/utils/TypeReference;)V Landroid/hardware/camera2/CaptureRequest$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;J)V Landroid/hardware/camera2/CaptureRequest;->LED_TRANSMIT:Landroid/hardware/camera2/CaptureRequest$Key; Landroid/hardware/camera2/CaptureRequest;->REQUEST_ID:Landroid/hardware/camera2/CaptureRequest$Key; @@ -940,6 +964,8 @@ Landroid/hardware/camera2/CaptureRequest;->TONEMAP_CURVE_RED:Landroid/hardware/c Landroid/hardware/camera2/CaptureResult;->JPEG_GPS_COORDINATES:Landroid/hardware/camera2/CaptureResult$Key; Landroid/hardware/camera2/CaptureResult;->JPEG_GPS_PROCESSING_METHOD:Landroid/hardware/camera2/CaptureResult$Key; Landroid/hardware/camera2/CaptureResult;->JPEG_GPS_TIMESTAMP:Landroid/hardware/camera2/CaptureResult$Key; +Landroid/hardware/camera2/CaptureResult$Key;->getNativeKey()Landroid/hardware/camera2/impl/CameraMetadataNative$Key; +Landroid/hardware/camera2/CaptureResult$Key;-><init>(Ljava/lang/String;Landroid/hardware/camera2/utils/TypeReference;)V Landroid/hardware/camera2/CaptureResult$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;J)V Landroid/hardware/camera2/CaptureResult$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;)V Landroid/hardware/camera2/CaptureResult;->LED_TRANSMIT:Landroid/hardware/camera2/CaptureResult$Key; @@ -960,7 +986,9 @@ Landroid/hardware/camera2/CaptureResult;->SYNC_FRAME_NUMBER:Landroid/hardware/ca Landroid/hardware/camera2/CaptureResult;->TONEMAP_CURVE_BLUE:Landroid/hardware/camera2/CaptureResult$Key; Landroid/hardware/camera2/CaptureResult;->TONEMAP_CURVE_GREEN:Landroid/hardware/camera2/CaptureResult$Key; Landroid/hardware/camera2/CaptureResult;->TONEMAP_CURVE_RED:Landroid/hardware/camera2/CaptureResult$Key; +Landroid/hardware/camera2/impl/CameraMetadataNative$Key;->getTag()I Landroid/hardware/camera2/impl/CameraMetadataNative;->mMetadataPtr:J +Landroid/hardware/camera2/utils/TypeReference;->createSpecializedTypeReference(Ljava/lang/reflect/Type;)Landroid/hardware/camera2/utils/TypeReference; Landroid/hardware/Camera;->addCallbackBuffer([BI)V Landroid/hardware/Camera;->mNativeContext:J Landroid/hardware/Camera;->openLegacy(II)Landroid/hardware/Camera; @@ -1276,6 +1304,10 @@ Landroid/net/ConnectivityManager;->TYPE_NONE:I Landroid/net/ConnectivityManager;->TYPE_PROXY:I Landroid/net/ConnectivityManager;->TYPE_WIFI_P2P:I Landroid/net/http/SslError;->mCertificate:Landroid/net/http/SslCertificate; +Landroid/net/IConnectivityManager;->getActiveLinkProperties()Landroid/net/LinkProperties; +Landroid/net/IConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkInfo; +Landroid/net/IConnectivityManager;->getAllNetworkInfo()[Landroid/net/NetworkInfo; +Landroid/net/IConnectivityManager;->getTetheredIfaces()[Ljava/lang/String; Landroid/net/IConnectivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IConnectivityManager; Landroid/net/IConnectivityManager$Stub$Proxy;->getActiveLinkProperties()Landroid/net/LinkProperties; Landroid/net/IConnectivityManager$Stub$Proxy;->getActiveNetworkInfo()Landroid/net/NetworkInfo; @@ -1395,6 +1427,7 @@ Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/Strin Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String; Landroid/net/wifi/WifiInfo;->DEFAULT_MAC_ADDRESS:Ljava/lang/String; Landroid/net/wifi/WifiInfo;->getMeteredHint()Z +Landroid/net/wifi/WifiInfo;->getWifiSsid()Landroid/net/wifi/WifiSsid; Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String; Landroid/net/wifi/WifiInfo;->removeDoubleQuotes(Ljava/lang/String;)Ljava/lang/String; Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V @@ -1403,11 +1436,12 @@ Landroid/net/wifi/WifiManager;->forget(ILandroid/net/wifi/WifiManager$ActionList Landroid/net/wifi/WifiManager;->isDualBandSupported()Z Landroid/net/wifi/WifiManager;->mService:Landroid/net/wifi/IWifiManager; Landroid/net/wifi/WifiManager;->save(Landroid/net/wifi/WifiConfiguration;Landroid/net/wifi/WifiManager$ActionListener;)V +Landroid/net/wifi/WifiSsid;->getOctets()[B Landroid/net/wifi/WifiSsid;->NONE:Ljava/lang/String; Landroid/nfc/NfcAdapter;->getAdapterState()I Landroid/nfc/NfcAdapter;->getDefaultAdapter()Landroid/nfc/NfcAdapter; -Landroid/nfc/NfcAdapter;->setNdefPushMessageCallback(Landroid/nfc/NfcAdapter$CreateNdefMessageCallback;Landroid/app/Activity;I)V Landroid/nfc/NfcAdapter;->getNfcAdapter(Landroid/content/Context;)Landroid/nfc/NfcAdapter; +Landroid/nfc/NfcAdapter;->setNdefPushMessageCallback(Landroid/nfc/NfcAdapter$CreateNdefMessageCallback;Landroid/app/Activity;I)V Landroid/opengl/GLSurfaceView$EglHelper;->mEglContext:Ljavax/microedition/khronos/egl/EGLContext; Landroid/opengl/GLSurfaceView$GLThread;->mEglHelper:Landroid/opengl/GLSurfaceView$EglHelper; Landroid/opengl/GLSurfaceView;->mGLThread:Landroid/opengl/GLSurfaceView$GLThread; @@ -1716,6 +1750,7 @@ Landroid/os/WorkSource;->mNum:I Landroid/os/WorkSource;->mUids:[I Landroid/os/WorkSource;->setReturningDiffs(Landroid/os/WorkSource;)[Landroid/os/WorkSource; Landroid/os/WorkSource;->size()I +Landroid/permissionpresenterservice/RuntimePermissionPresenterService;->onRevokeRuntimePermission(Ljava/lang/String;Ljava/lang/String;)V Landroid/preference/DialogPreference;->mBuilder:Landroid/app/AlertDialog$Builder; Landroid/preference/DialogPreference;->mDialogIcon:Landroid/graphics/drawable/Drawable; Landroid/preference/DialogPreference;->mDialog:Landroid/app/Dialog; @@ -1995,6 +2030,7 @@ Landroid/R$styleable;->Window_windowBackground:I Landroid/R$styleable;->Window_windowFrame:I Landroid/security/keystore/AndroidKeyStoreProvider;->getKeyStoreOperationHandle(Ljava/lang/Object;)J Landroid/security/KeyStore;->getInstance()Landroid/security/KeyStore; +Landroid/security/keystore/recovery/RecoveryController;->initRecoveryService(Ljava/lang/String;[B)V Landroid/security/net/config/RootTrustManager;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List; Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnectFailed()V Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnect(Ljava/lang/String;Landroid/media/session/MediaSession$Token;Landroid/os/Bundle;)V @@ -2290,6 +2326,7 @@ Landroid/view/Choreographer;->mLock:Ljava/lang/Object; Landroid/view/Choreographer;->scheduleVsyncLocked()V Landroid/view/Choreographer;->USE_VSYNC:Z Landroid/view/ContextThemeWrapper;->getThemeResId()I +Landroid/view/ContextThemeWrapper;->initializeTheme()V Landroid/view/ContextThemeWrapper;->mInflater:Landroid/view/LayoutInflater; Landroid/view/ContextThemeWrapper;->mResources:Landroid/content/res/Resources; Landroid/view/ContextThemeWrapper;->mTheme:Landroid/content/res/Resources$Theme; @@ -2448,6 +2485,7 @@ Landroid/view/textclassifier/TextClassificationManager;->getTextClassifier(I)Lan Landroid/view/textclassifier/TextClassifier;->classifyText(Ljava/lang/CharSequence;IILandroid/view/textclassifier/TextClassification$Options;)Landroid/view/textclassifier/TextClassification; Landroid/view/textclassifier/TextClassifier;->generateLinks(Ljava/lang/CharSequence;Landroid/view/textclassifier/TextLinks$Options;)Landroid/view/textclassifier/TextLinks; Landroid/view/textclassifier/TextClassifier;->suggestSelection(Ljava/lang/CharSequence;IILandroid/view/textclassifier/TextSelection$Options;)Landroid/view/textclassifier/TextSelection; +Landroid/view/textclassifier/TextLinks$Options;-><init>()V Landroid/view/textservice/TextServicesManager;->isSpellCheckerEnabled()Z Landroid/view/TextureView;->destroyHardwareLayer()V Landroid/view/TextureView;->destroyHardwareResources()V @@ -2523,6 +2561,7 @@ Landroid/view/View;->isVisibleToUser(Landroid/graphics/Rect;)Z Landroid/view/View;->isVisibleToUser()Z Landroid/view/View$ListenerInfo;-><init>()V Landroid/view/View$ListenerInfo;->mOnClickListener:Landroid/view/View$OnClickListener; +Landroid/view/View$ListenerInfo;->mOnDragListener:Landroid/view/View$OnDragListener; Landroid/view/View$ListenerInfo;->mOnFocusChangeListener:Landroid/view/View$OnFocusChangeListener; Landroid/view/View$ListenerInfo;->mOnLongClickListener:Landroid/view/View$OnLongClickListener; Landroid/view/View$ListenerInfo;->mOnTouchListener:Landroid/view/View$OnTouchListener; @@ -2677,6 +2716,7 @@ Landroid/widget/AbsListView$FlingRunnable;->start(I)V Landroid/widget/AbsListView;->invokeOnItemScrollListener()V Landroid/widget/AbsListView;->isVerticalScrollBarHidden()Z Landroid/widget/AbsListView;->mAdapter:Landroid/widget/ListAdapter; +Landroid/widget/AbsListView;->mDataSetObserver:Landroid/widget/AbsListView$AdapterDataSetObserver; Landroid/widget/AbsListView;->mEdgeGlowBottom:Landroid/widget/EdgeEffect; Landroid/widget/AbsListView;->mEdgeGlowTop:Landroid/widget/EdgeEffect; Landroid/widget/AbsListView;->mFastScroll:Landroid/widget/FastScroller; @@ -2784,6 +2824,8 @@ Landroid/widget/ListView;->fillUp(II)Landroid/view/View; Landroid/widget/ListView;->findViewTraversal(I)Landroid/view/View; Landroid/widget/ListView;->findViewWithTagTraversal(Ljava/lang/Object;)Landroid/view/View; Landroid/widget/ListView;->mAreAllItemsSelectable:Z +Landroid/widget/ListView;->mFooterViewInfos:Ljava/util/ArrayList; +Landroid/widget/ListView;->mHeaderViewInfos:Ljava/util/ArrayList; Landroid/widget/ListView;->setSelectionInt(I)V Landroid/widget/MediaController;->mAnchor:Landroid/view/View; Landroid/widget/MediaController;->mDecor:Landroid/view/View; @@ -2873,9 +2915,9 @@ Landroid/widget/Switch;->mThumbDrawable:Landroid/graphics/drawable/Drawable; Landroid/widget/Switch;->mTrackDrawable:Landroid/graphics/drawable/Drawable; Landroid/widget/TabHost$IntentContentStrategy;->getContentView()Landroid/view/View; Landroid/widget/TabHost$IntentContentStrategy;->tabClosed()V -Landroid/widget/TabHost$TabSpec;->mIndicatorStrategy:Landroid/widget/TabHost$IndicatorStrategy; Landroid/widget/TabHost;->mTabSpecs:Ljava/util/List; Landroid/widget/TabHost$TabSpec;->mContentStrategy:Landroid/widget/TabHost$ContentStrategy; +Landroid/widget/TabHost$TabSpec;->mIndicatorStrategy:Landroid/widget/TabHost$IndicatorStrategy; Landroid/widget/TabWidget;->mDrawBottomStrips:Z Landroid/widget/TabWidget;->mSelectedTab:I Landroid/widget/TabWidget;->setTabSelectionListener(Landroid/widget/TabWidget$OnTabSelectionChanged;)V @@ -2884,6 +2926,7 @@ Landroid/widget/TextView;->createEditorIfNeeded()V Landroid/widget/TextView;->getHorizontallyScrolling()Z Landroid/widget/TextView;->getTextColor(Landroid/content/Context;Landroid/content/res/TypedArray;I)I Landroid/widget/TextView;->isSingleLine()Z +Landroid/widget/TextView;->LINES:I Landroid/widget/TextView;->mCursorDrawableRes:I Landroid/widget/TextView;->mCurTextColor:I Landroid/widget/TextView;->mEditor:Landroid/widget/Editor; @@ -3422,9 +3465,13 @@ Ljava/io/FileDescriptor;->descriptor:I Ljava/io/FileDescriptor;->getInt$()I Ljava/io/FileDescriptor;->isSocket$()Z Ljava/io/FileDescriptor;->setInt$(I)V +Ljava/io/File;->filePath:Ljava/nio/file/Path; Ljava/io/File;->fs:Ljava/io/FileSystem; Ljava/io/FileInputStream;->fd:Ljava/io/FileDescriptor; Ljava/io/FileOutputStream;->fd:Ljava/io/FileDescriptor; +Ljava/io/File;->path:Ljava/lang/String; +Ljava/io/File;->prefixLength:I +Ljava/io/File;->status:Ljava/io/File$PathStatus; Ljava/io/ObjectStreamClass;->getConstructorId(Ljava/lang/Class;)J Ljava/io/ObjectStreamClass;->newInstance(Ljava/lang/Class;J)Ljava/lang/Object; Ljava/io/ObjectStreamClass;->newInstance()Ljava/lang/Object; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 289a4dd77723..539a01043657 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2102,18 +2102,24 @@ public class ActivityManager { private final GraphicBuffer mSnapshot; private final int mOrientation; private final Rect mContentInsets; + // Whether this snapshot is a down-sampled version of the full resolution, used mainly for + // low-ram devices private final boolean mReducedResolution; + // Whether or not the snapshot is a real snapshot or an app-theme generated snapshot due to + // the task having a secure window or having previews disabled private final boolean mIsRealSnapshot; + private final int mWindowingMode; private final float mScale; public TaskSnapshot(GraphicBuffer snapshot, int orientation, Rect contentInsets, - boolean reducedResolution, float scale, boolean isRealSnapshot) { + boolean reducedResolution, float scale, boolean isRealSnapshot, int windowingMode) { mSnapshot = snapshot; mOrientation = orientation; mContentInsets = new Rect(contentInsets); mReducedResolution = reducedResolution; mScale = scale; mIsRealSnapshot = isRealSnapshot; + mWindowingMode = windowingMode; } private TaskSnapshot(Parcel source) { @@ -2123,6 +2129,7 @@ public class ActivityManager { mReducedResolution = source.readBoolean(); mScale = source.readFloat(); mIsRealSnapshot = source.readBoolean(); + mWindowingMode = source.readInt(); } /** @@ -2163,6 +2170,13 @@ public class ActivityManager { } /** + * @return The windowing mode of the task when this snapshot was taken. + */ + public int getWindowingMode() { + return mWindowingMode; + } + + /** * @return The scale this snapshot was taken in. */ public float getScale() { @@ -2182,14 +2196,18 @@ public class ActivityManager { dest.writeBoolean(mReducedResolution); dest.writeFloat(mScale); dest.writeBoolean(mIsRealSnapshot); + dest.writeInt(mWindowingMode); } @Override public String toString() { - return "TaskSnapshot{mSnapshot=" + mSnapshot + " mOrientation=" + mOrientation + final int width = mSnapshot != null ? mSnapshot.getWidth() : 0; + final int height = mSnapshot != null ? mSnapshot.getHeight() : 0; + return "TaskSnapshot{mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")" + + " mOrientation=" + mOrientation + " mContentInsets=" + mContentInsets.toShortString() + " mReducedResolution=" + mReducedResolution + " mScale=" + mScale - + " mIsRealSnapshot=" + mIsRealSnapshot; + + " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode; } public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 4f88a03db435..eeec7caad7ee 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -972,6 +972,18 @@ public class Notification implements Parcelable public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory"; /** + * {@link #extras} key: boolean as supplied to + * {@link Builder#setShowRemoteInputSpinner(boolean)}. + * + * If set to true, then the view displaying the remote input history from + * {@link Builder#setRemoteInputHistory(CharSequence[])} will have a progress spinner. + * + * @see Builder#setShowRemoteInputSpinner(boolean) + * @hide + */ + public static final String EXTRA_SHOW_REMOTE_INPUT_SPINNER = "android.remoteInputSpinner"; + + /** * {@link #extras} key: this is a small piece of additional text as supplied to * {@link Builder#setContentInfo(CharSequence)}. */ @@ -3142,10 +3154,14 @@ public class Notification implements Parcelable private int mCachedContrastColor = COLOR_INVALID; private int mCachedContrastColorIsFor = COLOR_INVALID; /** - * Caches a ambient version of {@link #mCachedContrastColorIsFor}. + * Caches a ambient version of {@link #mCachedAmbientColorIsFor}. */ private int mCachedAmbientColor = COLOR_INVALID; private int mCachedAmbientColorIsFor = COLOR_INVALID; + /** + * A neutral color color that can be used for icons. + */ + private int mNeutralColor = COLOR_INVALID; /** * Caches an instance of StandardTemplateParams. Note that this may have been used before, @@ -3537,6 +3553,15 @@ public class Notification implements Parcelable } /** + * Sets whether remote history entries view should have a spinner. + * @hide + */ + public Builder setShowRemoteInputSpinner(boolean showSpinner) { + mN.extras.putBoolean(EXTRA_SHOW_REMOTE_INPUT_SPINNER, showSpinner); + return this; + } + + /** * Sets the number of items this notification represents. May be displayed as a badge count * for Launchers that support badging. */ @@ -4278,7 +4303,6 @@ public class Notification implements Parcelable private void resetStandardTemplate(RemoteViews contentView) { resetNotificationHeader(contentView); - resetContentMargins(contentView); contentView.setViewVisibility(R.id.right_icon, View.GONE); contentView.setViewVisibility(R.id.title, View.GONE); contentView.setTextViewText(R.id.title, null); @@ -4310,24 +4334,23 @@ public class Notification implements Parcelable mN.mUsesStandardHeader = false; } - private void resetContentMargins(RemoteViews contentView) { - contentView.setViewLayoutMarginEndDimen(R.id.line1, 0); - contentView.setViewLayoutMarginEndDimen(R.id.text, 0); - } - - private RemoteViews applyStandardTemplate(int resId) { - return applyStandardTemplate(resId, mParams.reset().fillTextsFrom(this)); + private RemoteViews applyStandardTemplate(int resId, TemplateBindResult result) { + return applyStandardTemplate(resId, mParams.reset().fillTextsFrom(this), + result); } /** * @param hasProgress whether the progress bar should be shown and set + * @param result */ - private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) { + private RemoteViews applyStandardTemplate(int resId, boolean hasProgress, + TemplateBindResult result) { return applyStandardTemplate(resId, mParams.reset().hasProgress(hasProgress) - .fillTextsFrom(this)); + .fillTextsFrom(this), result); } - private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p) { + private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p, + TemplateBindResult result) { RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId); resetStandardTemplate(contentView); @@ -4335,7 +4358,7 @@ public class Notification implements Parcelable final Bundle ex = mN.extras; updateBackgroundColor(contentView); bindNotificationHeader(contentView, p.ambient, p.headerTextSecondary); - bindLargeIcon(contentView, p.hideLargeIcon || p.ambient, p.alwaysShowReply); + bindLargeIconAndReply(contentView, p, result); boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex); if (p.title != null) { contentView.setViewVisibility(R.id.title, View.VISIBLE); @@ -4531,8 +4554,58 @@ public class Notification implements Parcelable } } - private void bindLargeIcon(RemoteViews contentView, boolean hideLargeIcon, - boolean alwaysShowReply) { + private void bindLargeIconAndReply(RemoteViews contentView, StandardTemplateParams p, + TemplateBindResult result) { + boolean largeIconShown = bindLargeIcon(contentView, p.hideLargeIcon || p.ambient); + boolean replyIconShown = bindReplyIcon(contentView, p.hideReplyIcon || p.ambient); + contentView.setViewVisibility(R.id.right_icon_container, + largeIconShown || replyIconShown ? View.VISIBLE : View.GONE); + int marginEnd = calculateMarginEnd(largeIconShown, replyIconShown); + contentView.setViewLayoutMarginEnd(R.id.line1, marginEnd); + contentView.setViewLayoutMarginEnd(R.id.text, marginEnd); + contentView.setViewLayoutMarginEnd(R.id.progress, marginEnd); + if (result != null) { + result.setIconMarginEnd(marginEnd); + } + } + + private int calculateMarginEnd(boolean largeIconShown, boolean replyIconShown) { + int marginEnd = 0; + int contentMargin = mContext.getResources().getDimensionPixelSize( + R.dimen.notification_content_margin_end); + int iconSize = mContext.getResources().getDimensionPixelSize( + R.dimen.notification_right_icon_size); + if (replyIconShown) { + // The size of the reply icon + marginEnd += iconSize; + + int replyInset = mContext.getResources().getDimensionPixelSize( + R.dimen.notification_reply_inset); + // We're subtracting the inset of the reply icon to make sure it's + // aligned nicely on the right, and remove it from the following padding + marginEnd -= replyInset * 2; + } + if (largeIconShown) { + // adding size of the right icon + marginEnd += iconSize; + + if (replyIconShown) { + // We also add some padding to the reply icon if it's around + marginEnd += contentMargin; + } + } + if (replyIconShown || largeIconShown) { + // The padding to the content + marginEnd += contentMargin; + } + return marginEnd; + } + + /** + * Bind the large icon. + * @return if the largeIcon is visible + */ + private boolean bindLargeIcon(RemoteViews contentView, boolean hideLargeIcon) { if (mN.mLargeIcon == null && mN.largeIcon != null) { mN.mLargeIcon = Icon.createWithBitmap(mN.largeIcon); } @@ -4541,51 +4614,35 @@ public class Notification implements Parcelable contentView.setViewVisibility(R.id.right_icon, View.VISIBLE); contentView.setImageViewIcon(R.id.right_icon, mN.mLargeIcon); processLargeLegacyIcon(mN.mLargeIcon, contentView); - int endMargin = R.dimen.notification_content_picture_margin; - contentView.setViewLayoutMarginEndDimen(R.id.line1, endMargin); - contentView.setViewLayoutMarginEndDimen(R.id.text, endMargin); - contentView.setViewLayoutMarginEndDimen(R.id.progress, endMargin); } - // Bind the reply action - Action action = findReplyAction(); + return showLargeIcon; + } - boolean actionVisible = action != null && (showLargeIcon || alwaysShowReply); - int replyId = showLargeIcon ? R.id.reply_icon_action : R.id.right_icon; + /** + * Bind the reply icon. + * @return if the reply icon is visible + */ + private boolean bindReplyIcon(RemoteViews contentView, boolean hideReplyIcon) { + boolean actionVisible = !hideReplyIcon; + Action action = null; if (actionVisible) { - // We're only showing the icon as big if we're hiding the large icon - int contrastColor = resolveContrastColor(); - int iconColor; - if (showLargeIcon) { - contentView.setDrawableTint(R.id.reply_icon_action, - true /* targetBackground */, - contrastColor, PorterDuff.Mode.SRC_ATOP); - contentView.setOnClickPendingIntent(R.id.right_icon, - action.actionIntent); - contentView.setRemoteInputs(R.id.right_icon, action.mRemoteInputs); - iconColor = NotificationColorUtil.isColorLight(contrastColor) - ? Color.BLACK : Color.WHITE; - } else { - contentView.setImageViewResource(R.id.right_icon, - R.drawable.ic_reply_notification_large); - contentView.setViewVisibility(R.id.right_icon, View.VISIBLE); - iconColor = contrastColor; - } - contentView.setDrawableTint(replyId, + action = findReplyAction(); + actionVisible = action != null; + } + if (actionVisible) { + contentView.setViewVisibility(R.id.reply_icon_action, View.VISIBLE); + contentView.setDrawableTint(R.id.reply_icon_action, false /* targetBackground */, - iconColor, + getNeutralColor(), PorterDuff.Mode.SRC_ATOP); - contentView.setOnClickPendingIntent(replyId, - action.actionIntent); - contentView.setRemoteInputs(replyId, action.mRemoteInputs); + contentView.setOnClickPendingIntent(R.id.reply_icon_action, action.actionIntent); + contentView.setRemoteInputs(R.id.reply_icon_action, action.mRemoteInputs); } else { - contentView.setRemoteInputs(R.id.right_icon, null); + contentView.setRemoteInputs(R.id.reply_icon_action, null); } - contentView.setViewVisibility(R.id.reply_icon_action, actionVisible && showLargeIcon - ? View.VISIBLE - : View.GONE); - contentView.setViewVisibility(R.id.right_icon_container, actionVisible || showLargeIcon - ? View.VISIBLE - : View.GONE); + contentView.setViewVisibility(R.id.reply_icon_action, + actionVisible ? View.VISIBLE : View.GONE); + return actionVisible; } private Action findReplyAction() { @@ -4620,8 +4677,7 @@ public class Notification implements Parcelable } private void bindActivePermissions(RemoteViews contentView, boolean ambient) { - int color = ambient ? resolveAmbientColor() - : isColorized() ? getPrimaryTextColor() : resolveContrastColor(); + int color = ambient ? resolveAmbientColor() : getNeutralColor(); contentView.setDrawableTint(R.id.camera, false, color, PorterDuff.Mode.SRC_ATOP); contentView.setDrawableTint(R.id.mic, false, color, PorterDuff.Mode.SRC_ATOP); contentView.setDrawableTint(R.id.overlay, false, color, PorterDuff.Mode.SRC_ATOP); @@ -4760,6 +4816,8 @@ public class Notification implements Parcelable big.setViewVisibility(R.id.notification_material_reply_container, View.GONE); big.setTextViewText(R.id.notification_material_reply_text_1, null); + big.setViewVisibility(R.id.notification_material_reply_text_1_container, View.GONE); + big.setViewVisibility(R.id.notification_material_reply_progress, View.GONE); big.setViewVisibility(R.id.notification_material_reply_text_2, View.GONE); big.setTextViewText(R.id.notification_material_reply_text_2, null); @@ -4770,13 +4828,15 @@ public class Notification implements Parcelable R.dimen.notification_content_margin); } - private RemoteViews applyStandardTemplateWithActions(int layoutId) { - return applyStandardTemplateWithActions(layoutId, mParams.reset().fillTextsFrom(this)); + private RemoteViews applyStandardTemplateWithActions(int layoutId, + TemplateBindResult result) { + return applyStandardTemplateWithActions(layoutId, mParams.reset().fillTextsFrom(this), + result); } private RemoteViews applyStandardTemplateWithActions(int layoutId, - StandardTemplateParams p) { - RemoteViews big = applyStandardTemplate(layoutId, p); + StandardTemplateParams p, TemplateBindResult result) { + RemoteViews big = applyStandardTemplate(layoutId, p, result); resetStandardTemplateWithActions(big); @@ -4810,10 +4870,19 @@ public class Notification implements Parcelable CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY); if (!p.ambient && validRemoteInput && replyText != null && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) { + boolean showSpinner = mN.extras.getBoolean(EXTRA_SHOW_REMOTE_INPUT_SPINNER); big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE); + big.setViewVisibility(R.id.notification_material_reply_text_1_container, + View.VISIBLE); big.setTextViewText(R.id.notification_material_reply_text_1, processTextSpans(replyText[0])); setTextViewColorSecondary(big, R.id.notification_material_reply_text_1); + big.setViewVisibility(R.id.notification_material_reply_progress, + showSpinner ? View.VISIBLE : View.GONE); + big.setProgressIndeterminateTintList( + R.id.notification_material_reply_progress, + ColorStateList.valueOf( + isColorized() ? getPrimaryTextColor() : resolveContrastColor())); if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])) { big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE); @@ -4883,7 +4952,7 @@ public class Notification implements Parcelable return styleView; } } - return applyStandardTemplate(getBaseLayoutResource()); + return applyStandardTemplate(getBaseLayoutResource(), null /* result */); } private boolean useExistingRemoteView() { @@ -4902,7 +4971,8 @@ public class Notification implements Parcelable result = mStyle.makeBigContentView(); hideLine1Text(result); } else if (mActions.size() != 0) { - result = applyStandardTemplateWithActions(getBigBaseLayoutResource()); + result = applyStandardTemplateWithActions(getBigBaseLayoutResource(), + null /* result */); } makeHeaderExpanded(result); return result; @@ -4939,7 +5009,8 @@ public class Notification implements Parcelable public RemoteViews makeAmbientNotification() { RemoteViews ambient = applyStandardTemplateWithActions( R.layout.notification_template_material_ambient, - mParams.reset().ambient(true).fillTextsFrom(this).hasProgress(false)); + mParams.reset().ambient(true).fillTextsFrom(this).hasProgress(false), + null /* result */); return ambient; } @@ -4982,7 +5053,7 @@ public class Notification implements Parcelable return null; } - return applyStandardTemplateWithActions(getBigBaseLayoutResource()); + return applyStandardTemplateWithActions(getBigBaseLayoutResource(), null /* result */); } /** @@ -5330,6 +5401,20 @@ public class Notification implements Parcelable return mCachedContrastColor = color; } + int resolveNeutralColor() { + if (mNeutralColor != COLOR_INVALID) { + return mNeutralColor; + } + int background = mContext.getColor( + com.android.internal.R.color.notification_material_background_color); + mNeutralColor = NotificationColorUtil.resolveDefaultColor(mContext, background); + if (Color.alpha(mNeutralColor) < 255) { + // alpha doesn't go well for color filters, so let's blend it manually + mNeutralColor = NotificationColorUtil.compositeColors(mNeutralColor, background); + } + return mNeutralColor; + } + int resolveAmbientColor() { if (mCachedAmbientColorIsFor == mN.color && mCachedAmbientColorIsFor != COLOR_INVALID) { return mCachedAmbientColor; @@ -5562,6 +5647,17 @@ public class Notification implements Parcelable } /** + * Gets a neutral color that can be used for icons or similar that should not stand out. + */ + private int getNeutralColor() { + if (isColorized()) { + return getSecondaryTextColor(); + } else { + return resolveNeutralColor(); + } + } + + /** * Same as getBackgroundColor but also resolved the default color to the background. */ private int resolveBackgroundColor() { @@ -5863,6 +5959,18 @@ public class Notification implements Parcelable } protected RemoteViews getStandardView(int layoutId) { + return getStandardView(layoutId, null); + } + + /** + * Get the standard view for this style. + * + * @param layoutId The layout id to use + * @param result The result where template bind information is saved. + * @return A remoteView for this style. + * @hide + */ + protected RemoteViews getStandardView(int layoutId, TemplateBindResult result) { checkBuilder(); // Nasty. @@ -5872,7 +5980,7 @@ public class Notification implements Parcelable mBuilder.setContentTitle(mBigContentTitle); } - RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId); + RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId, result); mBuilder.getAllExtras().putCharSequence(EXTRA_TITLE, oldBuilderContentTitle); @@ -6169,7 +6277,8 @@ public class Notification implements Parcelable mBuilder.mN.largeIcon = null; } - RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource()); + RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource(), + null /* result */); if (mSummaryTextSet) { contentView.setTextViewText(R.id.text, mBuilder.processTextSpans( mBuilder.processLegacyText(mSummaryText))); @@ -6356,7 +6465,9 @@ public class Notification implements Parcelable CharSequence text = mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT); mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null); - RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource()); + TemplateBindResult result = new TemplateBindResult(); + RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource(), result); + contentView.setInt(R.id.big_text, "setImageEndMargin", result.getIconMarginEnd()); mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, text); @@ -6739,7 +6850,7 @@ public class Notification implements Parcelable mBuilder.mOriginalActions = mBuilder.mActions; mBuilder.mActions = new ArrayList<>(); RemoteViews remoteViews = makeMessagingView(true /* displayImagesAtEnd */, - true /* showReplyIcon */); + false /* hideLargeIcon */); mBuilder.mActions = mBuilder.mOriginalActions; mBuilder.mOriginalActions = null; return remoteViews; @@ -6826,7 +6937,7 @@ public class Notification implements Parcelable */ @Override public RemoteViews makeBigContentView() { - return makeMessagingView(false /* displayImagesAtEnd */, false /* showReplyIcon */); + return makeMessagingView(false /* displayImagesAtEnd */, true /* hideLargeIcon */); } /** @@ -6834,11 +6945,11 @@ public class Notification implements Parcelable * * @param displayImagesAtEnd should images be displayed at the end of the content instead * of inline. - * @param showReplyIcon Should the reply affordance be shown at the end of the notification + * @param hideRightIcons Should the reply affordance be shown at the end of the notification * @return the created remoteView. */ @NonNull - private RemoteViews makeMessagingView(boolean displayImagesAtEnd, boolean showReplyIcon) { + private RemoteViews makeMessagingView(boolean displayImagesAtEnd, boolean hideRightIcons) { CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle) ? super.mBigContentTitle : mConversationTitle; @@ -6849,20 +6960,18 @@ public class Notification implements Parcelable nameReplacement = conversationTitle; conversationTitle = null; } - boolean hideLargeIcon = !showReplyIcon || isOneToOne; + TemplateBindResult bindResult = new TemplateBindResult(); RemoteViews contentView = mBuilder.applyStandardTemplateWithActions( mBuilder.getMessagingLayoutResource(), mBuilder.mParams.reset().hasProgress(false).title(conversationTitle).text(null) - .hideLargeIcon(hideLargeIcon) - .headerTextSecondary(conversationTitle) - .alwaysShowReply(showReplyIcon)); + .hideLargeIcon(hideRightIcons || isOneToOne) + .hideReplyIcon(hideRightIcons) + .headerTextSecondary(conversationTitle), + bindResult); addExtras(mBuilder.mN.extras); // also update the end margin if there is an image - int endMargin = R.dimen.notification_content_margin_end; - if (showReplyIcon) { - endMargin = R.dimen.notification_content_plus_picture_margin_end; - } - contentView.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin); + contentView.setViewLayoutMarginEnd(R.id.notification_messaging, + bindResult.getIconMarginEnd()); contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor", mBuilder.resolveContrastColor()); contentView.setBoolean(R.id.status_bar_latest_event_content, "setDisplayImagesAtEnd", @@ -6934,7 +7043,7 @@ public class Notification implements Parcelable @Override public RemoteViews makeHeadsUpContentView(boolean increasedHeight) { RemoteViews remoteViews = makeMessagingView(true /* displayImagesAtEnd */, - false /* showReplyIcon */); + true /* hideLargeIcon */); remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1); return remoteViews; } @@ -6953,11 +7062,16 @@ public class Notification implements Parcelable static final String KEY_DATA_MIME_TYPE = "type"; static final String KEY_DATA_URI= "uri"; static final String KEY_EXTRAS_BUNDLE = "extras"; + static final String KEY_REMOTE_INPUT_HISTORY = "remote_input_history"; private final CharSequence mText; private final long mTimestamp; @Nullable private final Person mSender; + /** True if this message was generated from the extra + * {@link Notification#EXTRA_REMOTE_INPUT_HISTORY} + */ + private final boolean mRemoteInputHistory; private Bundle mExtras = new Bundle(); private String mDataMimeType; @@ -6996,9 +7110,33 @@ public class Notification implements Parcelable * </p> */ public Message(@NonNull CharSequence text, long timestamp, @Nullable Person sender) { + this(text, timestamp, sender, false /* remoteHistory */); + } + + /** + * Constructor + * @param text A {@link CharSequence} to be displayed as the message content + * @param timestamp Time at which the message arrived + * @param sender The {@link Person} who sent the message. + * Should be <code>null</code> for messages by the current user, in which case + * the platform will insert the user set in {@code MessagingStyle(Person)}. + * @param remoteInputHistory True if the messages was generated from the extra + * {@link Notification#EXTRA_REMOTE_INPUT_HISTORY}. + * <p> + * The person provided should contain an Icon, set with + * {@link Person.Builder#setIcon(Icon)} and also have a name provided + * with {@link Person.Builder#setName(CharSequence)}. If multiple users have the same + * name, consider providing a key with {@link Person.Builder#setKey(String)} in order + * to differentiate between the different users. + * </p> + * @hide + */ + public Message(@NonNull CharSequence text, long timestamp, @Nullable Person sender, + boolean remoteInputHistory) { mText = text; mTimestamp = timestamp; mSender = sender; + mRemoteInputHistory = remoteInputHistory; } /** @@ -7088,6 +7226,15 @@ public class Notification implements Parcelable return mDataUri; } + /** + * @return True if the message was generated from + * {@link Notification#EXTRA_REMOTE_INPUT_HISTORY}. + * @hide + */ + public boolean isRemoteInputHistory() { + return mRemoteInputHistory; + } + private Bundle toBundle() { Bundle bundle = new Bundle(); if (mText != null) { @@ -7108,6 +7255,9 @@ public class Notification implements Parcelable if (mExtras != null) { bundle.putBundle(KEY_EXTRAS_BUNDLE, mExtras); } + if (mRemoteInputHistory) { + bundle.putBoolean(KEY_REMOTE_INPUT_HISTORY, mRemoteInputHistory); + } return bundle; } @@ -7159,7 +7309,8 @@ public class Notification implements Parcelable } Message message = new Message(bundle.getCharSequence(KEY_TEXT), bundle.getLong(KEY_TIMESTAMP), - senderPerson); + senderPerson, + bundle.getBoolean(KEY_REMOTE_INPUT_HISTORY, false)); if (bundle.containsKey(KEY_DATA_MIME_TYPE) && bundle.containsKey(KEY_DATA_URI)) { message.setData(bundle.getString(KEY_DATA_MIME_TYPE), @@ -7275,7 +7426,8 @@ public class Notification implements Parcelable CharSequence oldBuilderContentText = mBuilder.mN.extras.getCharSequence(EXTRA_TEXT); mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null); - RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource()); + TemplateBindResult result = new TemplateBindResult(); + RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource(), result); mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText); @@ -7304,7 +7456,8 @@ public class Notification implements Parcelable mBuilder.processTextSpans(mBuilder.processLegacyText(str))); mBuilder.setTextViewColorSecondary(contentView, rowIds[i]); contentView.setViewPadding(rowIds[i], 0, topPadding, 0, 0); - handleInboxImageMargin(contentView, rowIds[i], first); + handleInboxImageMargin(contentView, rowIds[i], first, + result.getIconMarginEnd()); if (first) { onlyViewId = rowIds[i]; } else { @@ -7336,17 +7489,18 @@ public class Notification implements Parcelable return !Objects.equals(getLines(), newS.getLines()); } - private void handleInboxImageMargin(RemoteViews contentView, int id, boolean first) { + private void handleInboxImageMargin(RemoteViews contentView, int id, boolean first, + int marginEndValue) { int endMargin = 0; if (first) { final int max = mBuilder.mN.extras.getInt(EXTRA_PROGRESS_MAX, 0); final boolean ind = mBuilder.mN.extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE); boolean hasProgress = max != 0 || ind; - if (mBuilder.mN.hasLargeIcon() && !hasProgress) { - endMargin = R.dimen.notification_content_picture_margin; + if (!hasProgress) { + endMargin = marginEndValue; } } - contentView.setViewLayoutMarginEndDimen(id, endMargin); + contentView.setViewLayoutMarginEnd(id, endMargin); } } @@ -7535,7 +7689,8 @@ public class Notification implements Parcelable private RemoteViews makeMediaContentView() { RemoteViews view = mBuilder.applyStandardTemplate( - R.layout.notification_template_material_media, false /* hasProgress */); + R.layout.notification_template_material_media, false, /* hasProgress */ + null /* result */); final int numActions = mBuilder.mActions.size(); final int N = mActionsToShowInCompact == null @@ -7559,7 +7714,7 @@ public class Notification implements Parcelable // handle the content margin int endMargin = R.dimen.notification_content_margin_end; if (mBuilder.mN.hasLargeIcon()) { - endMargin = R.dimen.notification_content_plus_picture_margin_end; + endMargin = R.dimen.notification_media_image_margin_end; } view.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin); return view; @@ -7580,8 +7735,7 @@ public class Notification implements Parcelable return null; } RemoteViews big = mBuilder.applyStandardTemplate( - R.layout.notification_template_material_big_media, - false); + R.layout.notification_template_material_big_media, false, null /* result */); if (actionCount > 0) { big.removeAllViews(com.android.internal.R.id.media_actions); @@ -7677,16 +7831,18 @@ public class Notification implements Parcelable if (mBuilder.mActions.size() == 0) { return makeStandardTemplateWithCustomContent(headsUpContentView); } + TemplateBindResult result = new TemplateBindResult(); RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions( - mBuilder.getBigBaseLayoutResource()); - buildIntoRemoteViewContent(remoteViews, headsUpContentView); + mBuilder.getBigBaseLayoutResource(), result); + buildIntoRemoteViewContent(remoteViews, headsUpContentView, result); return remoteViews; } private RemoteViews makeStandardTemplateWithCustomContent(RemoteViews customContent) { + TemplateBindResult result = new TemplateBindResult(); RemoteViews remoteViews = mBuilder.applyStandardTemplate( - mBuilder.getBaseLayoutResource()); - buildIntoRemoteViewContent(remoteViews, customContent); + mBuilder.getBaseLayoutResource(), result); + buildIntoRemoteViewContent(remoteViews, customContent, result); return remoteViews; } @@ -7697,14 +7853,15 @@ public class Notification implements Parcelable if (mBuilder.mActions.size() == 0) { return makeStandardTemplateWithCustomContent(bigContentView); } + TemplateBindResult result = new TemplateBindResult(); RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions( - mBuilder.getBigBaseLayoutResource()); - buildIntoRemoteViewContent(remoteViews, bigContentView); + mBuilder.getBigBaseLayoutResource(), result); + buildIntoRemoteViewContent(remoteViews, bigContentView, result); return remoteViews; } private void buildIntoRemoteViewContent(RemoteViews remoteViews, - RemoteViews customContent) { + RemoteViews customContent, TemplateBindResult result) { if (customContent != null) { // Need to clone customContent before adding, because otherwise it can no longer be // parceled independently of remoteViews. @@ -7714,11 +7871,10 @@ public class Notification implements Parcelable remoteViews.setReapplyDisallowed(); } // also update the end margin if there is an image - int endMargin = R.dimen.notification_content_margin_end; - if (mBuilder.mN.hasLargeIcon()) { - endMargin = R.dimen.notification_content_plus_picture_margin_end; - } - remoteViews.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin); + Resources resources = mBuilder.mContext.getResources(); + int endMargin = resources.getDimensionPixelSize( + R.dimen.notification_content_margin_end) + result.getIconMarginEnd(); + remoteViews.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin); } /** @@ -9322,6 +9478,25 @@ public class Notification implements Parcelable } } + /** + * A result object where information about the template that was created is saved. + */ + private static class TemplateBindResult { + int mIconMarginEnd; + + /** + * Get the margin end that needs to be added to any fields that may overlap + * with the right actions. + */ + public int getIconMarginEnd() { + return mIconMarginEnd; + } + + public void setIconMarginEnd(int iconMarginEnd) { + this.mIconMarginEnd = iconMarginEnd; + } + } + private static class StandardTemplateParams { boolean hasProgress = true; boolean ambient = false; @@ -9329,7 +9504,7 @@ public class Notification implements Parcelable CharSequence text; CharSequence headerTextSecondary; boolean hideLargeIcon; - public boolean alwaysShowReply; + boolean hideReplyIcon; final StandardTemplateParams reset() { hasProgress = true; @@ -9360,13 +9535,13 @@ public class Notification implements Parcelable return this; } - final StandardTemplateParams alwaysShowReply(boolean alwaysShowReply) { - this.alwaysShowReply = alwaysShowReply; + final StandardTemplateParams hideLargeIcon(boolean hideLargeIcon) { + this.hideLargeIcon = hideLargeIcon; return this; } - final StandardTemplateParams hideLargeIcon(boolean hideLargeIcon) { - this.hideLargeIcon = hideLargeIcon; + final StandardTemplateParams hideReplyIcon(boolean hideReplyIcon) { + this.hideReplyIcon = hideReplyIcon; return this; } diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 315259bdf388..bdaf80e374df 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -33,8 +33,11 @@ import android.os.Parcelable; import android.os.RemoteException; import android.os.UserHandle; import android.util.AndroidException; +import android.util.ArraySet; import android.util.proto.ProtoOutputStream; +import com.android.internal.os.IResultReceiver; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -93,7 +96,9 @@ import java.lang.annotation.RetentionPolicy; */ public final class PendingIntent implements Parcelable { private final IIntentSender mTarget; + private IResultReceiver mCancelReceiver; private IBinder mWhitelistToken; + private ArraySet<CancelListener> mCancelListeners; /** @hide */ @IntDef(flag = true, @@ -964,6 +969,74 @@ public final class PendingIntent implements Parcelable { } /** + * Register a listener to when this pendingIntent is cancelled. There are no guarantees on which + * thread a listener will be called and it's up to the caller to synchronize. This may + * trigger a synchronous binder call so should therefore usually be called on a background + * thread. + * + * @hide + */ + public void registerCancelListener(CancelListener cancelListener) { + synchronized (this) { + if (mCancelReceiver == null) { + mCancelReceiver = new IResultReceiver.Stub() { + @Override + public void send(int resultCode, Bundle resultData) throws RemoteException { + notifyCancelListeners(); + } + }; + } + if (mCancelListeners == null) { + mCancelListeners = new ArraySet<>(); + } + boolean wasEmpty = mCancelListeners.isEmpty(); + mCancelListeners.add(cancelListener); + if (wasEmpty) { + try { + ActivityManager.getService().registerIntentSenderCancelListener(mTarget, + mCancelReceiver); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + } + + private void notifyCancelListeners() { + ArraySet<CancelListener> cancelListeners; + synchronized (this) { + cancelListeners = new ArraySet<>(mCancelListeners); + } + int size = cancelListeners.size(); + for (int i = 0; i < size; i++) { + cancelListeners.valueAt(i).onCancelled(this); + } + } + + /** + * Un-register a listener to when this pendingIntent is cancelled. + * + * @hide + */ + public void unregisterCancelListener(CancelListener cancelListener) { + synchronized (this) { + if (mCancelListeners == null) { + return; + } + boolean wasEmpty = mCancelListeners.isEmpty(); + mCancelListeners.remove(cancelListener); + if (mCancelListeners.isEmpty() && !wasEmpty) { + try { + ActivityManager.getService().unregisterIntentSenderCancelListener(mTarget, + mCancelReceiver); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + } + + /** * Return the user handle of the application that created this * PendingIntent, that is the user under which you will actually be * sending the Intent. The returned UserHandle is supplied by the system, so @@ -1184,4 +1257,18 @@ public final class PendingIntent implements Parcelable { public IBinder getWhitelistToken() { return mWhitelistToken; } + + /** + * A listener to when a pending intent is cancelled + * + * @hide + */ + public interface CancelListener { + /** + * Called when a Pending Intent is cancelled. + * + * @param intent The intent that was cancelled. + */ + void onCancelled(PendingIntent intent); + } } diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java index 20eef6cc01d8..2a451ff07672 100644 --- a/core/java/android/app/admin/SystemUpdatePolicy.java +++ b/core/java/android/app/admin/SystemUpdatePolicy.java @@ -48,7 +48,37 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** - * A class that represents a local system update policy set by the device owner. + * Determines when over-the-air system updates are installed on a device. Only a device policy + * controller (DPC) running in device owner mode can set an update policy for the device—by calling + * the {@code DevicePolicyManager} method + * {@link DevicePolicyManager#setSystemUpdatePolicy setSystemUpdatePolicy()}. An update + * policy affects the pending system update (if there is one) and any future updates for the device. + * + * <p>If a policy is set on a device, the system doesn't notify the user about updates.</p> + * <h3>Example</h3> + * + * <p>The example below shows how a DPC might set a maintenance window for system updates:</p> + * <pre><code> + * private final MAINTENANCE_WINDOW_START = 1380; // 11pm + * private final MAINTENANCE_WINDOW_END = 120; // 2am + * + * // ... + * + * // Create the system update policy + * SystemUpdatePolicy policy = SystemUpdatePolicy.createWindowedInstallPolicy( + * MAINTENANCE_WINDOW_START, MAINTENANCE_WINDOW_END); + * + * // Get a DevicePolicyManager instance to set the policy on the device + * DevicePolicyManager dpm = + * (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); + * ComponentName adminComponent = getComponentName(context); + * dpm.setSystemUpdatePolicy(adminComponent, policy); + * </code></pre> + * + * <h3>Developer guide</h3> + * To learn more about managing system updates, read + * <a href="{@docRoot}/work/dpc/security.html#control_remote_software_updates">Control remote + * software updates</a>. * * @see DevicePolicyManager#setSystemUpdatePolicy * @see DevicePolicyManager#getSystemUpdatePolicy @@ -71,44 +101,37 @@ public final class SystemUpdatePolicy implements Parcelable { private static final int TYPE_UNKNOWN = -1; /** - * Install system update automatically as soon as one is available. + * Installs system updates (without user interaction) as soon as they become available. Setting + * this policy type immediately installs any pending updates that might be postponed or waiting + * for a maintenance window. */ public static final int TYPE_INSTALL_AUTOMATIC = 1; /** - * Install system update automatically within a daily maintenance window. An update can be - * delayed for a maximum of 30 days, after which the policy will no longer be effective and the - * system will revert back to its normal behavior as if no policy were set. - * - * <p>After this policy expires, resetting it to any policy other than - * {@link #TYPE_INSTALL_AUTOMATIC} will produce no effect, as the 30-day maximum delay has - * already been used up. - * The {@link #TYPE_INSTALL_AUTOMATIC} policy will still take effect to install the delayed - * system update immediately. + * Installs system updates (without user interaction) during a daily maintenance window. Set the + * start and end of the daily maintenance window, as minutes of the day, when creating a new + * {@code TYPE_INSTALL_WINDOWED} policy. See + * {@link #createWindowedInstallPolicy createWindowedInstallPolicy()}. * - * <p>Re-applying this policy or changing it to {@link #TYPE_POSTPONE} within the 30-day period - * will <i>not</i> extend policy expiration. - * However, the expiration will be recalculated when a new system update is made available. + * <p>No connectivity, not enough disk space, or a low battery are typical reasons Android might + * not install a system update in the daily maintenance window. After 30 days trying to install + * an update in the maintenance window (regardless of policy changes in this period), the system + * prompts the device user to install the update. */ public static final int TYPE_INSTALL_WINDOWED = 2; /** - * Incoming system updates (except for security updates) will be blocked for a maximum of 30 - * days, after which the policy will no longer be effective and the system will revert back to - * its normal behavior as if no policy were set. + * Postpones the installation of system updates for 30 days. After the 30-day period has ended, + * the system prompts the device user to install the update. * - * <p><b>Note:</b> security updates (e.g. monthly security patches) may <i>not</i> be affected - * by this policy, depending on the policy set by the device manufacturer and carrier. + * <p>The system limits each update to one 30-day postponement. The period begins when the + * system first postpones the update and setting new {@code TYPE_POSTPONE} policies won’t extend + * the period. If, after 30 days the update isn’t installed (through policy changes), the system + * prompts the user to install the update. * - * <p>After this policy expires, resetting it to any policy other than - * {@link #TYPE_INSTALL_AUTOMATIC} will produce no effect, as the 30-day maximum delay has - * already been used up. - * The {@link #TYPE_INSTALL_AUTOMATIC} policy will still take effect to install the delayed - * system update immediately. - * - * <p>Re-applying this policy or changing it to {@link #TYPE_INSTALL_WINDOWED} within the 30-day - * period will <i>not</i> extend policy expiration. - * However, the expiration will be recalculated when a new system update is made available. + * <p><strong>Note</strong>: Device manufacturers or carriers might choose to exempt important + * security updates from a postponement policy. Exempted updates notify the device user when + * they become available. */ public static final int TYPE_POSTPONE = 3; @@ -303,16 +326,20 @@ public final class SystemUpdatePolicy implements Parcelable { * Create a policy object and set it to: new system update will only be installed automatically * when the system clock is inside a daily maintenance window. If the start and end times are * the same, the window is considered to include the <i>whole 24 hours</i>. That is, updates can - * install at any time. If the given window in invalid, an {@link IllegalArgumentException} - * will be thrown. If start time is later than end time, the window is considered spanning + * install at any time. If start time is later than end time, the window is considered spanning * midnight (i.e. the end time denotes a time on the next day). The maintenance window will last - * for 30 days, after which the system will revert back to its normal behavior as if no policy - * were set. + * for 30 days for any given update, after which the window will no longer be effective and + * the pending update will be made available for manual installation as if no system update + * policy were set on the device. See {@link #TYPE_INSTALL_WINDOWED} for the details of this + * policy's behavior. * * @param startTime the start of the maintenance window, measured as the number of minutes from * midnight in the device's local time. Must be in the range of [0, 1440). * @param endTime the end of the maintenance window, measured as the number of minutes from * midnight in the device's local time. Must be in the range of [0, 1440). + * @throws IllegalArgumentException If the {@code startTime} or {@code endTime} isn't in the + * accepted range. + * @return The configured policy. * @see #TYPE_INSTALL_WINDOWED */ public static SystemUpdatePolicy createWindowedInstallPolicy(int startTime, int endTime) { @@ -329,8 +356,7 @@ public final class SystemUpdatePolicy implements Parcelable { /** * Create a policy object and set it to block installation for a maximum period of 30 days. - * After expiration the system will revert back to its normal behavior as if no policy were - * set. + * To learn more about this policy's behavior, see {@link #TYPE_POSTPONE}. * * <p><b>Note: </b> security updates (e.g. monthly security patches) will <i>not</i> be affected * by this policy. @@ -344,10 +370,9 @@ public final class SystemUpdatePolicy implements Parcelable { } /** - * Returns the type of system update policy. + * Returns the type of system update policy, or -1 if no policy has been set. * - * @return an integer, either one of {@link #TYPE_INSTALL_AUTOMATIC}, - * {@link #TYPE_INSTALL_WINDOWED} and {@link #TYPE_POSTPONE}, or -1 if no policy has been set. + @return The policy type or -1 if the type isn't set. */ @SystemUpdatePolicyType public int getPolicyType() { @@ -423,24 +448,16 @@ public final class SystemUpdatePolicy implements Parcelable { * be blocked and cannot be installed. When the device is outside the freeze periods, the normal * policy behavior will apply. * <p> - * Each freeze period is defined by a starting and finishing date (both inclusive). Since the - * freeze period repeats annually, both of these dates are simply represented by integers - * counting the number of days since year start, similar to {@link LocalDate#getDayOfYear()}. We - * do not consider leap year when handling freeze period so the valid range of the integer is - * always [1,365] (see last section for more details on leap year). If the finishing date is - * smaller than the starting date, the freeze period is considered to be spanning across - * year-end. - * <p> * Each individual freeze period is allowed to be at most 90 days long, and adjacent freeze * periods need to be at least 60 days apart. Also, the list of freeze periods should not * contain duplicates or overlap with each other. If any of these conditions is not met, a * {@link ValidationFailedException} will be thrown. * <p> - * Handling of leap year: we do not consider leap year when handling freeze period, in - * particular, + * Handling of leap year: we ignore leap years in freeze period calculations, in particular, * <ul> - * <li>When a freeze period is defined by the day of year, February 29th does not count as one - * day, so day 59 is February 28th while day 60 is March 1st.</li> + * <li>When a freeze period is defined, February 29th is disregarded so even though a freeze + * period can be specified to start or end on February 29th, it will be treated as if the period + * started or ended on February 28th.</li> * <li>When applying freeze period behavior to the device, a system clock of February 29th is * treated as if it were February 28th</li> * <li>When calculating the number of days of a freeze period or separation between two freeze diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java index debc32bd83eb..30f340c50e32 100644 --- a/core/java/android/app/backup/BackupManager.java +++ b/core/java/android/app/backup/BackupManager.java @@ -387,7 +387,7 @@ public class BackupManager { @SystemApi @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isBackupServiceActive(UserHandle user) { - mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "isBackupServiceActive"); checkServiceBinder(); if (sService != null) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c5fc06751e0e..6b6e14fb7173 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10775,6 +10775,7 @@ public final class Settings { * track_cpu_active_cluster_time (boolean) * read_binary_cpu_time (boolean) * proc_state_cpu_times_read_delay_ms (long) + * external_stats_collection_rate_limit_ms (long) * </pre> * * <p> diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java index 179d545f8ccd..72383cf377e9 100644 --- a/core/java/android/text/AndroidBidi.java +++ b/core/java/android/text/AndroidBidi.java @@ -32,8 +32,12 @@ import com.android.internal.annotations.VisibleForTesting; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public class AndroidBidi { - private static class EmojiBidiOverride extends BidiClassifier { - EmojiBidiOverride() { + /** + * Overrides ICU {@link BidiClassifier} in order to correctly handle character directions for + * newest emoji that ICU is not aware of. + */ + public static class EmojiBidiOverride extends BidiClassifier { + public EmojiBidiOverride() { super(null /* No persisting object needed */); } diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java index f65f39762b75..77f17a7d2377 100644 --- a/core/java/android/text/BidiFormatter.java +++ b/core/java/android/text/BidiFormatter.java @@ -21,6 +21,8 @@ import static android.text.TextDirectionHeuristics.FIRSTSTRONG_LTR; import android.annotation.Nullable; import android.view.View; +import com.android.internal.annotations.VisibleForTesting; + import java.util.Locale; /** @@ -570,8 +572,10 @@ public final class BidiFormatter { /** * An object that estimates the directionality of a given string by various methods. * + * @hide */ - private static class DirectionalityEstimator { + @VisibleForTesting + public static class DirectionalityEstimator { // Internal static variables and constants. @@ -598,7 +602,11 @@ public final class BidiFormatter { } } - private static byte getDirectionality(int codePoint) { + /** + * Return Character directionality. Same as {@link Character#getDirectionality(int)} except + * it overrides values for newest emoji that are not covered by ICU. + */ + public static byte getDirectionality(int codePoint) { if (Emoji.isNewEmoji(codePoint)) { // TODO: Fix or remove once emoji-data.text 5.0 is in ICU or update to 6.0. return Character.DIRECTIONALITY_OTHER_NEUTRALS; diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java index d33aad99e1a5..876c64eebf84 100644 --- a/core/java/android/text/Emoji.java +++ b/core/java/android/text/Emoji.java @@ -46,44 +46,49 @@ public class Emoji { return UCharacter.hasBinaryProperty(codePoint, UProperty.EMOJI_MODIFIER); } - // Returns true if the given code point is emoji modifier base. - public static boolean isEmojiModifierBase(int codePoint) { + // + + /** + * Returns true if the given code point is emoji modifier base. + * @param c codepoint to check + * @return true if is emoji modifier base + */ + public static boolean isEmojiModifierBase(int c) { // These two characters were removed from Emoji_Modifier_Base in Emoji 4.0, but we need to // keep them as emoji modifier bases since there are fonts and user-generated text out there // that treats these as potential emoji bases. - if (codePoint == 0x1F91D || codePoint == 0x1F93C) { + if (c == 0x1F91D || c == 0x1F93C) { return true; } - // Emoji Modifier Base characters new in Unicode emoji 5.0. - // From http://www.unicode.org/Public/emoji/5.0/emoji-data.txt - // TODO: Remove once emoji-data.text 5.0 is in ICU or update to 6.0. - if (codePoint == 0x1F91F - || (0x1F931 <= codePoint && codePoint <= 0x1F932) - || (0x1F9D1 <= codePoint && codePoint <= 0x1F9DD)) { + // Emoji Modifier Base characters new in Unicode emoji 11 + // From https://www.unicode.org/Public/emoji/11.0/emoji-data.txt + // TODO: Remove once emoji-data.text 11 is in ICU or update to 11. + if ((0x1F9B5 <= c && c <= 0x1F9B6) || (0x1F9B8 <= c && c <= 0x1F9B9)) { return true; } - return UCharacter.hasBinaryProperty(codePoint, UProperty.EMOJI_MODIFIER_BASE); + return UCharacter.hasBinaryProperty(c, UProperty.EMOJI_MODIFIER_BASE); } /** * Returns true if the character is a new emoji still not supported in our version of ICU. */ - public static boolean isNewEmoji(int codePoint) { - // Emoji characters new in Unicode emoji 5.0. - // From http://www.unicode.org/Public/emoji/5.0/emoji-data.txt - // TODO: Remove once emoji-data.text 5.0 is in ICU or update to 6.0. - if (codePoint < 0x1F6F7 || codePoint > 0x1F9E6) { + public static boolean isNewEmoji(int c) { + // Emoji characters new in Unicode emoji 11 + // From https://www.unicode.org/Public/emoji/11.0/emoji-data.txt + // TODO: Remove once emoji-data.text 11 is in ICU or update to 11. + if (c < 0x1F6F9 || c > 0x1F9FF) { // Optimization for characters outside the new emoji range. return false; } - return (0x1F6F7 <= codePoint && codePoint <= 0x1F6F8) - || codePoint == 0x1F91F - || (0x1F928 <= codePoint && codePoint <= 0x1F92F) - || (0x1F931 <= codePoint && codePoint <= 0x1F932) - || codePoint == 0x1F94C - || (0x1F95F <= codePoint && codePoint <= 0x1F96B) - || (0x1F992 <= codePoint && codePoint <= 0x1F997) - || (0x1F9D0 <= codePoint && codePoint <= 0x1F9E6); + return c == 0x265F || c == 0x267E || c == 0x1F6F9 || c == 0x1F97A + || (0x1F94D <= c && c <= 0x1F94F) + || (0x1F96C <= c && c <= 0x1F970) + || (0x1F973 <= c && c <= 0x1F976) + || (0x1F97C <= c && c <= 0x1F97F) + || (0x1F998 <= c && c <= 0x1F9A2) + || (0x1F9B0 <= c && c <= 0x1F9B9) + || (0x1F9C1 <= c && c <= 0x1F9C2) + || (0x1F9E7 <= c && c <= 0x1F9FF); } /** diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java index 1c67434b2609..e247c87fdb4c 100644 --- a/core/java/android/util/apk/ApkSigningBlockUtils.java +++ b/core/java/android/util/apk/ApkSigningBlockUtils.java @@ -92,6 +92,8 @@ final class ApkSigningBlockUtils { throw new SecurityException("No digests provided"); } + boolean neverVerified = true; + Map<Integer, byte[]> expected1MbChunkDigests = new ArrayMap<>(); if (expectedDigests.containsKey(CONTENT_DIGEST_CHUNKED_SHA256)) { expected1MbChunkDigests.put(CONTENT_DIGEST_CHUNKED_SHA256, @@ -101,18 +103,23 @@ final class ApkSigningBlockUtils { expected1MbChunkDigests.put(CONTENT_DIGEST_CHUNKED_SHA512, expectedDigests.get(CONTENT_DIGEST_CHUNKED_SHA512)); } - - if (expectedDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) { - verifyIntegrityForVerityBasedAlgorithm( - expectedDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256), apk, signatureInfo); - } else if (!expected1MbChunkDigests.isEmpty()) { + if (!expected1MbChunkDigests.isEmpty()) { try { verifyIntegrityFor1MbChunkBasedAlgorithm(expected1MbChunkDigests, apk.getFD(), signatureInfo); + neverVerified = false; } catch (IOException e) { throw new SecurityException("Cannot get FD", e); } - } else { + } + + if (expectedDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) { + verifyIntegrityForVerityBasedAlgorithm( + expectedDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256), apk, signatureInfo); + neverVerified = false; + } + + if (neverVerified) { throw new SecurityException("No known digest exists for integrity check"); } } diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index c0b40c8ceb3b..94b9bc099d56 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -64,4 +64,9 @@ interface IRecentsAnimationController { * Informs the system that the primary split-screen stack should be minimized. */ void setSplitScreenMinimized(boolean minimized); + + /** + * Hides the current input method if one is showing. + */ + void hideCurrentInputMethod(); } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 8395681f0139..131fe1395585 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -128,7 +128,10 @@ interface IWindowManager void overridePendingAppTransitionRemote(in RemoteAnimationAdapter remoteAnimationAdapter); void executeAppTransition(); - /** Used by system ui to report that recents has shown itself. */ + /** + * Used by system ui to report that recents has shown itself. + * @deprecated to be removed once prebuilts are updated + */ void endProlongedAnimations(); // Re-evaluate the current orientation from the caller's state. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 19ead600e2dc..4bd6fc8b665f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3272,7 +3272,8 @@ public final class ViewRootImpl implements ViewParent, // eglTerminate() for instance. if (mAttachInfo.mThreadedRenderer != null && !mAttachInfo.mThreadedRenderer.isEnabled() && - mAttachInfo.mThreadedRenderer.isRequested()) { + mAttachInfo.mThreadedRenderer.isRequested() && + mSurface.isValid()) { try { mAttachInfo.mThreadedRenderer.initializeIfNeeded( diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index b6bd14ed5efd..5ecbf90a4eca 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -946,6 +946,7 @@ public class RemoteViews implements Parcelable, Filter { } }; } + target.setTagInternal(R.id.pending_intent_tag, pendingIntent); target.setOnClickListener(listener); } @@ -1999,6 +2000,7 @@ public class RemoteViews implements Parcelable, Filter { /** Set width */ public static final int LAYOUT_WIDTH = 2; public static final int LAYOUT_MARGIN_BOTTOM_DIMEN = 3; + public static final int LAYOUT_MARGIN_END = 4; final int mProperty; final int mValue; @@ -2036,11 +2038,14 @@ public class RemoteViews implements Parcelable, Filter { if (layoutParams == null) { return; } + int value = mValue; switch (mProperty) { case LAYOUT_MARGIN_END_DIMEN: + value = resolveDimenPixelOffset(target, mValue); + // fall-through + case LAYOUT_MARGIN_END: if (layoutParams instanceof ViewGroup.MarginLayoutParams) { - int resolved = resolveDimenPixelOffset(target, mValue); - ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(resolved); + ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(value); target.setLayoutParams(layoutParams); } break; @@ -2980,6 +2985,20 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Equivalent to calling {@link android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int)}. + * Only works if the {@link View#getLayoutParams()} supports margins. + * Hidden for now since we don't want to support this for all different layout margins yet. + * + * @param viewId The id of the view to change + * @param endMargin a value in pixels for the end margin. + * @hide + */ + public void setViewLayoutMarginEnd(int viewId, @DimenRes int endMargin) { + addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END, + endMargin)); + } + + /** * Equivalent to setting {@link android.view.ViewGroup.MarginLayoutParams#bottomMargin}. * * @param bottomMarginDimen a dimen resource to read the margin from or 0 to clear the margin. diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 5da3874dbcec..a4680cab4b56 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -196,6 +196,7 @@ public class BatteryStatsImpl extends BatteryStats { static final int MSG_REPORT_CPU_UPDATE_NEEDED = 1; static final int MSG_REPORT_POWER_CHANGE = 2; static final int MSG_REPORT_CHARGING = 3; + static final int MSG_REPORT_RESET_STATS = 4; static final long DELAY_UPDATE_WAKELOCKS = 5*1000; private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader(); @@ -319,6 +320,7 @@ public class BatteryStatsImpl extends BatteryStats { public void batteryNeedsCpuUpdate(); public void batteryPowerChanged(boolean onBattery); public void batterySendBroadcast(Intent intent); + public void batteryStatsReset(); } public interface PlatformIdleStateCallback { @@ -373,7 +375,11 @@ public class BatteryStatsImpl extends BatteryStats { cb.batterySendBroadcast(intent); } break; - } + case MSG_REPORT_RESET_STATS: + if (cb != null) { + cb.batteryStatsReset(); + } + } } } @@ -10939,6 +10945,7 @@ public class BatteryStatsImpl extends BatteryStats { initDischarge(); clearHistoryLocked(); + mHandler.sendEmptyMessage(MSG_REPORT_RESET_STATS); } private void initActiveHistoryEventsLocked(long elapsedRealtimeMs, long uptimeMs) { @@ -13261,18 +13268,23 @@ public class BatteryStatsImpl extends BatteryStats { = "kernel_uid_readers_throttle_time"; public static final String KEY_UID_REMOVE_DELAY_MS = "uid_remove_delay_ms"; + public static final String KEY_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS + = "external_stats_collection_rate_limit_ms"; private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true; private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true; private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000; private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 10_000; private static final long DEFAULT_UID_REMOVE_DELAY_MS = 5L * 60L * 1000L; + private static final long DEFAULT_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS = 600_000; public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE; public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME; public long PROC_STATE_CPU_TIMES_READ_DELAY_MS = DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS; public long KERNEL_UID_READERS_THROTTLE_TIME = DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME; public long UID_REMOVE_DELAY_MS = DEFAULT_UID_REMOVE_DELAY_MS; + public long EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS + = DEFAULT_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -13318,6 +13330,9 @@ public class BatteryStatsImpl extends BatteryStats { DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME)); updateUidRemoveDelay( mParser.getLong(KEY_UID_REMOVE_DELAY_MS, DEFAULT_UID_REMOVE_DELAY_MS)); + EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS = mParser.getLong( + KEY_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS, + DEFAULT_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS); } } @@ -13367,6 +13382,14 @@ public class BatteryStatsImpl extends BatteryStats { pw.println(PROC_STATE_CPU_TIMES_READ_DELAY_MS); pw.print(KEY_KERNEL_UID_READERS_THROTTLE_TIME); pw.print("="); pw.println(KERNEL_UID_READERS_THROTTLE_TIME); + pw.print(KEY_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS); pw.print("="); + pw.println(EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS); + } + } + + public long getExternalStatsCollectionRateLimitMs() { + synchronized (this) { + return mConstants.EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS; } } diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 2c48506494bc..3315cb15d4b4 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -18,9 +18,11 @@ package com.android.internal.os; import android.os.Binder; import android.os.SystemClock; +import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; @@ -40,23 +42,22 @@ public class BinderCallsStats { private static final int CALL_SESSIONS_POOL_SIZE = 100; private static final BinderCallsStats sInstance = new BinderCallsStats(); - private volatile boolean mTrackingEnabled = false; + private volatile boolean mDetailedTracking = false; + @GuardedBy("mLock") private final SparseArray<UidEntry> mUidEntries = new SparseArray<>(); private final Queue<CallSession> mCallSessionsPool = new ConcurrentLinkedQueue<>(); + private final Object mLock = new Object(); + private long mStartTime = System.currentTimeMillis(); private BinderCallsStats() { } @VisibleForTesting - public BinderCallsStats(boolean trackingEnabled) { - mTrackingEnabled = trackingEnabled; + public BinderCallsStats(boolean detailedTracking) { + mDetailedTracking = detailedTracking; } public CallSession callStarted(Binder binder, int code) { - if (!mTrackingEnabled) { - return null; - } - return callStarted(binder.getClass().getName(), code); } @@ -73,32 +74,31 @@ public class BinderCallsStats { } public void callEnded(CallSession s) { - if (!mTrackingEnabled) { - return; - } Preconditions.checkNotNull(s); - final long cpuTimeNow = getThreadTimeMicro(); - final long duration = cpuTimeNow - s.mStarted; + long duration = mDetailedTracking ? getThreadTimeMicro() - s.mStarted : 1; s.mCallingUId = Binder.getCallingUid(); - synchronized (mUidEntries) { + synchronized (mLock) { UidEntry uidEntry = mUidEntries.get(s.mCallingUId); if (uidEntry == null) { uidEntry = new UidEntry(s.mCallingUId); mUidEntries.put(s.mCallingUId, uidEntry); } - // Find CallDesc entry and update its total time - CallStat callStat = uidEntry.mCallStats.get(s.mCallStat); - // Only create CallStat if it's a new entry, otherwise update existing instance - if (callStat == null) { - callStat = new CallStat(s.mCallStat.className, s.mCallStat.msg); - uidEntry.mCallStats.put(callStat, callStat); + if (mDetailedTracking) { + // Find CallDesc entry and update its total time + CallStat callStat = uidEntry.mCallStats.get(s.mCallStat); + // Only create CallStat if it's a new entry, otherwise update existing instance + if (callStat == null) { + callStat = new CallStat(s.mCallStat.className, s.mCallStat.msg); + uidEntry.mCallStats.put(callStat, callStat); + } + callStat.callCount++; + callStat.time += duration; } + uidEntry.time += duration; uidEntry.callCount++; - callStat.callCount++; - callStat.time += duration; } if (mCallSessionsPool.size() < CALL_SESSIONS_POOL_SIZE) { mCallSessionsPool.add(s); @@ -110,9 +110,11 @@ public class BinderCallsStats { Map<Integer, Long> uidCallCountMap = new HashMap<>(); long totalCallsCount = 0; long totalCallsTime = 0; + pw.print("Start time: "); + pw.println(DateFormat.format("yyyy-MM-dd HH:mm:ss", mStartTime)); int uidEntriesSize = mUidEntries.size(); List<UidEntry> entries = new ArrayList<>(); - synchronized (mUidEntries) { + synchronized (mLock) { for (int i = 0; i < uidEntriesSize; i++) { UidEntry e = mUidEntries.valueAt(i); entries.add(e); @@ -127,20 +129,9 @@ public class BinderCallsStats { totalCallsCount += e.callCount; } } - pw.println("Binder call stats:"); - pw.println(" Raw data (uid,call_desc,time):"); - entries.sort((o1, o2) -> { - if (o1.time < o2.time) { - return 1; - } else if (o1.time > o2.time) { - return -1; - } - return 0; - }); - StringBuilder sb = new StringBuilder(); - for (UidEntry uidEntry : entries) { - List<CallStat> callStats = new ArrayList<>(uidEntry.mCallStats.keySet()); - callStats.sort((o1, o2) -> { + if (mDetailedTracking) { + pw.println("Raw data (uid,call_desc,time):"); + entries.sort((o1, o2) -> { if (o1.time < o2.time) { return 1; } else if (o1.time > o2.time) { @@ -148,44 +139,73 @@ public class BinderCallsStats { } return 0; }); - for (CallStat e : callStats) { - sb.setLength(0); - sb.append(" ") - .append(uidEntry.uid).append(",").append(e).append(',').append(e.time); - pw.println(sb); + StringBuilder sb = new StringBuilder(); + for (UidEntry uidEntry : entries) { + List<CallStat> callStats = new ArrayList<>(uidEntry.mCallStats.keySet()); + callStats.sort((o1, o2) -> { + if (o1.time < o2.time) { + return 1; + } else if (o1.time > o2.time) { + return -1; + } + return 0; + }); + for (CallStat e : callStats) { + sb.setLength(0); + sb.append(" ") + .append(uidEntry.uid).append(",").append(e).append(',').append(e.time); + pw.println(sb); + } + } + pw.println(); + pw.println("Per UID Summary(UID: time, % of total_time, calls_count):"); + List<Map.Entry<Integer, Long>> uidTotals = new ArrayList<>(uidTimeMap.entrySet()); + uidTotals.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue())); + for (Map.Entry<Integer, Long> uidTotal : uidTotals) { + Long callCount = uidCallCountMap.get(uidTotal.getKey()); + pw.println(String.format(" %7d: %11d %3.0f%% %8d", + uidTotal.getKey(), uidTotal.getValue(), + 100d * uidTotal.getValue() / totalCallsTime, callCount)); + } + pw.println(); + pw.println(String.format(" Summary: total_time=%d, " + + "calls_count=%d, avg_call_time=%.0f", + totalCallsTime, totalCallsCount, + (double)totalCallsTime / totalCallsCount)); + } else { + pw.println("Per UID Summary(UID: calls_count, % of total calls_count):"); + List<Map.Entry<Integer, Long>> uidTotals = new ArrayList<>(uidTimeMap.entrySet()); + uidTotals.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue())); + for (Map.Entry<Integer, Long> uidTotal : uidTotals) { + Long callCount = uidCallCountMap.get(uidTotal.getKey()); + pw.println(String.format(" %7d: %8d %3.0f%%", + uidTotal.getKey(), callCount, 100d * uidTotal.getValue() / totalCallsTime)); } } - pw.println(); - pw.println(" Per UID Summary(UID: time, total_time_percentage, calls_count):"); - List<Map.Entry<Integer, Long>> uidTotals = new ArrayList<>(uidTimeMap.entrySet()); - uidTotals.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue())); - for (Map.Entry<Integer, Long> uidTotal : uidTotals) { - Long callCount = uidCallCountMap.get(uidTotal.getKey()); - pw.println(String.format(" %5d: %11d %3.0f%% %8d", - uidTotal.getKey(), uidTotal.getValue(), - 100d * uidTotal.getValue() / totalCallsTime, callCount)); - } - pw.println(); - pw.println(String.format(" Summary: total_time=%d, " - + "calls_count=%d, avg_call_time=%.0f", - totalCallsTime, totalCallsCount, - (double)totalCallsTime / totalCallsCount)); } - private static long getThreadTimeMicro() { - return SystemClock.currentThreadTimeMicro(); + private long getThreadTimeMicro() { + // currentThreadTimeMicro is expensive, so we measure cpu time only if detailed tracking is + // enabled + return mDetailedTracking ? SystemClock.currentThreadTimeMicro() : 0; } public static BinderCallsStats getInstance() { return sInstance; } - public void setTrackingEnabled(boolean enabled) { - mTrackingEnabled = enabled; + public void setDetailedTracking(boolean enabled) { + if (enabled != mDetailedTracking) { + reset(); + mDetailedTracking = enabled; + } } - public boolean isTrackingEnabled() { - return mTrackingEnabled; + public void reset() { + synchronized (mLock) { + mUidEntries.clear(); + mStartTime = System.currentTimeMillis(); + } } private static class CallStat { @@ -210,7 +230,7 @@ public class BinderCallsStats { CallStat callStat = (CallStat) o; - return msg == callStat.msg && (className == callStat.className); + return msg == callStat.msg && (className.equals(callStat.className)); } @Override diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 7e63adc27c9e..591f15fd5676 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -45,6 +45,7 @@ interface ILockSettings { boolean checkVoldPassword(int userId); boolean havePattern(int userId); boolean havePassword(int userId); + byte[] getHashFactor(String currentCredential, int userId); void setSeparateProfileChallengeEnabled(int userId, boolean enabled, String managedUserPassword); boolean getSeparateProfileChallengeEnabled(int userId); void registerStrongAuthTracker(in IStrongAuthTracker tracker); diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java index 09f7282f097a..1e7c11e75aec 100644 --- a/core/java/com/android/internal/widget/ImageFloatingTextView.java +++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java @@ -47,6 +47,7 @@ public class ImageFloatingTextView extends TextView { private boolean mFirstMeasure = true; private int mLayoutMaxLines = -1; private boolean mBlockLayouts; + private int mImageEndMargin; public ImageFloatingTextView(Context context) { this(context, null); @@ -98,13 +99,11 @@ public class ImageFloatingTextView extends TextView { } // we set the endmargin on the requested number of lines. - int endMargin = getContext().getResources().getDimensionPixelSize( - R.dimen.notification_content_picture_margin); int[] margins = null; if (mIndentLines > 0) { margins = new int[mIndentLines + 1]; for (int i = 0; i < mIndentLines; i++) { - margins[i] = endMargin; + margins[i] = mImageEndMargin; } } if (mResolvedDirection == LAYOUT_DIRECTION_RTL) { @@ -116,6 +115,11 @@ public class ImageFloatingTextView extends TextView { return builder.build(); } + @RemotableViewMethod + public void setImageEndMargin(int imageEndMargin) { + mImageEndMargin = imageEndMargin; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = MeasureSpec.getSize(heightMeasureSpec); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index d4ab4265b3fb..7c339fb6d6b1 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -66,8 +66,10 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.StringJoiner; /** * Utilities for the lock pattern and its settings. */ @@ -165,6 +167,7 @@ public class LockPatternUtils { public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle"; public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp"; + private static final String HISTORY_DELIMITER = ","; private final Context mContext; private final ContentResolver mContentResolver; @@ -507,31 +510,50 @@ public class LockPatternUtils { } /** + * Returns the password history hash factor, needed to check new password against password + * history with {@link #checkPasswordHistory(String, byte[], int)} + */ + public byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) { + try { + return getLockSettings().getHashFactor(currentPassword, userId); + } catch (RemoteException e) { + Log.e(TAG, "failed to get hash factor", e); + return null; + } + } + + /** * Check to see if a password matches any of the passwords stored in the * password history. * - * @param password The password to check. + * @param passwordToCheck The password to check. + * @param hashFactor Hash factor of the current user returned from + * {@link ILockSettings#getHashFactor} * @return Whether the password matches any in the history. */ - public boolean checkPasswordHistory(String password, int userId) { - String passwordHashString = new String( - passwordToHash(password, userId), StandardCharsets.UTF_8); + public boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) { + if (TextUtils.isEmpty(passwordToCheck)) { + Log.e(TAG, "checkPasswordHistory: empty password"); + return false; + } String passwordHistory = getString(PASSWORD_HISTORY_KEY, userId); - if (passwordHistory == null) { + if (TextUtils.isEmpty(passwordHistory)) { return false; } - // Password History may be too long... - int passwordHashLength = passwordHashString.length(); int passwordHistoryLength = getRequestedPasswordHistoryLength(userId); if(passwordHistoryLength == 0) { return false; } - int neededPasswordHistoryLength = passwordHashLength * passwordHistoryLength - + passwordHistoryLength - 1; - if (passwordHistory.length() > neededPasswordHistoryLength) { - passwordHistory = passwordHistory.substring(0, neededPasswordHistoryLength); + String legacyHash = legacyPasswordToHash(passwordToCheck, userId); + String passwordHash = passwordToHistoryHash(passwordToCheck, hashFactor, userId); + String[] history = passwordHistory.split(HISTORY_DELIMITER); + // Password History may be too long... + for (int i = 0; i < Math.min(passwordHistoryLength, history.length); i++) { + if (history[i].equals(legacyHash) || history[i].equals(passwordHash)) { + return true; + } } - return passwordHistory.contains(passwordHashString); + return false; } /** @@ -830,6 +852,7 @@ public class LockPatternUtils { updateEncryptionPasswordIfNeeded(password, PasswordMetrics.computeForPassword(password).quality, userHandle); updatePasswordHistory(password, userHandle); + onAfterChangingPassword(userHandle); } /** @@ -852,8 +875,15 @@ public class LockPatternUtils { } } + /** + * Store the hash of the *current* password in the password history list, if device policy + * enforces password history requirement. + */ private void updatePasswordHistory(String password, int userHandle) { - + if (TextUtils.isEmpty(password)) { + Log.e(TAG, "checkPasswordHistory: empty password"); + return; + } // Add the password to the password history. We assume all // password hashes have the same length for simplicity of implementation. String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle); @@ -864,16 +894,25 @@ public class LockPatternUtils { if (passwordHistoryLength == 0) { passwordHistory = ""; } else { - byte[] hash = passwordToHash(password, userHandle); - passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory; - // Cut it to contain passwordHistoryLength hashes - // and passwordHistoryLength -1 commas. - passwordHistory = passwordHistory.substring(0, Math.min(hash.length - * passwordHistoryLength + passwordHistoryLength - 1, passwordHistory - .length())); + final byte[] hashFactor = getPasswordHistoryHashFactor(password, userHandle); + String hash = passwordToHistoryHash(password, hashFactor, userHandle); + if (hash == null) { + Log.e(TAG, "Compute new style password hash failed, fallback to legacy style"); + hash = legacyPasswordToHash(password, userHandle); + } + if (TextUtils.isEmpty(passwordHistory)) { + passwordHistory = hash; + } else { + String[] history = passwordHistory.split(HISTORY_DELIMITER); + StringJoiner joiner = new StringJoiner(HISTORY_DELIMITER); + joiner.add(hash); + for (int i = 0; i < passwordHistoryLength - 1 && i < history.length; i++) { + joiner.add(history[i]); + } + passwordHistory = joiner.toString(); + } } setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle); - onAfterChangingPassword(userHandle); } /** @@ -1098,7 +1137,7 @@ public class LockPatternUtils { return Long.toHexString(salt); } - /* + /** * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash. * Not the most secure, but it is at least a second level of protection. First level is that * the file is in a location only readable by the system process. @@ -1107,7 +1146,7 @@ public class LockPatternUtils { * * @return the hash of the pattern in a byte array. */ - public byte[] passwordToHash(String password, int userId) { + public String legacyPasswordToHash(String password, int userId) { if (password == null) { return null; } @@ -1122,7 +1161,24 @@ public class LockPatternUtils { System.arraycopy(md5, 0, combined, sha1.length, md5.length); final char[] hexEncoded = HexEncoding.encode(combined); - return new String(hexEncoded).getBytes(StandardCharsets.UTF_8); + return new String(hexEncoded); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError("Missing digest algorithm: ", e); + } + } + + /** + * Hash the password for password history check purpose. + */ + private String passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId) { + if (TextUtils.isEmpty(passwordToHash) || hashFactor == null) { + return null; + } + try { + MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); + sha256.update(hashFactor); + sha256.update((passwordToHash + getSalt(userId)).getBytes()); + return new String(HexEncoding.encode(sha256.digest())); } catch (NoSuchAlgorithmException e) { throw new AssertionError("Missing digest algorithm: ", e); } @@ -1571,6 +1627,7 @@ public class LockPatternUtils { updateEncryptionPasswordIfNeeded(credential, quality, userId); updatePasswordHistory(credential, userId); + onAfterChangingPassword(userId); } else { if (!TextUtils.isEmpty(credential)) { throw new IllegalArgumentException("password must be emtpy for NONE type"); diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java index 07d78fe2abda..3f73237da12b 100644 --- a/core/java/com/android/internal/widget/MessagingGroup.java +++ b/core/java/com/android/internal/widget/MessagingGroup.java @@ -22,6 +22,8 @@ import android.annotation.Nullable; import android.annotation.StyleRes; import android.app.Person; import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Icon; @@ -29,6 +31,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Pools; +import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -36,6 +39,7 @@ import android.view.ViewParent; import android.view.ViewTreeObserver; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.ProgressBar; import android.widget.RemoteViews; import com.android.internal.R; @@ -58,6 +62,7 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou private CharSequence mAvatarName = ""; private Icon mAvatarIcon; private int mTextColor; + private int mSendingTextColor; private List<MessagingMessage> mMessages; private ArrayList<MessagingMessage> mAddedMessages = new ArrayList<>(); private boolean mFirstLayout; @@ -69,6 +74,8 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou private MessagingImageMessage mIsolatedMessage; private boolean mTransformingImages; private Point mDisplaySize = new Point(); + private ProgressBar mSendingSpinner; + private View mSendingSpinnerContainer; public MessagingGroup(@NonNull Context context) { super(context); @@ -96,6 +103,8 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou mSenderName.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR); mAvatarView = findViewById(R.id.message_icon); mImageContainer = findViewById(R.id.messaging_group_icon_container); + mSendingSpinner = findViewById(R.id.messaging_group_sending_progress); + mSendingSpinnerContainer = findViewById(R.id.messaging_group_sending_progress_container); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); mDisplaySize.x = displayMetrics.widthPixels; mDisplaySize.y = displayMetrics.heightPixels; @@ -139,17 +148,37 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou mAvatarView.setVisibility(VISIBLE); mSenderName.setVisibility(VISIBLE); mTextColor = getNormalTextColor(); + mSendingTextColor = calculateSendingTextColor(); + } + + public void setSending(boolean sending) { + int visibility = sending ? View.VISIBLE : View.GONE; + if (mSendingSpinnerContainer.getVisibility() != visibility) { + mSendingSpinnerContainer.setVisibility(visibility); + updateMessageColor(); + } } private int getNormalTextColor() { return mContext.getColor(R.color.notification_secondary_text_color_light); } + private int calculateSendingTextColor() { + TypedValue alphaValue = new TypedValue(); + mContext.getResources().getValue( + R.dimen.notification_secondary_text_disabled_alpha, alphaValue, true); + float alpha = alphaValue.getFloat(); + return Color.valueOf( + Color.red(mTextColor), + Color.green(mTextColor), + Color.blue(mTextColor), + alpha).toArgb(); + } + public void setAvatar(Icon icon) { mAvatarIcon = icon; mAvatarView.setImageIcon(icon); mAvatarSymbol = ""; - mLayoutColor = 0; mAvatarName = ""; } @@ -321,13 +350,26 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou || layoutColor != mLayoutColor) { setAvatar(cachedIcon); mAvatarSymbol = avatarSymbol; - mLayoutColor = layoutColor; + setLayoutColor(layoutColor); mAvatarName = avatarName; } } public void setLayoutColor(int layoutColor) { - mLayoutColor = layoutColor; + if (layoutColor != mLayoutColor){ + mLayoutColor = layoutColor; + mSendingSpinner.setIndeterminateTintList(ColorStateList.valueOf(mLayoutColor)); + } + } + + private void updateMessageColor() { + if (mMessages != null) { + int color = mSendingSpinnerContainer.getVisibility() == View.VISIBLE + ? mSendingTextColor : mTextColor; + for (MessagingMessage message : mMessages) { + message.setColor(message.getMessage().isRemoteInputHistory() ? color : mTextColor); + } + } } public void setMessages(List<MessagingMessage> group) { @@ -336,7 +378,6 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou MessagingImageMessage isolatedMessage = null; for (int messageIndex = 0; messageIndex < group.size(); messageIndex++) { MessagingMessage message = group.get(messageIndex); - message.setColor(mTextColor); if (message.getGroup() != this) { message.setMessagingGroup(this); mAddedMessages.add(message); @@ -375,7 +416,14 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou mImageContainer.removeAllViews(); } mIsolatedMessage = isolatedMessage; + updateImageContainerVisibility(); mMessages = group; + updateMessageColor(); + } + + private void updateImageContainerVisibility() { + mImageContainer.setVisibility(mIsolatedMessage != null && mImagesAtEnd + ? View.VISIBLE : View.GONE); } /** @@ -477,7 +525,7 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou public void setDisplayImagesAtEnd(boolean atEnd) { if (mImagesAtEnd != atEnd) { mImagesAtEnd = atEnd; - mImageContainer.setVisibility(atEnd ? View.VISIBLE : View.GONE); + updateImageContainerVisibility(); } } diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java index f8236c78ac43..df20e639adf0 100644 --- a/core/java/com/android/internal/widget/MessagingLayout.java +++ b/core/java/com/android/internal/widget/MessagingLayout.java @@ -149,7 +149,9 @@ public class MessagingLayout extends FrameLayout { } addRemoteInputHistoryToMessages(newMessages, extras.getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY)); - bind(newMessages, newHistoricMessages); + boolean showSpinner = + extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false); + bind(newMessages, newHistoricMessages, showSpinner); } private void addRemoteInputHistoryToMessages( @@ -161,17 +163,18 @@ public class MessagingLayout extends FrameLayout { for (int i = remoteInputHistory.length - 1; i >= 0; i--) { CharSequence message = remoteInputHistory[i]; newMessages.add(new Notification.MessagingStyle.Message( - message, 0, (Person) null)); + message, 0, (Person) null, true /* remoteHistory */)); } } private void bind(List<Notification.MessagingStyle.Message> newMessages, - List<Notification.MessagingStyle.Message> newHistoricMessages) { + List<Notification.MessagingStyle.Message> newHistoricMessages, + boolean showSpinner) { List<MessagingMessage> historicMessages = createMessages(newHistoricMessages, true /* isHistoric */); List<MessagingMessage> messages = createMessages(newMessages, false /* isHistoric */); - addMessagesToGroups(historicMessages, messages); + addMessagesToGroups(historicMessages, messages, showSpinner); // Let's remove the remaining messages mMessages.forEach(REMOVE_MESSAGE); @@ -308,7 +311,7 @@ public class MessagingLayout extends FrameLayout { } private void addMessagesToGroups(List<MessagingMessage> historicMessages, - List<MessagingMessage> messages) { + List<MessagingMessage> messages, boolean showSpinner) { // Let's first find our groups! List<List<MessagingMessage>> groups = new ArrayList<>(); List<Person> senders = new ArrayList<>(); @@ -317,11 +320,11 @@ public class MessagingLayout extends FrameLayout { findGroups(historicMessages, messages, groups, senders); // Let's now create the views and reorder them accordingly - createGroupViews(groups, senders); + createGroupViews(groups, senders, showSpinner); } private void createGroupViews(List<List<MessagingMessage>> groups, - List<Person> senders) { + List<Person> senders, boolean showSpinner) { mGroups.clear(); for (int groupIndex = 0; groupIndex < groups.size(); groupIndex++) { List<MessagingMessage> group = groups.get(groupIndex); @@ -346,6 +349,7 @@ public class MessagingLayout extends FrameLayout { nameOverride = mNameReplacement; } newGroup.setSender(sender, nameOverride); + newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner); mGroups.add(newGroup); if (mMessagingLinearLayout.indexOfChild(newGroup) != groupIndex) { diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java index a2cc7cfb856c..f0b60685b70e 100644 --- a/core/java/com/android/internal/widget/MessagingMessage.java +++ b/core/java/com/android/internal/widget/MessagingMessage.java @@ -82,6 +82,9 @@ public interface MessagingMessage extends MessagingLinearLayout.MessagingChild { if (!Objects.equals(message.getDataUri(), ownMessage.getDataUri())) { return false; } + if (message.isRemoteInputHistory() != ownMessage.isRemoteInputHistory()) { + return false; + } return true; } diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp index 162822092af6..567bb075d746 100644 --- a/core/jni/android_hardware_camera2_DngCreator.cpp +++ b/core/jni/android_hardware_camera2_DngCreator.cpp @@ -1723,13 +1723,13 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image // Adjust the bad pixel coordinates to be relative to the origin of the active area DNG tag std::vector<uint32_t> v; - for (size_t i = 0; i < entry3.count; i+=2) { + for (size_t i = 0; i < entry3.count; i += 2) { int32_t x = entry3.data.i32[i]; int32_t y = entry3.data.i32[i + 1]; x -= static_cast<int32_t>(xmin); y -= static_cast<int32_t>(ymin); if (x < 0 || y < 0 || static_cast<uint32_t>(x) >= width || - static_cast<uint32_t>(y) >= width) { + static_cast<uint32_t>(y) >= height) { continue; } v.push_back(x); diff --git a/core/res/res/drawable/ic_reply_notification.xml b/core/res/res/drawable/ic_reply_notification.xml index 88b8c5b7ddef..a9864b09207a 100644 --- a/core/res/res/drawable/ic_reply_notification.xml +++ b/core/res/res/drawable/ic_reply_notification.xml @@ -13,15 +13,20 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="10dp" - android:height="10dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0"> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M10.0,9.0L10.0,5.0l-7.0,7.0 7.0,7.0l0.0,-4.1c5.0,0.0 8.5,1.6 11.0,5.1 -1.0,-5.0 -4.0,-10.0 -11.0,-11.0z"/> - <path - android:pathData="M0 0h24v24H0z" - android:fillColor="#00000000"/> -</vector> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:inset="@dimen/notification_reply_inset"> + <vector android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + <path + android:fillColor="#000000" + android:strokeWidth="1" + android:pathData="M16,10 L6.83,10 L9,7.83 L10.41,6.42 L9,5 L3,11 L9,17 L10.41,15.59 L9,14.17 L6.83,12 L16,12 C17.65,12 19,13.35 19,15 L19,19 L21,19 L21,15 C21,12.24 18.76,10 16,10 Z" /> + <path + android:fillColor="#000000" + android:strokeWidth="1" + android:pathData="M16,10 L6.83,10 L9,7.83 L10.41,6.42 L9,5 L3,11 L9,17 L10.41,15.59 L9,14.17 L6.83,12 L16,12 C17.65,12 19,13.35 19,15 L19,19 L21,19 L21,15 C21,12.24 18.76,10 16,10 Z" /> + </vector> +</inset> diff --git a/core/res/res/drawable/ic_reply_notification_large.xml b/core/res/res/drawable/ic_reply_notification_large.xml deleted file mode 100644 index e75afddfead3..000000000000 --- a/core/res/res/drawable/ic_reply_notification_large.xml +++ /dev/null @@ -1,29 +0,0 @@ -<!-- - ~ Copyright (C) 2017 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> -<inset xmlns:android="http://schemas.android.com/apk/res/android" - android:inset="8dp"> - <vector android:width="24dp" - android:height="24dp" - android:viewportHeight="24.0" - android:viewportWidth="24.0"> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M10.0,9.0L10.0,5.0l-7.0,7.0 7.0,7.0l0.0,-4.1c5.0,0.0 8.5,1.6 11.0,5.1 -1.0,-5.0 -4.0,-10.0 -11.0,-11.0z"/> - <path - android:fillColor="#00000000" - android:pathData="M0 0h24v24H0z"/> - </vector> -</inset> diff --git a/core/res/res/drawable/notification_reply_background.xml b/core/res/res/drawable/notification_reply_background.xml deleted file mode 100644 index 08e22f2f9729..000000000000 --- a/core/res/res/drawable/notification_reply_background.xml +++ /dev/null @@ -1,24 +0,0 @@ -<!-- - ~ Copyright (C) 2017 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="oval"> - <solid - android:color="#ff757575"/> - <size - android:width="16dp" - android:height="16dp"/> -</shape> diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml index e5a9854d50c7..6ac0b1756234 100644 --- a/core/res/res/layout/global_actions_item.xml +++ b/core/res/res/layout/global_actions_item.xml @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> +<!-- Used with LegacyGlobalActions. --> <!-- RelativeLayouts have an issue enforcing minimum heights, so just work around this for now with LinearLayouts. --> diff --git a/core/res/res/layout/notification_material_action_tombstone.xml b/core/res/res/layout/notification_material_action_tombstone.xml index 817f298f0c6f..9fa7c6a28020 100644 --- a/core/res/res/layout/notification_material_action_tombstone.xml +++ b/core/res/res/layout/notification_material_action_tombstone.xml @@ -27,7 +27,7 @@ android:singleLine="true" android:ellipsize="end" android:textAlignment="viewStart" - android:alpha="0.5" + android:alpha="@dimen/notification_action_disabled_alpha" android:enabled="false" android:background="@drawable/notification_material_action_background" /> diff --git a/core/res/res/layout/notification_material_reply_text.xml b/core/res/res/layout/notification_material_reply_text.xml index 84603b06604e..dbf2dd008101 100644 --- a/core/res/res/layout/notification_material_reply_text.xml +++ b/core/res/res/layout/notification_material_reply_text.xml @@ -30,6 +30,7 @@ android:id="@+id/action_divider" android:layout_marginTop="@dimen/notification_content_margin" android:layout_marginBottom="@dimen/notification_content_margin" + android:layout_marginEnd="@dimen/notification_content_margin_end" android:background="@drawable/notification_template_divider" /> <TextView @@ -50,12 +51,31 @@ android:textAppearance="@style/TextAppearance.Material.Notification.Reply" android:singleLine="true" /> - <TextView - android:id="@+id/notification_material_reply_text_1" + <LinearLayout + android:id="@+id/notification_material_reply_text_1_container" android:layout_width="match_parent" android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginStart="@dimen/notification_content_margin_start" + android:layout_marginEnd="@dimen/notification_content_margin_end"> + <TextView + android:id="@+id/notification_material_reply_text_1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginEnd="@dimen/notification_content_margin_end" + android:layout_gravity="center" + android:textAppearance="@style/TextAppearance.Material.Notification.Reply" + android:singleLine="true" /> + <ProgressBar + android:id="@+id/notification_material_reply_progress" + android:layout_height="@dimen/messaging_group_sending_progress_size" + android:layout_width="@dimen/messaging_group_sending_progress_size" + android:layout_marginStart="@dimen/notification_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" - android:textAppearance="@style/TextAppearance.Material.Notification.Reply" - android:singleLine="true" /> + android:layout_gravity="center" + android:indeterminate="true" + style="?android:attr/progressBarStyleSmall" /> + </LinearLayout> </LinearLayout> diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml index 53514a341504..10c750972961 100644 --- a/core/res/res/layout/notification_template_material_messaging.xml +++ b/core/res/res/layout/notification_template_material_messaging.xml @@ -52,7 +52,9 @@ <include layout="@layout/notification_template_smart_reply_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_content_margin" /> + android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginStart="@dimen/notification_content_margin_start" + android:layout_marginEnd="@dimen/notification_content_margin_end" /> <include layout="@layout/notification_material_action_list" /> </com.android.internal.widget.RemeasuringLinearLayout> <include layout="@layout/notification_template_right_icon"/> diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml index bd1030ee14f5..d2fd467c3e00 100644 --- a/core/res/res/layout/notification_template_messaging_group.xml +++ b/core/res/res/layout/notification_template_messaging_group.xml @@ -50,4 +50,19 @@ android:layout_height="@dimen/messaging_avatar_size" android:layout_marginStart="12dp" android:visibility="gone"/> + <FrameLayout + android:id="@+id/messaging_group_sending_progress_container" + android:layout_width="@dimen/messaging_group_sending_progress_size" + android:layout_height="@dimen/messaging_avatar_size" + android:layout_marginStart="12dp" + android:layout_gravity="top" + android:visibility="gone"> + <ProgressBar + android:id="@+id/messaging_group_sending_progress" + android:layout_height="@dimen/messaging_group_sending_progress_size" + android:layout_width="@dimen/messaging_group_sending_progress_size" + android:layout_gravity="center" + android:indeterminate="true" + style="?android:attr/progressBarStyleSmall" /> + </FrameLayout> </com.android.internal.widget.MessagingGroup> diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml index 0b97e45b8eed..ee416ad36b8a 100644 --- a/core/res/res/layout/notification_template_right_icon.xml +++ b/core/res/res/layout/notification_template_right_icon.xml @@ -14,30 +14,29 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<!-- The view only has 8dp padding at the end instead of notification_content_margin_end, + since the reply icon has an inset of 8dp and we want it to visually start at the start of the + icon. --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/right_icon_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/notification_content_margin_top" + android:layout_marginEnd="8dp" android:layout_gravity="top|end"> <ImageView android:id="@+id/right_icon" android:layout_width="@dimen/notification_right_icon_size" android:layout_height="@dimen/notification_right_icon_size" android:layout_gravity="top|end" - android:layout_marginEnd="@dimen/notification_content_margin_end" + android:layout_marginEnd="8dp" android:scaleType="centerCrop" android:importantForAccessibility="no" /> - <ImageButton android:id="@+id/reply_icon_action" - android:layout_width="16dp" - android:layout_height="16dp" - android:layout_gravity="top|end" - android:layout_marginTop="27dp" - android:layout_marginEnd="16dp" - android:background="@drawable/notification_reply_background" - android:src="@drawable/ic_reply_notification" - android:scaleType="center" - android:contentDescription="@string/notification_reply_button_accessibility" - visiblity="gone"/> -</FrameLayout> + <ImageView android:id="@+id/reply_icon_action" + android:layout_width="@dimen/notification_right_icon_size" + android:layout_height="@dimen/notification_right_icon_size" + android:layout_gravity="top|end" + android:contentDescription="@string/notification_reply_button_accessibility" + android:scaleType="centerCrop" + android:src="@drawable/ic_reply_notification"/> +</LinearLayout> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index da9fed080aed..095a632c4acd 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -137,6 +137,7 @@ <color name="notification_primary_text_color_light">@color/primary_text_default_material_light</color> <color name="notification_primary_text_color_dark">@color/primary_text_default_material_dark</color> <color name="notification_secondary_text_color_light">@color/primary_text_default_material_light</color> + <item name="notification_secondary_text_disabled_alpha" format="float" type="dimen">0.30</item> <color name="notification_secondary_text_color_dark">@color/primary_text_default_material_dark</color> <color name="notification_default_color_dark">@color/primary_text_default_material_light</color> <color name="notification_default_color_light">#a3202124</color> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index a135b28c196a..84f23a9c07e9 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -162,19 +162,14 @@ <!-- The margin on the start of the content view --> <dimen name="notification_content_margin_start">16dp</dimen> - <!-- The margin on the end of the content view - Keep in sync with notification_content_plus_picture_margin! --> + <!-- The margin on the end of the content view. --> <dimen name="notification_content_margin_end">16dp</dimen> - <!-- The margin on the end of the content view with a picture. - Keep in sync with notification_content_plus_picture_margin! --> - <dimen name="notification_content_picture_margin">56dp</dimen> + <!-- The inset of the reply icon. --> + <dimen name="notification_reply_inset">8dp</dimen> - <!-- The margin on the end of the content view with a picture, plus the standard - content end margin. - Keep equal to (notification_content_picture_margin + notification_content_margin_end)! - --> - <dimen name="notification_content_plus_picture_margin_end">72dp</dimen> + <!-- The margin for text at the end of the image view for media notifications --> + <dimen name="notification_media_image_margin_end">72dp</dimen> <!-- The additional margin on the sides of the ambient view. --> <dimen name="notification_extra_margin_ambient">16dp</dimen> @@ -616,7 +611,9 @@ <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.--> <dimen name="notification_media_image_max_width">280dp</dimen> <!-- The size of the right icon --> - <dimen name="notification_right_icon_size">38dp</dimen> + <dimen name="notification_right_icon_size">36dp</dimen> + <!-- The alpha of a disabled notification button --> + <item type="dimen" format="float" name="notification_action_disabled_alpha">0.5</item> <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. --> <dimen name="notification_custom_view_max_image_height_low_ram">208dp</dimen> @@ -631,10 +628,12 @@ <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.--> <dimen name="notification_media_image_max_width_low_ram">100dp</dimen> <!-- The size of the right icon image when on low ram --> - <dimen name="notification_right_icon_size_low_ram">40dp</dimen> + <dimen name="notification_right_icon_size_low_ram">@dimen/notification_right_icon_size_low_ram</dimen> <dimen name="messaging_avatar_size">@dimen/notification_right_icon_size</dimen> + <dimen name="messaging_group_sending_progress_size">24dp</dimen> + <!-- Max width/height of the autofill data set picker as a fraction of the screen width/height --> <dimen name="autofill_dataset_picker_max_width">90%</dimen> <dimen name="autofill_dataset_picker_max_height">90%</dimen> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index c90a0df5d7b1..47d04edfc281 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -128,6 +128,7 @@ <item type="id" name="accessibilityActionContextClick" /> <item type="id" name="remote_input_tag" /> + <item type="id" name="pending_intent_tag" /> <item type="id" name="cross_task_transition" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 590f98800874..1785034783a7 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2615,6 +2615,7 @@ <java-symbol type="id" name="actions_container" /> <java-symbol type="id" name="smart_reply_container" /> <java-symbol type="id" name="remote_input_tag" /> + <java-symbol type="id" name="pending_intent_tag" /> <java-symbol type="attr" name="seekBarDialogPreferenceStyle" /> <java-symbol type="string" name="ext_media_status_removed" /> @@ -2668,8 +2669,10 @@ <java-symbol type="id" name="notification_material_reply_container" /> <java-symbol type="id" name="notification_material_reply_text_1" /> + <java-symbol type="id" name="notification_material_reply_text_1_container" /> <java-symbol type="id" name="notification_material_reply_text_2" /> <java-symbol type="id" name="notification_material_reply_text_3" /> + <java-symbol type="id" name="notification_material_reply_progress" /> <java-symbol type="string" name="notification_hidden_text" /> <java-symbol type="id" name="app_name_text" /> @@ -2689,7 +2692,7 @@ <java-symbol type="dimen" name="notification_header_shrink_min_width" /> <java-symbol type="dimen" name="notification_content_margin_start" /> <java-symbol type="dimen" name="notification_content_margin_end" /> - <java-symbol type="dimen" name="notification_content_picture_margin" /> + <java-symbol type="dimen" name="notification_reply_inset" /> <java-symbol type="dimen" name="notification_content_margin_top" /> <java-symbol type="dimen" name="notification_content_margin" /> <java-symbol type="dimen" name="notification_header_background_height" /> @@ -2873,8 +2876,9 @@ <java-symbol type="bool" name="config_supportPreRebootSecurityLogs" /> - <java-symbol type="dimen" name="notification_content_plus_picture_margin_end" /> + <java-symbol type="dimen" name="notification_media_image_margin_end" /> <java-symbol type="id" name="notification_action_list_margin_target" /> + <java-symbol type="dimen" name="notification_action_disabled_alpha" /> <!-- Pinner Service --> <java-symbol type="array" name="config_defaultPinnerServiceFiles" /> @@ -2999,6 +3003,7 @@ <java-symbol type="color" name="notification_secondary_text_color_dark" /> <java-symbol type="color" name="notification_default_color_light" /> <java-symbol type="color" name="notification_default_color_dark" /> + <java-symbol type="dimen" name="notification_secondary_text_disabled_alpha" /> <java-symbol type="string" name="app_category_game" /> <java-symbol type="string" name="app_category_audio" /> @@ -3252,13 +3257,15 @@ <java-symbol type="id" name="clip_children_set_tag" /> <java-symbol type="id" name="clip_to_padding_tag" /> <java-symbol type="id" name="clip_children_tag" /> - <java-symbol type="drawable" name="ic_reply_notification_large" /> <java-symbol type="dimen" name="messaging_avatar_size" /> + <java-symbol type="dimen" name="messaging_group_sending_progress_size" /> <java-symbol type="dimen" name="messaging_image_rounding" /> <java-symbol type="dimen" name="messaging_image_min_size" /> <java-symbol type="dimen" name="messaging_image_max_height" /> <java-symbol type="dimen" name="messaging_image_extra_spacing" /> <java-symbol type="id" name="messaging_group_icon_container" /> + <java-symbol type="id" name="messaging_group_sending_progress" /> + <java-symbol type="id" name="messaging_group_sending_progress_container" /> <java-symbol type="integer" name="config_stableDeviceDisplayWidth" /> <java-symbol type="integer" name="config_stableDeviceDisplayHeight" /> diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java index 370659eb99d9..fdaba089490e 100644 --- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java +++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java @@ -123,6 +123,7 @@ public class RadioTunerTest { private void resetCallback() { verify(mCallback, atLeast(0)).onMetadataChanged(any()); verify(mCallback, atLeast(0)).onProgramInfoChanged(any()); + verify(mCallback, atLeast(0)).onProgramListChanged(); verifyNoMoreInteractions(mCallback); Mockito.reset(mCallback); } diff --git a/core/tests/coretests/src/android/text/EmojiTest.java b/core/tests/coretests/src/android/text/EmojiTest.java new file mode 100644 index 000000000000..313f1b6a6614 --- /dev/null +++ b/core/tests/coretests/src/android/text/EmojiTest.java @@ -0,0 +1,120 @@ +/* + * Copyright 2018 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.text; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.icu.lang.UCharacterDirection; +import android.icu.text.Bidi; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Emoji and ICU drops does not happen at the same time. Therefore there are almost always cases + * where the existing ICU version is not aware of the latest emoji that Android supports. + * This test covers Emoji and ICU related functions where other components such as + * {@link AndroidBidi}, {@link BidiFormatter} depend on. The tests are collected into the same + * class since the changes effect all those classes. + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class EmojiTest { + + @Test + public void testIsNewEmoji_Emoji5() { + // each row in the data is the range of emoji + final int[][][] data = new int[][][]{ + { // EMOJI 5 + // range of emoji: i.e from 0x1F6F7 to 0x1F6F8 inclusive + {0x1F6F7, 0x1F6F8}, + {0x1F91F, 0x1F91F}, + {0x1F928, 0x1F92F}, + {0x1F94C, 0x1F94C}, + {0x1F95F, 0x1F96B}, + {0x1F992, 0x1F997}, + {0x1F9D0, 0x1F9E6}, + }, + { // EMOJI 11 + {0x265F, 0x265F}, + {0x267E, 0x267E}, + {0x1F6F9, 0x1F6F9}, + {0x1F94D, 0x1F94F}, + {0x1F96C, 0x1F970}, + {0x1F973, 0x1F976}, + {0x1F97A, 0x1F97A}, + {0x1F97C, 0x1F97F}, + {0x1F998, 0x1F9A2}, + {0x1F9B0, 0x1F9B9}, + {0x1F9C1, 0x1F9C2}, + {0x1F9E7, 0x1F9FF}, + } + }; + + final Bidi icuBidi = new Bidi(0 /* maxLength */, 0 /* maxRunCount */); + icuBidi.setCustomClassifier(new AndroidBidi.EmojiBidiOverride()); + + for (int version = 0; version < data.length; version++) { + for (int row = 0; row < data[version].length; row++) { + for (int c = data[version][row][0]; c < data[version][row][1]; c++) { + assertTrue(Integer.toHexString(c) + " should be emoji", Emoji.isEmoji(c)); + + assertEquals(Integer.toHexString(c) + " should have neutral directionality", + Character.DIRECTIONALITY_OTHER_NEUTRALS, + BidiFormatter.DirectionalityEstimator.getDirectionality(c)); + + assertEquals(Integer.toHexString(c) + " shoud be OTHER_NEUTRAL for ICU Bidi", + UCharacterDirection.OTHER_NEUTRAL, icuBidi.getCustomizedClass(c)); + } + } + } + } + + @Test + public void testisEmojiModifierBase_LegacyCompat() { + assertTrue(Emoji.isEmojiModifierBase(0x1F91D)); + assertTrue(Emoji.isEmojiModifierBase(0x1F93C)); + } + + @Test + public void testisEmojiModifierBase() { + // each row in the data is the range of emoji + final int[][][] data = new int[][][]{ + { // EMOJI 5 + // range of emoji: i.e from 0x1F91F to 0x1F91F inclusive + {0x1F91F, 0x1F91F}, + {0x1F931, 0x1F932}, + {0x1F9D1, 0x1F9DD}, + }, + { // EMOJI 11 + {0x1F9B5, 0x1F9B6}, + {0x1F9B8, 0x1F9B9} + } + }; + for (int version = 0; version < data.length; version++) { + for (int row = 0; row < data[version].length; row++) { + for (int c = data[version][row][0]; c < data[version][row][1]; c++) { + assertTrue(Integer.toHexString(c) + " should be emoji modifier base", + Emoji.isEmojiModifierBase(c)); + } + } + } + } +} diff --git a/location/java/android/location/GnssMeasurementsEvent.java b/location/java/android/location/GnssMeasurementsEvent.java index 072a7fefb665..34c73549c5df 100644 --- a/location/java/android/location/GnssMeasurementsEvent.java +++ b/location/java/android/location/GnssMeasurementsEvent.java @@ -74,6 +74,13 @@ public final class GnssMeasurementsEvent implements Parcelable { /** * The client is not allowed to register for GNSS Measurements in general or in the * requested mode. + * + * <p>Such a status is returned when a client tries to request a functionality from the GNSS + * chipset while another client has an ongoing request that does not allow such + * functionality to be performed. + * + * <p>If such a status is received, one would try again at a later time point where no + * other client is having a conflicting request. */ public static final int STATUS_NOT_ALLOWED = 3; diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 000317e688da..16f6284b6031 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -1261,6 +1261,11 @@ static void android_media_MediaCodec_setInputSurface( sp<PersistentSurface> persistentSurface = android_media_MediaCodec_getPersistentInputSurface(env, object); + if (persistentSurface == NULL) { + throwExceptionAsNecessary( + env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid"); + return; + } status_t err = codec->setInputSurface(persistentSurface); if (err != NO_ERROR) { throwExceptionAsNecessary(env, err); diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index 50c6aac57e8f..3b1e4ce7e97a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -27,8 +27,10 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Objects; /** @@ -191,6 +193,7 @@ public class CachedBluetoothDeviceManager { log("updateHearingAidsDevices: getHearingAidProfile() is null"); return; } + final Set<Long> syncIdChangedSet = new HashSet<Long>(); for (CachedBluetoothDevice cachedDevice : mCachedDevices) { if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) { continue; @@ -200,9 +203,12 @@ public class CachedBluetoothDeviceManager { if (newHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID) { cachedDevice.setHiSyncId(newHiSyncId); - onHiSyncIdChanged(newHiSyncId); + syncIdChangedSet.add(newHiSyncId); } } + for (Long syncId : syncIdChangedSet) { + onHiSyncIdChanged(syncId); + } } /** diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java index c3bd16195140..bab3cab3795c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java @@ -486,11 +486,14 @@ public class CachedBluetoothDeviceManagerTest { doAnswer((invocation) -> mHearingAidProfile).when(mLocalProfileManager) .getHearingAidProfile(); doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice1); + doAnswer((invocation) -> HISYNCID1).when(mHearingAidProfile).getHiSyncId(mDevice2); mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); + mCachedDeviceManager.mCachedDevices.add(mCachedDevice2); mCachedDeviceManager.updateHearingAidsDevices(mLocalProfileManager); - // Assert that the mCachedDevice1 has an updated HiSyncId. + // Assert that the mCachedDevice1 and mCachedDevice2 have an updated HiSyncId. assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1); + assertThat(mCachedDevice2.getHiSyncId()).isEqualTo(HISYNCID1); } /** diff --git a/packages/SystemUI/res/layout/global_actions_item.xml b/packages/SystemUI/res/layout/global_actions_item.xml index bf3aea8ab6dd..66a4b737d09b 100644 --- a/packages/SystemUI/res/layout/global_actions_item.xml +++ b/packages/SystemUI/res/layout/global_actions_item.xml @@ -25,8 +25,8 @@ android:minHeight="92dp" android:gravity="center" android:orientation="vertical" - android:paddingEnd="0dip" - android:paddingStart="0dip"> + android:paddingEnd="4dip" + android:paddingStart="4dip"> <ImageView android:id="@*android:id/icon" diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml index 4a6af9e139d5..b715def73294 100644 --- a/packages/SystemUI/res/layout/global_actions_wrapped.xml +++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml @@ -17,7 +17,7 @@ android:layout_gravity="top|right" android:gravity="center" android:orientation="vertical" - android:padding="16dp" + android:padding="12dp" android:translationZ="9dp" /> </com.android.systemui.HardwareUiLayout> diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml index dcb8aaf2a6a8..5f73beff92e4 100644 --- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml +++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml @@ -15,15 +15,28 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/quick_qs_status_icons" android:layout_width="match_parent" android:layout_height="20dp" android:layout_marginTop="8dp" android:layout_marginBottom="14dp" + android:layout_marginStart="8dp" android:layout_marginEnd="@dimen/notification_side_paddings" android:layout_below="@id/quick_status_bar_system_icons" android:paddingEnd="@dimen/status_bar_padding_end" > + <com.android.systemui.statusbar.policy.DateView + android:id="@+id/date" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:gravity="center_vertical" + android:singleLine="true" + android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" + android:textSize="@dimen/qs_time_collapsed_size" + systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" /> + <com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons" android:layout_width="0dp" diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml index 7b9cd2aee862..a9fe8620cf48 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml @@ -41,16 +41,6 @@ android:textAppearance="@style/TextAppearance.StatusBar.Clock" systemui:showDark="false" /> - <com.android.systemui.statusbar.policy.DateView - android:id="@+id/date" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center_vertical" - android:singleLine="true" - android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" - android:textSize="@dimen/qs_time_collapsed_size" - systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" /> - <android.widget.Space android:id="@+id/space" android:layout_width="0dp" diff --git a/packages/SystemUI/res/layout/smart_reply_view.xml b/packages/SystemUI/res/layout/smart_reply_view.xml index 9b2dd95005bb..aa5549f35a34 100644 --- a/packages/SystemUI/res/layout/smart_reply_view.xml +++ b/packages/SystemUI/res/layout/smart_reply_view.xml @@ -23,7 +23,6 @@ android:id="@+id/smart_reply_view" android:layout_height="wrap_content" android:layout_width="wrap_content" - android:layout_marginStart="12dp" systemui:spacing="@dimen/smart_reply_button_spacing" systemui:singleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_single_line" systemui:doubleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_double_line"> diff --git a/packages/SystemUI/res/layout/volume_dnd_icon.xml b/packages/SystemUI/res/layout/volume_dnd_icon.xml index 215b2300992a..acf9aedd5a3c 100644 --- a/packages/SystemUI/res/layout/volume_dnd_icon.xml +++ b/packages/SystemUI/res/layout/volume_dnd_icon.xml @@ -15,16 +15,16 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="14dp" - android:layout_height="14dp" - android:layout_marginTop="6dp" - android:layout_marginRight="6dp" - android:layout_gravity="right|top"> + android:layout_width="@dimen/volume_dialog_panel_width" + android:layout_height="wrap_content"> <ImageView android:id="@+id/dnd_icon" - android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_width="14dp" + android:layout_height="14dp" + android:layout_marginTop="6dp" + android:layout_marginRight="6dp" + android:layout_gravity="right|top" android:src="@drawable/ic_dnd" android:tint="?android:attr/textColorTertiary"/> </FrameLayout> diff --git a/packages/SystemUI/res/values-h320dp/config.xml b/packages/SystemUI/res/values-h320dp/config.xml new file mode 100644 index 000000000000..a9c19db0f46f --- /dev/null +++ b/packages/SystemUI/res/values-h320dp/config.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (c) 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +--> + +<resources> + <!-- The number of rows in the QuickSettings --> + <integer name="quick_settings_num_rows">2</integer> +</resources> diff --git a/packages/SystemUI/res/values-h600dp/config.xml b/packages/SystemUI/res/values-h600dp/config.xml new file mode 100644 index 000000000000..8616e3e62779 --- /dev/null +++ b/packages/SystemUI/res/values-h600dp/config.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (c) 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +--> + +<resources> + <!-- The number of rows in the QuickSettings --> + <integer name="quick_settings_num_rows">3</integer> +</resources> diff --git a/packages/SystemUI/res/values-sw410dp/config.xml b/packages/SystemUI/res/values-sw410dp/config.xml index 362c1d214b0e..8ace7bf13573 100644 --- a/packages/SystemUI/res/values-sw410dp/config.xml +++ b/packages/SystemUI/res/values-sw410dp/config.xml @@ -20,8 +20,5 @@ <!-- These resources are around just to allow their values to be customized for different hardware and product builds. --> <resources> - <integer name="quick_settings_num_rows">2</integer> - <integer name="quick_settings_num_rows_portrait">3</integer> - <bool name="quick_settings_show_full_alarm">true</bool> </resources> diff --git a/packages/SystemUI/res/values-sw540dp/config.xml b/packages/SystemUI/res/values-sw540dp/config.xml deleted file mode 100644 index e554fc6dd4d1..000000000000 --- a/packages/SystemUI/res/values-sw540dp/config.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 2016, 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. -*/ ---> - -<!-- These resources are around just to allow their values to be customized - for different hardware and product builds. --> -<resources> - <integer name="quick_settings_num_rows">3</integer> -</resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 7eb08c4c3582..88e3331ff76c 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -112,7 +112,6 @@ <!-- The number of rows in the QuickSettings --> <integer name="quick_settings_num_rows">1</integer> - <integer name="quick_settings_num_rows_portrait">2</integer> <!-- The number of columns that the top level tiles span in the QuickSettings --> <integer name="quick_settings_user_time_settings_tile_span">1</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index a1e5b0e6e5e2..875000c84260 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -899,8 +899,6 @@ <dimen name="default_gear_space">18dp</dimen> <dimen name="cell_overlay_padding">18dp</dimen> - <dimen name="hwui_edge_margin">16dp</dimen> - <dimen name="global_actions_panel_width">120dp</dimen> <dimen name="global_actions_top_padding">120dp</dimen> @@ -916,7 +914,7 @@ <dimen name="corner_size">8dp</dimen> <dimen name="top_padding">0dp</dimen> <dimen name="bottom_padding">48dp</dimen> - <dimen name="edge_margin">16dp</dimen> + <dimen name="edge_margin">8dp</dimen> <dimen name="rounded_corner_radius">0dp</dimen> <dimen name="rounded_corner_content_padding">0dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 6c507be44df3..d82b00c316a8 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -59,7 +59,7 @@ <string name="status_bar_latest_events_title">Notifications</string> <!-- When the battery is low, this is displayed to the user in a dialog. The title of the low battery alert. [CHAR LIMIT=NONE]--> - <string name="battery_low_title">Battery is low</string> + <string name="battery_low_title">Battery may run out soon</string> <!-- A message that appears when the battery level is getting low in a dialog. This is appended to the subtitle of the low battery alert. "percentage" is the percentage of battery diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 20d883435aef..804ca2cf1db7 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -173,7 +173,7 @@ <style name="TextAppearance.StatusBar.Expanded.Date"> <item name="android:textSize">@dimen/qs_time_expanded_size</item> <item name="android:textStyle">normal</item> - <item name="android:textColor">#ffffffff</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:fontFamily">sans-serif</item> </style> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java index 924e85dec37a..7429cb5c19d9 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java @@ -17,6 +17,7 @@ package com.android.systemui.shared.recents.model; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; +import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_UNDEFINED; import android.app.ActivityManager.TaskSnapshot; import android.graphics.Bitmap; @@ -32,6 +33,7 @@ public class ThumbnailData { public Rect insets; public boolean reducedResolution; public boolean isRealSnapshot; + public int windowingMode; public float scale; public ThumbnailData() { @@ -41,6 +43,7 @@ public class ThumbnailData { reducedResolution = false; scale = 1f; isRealSnapshot = true; + windowingMode = WINDOWING_MODE_UNDEFINED; } public ThumbnailData(TaskSnapshot snapshot) { @@ -50,5 +53,6 @@ public class ThumbnailData { reducedResolution = snapshot.isReducedResolution(); scale = snapshot.getScale(); isRealSnapshot = snapshot.isRealSnapshot(); + windowingMode = snapshot.getWindowingMode(); } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index 80e226d929cd..9bebb14dabf0 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -69,6 +69,14 @@ public class RecentsAnimationControllerCompat { } } + public void hideCurrentInputMethod() { + try { + mAnimationController.hideCurrentInputMethod(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to set hide input method", e); + } + } + public void finish(boolean toHome) { try { mAnimationController.finish(toHome); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index 9355acf1db1d..07b980ef3f5e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -60,6 +60,16 @@ public class WindowManagerWrapper { public static final int ACTIVITY_TYPE_STANDARD = WindowConfiguration.ACTIVITY_TYPE_STANDARD; + public static final int WINDOWING_MODE_UNDEFINED = WindowConfiguration.WINDOWING_MODE_UNDEFINED; + public static final int WINDOWING_MODE_FULLSCREEN = + WindowConfiguration.WINDOWING_MODE_FULLSCREEN; + public static final int WINDOWING_MODE_PINNED = WindowConfiguration.WINDOWING_MODE_PINNED; + public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = + WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; + public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = + WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; + public static final int WINDOWING_MODE_FREEFORM = WindowConfiguration.WINDOWING_MODE_FREEFORM; + private static final WindowManagerWrapper sInstance = new WindowManagerWrapper(); public static WindowManagerWrapper getInstance() { @@ -104,14 +114,6 @@ public class WindowManagerWrapper { } } - public void endProlongedAnimations() { - try { - WindowManagerGlobal.getWindowManagerService().endProlongedAnimations(); - } catch (RemoteException e) { - Log.w(TAG, "Failed to end prolonged animations: ", e); - } - } - /** * Enable or disable haptic feedback on the navigation bar buttons. */ @@ -131,4 +133,12 @@ public class WindowManagerWrapper { Log.w(TAG, "Failed to set shelf height"); } } + + public void setRecentsVisibility(boolean visible) { + try { + WindowManagerGlobal.getWindowManagerService().setRecentsVisibility(visible); + } catch (RemoteException e) { + Log.w(TAG, "Failed to set recents visibility"); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 5fce0a6d641c..7d19784aad03 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -21,6 +21,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Process; +import android.os.ServiceManager; import android.util.ArrayMap; import android.view.IWindowManager; import android.view.WindowManagerGlobal; @@ -28,6 +29,7 @@ import android.view.WindowManagerGlobal; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ColorDisplayController; import com.android.internal.logging.MetricsLogger; +import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.Preconditions; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.assist.AssistManager; @@ -320,6 +322,9 @@ public class Dependency extends SystemUI { mProviders.put(VibratorHelper.class, () -> new VibratorHelper(mContext)); + mProviders.put(IStatusBarService.class, () -> IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE))); + // Put all dependencies above here so the factory can override them if it wants. SystemUIFactory.getInstance().injectDependencies(mProviders, mContext); } diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java index 3bdb247b64c2..98dc3219acc6 100644 --- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java +++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java @@ -89,7 +89,7 @@ public class HardwareUiLayout extends FrameLayout implements Tunable { mEdgeBleed = Settings.Secure.getInt(getContext().getContentResolver(), EDGE_BLEED, 0) != 0; mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(), - ROUNDED_DIVIDER, 1) != 0; + ROUNDED_DIVIDER, 0) != 0; updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding()); mBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext()); if (mChild != null) { diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index ac4da73a2a9a..721890f0aee9 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -20,7 +20,6 @@ import android.app.AlarmManager; import android.content.Context; import android.util.ArrayMap; import android.util.Log; -import android.view.View; import android.view.ViewGroup; import com.android.internal.logging.MetricsLogger; @@ -43,12 +42,11 @@ import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.ScrimView; -import com.android.systemui.statusbar.SmartReplyLogger; +import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; -import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LockIcon; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -58,7 +56,6 @@ import com.android.systemui.statusbar.phone.ScrimState; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.SmartReplyConstants; import java.util.function.Consumer; @@ -150,6 +147,6 @@ public class SystemUIFactory { () -> new NotificationViewHierarchyManager(context)); providers.put(NotificationEntryManager.class, () -> new NotificationEntryManager(context)); providers.put(KeyguardDismissUtil.class, KeyguardDismissUtil::new); - providers.put(SmartReplyLogger.class, () -> new SmartReplyLogger(context)); + providers.put(SmartReplyController.class, () -> new SmartReplyController()); } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java index 8515bf2e2968..4fea45c39d5d 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java @@ -116,6 +116,7 @@ public class AlwaysOnDisplayPolicy { private SettingsObserver mSettingsObserver; public AlwaysOnDisplayPolicy(Context context) { + context = context.getApplicationContext(); mContext = context; mParser = new KeyValueListParser(','); mSettingsObserver = new SettingsObserver(context.getMainThreadHandler()); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 5bf62f638235..e9d78d9b4fdf 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -61,13 +61,14 @@ public class DozeFactory { DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock); machine.setParts(new DozeMachine.Part[]{ - new DozePauser(handler, machine, alarmManager, new AlwaysOnDisplayPolicy(context)), + new DozePauser(handler, machine, alarmManager, params.getPolicy()), new DozeFalsingManagerAdapter(FalsingManager.getInstance(context)), createDozeTriggers(context, sensorManager, host, alarmManager, config, params, handler, wakeLock, machine), createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params), new DozeScreenState(wrappedService, handler, params, wakeLock), - createDozeScreenBrightness(context, wrappedService, sensorManager, host, handler), + createDozeScreenBrightness(context, wrappedService, sensorManager, host, params, + handler), new DozeWallpaperState(context, params) }); @@ -76,11 +77,11 @@ public class DozeFactory { private DozeMachine.Part createDozeScreenBrightness(Context context, DozeMachine.Service service, SensorManager sensorManager, DozeHost host, - Handler handler) { + DozeParameters params, Handler handler) { Sensor sensor = DozeSensors.findSensorWithType(sensorManager, context.getString(R.string.doze_brightness_sensor_type)); return new DozeScreenBrightness(context, service, sensorManager, sensor, host, handler, - new AlwaysOnDisplayPolicy(context)); + params.getPolicy()); } private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager, diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java index f72bff5d651e..a0fdb9dc5b90 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java @@ -21,6 +21,7 @@ import android.util.Log; import android.view.Display; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.util.wakelock.SettableWakeLock; import com.android.systemui.util.wakelock.WakeLock; /** @@ -43,15 +44,14 @@ public class DozeScreenState implements DozeMachine.Part { private final DozeParameters mParameters; private int mPendingScreenState = Display.STATE_UNKNOWN; - private boolean mWakeLockHeld; - private WakeLock mWakeLock; + private SettableWakeLock mWakeLock; public DozeScreenState(DozeMachine.Service service, Handler handler, DozeParameters parameters, WakeLock wakeLock) { mDozeService = service; mHandler = handler; mParameters = parameters; - mWakeLock = wakeLock; + mWakeLock = new SettableWakeLock(wakeLock); } @Override @@ -64,6 +64,7 @@ public class DozeScreenState implements DozeMachine.Part { mHandler.removeCallbacks(mApplyPendingScreenState); applyScreenState(screenState); + mWakeLock.setAcquired(false); return; } @@ -84,9 +85,8 @@ public class DozeScreenState implements DozeMachine.Part { boolean shouldDelayTransition = newState == DozeMachine.State.DOZE_AOD && mParameters.shouldControlScreenOff(); - if (!mWakeLockHeld && shouldDelayTransition) { - mWakeLockHeld = true; - mWakeLock.acquire(); + if (shouldDelayTransition) { + mWakeLock.setAcquired(true); } if (!messagePending) { @@ -118,10 +118,7 @@ public class DozeScreenState implements DozeMachine.Part { if (DEBUG) Log.d(TAG, "setDozeScreenState(" + screenState + ")"); mDozeService.setDozeScreenState(screenState); mPendingScreenState = Display.STATE_UNKNOWN; - if (mWakeLockHeld) { - mWakeLockHeld = false; - mWakeLock.release(); - } + mWakeLock.setAcquired(false); } } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index aa264190f800..73393047cc45 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -62,6 +62,7 @@ public class DozeService extends DreamService public void onDestroy() { Dependency.get(PluginManager.class).removePluginListener(this); super.onDestroy(); + mDozeMachine = null; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index f7a258a2c959..be3e322f598f 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -85,7 +85,7 @@ public class DozeTriggers implements DozeMachine.Part { mAllowPulseTriggers = allowPulseTriggers; mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters, config, wakeLock, this::onSensor, this::onProximityFar, - new AlwaysOnDisplayPolicy(context)); + dozeParameters.getPolicy()); mUiModeManager = mContext.getSystemService(UiModeManager.class); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index 1fd60239ee98..8cfba2cc53d7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -375,11 +375,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { } private int getRows() { - final Resources res = getContext().getResources(); - if (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - return res.getInteger(R.integer.quick_settings_num_rows_portrait); - } - return Math.max(1, res.getInteger(R.integer.quick_settings_num_rows)); + return Math.max(1, getResources().getInteger(R.integer.quick_settings_num_rows)); } public void setMaxRows(int maxRows) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java index fd9ddb0fd0ac..b7907a605ca5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java @@ -284,6 +284,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, final boolean isDemo = UserManager.isDeviceInDemoMode(mContext); mMultiUserSwitch.setVisibility(showUserSwitcher(isDemo) ? View.VISIBLE : View.INVISIBLE); mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); + mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE); } private boolean showUserSwitcher(boolean isDemo) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 5d7dcbbf08d1..f027c4bfb6d0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -98,7 +98,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements private View mSystemIconsView; private View mQuickQsStatusIcons; - private View mDate; private View mHeaderTextContainerView; /** View containing the next alarm and ringer mode info. */ private View mStatusContainer; @@ -148,8 +147,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements super.onFinishInflate(); mHeaderQsPanel = findViewById(R.id.quick_qs_panel); - mDate = findViewById(R.id.date); - mDate.setOnClickListener(this); mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons); mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons); StatusIconContainer iconContainer = findViewById(R.id.statusIcons); @@ -183,6 +180,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements mBatteryMeterView.setForceShowPercent(true); mClockView = findViewById(R.id.clock); mDateView = findViewById(R.id.date); + mDateView.setOnClickListener(this); } private void updateStatusText() { @@ -261,7 +259,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE; mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor); mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor); - mDateView.useWallpaperTextColor(shouldUseWallpaperTextColor); } @Override @@ -366,6 +363,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements @Override public void onAttachedToWindow() { + super.onAttachedToWindow(); Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager); requestApplyInsets(); } @@ -414,7 +412,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements @Override public void onClick(View v) { - if(v == mDate){ + if(v == mDateView){ Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(new Intent( AlarmClock.ACTION_SHOW_ALARMS),0); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index 00d6bd0d307f..6bf0793a69cb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -98,7 +98,8 @@ public class HotspotTile extends QSTileImpl<AirplaneBooleanState> { @Override protected void handleClick() { final boolean isEnabled = mState.value; - if (!isEnabled && mAirplaneMode.getValue() != 0) { + if (!isEnabled && + (mAirplaneMode.getValue() != 0 || mDataSaverController.isDataSaverEnabled())) { return; } // Immediately enter transient enabling state when turning hotspot on. diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 95b311ff8e3e..36a12559d6b8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -835,9 +835,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD @Override public boolean onPreDraw() { mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this); - // We post to make sure that this information is delivered after this traversals is - // finished. - mRecentsView.post(() -> WindowManagerWrapper.getInstance().endProlongedAnimations()); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index e527be1a61f9..5477468505a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -81,7 +81,7 @@ public class NotificationContentView extends FrameLayout { private SmartReplyConstants mSmartReplyConstants; private SmartReplyView mExpandedSmartReplyView; - private SmartReplyLogger mSmartReplyLogger; + private SmartReplyController mSmartReplyController; private NotificationViewWrapper mContractedWrapper; private NotificationViewWrapper mExpandedWrapper; @@ -154,7 +154,7 @@ public class NotificationContentView extends FrameLayout { super(context, attrs); mHybridGroupManager = new HybridGroupManager(getContext(), this); mSmartReplyConstants = Dependency.get(SmartReplyConstants.class); - mSmartReplyLogger = Dependency.get(SmartReplyLogger.class); + mSmartReplyController = Dependency.get(SmartReplyController.class); initView(); } @@ -1359,7 +1359,7 @@ public class NotificationContentView extends FrameLayout { applySmartReplyView(mExpandedChild, remoteInput, pendingIntent, entry); if (mExpandedSmartReplyView != null && remoteInput != null && remoteInput.getChoices() != null && remoteInput.getChoices().length > 0) { - mSmartReplyLogger.smartRepliesAdded(entry, remoteInput.getChoices().length); + mSmartReplyController.smartRepliesAdded(entry, remoteInput.getChoices().length); } } } @@ -1377,6 +1377,13 @@ public class NotificationContentView extends FrameLayout { smartReplyContainer.setVisibility(View.GONE); return null; } + // If we are showing the spinner we don't want to add the buttons. + boolean showingSpinner = entry.notification.getNotification() + .extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false); + if (showingSpinner) { + smartReplyContainer.setVisibility(View.GONE); + return null; + } SmartReplyView smartReplyView = null; if (smartReplyContainer.getChildCount() == 0) { smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer); @@ -1389,7 +1396,7 @@ public class NotificationContentView extends FrameLayout { } if (smartReplyView != null) { smartReplyView.setRepliesFromRemoteInput(remoteInput, pendingIntent, - mSmartReplyLogger, entry); + mSmartReplyController, entry, smartReplyContainer); smartReplyContainer.setVisibility(View.VISIBLE); } return smartReplyView; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java index 3a79e70bfc7d..7681530503a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java @@ -474,37 +474,12 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. if (FORCE_REMOTE_INPUT_HISTORY && shouldKeepForRemoteInput(entry) && entry.row != null && !entry.row.isDismissed()) { - StatusBarNotification sbn = entry.notification; - - Notification.Builder b = Notification.Builder - .recoverBuilder(mContext, sbn.getNotification().clone()); - CharSequence[] oldHistory = sbn.getNotification().extras - .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY); - CharSequence[] newHistory; - if (oldHistory == null) { - newHistory = new CharSequence[1]; - } else { - newHistory = new CharSequence[oldHistory.length + 1]; - System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length); - } CharSequence remoteInputText = entry.remoteInputText; if (TextUtils.isEmpty(remoteInputText)) { remoteInputText = entry.remoteInputTextWhenReset; } - newHistory[0] = String.valueOf(remoteInputText); - b.setRemoteInputHistory(newHistory); - - Notification newNotification = b.build(); - - // Undo any compatibility view inflation - newNotification.contentView = sbn.getNotification().contentView; - newNotification.bigContentView = sbn.getNotification().bigContentView; - newNotification.headsUpContentView = sbn.getNotification().headsUpContentView; - - StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(), - sbn.getOpPkg(), - sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), - newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); + StatusBarNotification newSbn = rebuildNotificationWithRemoteInput(entry, + remoteInputText, false /* showSpinner */); boolean updated = false; entry.onRemoteInputInserted(); try { @@ -554,6 +529,39 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. mCallback.onNotificationRemoved(key, old); } + public StatusBarNotification rebuildNotificationWithRemoteInput(NotificationData.Entry entry, + CharSequence remoteInputText, boolean showSpinner) { + StatusBarNotification sbn = entry.notification; + + Notification.Builder b = Notification.Builder + .recoverBuilder(mContext, sbn.getNotification().clone()); + CharSequence[] oldHistory = sbn.getNotification().extras + .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY); + CharSequence[] newHistory; + if (oldHistory == null) { + newHistory = new CharSequence[1]; + } else { + newHistory = new CharSequence[oldHistory.length + 1]; + System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length); + } + newHistory[0] = String.valueOf(remoteInputText); + b.setRemoteInputHistory(newHistory); + b.setShowRemoteInputSpinner(showSpinner); + + Notification newNotification = b.build(); + + // Undo any compatibility view inflation + newNotification.contentView = sbn.getNotification().contentView; + newNotification.bigContentView = sbn.getNotification().bigContentView; + newNotification.headsUpContentView = sbn.getNotification().headsUpContentView; + + StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(), + sbn.getOpPkg(), + sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(), + newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime()); + return newSbn; + } + private boolean shouldKeepForRemoteInput(NotificationData.Entry entry) { if (entry == null) { return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index abc261e6bbf6..f737a8cec4f0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -172,27 +172,28 @@ public class NotificationMediaManager implements Dumpable { } } - if (mediaNotification != null) { - mMediaNotificationKey = mediaNotification.notification.getKey(); - if (DEBUG_MEDIA) { - Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key=" - + mMediaNotificationKey + " controller=" + mMediaController); - } - } - if (controller != null && !sameSessions(mMediaController, controller)) { // We have a new media session - clearCurrentMediaNotification(); + clearCurrentMediaNotificationSession(); mMediaController = controller; mMediaController.registerCallback(mMediaListener); mMediaMetadata = mMediaController.getMetadata(); if (DEBUG_MEDIA) { - Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: " - + mMediaMetadata); + Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: " + + mMediaController + ", receive metadata: " + mMediaMetadata); } metaDataChanged = true; } + + if (mediaNotification != null + && !mediaNotification.notification.getKey().equals(mMediaNotificationKey)) { + mMediaNotificationKey = mediaNotification.notification.getKey(); + if (DEBUG_MEDIA) { + Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key=" + + mMediaNotificationKey); + } + } } if (metaDataChanged) { @@ -203,15 +204,7 @@ public class NotificationMediaManager implements Dumpable { public void clearCurrentMediaNotification() { mMediaNotificationKey = null; - mMediaMetadata = null; - if (mMediaController != null) { - if (DEBUG_MEDIA) { - Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: " - + mMediaController.getPackageName()); - } - mMediaController.unregisterCallback(mMediaListener); - } - mMediaController = null; + clearCurrentMediaNotificationSession(); } @Override @@ -265,4 +258,16 @@ public class NotificationMediaManager implements Dumpable { entry.getExpandedContentView() .findViewById(com.android.internal.R.id.media_actions) != null; } + + private void clearCurrentMediaNotificationSession() { + mMediaMetadata = null; + if (mMediaController != null) { + if (DEBUG_MEDIA) { + Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: " + + mMediaController.getPackageName()); + } + mMediaController.unregisterCallback(mMediaListener); + } + mMediaController = null; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java index 75dd77d8ec3a..67da68cd9e92 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java @@ -15,24 +15,32 @@ */ package com.android.systemui.statusbar; -import android.content.Context; import android.os.RemoteException; -import android.os.ServiceManager; +import android.service.notification.StatusBarNotification; + import com.android.internal.statusbar.IStatusBarService; +import com.android.systemui.Dependency; + /** - * Handles reporting when smart replies are added to a notification + * Handles when smart replies are added to a notification * and clicked upon. */ -public class SmartReplyLogger { - protected IStatusBarService mBarService; +public class SmartReplyController { + private IStatusBarService mBarService; + private NotificationEntryManager mNotificationEntryManager; - public SmartReplyLogger(Context context) { - mBarService = IStatusBarService.Stub.asInterface( - ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + public SmartReplyController() { + mBarService = Dependency.get(IStatusBarService.class); + mNotificationEntryManager = Dependency.get(NotificationEntryManager.class); } - public void smartReplySent(NotificationData.Entry entry, int replyIndex) { + public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply) { + StatusBarNotification newSbn = + mNotificationEntryManager.rebuildNotificationWithRemoteInput(entry, reply, + true /* showSpinner */); + mNotificationEntryManager.updateNotification(newSbn, null /* ranking */); + try { mBarService.onNotificationSmartReplySent(entry.notification.getKey(), replyIndex); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java index 5f7b638dc872..c9dcc5c688ec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java @@ -16,16 +16,25 @@ package com.android.systemui.statusbar.notification; +import android.app.PendingIntent; import android.content.Context; +import android.content.res.ColorStateList; import android.graphics.Color; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.service.notification.StatusBarNotification; +import android.util.ArraySet; import android.view.View; +import android.widget.Button; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import com.android.internal.util.NotificationColorUtil; import com.android.internal.widget.NotificationActionListLayout; +import com.android.systemui.Dependency; +import com.android.systemui.UiOffloadThread; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.TransformableView; @@ -43,12 +52,14 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp private TextView mTitle; private TextView mText; protected View mActionsContainer; - private View mReplyAction; + private ImageView mReplyAction; private Rect mTmpRect = new Rect(); private int mContentHeight; private int mMinHeightHint; private NotificationActionListLayout mActions; + private ArraySet<PendingIntent> mCancelledPendingIntents = new ArraySet<>(); + private UiOffloadThread mUiOffloadThread; protected NotificationTemplateViewWrapper(Context ctx, View view, ExpandableNotificationRow row) { @@ -137,6 +148,98 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container); mActions = mView.findViewById(com.android.internal.R.id.actions); mReplyAction = mView.findViewById(com.android.internal.R.id.reply_icon_action); + updatePendingIntentCancellations(); + } + + private void updatePendingIntentCancellations() { + if (mActions != null) { + int numActions = mActions.getChildCount(); + for (int i = 0; i < numActions; i++) { + Button action = (Button) mActions.getChildAt(i); + performOnPendingIntentCancellation(action, () -> { + if (action.isEnabled()) { + action.setEnabled(false); + // The visual appearance doesn't look disabled enough yet, let's add the + // alpha as well. Since Alpha doesn't play nicely right now with the + // transformation, we rather blend it manually with the background color. + ColorStateList textColors = action.getTextColors(); + int[] colors = textColors.getColors(); + int[] newColors = new int[colors.length]; + float disabledAlpha = mView.getResources().getFloat( + com.android.internal.R.dimen.notification_action_disabled_alpha); + for (int j = 0; j < colors.length; j++) { + int color = colors[j]; + color = blendColorWithBackground(color, disabledAlpha); + newColors[j] = color; + } + ColorStateList newColorStateList = new ColorStateList( + textColors.getStates(), newColors); + action.setTextColor(newColorStateList); + } + }); + } + } + if (mReplyAction != null) { + performOnPendingIntentCancellation(mReplyAction, () -> { + if (mReplyAction != null && mReplyAction.isEnabled()) { + mReplyAction.setEnabled(false); + // The visual appearance doesn't look disabled enough yet, let's add the + // alpha as well. Since Alpha doesn't play nicely right now with the + // transformation, we rather blend it manually with the background color. + Drawable drawable = mReplyAction.getDrawable().mutate(); + PorterDuffColorFilter colorFilter = + (PorterDuffColorFilter) drawable.getColorFilter(); + float disabledAlpha = mView.getResources().getFloat( + com.android.internal.R.dimen.notification_action_disabled_alpha); + if (colorFilter != null) { + int color = colorFilter.getColor(); + color = blendColorWithBackground(color, disabledAlpha); + drawable.mutate().setColorFilter(color, colorFilter.getMode()); + } else { + mReplyAction.setAlpha(disabledAlpha); + } + } + }); + } + } + + private int blendColorWithBackground(int color, float alpha) { + // alpha doesn't go well for color filters, so let's blend it manually + return NotificationColorUtil.compositeColors(Color.argb((int) (alpha * 255), + Color.red(color), Color.green(color), Color.blue(color)), resolveBackgroundColor()); + } + + private void performOnPendingIntentCancellation(View view, Runnable cancellationRunnable) { + PendingIntent pendingIntent = (PendingIntent) view.getTag( + com.android.internal.R.id.pending_intent_tag); + if (pendingIntent == null) { + return; + } + if (mCancelledPendingIntents.contains(pendingIntent)) { + cancellationRunnable.run(); + } else { + PendingIntent.CancelListener listener = (PendingIntent intent) -> { + mView.post(() -> { + mCancelledPendingIntents.add(pendingIntent); + cancellationRunnable.run(); + }); + }; + if (mUiOffloadThread == null) { + mUiOffloadThread = Dependency.get(UiOffloadThread.class); + } + mUiOffloadThread.submit(() -> pendingIntent.registerCancelListener(listener)); + view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + mUiOffloadThread.submit(() -> pendingIntent.registerCancelListener(listener)); + } + + @Override + public void onViewDetachedFromWindow(View v) { + mUiOffloadThread.submit(() -> pendingIntent.unregisterCancelListener(listener)); + } + }); + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java index b09df158072c..93a9947a3c9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java @@ -175,6 +175,15 @@ public abstract class NotificationViewWrapper implements TransformableView { return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor; } + protected int resolveBackgroundColor() { + int customBackgroundColor = getCustomBackgroundColor(); + if (customBackgroundColor != 0) { + return customBackgroundColor; + } + return mView.getContext().getColor( + com.android.internal.R.color.notification_material_background_color); + } + public void setLegacy(boolean legacy) { } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 07b79a209b82..d2d9c4c9613b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -59,9 +59,9 @@ public class DozeParameters implements TunerService.Tunable { @VisibleForTesting protected DozeParameters(Context context) { - mContext = context; + mContext = context.getApplicationContext(); mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext); - mAlwaysOnPolicy = new AlwaysOnDisplayPolicy(context); + mAlwaysOnPolicy = new AlwaysOnDisplayPolicy(mContext); mControlScreenOffAnimation = !getDisplayNeedsBlanking(); mPowerManager = mContext.getSystemService(PowerManager.class); @@ -243,6 +243,10 @@ public class DozeParameters implements TunerService.Tunable { mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT); } + public AlwaysOnDisplayPolicy getPolicy() { + return mAlwaysOnPolicy; + } + /** * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are * listed, will not match numbers that are listed with a ! prefix, and will match / not match diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java index 94ac4f6286a2..669a8c83a6c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java @@ -82,6 +82,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba mSlotWifi = mContext.getString(com.android.internal.R.string.status_bar_wifi); mSlotEthernet = mContext.getString(com.android.internal.R.string.status_bar_ethernet); mSlotVpn = mContext.getString(com.android.internal.R.string.status_bar_vpn); + mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity); mIconController = iconController; mNetworkController = Dependency.get(NetworkController.class); @@ -108,10 +109,6 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba return isBranded ? R.drawable.stat_sys_branded_vpn : R.drawable.stat_sys_vpn_ic; } - private void updateActivityEnabled() { - mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity); - } - /** * From SecurityController */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java index ef630c7205e1..dcce77c7c355 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java @@ -43,17 +43,6 @@ public class DateView extends TextView { private String mLastText; private String mDatePattern; - /** - * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings - * for text. - */ - private boolean mUseWallpaperTextColor; - - /** - * Color to be set on this {@link TextView}, when wallpaperTextColor is <b>not</b> utilized. - */ - private int mNonAdaptedTextColor; - private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -74,7 +63,6 @@ public class DateView extends TextView { public DateView(Context context, AttributeSet attrs) { super(context, attrs); - mNonAdaptedTextColor = getCurrentTextColor(); TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.DateView, @@ -130,25 +118,6 @@ public class DateView extends TextView { } } - /** - * Sets whether the date view uses the wallpaperTextColor. If we're not using it, we'll revert - * back to dark-mode-based/tinted colors. - * - * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for text color - */ - public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) { - if (shouldUseWallpaperTextColor == mUseWallpaperTextColor) { - return; - } - mUseWallpaperTextColor = shouldUseWallpaperTextColor; - - if (mUseWallpaperTextColor) { - setTextColor(Utils.getColorAttr(mContext, R.attr.wallpaperTextColor)); - } else { - setTextColor(mNonAdaptedTextColor); - } - } - public void setDatePattern(String pattern) { if (TextUtils.equals(pattern, mDatePattern)) { return; 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 143168210a51..b4fa2e8b16f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -26,7 +26,7 @@ import com.android.keyguard.KeyguardHostView.OnDismissAction; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.statusbar.NotificationData; -import com.android.systemui.statusbar.SmartReplyLogger; +import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; @@ -73,6 +73,8 @@ public class SmartReplyView extends ViewGroup { private PriorityQueue<Button> mCandidateButtonQueueForSqueezing; + private View mSmartReplyContainer; + public SmartReplyView(Context context, AttributeSet attrs) { super(context, attrs); mConstants = Dependency.get(SmartReplyConstants.class); @@ -133,7 +135,9 @@ public class SmartReplyView extends ViewGroup { } public void setRepliesFromRemoteInput(RemoteInput remoteInput, PendingIntent pendingIntent, - SmartReplyLogger smartReplyLogger, NotificationData.Entry entry) { + SmartReplyController smartReplyController, NotificationData.Entry entry, + View smartReplyContainer) { + mSmartReplyContainer = smartReplyContainer; removeAllViews(); if (remoteInput != null && pendingIntent != null) { CharSequence[] choices = remoteInput.getChoices(); @@ -141,7 +145,7 @@ public class SmartReplyView extends ViewGroup { for (int i = 0; i < choices.length; ++i) { Button replyButton = inflateReplyButton( getContext(), this, i, choices[i], remoteInput, pendingIntent, - smartReplyLogger, entry); + smartReplyController, entry); addView(replyButton); } } @@ -157,7 +161,7 @@ public class SmartReplyView extends ViewGroup { @VisibleForTesting Button inflateReplyButton(Context context, ViewGroup root, int replyIndex, CharSequence choice, RemoteInput remoteInput, PendingIntent pendingIntent, - SmartReplyLogger smartReplyLogger, NotificationData.Entry entry) { + SmartReplyController smartReplyController, NotificationData.Entry entry) { Button b = (Button) LayoutInflater.from(context).inflate( R.layout.smart_reply_button, root, false); b.setText(choice); @@ -173,7 +177,8 @@ public class SmartReplyView extends ViewGroup { } catch (PendingIntent.CanceledException e) { Log.w(TAG, "Unable to send smart reply", e); } - smartReplyLogger.smartReplySent(entry, replyIndex); + smartReplyController.smartReplySent(entry, replyIndex, b.getText()); + mSmartReplyContainer.setVisibility(View.GONE); return false; // do not defer }; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java index 5a4478f072e0..611d4eb67824 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java @@ -16,21 +16,14 @@ package com.android.systemui.tuner; import android.app.ActivityManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; import android.os.Looper; -import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.provider.Settings.Secure; @@ -38,15 +31,12 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; +import com.android.internal.util.ArrayUtils; import com.android.systemui.DemoMode; import com.android.systemui.Dependency; -import com.android.systemui.R; -import com.android.systemui.SysUiServiceProvider; -import com.android.systemui.SystemUI; -import com.android.systemui.SystemUIApplication; +import com.android.systemui.qs.QSTileHost; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.phone.StatusBarIconController; -import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.util.leak.LeakDetector; import java.util.HashMap; @@ -58,7 +48,13 @@ public class TunerServiceImpl extends TunerService { private static final String TUNER_VERSION = "sysui_tuner_version"; - private static final int CURRENT_TUNER_VERSION = 2; + private static final int CURRENT_TUNER_VERSION = 4; + + // Things that use the tunable infrastructure but are now real user settings and + // shouldn't be reset with tuner settings. + private static final String[] RESET_BLACKLIST = new String[] { + QSTileHost.TILES_SETTING, + }; private final Observer mObserver = new Observer(); // Map of Uris we listen on to their settings keys. @@ -119,6 +115,11 @@ public class TunerServiceImpl extends TunerService { if (oldVersion < 2) { setTunerEnabled(mContext, false); } + // 3 Removed because of a revert. + if (oldVersion < 4) { + // Delay this so that we can wait for everything to be registered first. + new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(() -> clearAll(), 5000); + } setValue(TUNER_VERSION, newVersion); } @@ -226,6 +227,9 @@ public class TunerServiceImpl extends TunerService { mContext.sendBroadcast(intent); for (String key : mTunableLookup.keySet()) { + if (ArrayUtils.contains(RESET_BLACKLIST, key)) { + continue; + } Settings.Secure.putString(mContentResolver, key, null); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java index 66836365705e..b6039b66e6cb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java @@ -25,8 +25,10 @@ import static com.android.systemui.doze.DozeMachine.State.INITIALIZED; import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED; import static com.android.systemui.utils.os.FakeHandler.Mode.QUEUEING; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -41,6 +43,7 @@ import android.view.Display; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.wakelock.WakeLock; +import com.android.systemui.util.wakelock.WakeLockFake; import com.android.systemui.utils.os.FakeHandler; import org.junit.Before; @@ -58,8 +61,7 @@ public class DozeScreenStateTest extends SysuiTestCase { FakeHandler mHandlerFake; @Mock DozeParameters mDozeParameters; - @Mock - WakeLock mWakeLock; + WakeLockFake mWakeLock; @Before public void setUp() throws Exception { @@ -68,6 +70,7 @@ public class DozeScreenStateTest extends SysuiTestCase { when(mDozeParameters.getAlwaysOn()).thenReturn(true); mServiceFake = new DozeServiceFake(); mHandlerFake = new FakeHandler(Looper.getMainLooper()); + mWakeLock = new WakeLockFake(); mScreen = new DozeScreenState(mServiceFake, mHandlerFake, mDozeParameters, mWakeLock); } @@ -158,14 +161,29 @@ public class DozeScreenStateTest extends SysuiTestCase { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mHandlerFake.dispatchQueuedMessages(); - reset(mWakeLock); mScreen.transitionTo(INITIALIZED, DOZE_AOD); - verify(mWakeLock).acquire(); - verify(mWakeLock, never()).release(); + assertThat(mWakeLock.isHeld(), is(true)); mHandlerFake.dispatchQueuedMessages(); - verify(mWakeLock).release(); + assertThat(mWakeLock.isHeld(), is(false)); + } + + @Test + public void test_releasesWakeLock_abortingLowPowerDelayed() { + // Transition to low power mode will be delayed to let + // animations play at 60 fps. + when(mDozeParameters.shouldControlScreenOff()).thenReturn(true); + mHandlerFake.setMode(QUEUEING); + + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mHandlerFake.dispatchQueuedMessages(); + + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + assertThat(mWakeLock.isHeld(), is(true)); + mScreen.transitionTo(DOZE_AOD, FINISH); + + assertThat(mWakeLock.isHeld(), is(false)); } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java index 7cfd7a3d1822..8172626a4b5c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java @@ -367,4 +367,44 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntryManager.tagForeground(mEntry.notification); Assert.assertEquals(0, mEntry.mActiveAppOps.size()); } + + @Test + public void testRebuildWithRemoteInput_noExistingInputNoSpinner() { + StatusBarNotification newSbn = + mEntryManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", false); + CharSequence[] messages = newSbn.getNotification().extras + .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY); + Assert.assertEquals(1, messages.length); + Assert.assertEquals("A Reply", messages[0]); + Assert.assertFalse(newSbn.getNotification().extras + .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)); + } + + @Test + public void testRebuildWithRemoteInput_noExistingInputWithSpinner() { + StatusBarNotification newSbn = + mEntryManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", true); + CharSequence[] messages = newSbn.getNotification().extras + .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY); + Assert.assertEquals(1, messages.length); + Assert.assertEquals("A Reply", messages[0]); + Assert.assertTrue(newSbn.getNotification().extras + .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)); + } + + @Test + public void testRebuildWithRemoteInput_withExistingInput() { + // Setup a notification entry with 1 remote input. + StatusBarNotification newSbn = + mEntryManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", false); + NotificationData.Entry entry = new NotificationData.Entry(newSbn); + + // Try rebuilding to add another reply. + newSbn = mEntryManager.rebuildNotificationWithRemoteInput(entry, "Reply 2", true); + CharSequence[] messages = newSbn.getNotification().extras + .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY); + Assert.assertEquals(2, messages.length); + Assert.assertEquals("Reply 2", messages[0]); + Assert.assertEquals("A Reply", messages[1]); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java new file mode 100644 index 000000000000..84dceae0debf --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018 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 static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Notification; +import android.os.RemoteException; +import android.service.notification.StatusBarNotification; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.statusbar.IStatusBarService; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class SmartReplyControllerTest extends SysuiTestCase { + private static final String TEST_NOTIFICATION_KEY = "akey"; + private static final String TEST_CHOICE_TEXT = "A Reply"; + private static final int TEST_CHOICE_INDEX = 2; + private static final int TEST_CHOICE_COUNT = 4; + + private Notification mNotification; + private NotificationData.Entry mEntry; + + @Mock + private NotificationEntryManager mNotificationEntryManager; + @Mock + private IStatusBarService mIStatusBarService; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mDependency.injectTestDependency(NotificationEntryManager.class, + mNotificationEntryManager); + mDependency.injectTestDependency(IStatusBarService.class, mIStatusBarService); + + mNotification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text").build(); + StatusBarNotification sbn = mock(StatusBarNotification.class); + when(sbn.getNotification()).thenReturn(mNotification); + when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY); + mEntry = new NotificationData.Entry(sbn); + } + + @Test + public void testSendSmartReply_updatesRemoteInput() throws RemoteException { + StatusBarNotification sbn = mock(StatusBarNotification.class); + when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY); + when(mNotificationEntryManager.rebuildNotificationWithRemoteInput( + argThat(entry -> entry.notification.getKey().equals(TEST_NOTIFICATION_KEY)), + eq(TEST_CHOICE_TEXT), eq(true))).thenReturn(sbn); + + SmartReplyController controller = new SmartReplyController(); + controller.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT); + + // Sending smart reply should make calls to NotificationEntryManager + // to update the notification with reply and spinner. + verify(mNotificationEntryManager).rebuildNotificationWithRemoteInput( + argThat(entry -> entry.notification.getKey().equals(TEST_NOTIFICATION_KEY)), + eq(TEST_CHOICE_TEXT), eq(true)); + verify(mNotificationEntryManager).updateNotification( + argThat(sbn2 -> sbn2.getKey().equals(TEST_NOTIFICATION_KEY)), isNull()); + } + + @Test + public void testSendSmartReply_logsToStatusBar() throws RemoteException { + StatusBarNotification sbn = mock(StatusBarNotification.class); + when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY); + when(mNotificationEntryManager.rebuildNotificationWithRemoteInput( + argThat(entry -> entry.notification.getKey().equals(TEST_NOTIFICATION_KEY)), + eq(TEST_CHOICE_TEXT), eq(true))).thenReturn(sbn); + + SmartReplyController controller = new SmartReplyController(); + controller.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT); + + // Check we log the result to the status bar service. + verify(mIStatusBarService).onNotificationSmartReplySent(TEST_NOTIFICATION_KEY, + TEST_CHOICE_INDEX); + } + + @Test + public void testShowSmartReply_logsToStatusBar() throws RemoteException { + SmartReplyController controller = new SmartReplyController(); + controller.smartRepliesAdded(mEntry, TEST_CHOICE_COUNT); + + // Check we log the result to the status bar service. + verify(mIStatusBarService).onNotificationSmartRepliesAdded(TEST_NOTIFICATION_KEY, + TEST_CHOICE_COUNT); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java index 2bb810665f3a..99c06e62d4bb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java @@ -23,9 +23,10 @@ import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.Notification; import android.app.PendingIntent; import android.app.RemoteInput; import android.content.Intent; @@ -44,7 +45,7 @@ import com.android.keyguard.KeyguardHostView.OnDismissAction; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationData; -import com.android.systemui.statusbar.SmartReplyLogger; +import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import java.util.concurrent.atomic.AtomicReference; @@ -64,19 +65,22 @@ public class SmartReplyViewTest extends SysuiTestCase { private static final String TEST_ACTION = "com.android.SMART_REPLY_VIEW_ACTION"; private static final String[] TEST_CHOICES = new String[]{"Hello", "What's up?", "I'm here"}; + private static final String TEST_NOTIFICATION_KEY = "akey"; private static final int WIDTH_SPEC = MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY); private static final int HEIGHT_SPEC = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST); private BlockingQueueIntentReceiver mReceiver; private SmartReplyView mView; + private View mContainer; private int mSingleLinePaddingHorizontal; private int mDoubleLinePaddingHorizontal; private int mSpacing; - @Mock private SmartReplyLogger mLogger; + @Mock private SmartReplyController mLogger; private NotificationData.Entry mEntry; + private Notification mNotification; @Before public void setUp() { @@ -86,6 +90,7 @@ public class SmartReplyViewTest extends SysuiTestCase { mDependency.get(KeyguardDismissUtil.class).setDismissHandler( (action, cancelAction, afterKeyguardGone) -> action.onDismiss()); + mContainer = new View(mContext, null); mView = SmartReplyView.inflate(mContext, null); @@ -96,9 +101,14 @@ public class SmartReplyViewTest extends SysuiTestCase { R.dimen.smart_reply_button_padding_horizontal_double_line); mSpacing = res.getDimensionPixelSize(R.dimen.smart_reply_button_spacing); - StatusBarNotification notification = mock(StatusBarNotification.class); - when(notification.getKey()).thenReturn("akey"); - mEntry = new NotificationData.Entry(notification); + mNotification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text").build(); + StatusBarNotification sbn = mock(StatusBarNotification.class); + when(sbn.getNotification()).thenReturn(mNotification); + when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY); + mEntry = new NotificationData.Entry(sbn); } @After @@ -155,10 +165,18 @@ public class SmartReplyViewTest extends SysuiTestCase { } @Test - public void testSendSmartReply_LoggerCall() { + public void testSendSmartReply_controllerCalled() { setRepliesFromRemoteInput(TEST_CHOICES); mView.getChildAt(2).performClick(); - verify(mLogger).smartReplySent(mEntry, 2); + verify(mLogger).smartReplySent(mEntry, 2, TEST_CHOICES[2]); + } + + @Test + public void testSendSmartReply_hidesContainer() { + mContainer.setVisibility(View.VISIBLE); + setRepliesFromRemoteInput(TEST_CHOICES); + mView.getChildAt(0).performClick(); + assertEquals(View.GONE, mContainer.getVisibility()); } @Test @@ -340,7 +358,7 @@ public class SmartReplyViewTest extends SysuiTestCase { PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(TEST_ACTION), 0); RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices(choices).build(); - mView.setRepliesFromRemoteInput(input, pendingIntent, mLogger, mEntry); + mView.setRepliesFromRemoteInput(input, pendingIntent, mLogger, mEntry, mContainer); } /** Builds a {@link ViewGroup} whose measures and layout mirror a {@link SmartReplyView}. */ diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index cd2e2a4a28d2..e33ef1fc8a6c 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5697,6 +5697,26 @@ message MetricsEvent { // internal platform metrics use. NOTIFICATION_SHADE_COUNT = 1395; + // ACTION: DND Settings > What to block + // OS: P + ACTION_ZEN_SOUND_ONLY = 1396; + + // ACTION: DND Settings > Notifications + // OS: P + ACTION_ZEN_SOUND_AND_VIS_EFFECTS = 1397; + + // ACTION: DND Settings > Notifications + // OS: P + ACTION_ZEN_SHOW_CUSTOM = 1398; + + // ACTION: DND Settings > Notifications + // OS: P + ACTION_ZEN_CUSTOM = 1399; + + // Screen: DND Settings > Notifications + // OS: P + SETTINGS_ZEN_NOTIFICATIONS = 1400; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto index 490a59e770ec..27febefc39dc 100644 --- a/proto/src/task_snapshot.proto +++ b/proto/src/task_snapshot.proto @@ -28,4 +28,5 @@ int32 inset_right = 4; int32 inset_bottom = 5; bool is_real_snapshot = 6; + int32 windowing_mode = 7; }
\ No newline at end of file diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index 2ed451610354..ae14dfaa4db1 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -30,26 +30,58 @@ public class BinderCallsStatsService extends Binder { private static final String TAG = "BinderCallsStatsService"; - private static final String PERSIST_SYS_BINDER_CPU_STATS_TRACKING - = "persist.sys.binder_cpu_stats_tracking"; + private static final String PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING + = "persist.sys.binder_calls_detailed_tracking"; public static void start() { BinderCallsStatsService service = new BinderCallsStatsService(); ServiceManager.addService("binder_calls_stats", service); - // TODO Enable by default on eng/userdebug builds - boolean trackingEnabledDefault = false; - boolean trackingEnabled = SystemProperties.getBoolean(PERSIST_SYS_BINDER_CPU_STATS_TRACKING, - trackingEnabledDefault); + boolean detailedTrackingEnabled = SystemProperties.getBoolean( + PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, false); - if (trackingEnabled) { + if (detailedTrackingEnabled) { Slog.i(TAG, "Enabled CPU usage tracking for binder calls. Controlled by " - + PERSIST_SYS_BINDER_CPU_STATS_TRACKING); - BinderCallsStats.getInstance().setTrackingEnabled(true); + + PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING + + " or via dumpsys binder_calls_stats --enable-detailed-tracking"); + BinderCallsStats.getInstance().setDetailedTracking(true); } } + public static void reset() { + Slog.i(TAG, "Resetting stats"); + BinderCallsStats.getInstance().reset(); + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (args != null) { + for (final String arg : args) { + if ("--reset".equals(arg)) { + reset(); + pw.println("binder_calls_stats reset."); + return; + } else if ("--enable-detailed-tracking".equals(arg)) { + SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, "1"); + BinderCallsStats.getInstance().setDetailedTracking(true); + pw.println("Detailed tracking enabled"); + return; + } else if ("--disable-detailed-tracking".equals(arg)) { + SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, ""); + BinderCallsStats.getInstance().setDetailedTracking(false); + pw.println("Detailed tracking disabled"); + return; + } else if ("-h".equals(arg)) { + pw.println("binder_calls_stats commands:"); + pw.println(" --reset: Reset stats"); + pw.println(" --enable-detailed-tracking: Enables detailed tracking"); + pw.println(" --disable-detailed-tracking: Disables detailed tracking"); + return; + } else { + pw.println("Unknown option: " + arg); + return; + } + } + } BinderCallsStats.getInstance().dump(pw); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5afb0a622208..9994462531b2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -238,8 +238,9 @@ public class ConnectivityService extends IConnectivityManager.Stub private KeyStore mKeyStore; + @VisibleForTesting @GuardedBy("mVpns") - private final SparseArray<Vpn> mVpns = new SparseArray<Vpn>(); + protected final SparseArray<Vpn> mVpns = new SparseArray<Vpn>(); // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by // a direct call to LockdownVpnTracker.isEnabled(). @@ -929,6 +930,15 @@ public class ConnectivityService extends IConnectivityManager.Stub deps); } + private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) { + final NetworkCapabilities netCap = new NetworkCapabilities(); + netCap.addCapability(NET_CAPABILITY_INTERNET); + netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED); + netCap.removeCapability(NET_CAPABILITY_NOT_VPN); + netCap.setSingleUid(uid); + return netCap; + } + private NetworkRequest createDefaultInternetRequestForTransport( int transportType, NetworkRequest.Type type) { NetworkCapabilities netCap = new NetworkCapabilities(); @@ -1181,12 +1191,20 @@ public class ConnectivityService extends IConnectivityManager.Stub int vpnNetId = NETID_UNSET; synchronized (mVpns) { final Vpn vpn = mVpns.get(user); + // TODO : now that capabilities contain the UID, the appliesToUid test should + // be removed as the satisfying test below should be enough. if (vpn != null && vpn.appliesToUid(uid)) vpnNetId = vpn.getNetId(); } NetworkAgentInfo nai; if (vpnNetId != NETID_UNSET) { nai = getNetworkAgentInfoForNetId(vpnNetId); - if (nai != null) return nai.network; + if (nai != null) { + final NetworkCapabilities requiredCaps = + createDefaultNetworkCapabilitiesForUid(uid); + if (requiredCaps.satisfiedByNetworkCapabilities(nai.networkCapabilities)) { + return nai.network; + } + } } nai = getDefaultNetwork(); if (nai != null @@ -1401,8 +1419,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions( NetworkCapabilities nc, int callerPid, int callerUid) { final NetworkCapabilities newNc = new NetworkCapabilities(nc); - if (!checkSettingsPermission(callerPid, callerUid)) newNc.setUids(null); - if (!checkSettingsPermission(callerPid, callerUid)) newNc.setSSID(null); + if (!checkSettingsPermission(callerPid, callerUid)) { + newNc.setUids(null); + newNc.setSSID(null); + } return newNc; } @@ -4304,8 +4324,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // the default network request. This allows callers to keep track of // the system default network. if (type == NetworkRequest.Type.TRACK_DEFAULT) { - networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities); - networkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN); + networkCapabilities = createDefaultNetworkCapabilitiesForUid(Binder.getCallingUid()); enforceAccessPermission(); } else { networkCapabilities = new NetworkCapabilities(networkCapabilities); @@ -4562,7 +4581,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated. private final NetworkRequest mDefaultRequest; - + // Request used to optionally keep mobile data active even when higher // priority networks like Wi-Fi are active. private final NetworkRequest mDefaultMobileDataRequest; diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 2b3c5852ac8b..aaa42e575ae8 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -327,13 +327,16 @@ public class DeviceIdleController extends SystemService private final int[] mEventCmds = new int[EVENT_BUFFER_SIZE]; private final long[] mEventTimes = new long[EVENT_BUFFER_SIZE]; + private final String[] mEventReasons = new String[EVENT_BUFFER_SIZE]; - private void addEvent(int cmd) { + private void addEvent(int cmd, String reason) { if (mEventCmds[0] != cmd) { System.arraycopy(mEventCmds, 0, mEventCmds, 1, EVENT_BUFFER_SIZE - 1); System.arraycopy(mEventTimes, 0, mEventTimes, 1, EVENT_BUFFER_SIZE - 1); + System.arraycopy(mEventReasons, 0, mEventReasons, 1, EVENT_BUFFER_SIZE - 1); mEventCmds[0] = cmd; mEventTimes[0] = SystemClock.elapsedRealtime(); + mEventReasons[0] = reason; } } @@ -2061,7 +2064,7 @@ public class DeviceIdleController extends SystemService mMaintenanceStartTime = 0; resetIdleManagementLocked(); resetLightIdleManagementLocked(); - addEvent(EVENT_NORMAL); + addEvent(EVENT_NORMAL, activeReason); } } @@ -2158,7 +2161,7 @@ public class DeviceIdleController extends SystemService if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE."); mLightState = LIGHT_STATE_IDLE; EventLogTags.writeDeviceIdleLight(mLightState, reason); - addEvent(EVENT_LIGHT_IDLE); + addEvent(EVENT_LIGHT_IDLE, null); mGoingIdleWakeLock.acquire(); mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON_LIGHT); break; @@ -2179,7 +2182,7 @@ public class DeviceIdleController extends SystemService "Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE."); mLightState = LIGHT_STATE_IDLE_MAINTENANCE; EventLogTags.writeDeviceIdleLight(mLightState, reason); - addEvent(EVENT_LIGHT_MAINTENANCE); + addEvent(EVENT_LIGHT_MAINTENANCE, null); mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF); } else { // We'd like to do maintenance, but currently don't have network @@ -2284,7 +2287,7 @@ public class DeviceIdleController extends SystemService cancelLightAlarmLocked(); } EventLogTags.writeDeviceIdle(mState, reason); - addEvent(EVENT_DEEP_IDLE); + addEvent(EVENT_DEEP_IDLE, null); mGoingIdleWakeLock.acquire(); mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON); break; @@ -2303,7 +2306,7 @@ public class DeviceIdleController extends SystemService } mState = STATE_IDLE_MAINTENANCE; EventLogTags.writeDeviceIdle(mState, reason); - addEvent(EVENT_DEEP_MAINTENANCE); + addEvent(EVENT_DEEP_MAINTENANCE, null); mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF); break; } @@ -2414,7 +2417,7 @@ public class DeviceIdleController extends SystemService mCurIdleBudget = 0; mMaintenanceStartTime = 0; EventLogTags.writeDeviceIdle(mState, type); - addEvent(EVENT_NORMAL); + addEvent(EVENT_NORMAL, type); becomeInactive = true; } if (mLightState == LIGHT_STATE_OVERRIDE) { @@ -3273,8 +3276,14 @@ public class DeviceIdleController extends SystemService pw.print(" "); pw.print(label); pw.print(": "); - TimeUtils.formatDuration(mEventTimes[i], now, pw);; + TimeUtils.formatDuration(mEventTimes[i], now, pw); + if (mEventReasons[i] != null) { + pw.print(" ("); + pw.print(mEventReasons[i]); + pw.print(")"); + } pw.println(); + } } diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 309a75a6a6de..7b02a4fb3fd8 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -86,6 +86,7 @@ import com.android.server.location.ActivityRecognitionProxy; import com.android.server.location.GeocoderProxy; import com.android.server.location.GeofenceManager; import com.android.server.location.GeofenceProxy; +import com.android.server.location.GnssBatchingProvider; import com.android.server.location.GnssLocationProvider; import com.android.server.location.GnssMeasurementsProvider; import com.android.server.location.GnssNavigationMessageProvider; @@ -244,7 +245,7 @@ public class LocationManagerService extends ILocationManager.Stub { private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider; - private GnssLocationProvider.GnssBatchingProvider mGnssBatchingProvider; + private GnssBatchingProvider mGnssBatchingProvider; private IBatchedLocationCallback mGnssBatchingCallback; private LinkedCallback mGnssBatchingDeathCallback; private boolean mGnssBatchingInProgress = false; @@ -1176,7 +1177,7 @@ public class LocationManagerService extends ILocationManager.Stub { "Location Hardware permission not granted to access hardware batching"); if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) { - return mGnssBatchingProvider.getSize(); + return mGnssBatchingProvider.getBatchSize(); } else { return 0; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c9dbd45c5be4..6cd6a31c0f99 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -433,6 +433,7 @@ import com.android.internal.util.Preconditions; import com.android.server.AlarmManagerInternal; import com.android.server.AppOpsService; import com.android.server.AttributeCache; +import com.android.server.BinderCallsStatsService; import com.android.server.DeviceIdleController; import com.android.server.IntentResolver; import com.android.server.IoThread; @@ -3413,6 +3414,11 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public void batteryStatsReset() { + BinderCallsStatsService.reset(); + } + + @Override public void batterySendBroadcast(Intent intent) { synchronized (this) { broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, @@ -8476,8 +8482,19 @@ public class ActivityManagerService extends IActivityManager.Stub if (!(sender instanceof PendingIntentRecord)) { return; } + boolean isCancelled; synchronized(this) { - ((PendingIntentRecord)sender).registerCancelListenerLocked(receiver); + PendingIntentRecord pendingIntent = (PendingIntentRecord) sender; + isCancelled = pendingIntent.canceled; + if (!isCancelled) { + pendingIntent.registerCancelListenerLocked(receiver); + } + } + if (isCancelled) { + try { + receiver.send(Activity.RESULT_CANCELED, null); + } catch (RemoteException e) { + } } } @@ -14542,6 +14559,10 @@ public class ActivityManagerService extends IActivityManager.Stub } void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { + if (pid == Process.myPid()) { + Slog.wtf(TAG, "system can't run remote animation"); + return; + } synchronized (ActivityManagerService.this) { final ProcessRecord pr; synchronized (mPidsSelfLocked) { @@ -21961,54 +21982,6 @@ public class ActivityManagerService extends IActivityManager.Stub // INSTRUMENTATION // ========================================================= - private static String[] HIDDENAPI_EXEMPT_PACKAGES = { - "com.android.bluetooth.tests", - "com.android.managedprovisioning.tests", - "com.android.frameworks.coretests", - "com.android.frameworks.coretests.binderproxycountingtestapp", - "com.android.frameworks.coretests.binderproxycountingtestservice", - "com.android.frameworks.tests.net", - "com.android.frameworks.tests.uiservices", - "com.android.coretests.apps.bstatstestapp", - "com.android.servicestests.apps.conntestapp", - "com.android.frameworks.servicestests", - "com.android.frameworks.utiltests", - "com.android.mtp.tests", - "android.mtp", - "com.android.documentsui.tests", - "com.android.shell.tests", - "com.android.systemui.tests", - "com.android.testables", - "android.net.wifi.test", - "com.android.server.wifi.test", - "com.android.frameworks.telephonytests", - "com.android.providers.contacts.tests", - "com.android.providers.contacts.tests2", - "com.android.settings.tests.unit", - "com.android.server.telecom.tests", - "com.android.vcard.tests", - "com.android.providers.blockednumber.tests", - "android.settings.functional", - "com.android.notification.functional", - "com.android.frameworks.dexloggertest", - "com.android.server.usb", - "com.android.providers.downloads.tests", - "com.android.emergency.tests.unit", - "com.android.providers.calendar.tests", - "com.android.settingslib", - "com.android.rs.test", - "com.android.printspooler.outofprocess.tests", - "com.android.cellbroadcastreceiver.tests.unit", - "com.android.providers.telephony.tests", - "com.android.carrierconfig.tests", - "com.android.phone.tests", - "com.android.service.ims.presence.tests", - "com.android.providers.setting.test", - "com.android.frameworks.locationtests", - "com.android.frameworks.coretests.privacy", - "com.android.settings.ui", - }; - public boolean startInstrumentation(ComponentName className, String profileFile, int flags, Bundle arguments, IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection, @@ -22096,12 +22069,6 @@ public class ActivityManagerService extends IActivityManager.Stub mUsageStatsService.reportEvent(ii.targetPackage, userId, UsageEvents.Event.SYSTEM_INTERACTION); } - // TODO: Temporary whitelist of packages which need to be exempt from hidden API - // checks. Remove this as soon as the testing infrastructure allows to set - // the flag in AndroidTest.xml. - if (Arrays.asList(HIDDENAPI_EXEMPT_PACKAGES).contains(ai.packageName)) { - disableHiddenApiChecks = true; - } ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, abiOverride); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 95bae2eb24a8..9fb3e11446ce 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3802,7 +3802,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // and the resumed activity is not yet visible, then hold off on // finishing until the resumed one becomes visible. - final ActivityRecord next = mStackSupervisor.topRunningActivityLocked(); + // The activity that we are finishing may be over the lock screen. In this case, we do not + // want to consider activities that cannot be shown on the lock screen as running and should + // proceed with finishing the activity if there is no valid next top running activity. + final ActivityRecord next = mStackSupervisor.topRunningActivityLocked( + true /* considerKeyguardState */); if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible) && next != null && !next.nowVisible) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 0dc2445109ea..e5565dccc70e 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1210,6 +1210,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } ActivityRecord topRunningActivityLocked() { + return topRunningActivityLocked(false /* considerKeyguardState */); + } + + /** + * Returns the top running activity in the focused stack. In the case the focused stack has no + * such activity, the next focusable stack on top of a display is returned. + * @param considerKeyguardState Indicates whether the locked state should be considered. if + * {@code true} and the keyguard is locked, only activities that + * can be shown on top of the keyguard will be considered. + * @return The top running activity. {@code null} if none is available. + */ + ActivityRecord topRunningActivityLocked(boolean considerKeyguardState) { final ActivityStack focusedStack = mFocusedStack; ActivityRecord r = focusedStack.topRunningActivityLocked(); if (r != null) { @@ -1228,16 +1240,33 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (display == null) { continue; } - for (int j = display.getChildCount() - 1; j >= 0; --j) { - final ActivityStack stack = display.getChildAt(j); - if (stack != focusedStack && stack.isTopStackOnDisplay() && stack.isFocusable()) { - r = stack.topRunningActivityLocked(); - if (r != null) { - return r; - } - } + + // TODO: We probably want to consider the top fullscreen stack as we could have a pinned + // stack on top. + final ActivityStack topStack = display.getTopStack(); + + // Only consider focusable top stacks other than the current focused one. + if (topStack == null || !topStack.isFocusable() || topStack == focusedStack) { + continue; + } + + final ActivityRecord topActivity = topStack.topRunningActivityLocked(); + + // Skip if no top activity. + if (topActivity == null) { + continue; + } + + final boolean keyguardLocked = getKeyguardController().isKeyguardLocked(); + + // This activity can be considered the top running activity if we are not + // considering the locked state, the keyguard isn't locked, or we can show when + // locked. + if (!considerKeyguardState || !keyguardLocked || topActivity.canShowWhenLocked()) { + return topActivity; } } + return null; } diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java index 6c4554646e6e..31ccf3530fb9 100644 --- a/services/core/java/com/android/server/am/ActivityStartController.java +++ b/services/core/java/com/android/server/am/ActivityStartController.java @@ -350,7 +350,8 @@ public class ActivityStartController { "FLAG_CANT_SAVE_STATE not supported here"); } - final SafeActivityOptions checkedOptions = i == intents.length - 1 + final boolean top = i == intents.length - 1; + final SafeActivityOptions checkedOptions = top ? options : null; final int res = obtainStarter(intent, reason) @@ -367,6 +368,10 @@ public class ActivityStartController { .setActivityOptions(checkedOptions) .setComponentSpecified(componentSpecified) .setOutActivity(outActivity) + + // Top activity decides on animation being run, so we allow only for the + // top one as otherwise an activity below might consume it. + .setAllowPendingRemoteAnimationRegistryLookup(top /* allowLookup*/) .execute(); if (res < 0) { diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index fb89e6711a18..7ff7d9a9b6c4 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -314,6 +314,12 @@ class ActivityStarter { WaitResult waitResult; /** + * If set to {@code true}, allows this activity start to look into + * {@link PendingRemoteAnimationRegistry} + */ + boolean allowPendingRemoteAnimationRegistryLookup; + + /** * Indicates that we should wait for the result of the start request. This flag is set when * {@link ActivityStarter#setMayWait(int)} is called. * {@see ActivityStarter#startActivityMayWait}. @@ -360,6 +366,7 @@ class ActivityStarter { waitResult = null; mayWait = false; avoidMoveToFront = false; + allowPendingRemoteAnimationRegistryLookup = true; } /** @@ -395,6 +402,8 @@ class ActivityStarter { waitResult = request.waitResult; mayWait = request.mayWait; avoidMoveToFront = request.avoidMoveToFront; + allowPendingRemoteAnimationRegistryLookup + = request.allowPendingRemoteAnimationRegistryLookup; } } @@ -477,7 +486,8 @@ class ActivityStarter { mRequest.resultWho, mRequest.requestCode, mRequest.startFlags, mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId, - mRequest.inTask, mRequest.reason); + mRequest.inTask, mRequest.reason, + mRequest.allowPendingRemoteAnimationRegistryLookup); } else { return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo, @@ -486,7 +496,8 @@ class ActivityStarter { mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.componentSpecified, - mRequest.outActivity, mRequest.inTask, mRequest.reason); + mRequest.outActivity, mRequest.inTask, mRequest.reason, + mRequest.allowPendingRemoteAnimationRegistryLookup); } } finally { onExecutionComplete(); @@ -517,7 +528,8 @@ class ActivityStarter { IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, - ActivityRecord[] outActivity, TaskRecord inTask, String reason) { + ActivityRecord[] outActivity, TaskRecord inTask, String reason, + boolean allowPendingRemoteAnimationRegistryLookup) { if (TextUtils.isEmpty(reason)) { throw new IllegalArgumentException("Need to specify a reason."); @@ -530,7 +542,7 @@ class ActivityStarter { aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord, - inTask); + inTask, allowPendingRemoteAnimationRegistryLookup); if (outActivity != null) { // mLastStartActivityRecord[0] is set in the call to startActivity above. @@ -560,7 +572,7 @@ class ActivityStarter { String callingPackage, int realCallingPid, int realCallingUid, int startFlags, SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, - TaskRecord inTask) { + TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) { int err = ActivityManager.START_SUCCESS; // Pull the optional Ephemeral Installer-only bundle out of the options early. final Bundle verificationBundle @@ -709,8 +721,11 @@ class ActivityStarter { ActivityOptions checkedOptions = options != null ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null; - checkedOptions = mService.getActivityStartController().getPendingRemoteAnimationRegistry() - .overrideOptionsIfNeeded(callingPackage, checkedOptions); + if (allowPendingRemoteAnimationRegistryLookup) { + checkedOptions = mService.getActivityStartController() + .getPendingRemoteAnimationRegistry() + .overrideOptionsIfNeeded(callingPackage, checkedOptions); + } if (mService.mController != null) { try { // The Intent we give to the watcher has the extra data @@ -928,7 +943,8 @@ class ActivityStarter { IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, WaitResult outResult, Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity, - int userId, TaskRecord inTask, String reason) { + int userId, TaskRecord inTask, String reason, + boolean allowPendingRemoteAnimationRegistryLookup) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -1070,7 +1086,8 @@ class ActivityStarter { int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, - ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason); + ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason, + allowPendingRemoteAnimationRegistryLookup); Binder.restoreCallingIdentity(origId); @@ -2567,6 +2584,11 @@ class ActivityStarter { return this; } + ActivityStarter setAllowPendingRemoteAnimationRegistryLookup(boolean allowLookup) { + mRequest.allowPendingRemoteAnimationRegistryLookup = allowLookup; + return this; + } + void dump(PrintWriter pw, String prefix) { prefix = prefix + " "; pw.print(prefix); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 35b7f2b4fe86..a6dafbb1db36 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -476,7 +476,8 @@ class AppErrors { } catch (IllegalArgumentException e) { // Hmm, that didn't work, app might have crashed before creating a // recents entry. Let's see if we have a safe-to-restart intent. - final Set<String> cats = task.intent.getCategories(); + final Set<String> cats = task.intent != null + ? task.intent.getCategories() : null; if (cats != null && cats.contains(Intent.CATEGORY_LAUNCHER)) { mService.getActivityStartController().startActivityInPackage( task.mCallingUid, callingPid, callingUid, task.mCallingPackage, diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 2291e44d9e06..87194bc8e771 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -117,6 +117,13 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { private WifiActivityEnergyInfo mLastInfo = new WifiActivityEnergyInfo(0, 0, 0, new long[]{0}, 0, 0, 0, 0); + /** + * Timestamp at which all external stats were last collected in + * {@link SystemClock#elapsedRealtime()} time base. + */ + @GuardedBy("this") + private long mLastCollectionTimeStamp; + BatteryExternalStatsWorker(Context context, BatteryStatsImpl stats) { mContext = context; mStats = stats; @@ -259,6 +266,12 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { return mCurrentFuture; } + long getLastCollectionTimeStamp() { + synchronized (this) { + return mLastCollectionTimeStamp; + } + } + private final Runnable mSyncTask = new Runnable() { @Override public void run() { @@ -312,6 +325,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } catch (Exception e) { Slog.wtf(TAG, "Error updating external stats: ", e); } + + synchronized (BatteryExternalStatsWorker.this) { + mLastCollectionTimeStamp = SystemClock.elapsedRealtime(); + } } }; diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 9c2b1a5d17aa..0c328a89ef84 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -1541,7 +1541,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub } long ident = Binder.clearCallingIdentity(); try { - syncStats("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL); + if (shouldCollectExternalStats()) { + syncStats("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL); + } synchronized (mStats) { return getHealthStatsForUidLocked(requestUid); } @@ -1565,7 +1567,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub long ident = Binder.clearCallingIdentity(); int i=-1; try { - syncStats("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL); + if (shouldCollectExternalStats()) { + syncStats("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL); + } synchronized (mStats) { final int N = requestUids.length; final HealthStatsParceler[] results = new HealthStatsParceler[N]; @@ -1583,6 +1587,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } + private boolean shouldCollectExternalStats() { + return (SystemClock.elapsedRealtime() - mWorker.getLastCollectionTimeStamp()) + > mStats.getExternalStatsCollectionRateLimitMs(); + } + /** * Returns whether the Binder.getCallingUid is the only thing in requestUids. */ diff --git a/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java b/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java index 84dca7fe1c8a..d9878cd09fe4 100644 --- a/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java +++ b/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java @@ -16,6 +16,9 @@ package com.android.server.am; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; + import android.app.AlertDialog; import android.content.Context; import android.content.Intent; @@ -23,6 +26,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Build; import android.os.SystemPropertiesProto; +import android.util.Log; import android.view.Window; import android.view.WindowManager; import android.widget.CheckBox; @@ -31,6 +35,8 @@ import com.android.internal.R; import com.android.server.utils.AppInstallerUtil; public class DeprecatedTargetSdkVersionDialog { + private static final String TAG = TAG_WITH_CLASS_NAME ? "DeprecatedTargetSdkVersionDialog" : TAG_AM; + private final AlertDialog mDialog; private final String mPackageName; @@ -74,6 +80,7 @@ public class DeprecatedTargetSdkVersionDialog { } public void show() { + Log.w(TAG, "Showing SDK deprecation warning for package " + mPackageName); mDialog.show(); } diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java index bef650b90f44..151ef4942432 100644 --- a/services/core/java/com/android/server/am/LockTaskController.java +++ b/services/core/java/com/android/server/am/LockTaskController.java @@ -555,11 +555,12 @@ public class LockTaskController { return; } - if (mLockTaskModeTasks.isEmpty()) { + final Intent taskIntent = task.intent; + if (mLockTaskModeTasks.isEmpty() && taskIntent != null) { mSupervisor.mRecentTasks.onLockTaskModeStateChanged(lockTaskModeState, task.userId); // Start lock task on the handler thread mHandler.post(() -> performStartLockTask( - task.intent.getComponent().getPackageName(), + taskIntent.getComponent().getPackageName(), task.userId, lockTaskModeState)); } diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index a20452bb5074..c83bacbe7a1e 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -550,7 +550,7 @@ class RecentTasks { continue; } - ComponentName cn = tr.intent.getComponent(); + ComponentName cn = tr.intent != null ? tr.intent.getComponent() : null; final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName) && (filterByClasses == null || filterByClasses.contains(cn.getClassName())); if (sameComponent) { diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 0e418ad4cb88..1cd1dd6da529 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -203,7 +203,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi String rootAffinity; // Initial base affinity, or null; does not change from initial root. final IVoiceInteractionSession voiceSession; // Voice interaction session driving task final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app - Intent intent; // The original intent that started the task. + Intent intent; // The original intent that started the task. Note that this value can + // be null. Intent affinityIntent; // Intent of affinity-moved activity that started this task. int effectiveUid; // The current effective uid of the identity of this task. ComponentName origActivity; // The non-alias activity component of the intent. @@ -897,12 +898,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi // the real activity that will be launched not the alias, so we need to use an intent with // the component name pointing to the real activity not the alias in the activity record. intent.setComponent(r.realActivity); - return this.intent.filterEquals(intent); + return intent.filterEquals(this.intent); } boolean returnsToHomeStack() { final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME; - return (intent.getFlags() & returnHomeFlags) == returnHomeFlags; + return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags; } void setPrevAffiliate(TaskRecord prevAffiliate) { @@ -2165,9 +2166,11 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi out.endTag(null, TAG_AFFINITYINTENT); } - out.startTag(null, TAG_INTENT); - intent.saveToXml(out); - out.endTag(null, TAG_INTENT); + if (intent != null) { + out.startTag(null, TAG_INTENT); + intent.saveToXml(out); + out.endTag(null, TAG_INTENT); + } final ArrayList<ActivityRecord> activities = mActivities; final int numActivities = activities.size(); diff --git a/services/core/java/com/android/server/location/GnssBatchingProvider.java b/services/core/java/com/android/server/location/GnssBatchingProvider.java new file mode 100644 index 000000000000..f3918ee9e8ff --- /dev/null +++ b/services/core/java/com/android/server/location/GnssBatchingProvider.java @@ -0,0 +1,145 @@ +package com.android.server.location; + +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Manages GNSS Batching operations. + * + * <p>This class is not thread safe (It's client's responsibility to make sure calls happen on + * the same thread). + */ +public class GnssBatchingProvider { + + private static final String TAG = "GnssBatchingProvider"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final GnssBatchingProviderNative mNative; + private boolean mEnabled; + private boolean mStarted; + private long mPeriodNanos; + private boolean mWakeOnFifoFull; + + GnssBatchingProvider() { + this(new GnssBatchingProviderNative()); + } + + @VisibleForTesting + GnssBatchingProvider(GnssBatchingProviderNative gnssBatchingProviderNative) { + mNative = gnssBatchingProviderNative; + } + + /** + * Returns the GNSS batching size + */ + public int getBatchSize() { + return mNative.getBatchSize(); + } + + /** Enable GNSS batching. */ + public void enable() { + mEnabled = mNative.initBatching(); + if (!mEnabled) { + Log.e(TAG, "Failed to initialize GNSS batching"); + } + } + + /** + * Starts the hardware batching operation + */ + public boolean start(long periodNanos, boolean wakeOnFifoFull) { + if (!mEnabled) { + throw new IllegalStateException(); + } + if (periodNanos <= 0) { + Log.e(TAG, "Invalid periodNanos " + periodNanos + + " in batching request, not started"); + return false; + } + mStarted = mNative.startBatch(periodNanos, wakeOnFifoFull); + if (mStarted) { + mPeriodNanos = periodNanos; + mWakeOnFifoFull = wakeOnFifoFull; + } + return mStarted; + } + + /** + * Forces a flush of existing locations from the hardware batching + */ + public void flush() { + if (!mStarted) { + Log.w(TAG, "Cannot flush since GNSS batching has not started."); + return; + } + mNative.flushBatch(); + } + + /** + * Stops the batching operation + */ + public boolean stop() { + boolean stopped = mNative.stopBatch(); + if (stopped) { + mStarted = false; + } + return stopped; + } + + /** Disable GNSS batching. */ + public void disable() { + stop(); + mNative.cleanupBatching(); + mEnabled = false; + } + + // TODO(b/37460011): Use this with death recovery logic. + void resumeIfStarted() { + if (DEBUG) { + Log.d(TAG, "resumeIfStarted"); + } + if (mStarted) { + mNative.startBatch(mPeriodNanos, mWakeOnFifoFull); + } + } + + @VisibleForTesting + static class GnssBatchingProviderNative { + public int getBatchSize() { + return native_get_batch_size(); + } + + public boolean startBatch(long periodNanos, boolean wakeOnFifoFull) { + return native_start_batch(periodNanos, wakeOnFifoFull); + } + + public void flushBatch() { + native_flush_batch(); + } + + public boolean stopBatch() { + return native_stop_batch(); + } + + public boolean initBatching() { + return native_init_batching(); + } + + public void cleanupBatching() { + native_cleanup_batching(); + } + } + + private static native int native_get_batch_size(); + + private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull); + + private static native void native_flush_batch(); + + private static native boolean native_stop_batch(); + + private static native boolean native_init_batching(); + + private static native void native_cleanup_batching(); +} diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index a8082986614c..756d06bc789d 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -418,6 +418,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener(); private final LocationChangeListener mFusedLocationListener = new FusedLocationListener(); private final NtpTimeHelper mNtpTimeHelper; + private final GnssBatchingProvider mGnssBatchingProvider; // Handler for processing events private Handler mHandler; @@ -885,6 +886,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt mGnssSatelliteBlacklistHelper = new GnssSatelliteBlacklistHelper(mContext, looper, this); mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist); + mGnssBatchingProvider = new GnssBatchingProvider(); } /** @@ -1061,6 +1063,12 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt locationListener = mFusedLocationListener; } + if (!locationManager.isProviderEnabled(provider)) { + Log.w(TAG, "Unable to request location since " + provider + + " provider does not exist or is not enabled."); + return; + } + Log.i(TAG, String.format( "GNSS HAL Requesting location updates from %s provider for %d millis.", @@ -1267,7 +1275,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt mGnssMeasurementsProvider.onGpsEnabledChanged(); mGnssNavigationMessageProvider.onGpsEnabledChanged(); - enableBatching(); + mGnssBatchingProvider.enable(); } else { synchronized (mLock) { mEnabled = false; @@ -1299,7 +1307,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt mAlarmManager.cancel(mWakeupIntent); mAlarmManager.cancel(mTimeoutIntent); - disableBatching(); + mGnssBatchingProvider.disable(); // do this before releasing wakelock native_cleanup(); @@ -2001,58 +2009,11 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt }; } - public interface GnssBatchingProvider { - /** - * Returns the GNSS batching size - */ - int getSize(); - - /** - * Starts the hardware batching operation - */ - boolean start(long periodNanos, boolean wakeOnFifoFull); - - /** - * Forces a flush of existing locations from the hardware batching - */ - void flush(); - - /** - * Stops the batching operation - */ - boolean stop(); - } - /** * @hide */ public GnssBatchingProvider getGnssBatchingProvider() { - return new GnssBatchingProvider() { - @Override - public int getSize() { - return native_get_batch_size(); - } - - @Override - public boolean start(long periodNanos, boolean wakeOnFifoFull) { - if (periodNanos <= 0) { - Log.e(TAG, "Invalid periodNanos " + periodNanos + - "in batching request, not started"); - return false; - } - return native_start_batch(periodNanos, wakeOnFifoFull); - } - - @Override - public void flush() { - native_flush_batch(); - } - - @Override - public boolean stop() { - return native_stop_batch(); - } - }; + return mGnssBatchingProvider; } public interface GnssMetricsProvider { @@ -2075,23 +2036,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt } /** - * Initialize Batching if enabled - */ - private void enableBatching() { - if (!native_init_batching()) { - Log.e(TAG, "Failed to initialize GNSS batching"); - } - } - - /** - * Disable batching - */ - private void disableBatching() { - native_stop_batch(); - native_cleanup_batching(); - } - - /** * called from native code - GNSS location batch callback */ private void reportLocationBatch(Location[] locationArray) { @@ -2912,19 +2856,5 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn); private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds); - - // GNSS Batching - private static native int native_get_batch_size(); - - private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull); - - private static native void native_flush_batch(); - - private static native boolean native_stop_batch(); - - private static native boolean native_init_batching(); - - private static native void native_cleanup_batching(); - } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index f1fd00b4ea2a..1078f6eefa76 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -1742,7 +1742,8 @@ public class LockSettingsService extends ILockSettings.Stub { if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential)); } else { - hash = mLockPatternUtils.passwordToHash(credential, userId); + hash = mLockPatternUtils.legacyPasswordToHash(credential, userId) + .getBytes(StandardCharsets.UTF_8); } if (Arrays.equals(hash, storedHash.hash)) { if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { @@ -2532,6 +2533,33 @@ public class LockSettingsService extends ILockSettings.Stub { mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId); } + /** + * Returns a fixed pseudorandom byte string derived from the user's synthetic password. + * This is used to salt the password history hash to protect the hash against offline + * bruteforcing, since rederiving this value requires a successful authentication. + */ + @Override + public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException { + checkPasswordReadPermission(userId); + if (TextUtils.isEmpty(currentCredential)) { + currentCredential = null; + } + synchronized (mSpManager) { + if (!isSyntheticPasswordBasedCredentialLocked(userId)) { + Slog.w(TAG, "Synthetic password not enabled"); + return null; + } + long handle = getSyntheticPasswordHandleLocked(userId); + AuthenticationResult auth = mSpManager.unwrapPasswordBasedSyntheticPassword( + getGateKeeperService(), handle, currentCredential, userId, null); + if (auth.authToken == null) { + Slog.w(TAG, "Current credential is incorrect"); + return null; + } + return auth.authToken.derivePasswordHashFactor(); + } + } + private long addEscrowToken(byte[] token, int userId) throws RemoteException { if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); synchronized (mSpManager) { diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 0700ab35df1b..596daeb1427b 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -123,6 +123,7 @@ public class SyntheticPasswordManager { private static final byte[] PERSONALIZATION_FBE_KEY = "fbe-key".getBytes(); private static final byte[] PERSONALIZATION_AUTHSECRET_KEY = "authsecret-hal".getBytes(); private static final byte[] PERSONALIZATION_SP_SPLIT = "sp-split".getBytes(); + private static final byte[] PERSONALIZATION_PASSWORD_HASH = "pw-hash".getBytes(); private static final byte[] PERSONALIZATION_E0 = "e0-encryption".getBytes(); private static final byte[] PERSONALISATION_WEAVER_PASSWORD = "weaver-pwd".getBytes(); private static final byte[] PERSONALISATION_WEAVER_KEY = "weaver-key".getBytes(); @@ -165,6 +166,11 @@ public class SyntheticPasswordManager { syntheticPassword.getBytes()); } + public byte[] derivePasswordHashFactor() { + return SyntheticPasswordCrypto.personalisedHash(PERSONALIZATION_PASSWORD_HASH, + syntheticPassword.getBytes()); + } + private void initialize(byte[] P0, byte[] P1) { this.P1 = P1; this.syntheticPassword = String.valueOf(HexEncoding.encode( diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 477b062ac90f..269a0dac41ab 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -71,9 +71,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; /** * Manages the lifecycle of application-provided services bound by system server. @@ -401,15 +399,20 @@ abstract public class ManagedServices { approvedByType = new ArrayMap<>(); mApproved.put(userId, approvedByType); } + + ArraySet<String> approvedList = approvedByType.get(isPrimary); + if (approvedList == null) { + approvedList = new ArraySet<>(); + approvedByType.put(isPrimary, approvedList); + } + String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR); - final ArraySet<String> approvedList = new ArraySet<>(); for (String pkgOrComponent : approvedArray) { String approvedItem = getApprovedValue(pkgOrComponent); if (approvedItem != null) { approvedList.add(approvedItem); } } - approvedByType.put(isPrimary, approvedList); } protected boolean isComponentEnabledForPackage(String pkg) { diff --git a/services/core/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java index c64e745a3ac2..5cbe1a1e9816 100644 --- a/services/core/java/com/android/server/os/SchedulingPolicyService.java +++ b/services/core/java/com/android/server/os/SchedulingPolicyService.java @@ -24,6 +24,8 @@ import android.os.Process; import android.os.RemoteException; import android.util.Log; +import com.android.server.SystemServerInitThreadPool; + /** * The implementation of the scheduling policy service interface. * @@ -62,11 +64,18 @@ public class SchedulingPolicyService extends ISchedulingPolicyService.Stub { // (Note that if mediaserver thinks we're in boosted state before the crash, // the state could go out of sync temporarily until mediaserver enables/disable // boost next time, but this won't be a big issue.) - int[] nativePids = Process.getPidsForCommands(MEDIA_PROCESS_NAMES); - if (nativePids != null && nativePids.length == 1) { - mBoostedPid = nativePids[0]; - disableCpusetBoost(nativePids[0]); - } + SystemServerInitThreadPool.get().submit(() -> { + synchronized (mDeathRecipient) { + // only do this if we haven't already got a request to boost. + if (mBoostedPid == -1) { + int[] nativePids = Process.getPidsForCommands(MEDIA_PROCESS_NAMES); + if (nativePids != null && nativePids.length == 1) { + mBoostedPid = nativePids[0]; + disableCpusetBoost(nativePids[0]); + } + } + } + }, TAG + ".<init>"); } // TODO(b/35196900) We should pass the period in time units, rather @@ -107,7 +116,9 @@ public class SchedulingPolicyService extends ISchedulingPolicyService.Stub { // Request to move media.codec process between SP_FOREGROUND and SP_TOP_APP. public int requestCpusetBoost(boolean enable, IBinder client) { - if (!isPermitted()) { + // Can only allow mediaserver to call this. + if (Binder.getCallingPid() != Process.myPid() && + Binder.getCallingUid() != Process.MEDIA_UID) { return PackageManager.PERMISSION_DENIED; } @@ -201,7 +212,6 @@ public class SchedulingPolicyService extends ISchedulingPolicyService.Stub { switch (Binder.getCallingUid()) { case Process.AUDIOSERVER_UID: // fastcapture, fastmixer - case Process.MEDIA_UID: // mediaserver case Process.CAMERASERVER_UID: // camera high frame rate recording case Process.BLUETOOTH_UID: // Bluetooth audio playback return true; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a20023128ff5..866de76d10e4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -13625,25 +13625,15 @@ public class PackageManagerService extends IPackageManager.Stub // install reason correctly. return installReason; } - - final IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface( - ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); - if (dpm != null) { - ComponentName owner = null; - try { - owner = dpm.getDeviceOwnerComponent(true /* callingUserOnly */); - if (owner == null) { - owner = dpm.getProfileOwner(UserHandle.getUserId(installerUid)); - } - } catch (RemoteException e) { - } - if (owner != null && owner.getPackageName().equals(installerPackageName)) { - // If the install is being performed by a device or profile owner, the install - // reason should be enterprise policy. - return PackageManager.INSTALL_REASON_POLICY; - } + final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage( + UserHandle.getUserId(installerUid)); + if (ownerPackage != null && ownerPackage.equals(installerPackageName)) { + // If the install is being performed by a device or profile owner, the install + // reason should be enterprise policy. + return PackageManager.INSTALL_REASON_POLICY; } + if (installReason == PackageManager.INSTALL_REASON_POLICY) { // If the install is being performed by a regular app (i.e. neither system app nor // device or profile owner), we have no reason to believe that the app is acting on @@ -14040,7 +14030,11 @@ public class PackageManagerService extends IPackageManager.Stub throw new IllegalArgumentException("CallingPackage " + callingPackage + " does not" + " belong to calling app id " + UserHandle.getAppId(callingUid)); } - + if (!PLATFORM_PACKAGE_NAME.equals(callingPackage) + && mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId) != null) { + throw new UnsupportedOperationException("Cannot suspend/unsuspend packages. User " + + userId + " has an active DO or PO"); + } if (ArrayUtils.isEmpty(packageNames)) { return packageNames; } @@ -17425,6 +17419,7 @@ public class PackageManagerService extends IPackageManager.Stub // 1) it is not forward locked. // 2) it is not on on an external ASEC container. // 3) it is not an instant app or if it is then dexopt is enabled via gservices. + // 4) it is not debuggable. // // Note that we do not dexopt instant apps by default. dexopt can take some time to // complete, so we skip this step during installation. Instead, we'll take extra time @@ -17436,7 +17431,8 @@ public class PackageManagerService extends IPackageManager.Stub && !forwardLocked && !pkg.applicationInfo.isExternalAsec() && (!instantApp || Global.getInt(mContext.getContentResolver(), - Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0); + Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) + && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0); if (performDexopt) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java index e67364a26e5c..a374e1484b28 100644 --- a/services/core/java/com/android/server/pm/ProtectedPackages.java +++ b/services/core/java/com/android/server/pm/ProtectedPackages.java @@ -88,6 +88,13 @@ public class ProtectedPackages { return false; } + public synchronized String getDeviceOwnerOrProfileOwnerPackage(int userId) { + if (mDeviceOwnerUserId == userId) { + return mDeviceOwnerPackage; + } + return mProfileOwnerPackages.get(userId); + } + /** * Returns {@code true} if a given package is protected. Otherwise, returns {@code false}. * diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 61e82cd2d339..20283a792cfb 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -16,6 +16,7 @@ package com.android.server.power; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; @@ -97,7 +98,7 @@ final class Notifier { private final ActivityManagerInternal mActivityManagerInternal; private final InputManagerInternal mInputManagerInternal; private final InputMethodManagerInternal mInputMethodManagerInternal; - private final StatusBarManagerInternal mStatusBarManagerInternal; + @Nullable private final StatusBarManagerInternal mStatusBarManagerInternal; private final TrustManager mTrustManager; private final NotifierHandler mHandler; @@ -738,7 +739,9 @@ final class Notifier { private void showWirelessChargingStarted(int batteryLevel) { playChargingStartedSound(); - mStatusBarManagerInternal.showChargingAnimation(batteryLevel); + if (mStatusBarManagerInternal != null) { + mStatusBarManagerInternal.showChargingAnimation(batteryLevel); + } mSuspendBlocker.release(); } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 0dc06b27a605..c7617546780d 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -82,6 +82,7 @@ import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.res.Configuration; +import android.content.res.ResourceId; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -245,7 +246,6 @@ public class AppTransition implements Dump { private int mLastClipRevealMaxTranslation; private boolean mLastHadClipReveal; - private boolean mProlongedAnimationsEnded; private final boolean mGridLayoutRecentsEnabled; private final boolean mLowRamRecentsEnabled; @@ -423,27 +423,12 @@ public class AppTransition implements Dump { mService.getDefaultDisplayContentLocked().getDockedDividerController() .notifyAppTransitionStarting(openingApps, transit); - // Prolong the start for the transition when docking a task from recents, unless recents - // ended it already then we don't need to wait. - if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) { - for (int i = openingApps.size() - 1; i >= 0; i--) { - final AppWindowToken app = openingApps.valueAt(i); - app.startDelayingAnimationStart(); - } - } if (mRemoteAnimationController != null) { mRemoteAnimationController.goodToGo(); } return redoLayout; } - /** - * Let the transitions manager know that the somebody wanted to end the prolonged animations. - */ - void notifyProlongedAnimationsEnded() { - mProlongedAnimationsEnded = true; - } - void clear() { mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE; mNextAppTransitionPackage = null; @@ -452,7 +437,6 @@ public class AppTransition implements Dump { mNextAppTransitionAnimationsSpecsFuture = null; mDefaultNextAppTransitionAnimationSpec = null; mAnimationFinishedCallback = null; - mProlongedAnimationsEnded = false; } void freeze() { @@ -555,25 +539,25 @@ public class AppTransition implements Dump { } Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) { - int anim = 0; + int resId = ResourceId.ID_NULL; Context context = mContext; if (animAttr >= 0) { AttributeCache.Entry ent = getCachedAnimations(lp); if (ent != null) { context = ent.context; - anim = ent.array.getResourceId(animAttr, 0); + resId = ent.array.getResourceId(animAttr, 0); } } - anim = updateToTranslucentAnimIfNeeded(anim, transit); - if (anim != 0) { - return AnimationUtils.loadAnimation(context, anim); + resId = updateToTranslucentAnimIfNeeded(resId, transit); + if (ResourceId.isValid(resId)) { + return AnimationUtils.loadAnimation(context, resId); } return null; } Animation loadAnimationRes(LayoutParams lp, int resId) { Context context = mContext; - if (resId >= 0) { + if (ResourceId.isValid(resId)) { AttributeCache.Entry ent = getCachedAnimations(lp); if (ent != null) { context = ent.context; @@ -584,18 +568,12 @@ public class AppTransition implements Dump { } private Animation loadAnimationRes(String packageName, int resId) { - int anim = 0; - Context context = mContext; - if (resId >= 0) { + if (ResourceId.isValid(resId)) { AttributeCache.Entry ent = getCachedAnimations(packageName, resId); if (ent != null) { - context = ent.context; - anim = resId; + return AnimationUtils.loadAnimation(ent.context, resId); } } - if (anim != 0) { - return AnimationUtils.loadAnimation(context, anim); - } return null; } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 79b230d45110..b057b1d8fb52 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -47,7 +47,9 @@ import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; +import android.view.inputmethod.InputMethodManagerInternal; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.InsetUtils; import com.google.android.collect.Sets; @@ -220,6 +222,20 @@ public class RecentsAnimationController implements DeathRecipient { Binder.restoreCallingIdentity(token); } } + + @Override + public void hideCurrentInputMethod() { + final long token = Binder.clearCallingIdentity(); + try { + final InputMethodManagerInternal inputMethodManagerInternal = + LocalServices.getService(InputMethodManagerInternal.class); + if (inputMethodManagerInternal != null) { + inputMethodManagerInternal.hideCurrentInputMethod(); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } }; /** diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 5f9d679d7f07..6b13edd072cd 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -273,9 +273,8 @@ class TaskSnapshotController { return null; } return new TaskSnapshot(buffer, top.getConfiguration().orientation, - getInsets(mainWindow), - isLowRamDevice /* reduced */, scaleFraction /* scale */, - true /* isRealSnapshot */); + getInsets(mainWindow), isLowRamDevice /* reduced */, scaleFraction /* scale */, + true /* isRealSnapshot */, task.getWindowingMode()); } private boolean shouldDisableSnapshots() { @@ -365,7 +364,7 @@ class TaskSnapshotController { return new TaskSnapshot(hwBitmap.createGraphicBufferHandle(), topChild.getConfiguration().orientation, mainWindow.mStableInsets, ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */, - false /* isRealSnapshot */); + false /* isRealSnapshot */, task.getWindowingMode()); } /** diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java index 31da5f3ff1c8..b682a3262da1 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java @@ -90,7 +90,7 @@ class TaskSnapshotLoader { return new TaskSnapshot(buffer, proto.orientation, new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom), reducedResolution, reducedResolution ? REDUCED_SCALE : 1f, - proto.isRealSnapshot); + proto.isRealSnapshot, proto.windowingMode); } catch (IOException e) { Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId); return null; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index 086fffa9d621..408fb3ce36c9 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -24,9 +24,7 @@ import android.annotation.TestApi; import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.graphics.Bitmap; -import android.graphics.Bitmap.CompressFormat; import android.graphics.Bitmap.Config; -import android.graphics.GraphicBuffer; import android.os.Process; import android.os.SystemClock; import android.util.ArraySet; @@ -41,7 +39,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayDeque; -import java.util.ArrayList; /** * Persists {@link TaskSnapshot}s to disk. @@ -319,6 +316,7 @@ class TaskSnapshotPersister { proto.insetRight = mSnapshot.getContentInsets().right; proto.insetBottom = mSnapshot.getContentInsets().bottom; proto.isRealSnapshot = mSnapshot.isRealSnapshot(); + proto.windowingMode = mSnapshot.getWindowingMode(); final byte[] bytes = TaskSnapshotProto.toByteArray(proto); final File file = getProtoFile(mTaskId, mUserId); final AtomicFile atomicFile = new AtomicFile(file); diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index ae9e80268741..7d4d7cb9c71c 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -751,8 +751,9 @@ public class TaskStack extends WindowContainer<Task> implements * Used to make room for shadows in the pinned windowing mode. */ int getStackOutset() { - if (inPinnedWindowingMode()) { - final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics(); + DisplayContent displayContent = getDisplayContent(); + if (inPinnedWindowingMode() && displayContent != null) { + final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics(); // We multiply by two to match the client logic for converting view elevation // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets} diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 331a0bd3da11..eab391ed74ce 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -183,6 +183,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // build a surface. mSurfaceControl = makeSurface().build(); getPendingTransaction().show(mSurfaceControl); + updateSurfacePosition(); } else { // If we have a surface but a new parent, we just need to perform a reparent. Go through // surface animator such that hierarchy is preserved when animating, i.e. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 09e43f843983..06e8d4718cd2 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2204,7 +2204,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mInputMethodWindow == win) { setInputMethodWindowLocked(null); } - boolean stopped = win.mAppToken != null ? win.mAppToken.mAppStopped : false; + boolean stopped = win.mAppToken != null ? win.mAppToken.mAppStopped : true; // We set mDestroying=true so AppWindowToken#notifyAppStopped in-to destroy surfaces // will later actually destroy the surface if we do not do so here. Normally we leave // this to the exit animation. @@ -2677,15 +2677,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void endProlongedAnimations() { - synchronized (mWindowMap) { - for (final WindowState win : mWindowMap.values()) { - final AppWindowToken appToken = win.mAppToken; - if (appToken != null) { - appToken.endDelayingAnimationStart(); - } - } - mAppTransition.notifyProlongedAnimationsEnded(); - } + // TODO: Remove once clients are updated. } @Override @@ -5816,6 +5808,7 @@ public class WindowManagerService extends IWindowManager.Stub final int displayId = mFrozenDisplayId; mFrozenDisplayId = INVALID_DISPLAY; mDisplayFrozen = false; + mInputMonitor.thawInputDispatchingLw(); mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime); StringBuilder sb = new StringBuilder(128); sb.append("Screen frozen for "); @@ -5862,8 +5855,6 @@ public class WindowManagerService extends IWindowManager.Stub updateRotation = true; } - mInputMonitor.thawInputDispatchingLw(); - boolean configChanged; // While the display is frozen we don't re-compute the orientation @@ -5952,12 +5943,8 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setRecentsVisibility(boolean visible) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Caller does not hold permission " - + android.Manifest.permission.STATUS_BAR); - } - + mAmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR, + "setRecentsVisibility()"); synchronized (mWindowMap) { mPolicy.setRecentsVisibilityLw(visible); } diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index e18eee267610..92ef9f16ca93 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -2050,7 +2050,7 @@ static jboolean android_location_GnssLocationProvider_set_satellite_blacklist( } -static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) { +static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return 0; // batching not supported, size = 0 } @@ -2062,7 +2062,7 @@ static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass } } -static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) { +static jboolean android_location_GnssBatchingProvider_init_batching(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return JNI_FALSE; // batching not supported } @@ -2071,14 +2071,14 @@ static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jcl return static_cast<jboolean>(gnssBatchingIface->init(gnssBatchingCbIface)); } -static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) { +static void android_location_GnssBatchingProvider_cleanup_batching(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return; // batching not supported } gnssBatchingIface->cleanup(); } -static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass, +static jboolean android_location_GnssBatchingProvider_start_batch(JNIEnv*, jclass, jlong periodNanos, jboolean wakeOnFifoFull) { if (gnssBatchingIface == nullptr) { return JNI_FALSE; // batching not supported @@ -2095,7 +2095,7 @@ static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclas return static_cast<jboolean>(gnssBatchingIface->start(options)); } -static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) { +static void android_location_GnssBatchingProvider_flush_batch(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return; // batching not supported } @@ -2103,7 +2103,7 @@ static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) { gnssBatchingIface->flush(); } -static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) { +static jboolean android_location_GnssBatchingProvider_stop_batch(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return JNI_FALSE; // batching not supported } @@ -2241,30 +2241,36 @@ static const JNINativeMethod sMethods[] = { {"native_set_satellite_blacklist", "([I[I)Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_set_satellite_blacklist)}, +}; + +static const JNINativeMethod sMethodsBatching[] = { + /* name, signature, funcPtr */ {"native_get_batch_size", "()I", - reinterpret_cast<void *>(android_location_GnssLocationProvider_get_batch_size)}, - {"native_init_batching", - "()Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_init_batching)}, + reinterpret_cast<void *>(android_location_GnssBatchingProvider_get_batch_size)}, {"native_start_batch", "(JZ)Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_start_batch)}, + reinterpret_cast<void *>(android_location_GnssBatchingProvider_start_batch)}, {"native_flush_batch", "()V", - reinterpret_cast<void *>(android_location_GnssLocationProvider_flush_batch)}, + reinterpret_cast<void *>(android_location_GnssBatchingProvider_flush_batch)}, {"native_stop_batch", "()Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_stop_batch)}, + reinterpret_cast<void *>(android_location_GnssBatchingProvider_stop_batch)}, {"native_init_batching", "()Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_init_batching)}, + reinterpret_cast<void *>(android_location_GnssBatchingProvider_init_batching)}, {"native_cleanup_batching", "()V", - reinterpret_cast<void *>(android_location_GnssLocationProvider_cleanup_batching)}, + reinterpret_cast<void *>(android_location_GnssBatchingProvider_cleanup_batching)}, }; int register_android_server_location_GnssLocationProvider(JNIEnv* env) { + jniRegisterNativeMethods( + env, + "com/android/server/location/GnssBatchingProvider", + sMethodsBatching, + NELEM(sMethodsBatching)); return jniRegisterNativeMethods( env, "com/android/server/location/GnssLocationProvider", diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index e07b89f232b1..51ce7c20dd5e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -73,6 +73,9 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER; import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER; + +import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; + import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.TEXT; @@ -9193,8 +9196,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { long id = mInjector.binderClearCallingIdentity(); try { - return mIPackageManager.setPackagesSuspendedAsUser( - packageNames, suspended, null, null, null, "android", callingUserId); + return mIPackageManager.setPackagesSuspendedAsUser(packageNames, suspended, + null, null, null, PLATFORM_PACKAGE_NAME, callingUserId); } catch (RemoteException re) { // Shouldn't happen. Slog.e(LOG_TAG, "Failed talking to the package manager", re); diff --git a/services/robotests/src/com/android/server/location/GnssBatchingProviderTest.java b/services/robotests/src/com/android/server/location/GnssBatchingProviderTest.java new file mode 100644 index 000000000000..504609472fa6 --- /dev/null +++ b/services/robotests/src/com/android/server/location/GnssBatchingProviderTest.java @@ -0,0 +1,91 @@ +package com.android.server.location; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.platform.test.annotations.Presubmit; + +import com.android.server.location.GnssBatchingProvider.GnssBatchingProviderNative; +import com.android.server.testing.FrameworkRobolectricTestRunner; +import com.android.server.testing.SystemLoaderPackages; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +/** + * Unit tests for {@link GnssBatchingProvider}. + */ +@RunWith(FrameworkRobolectricTestRunner.class) +@Config( + manifest = Config.NONE, + shadows = { + }, + sdk = 27 +) +@SystemLoaderPackages({"com.android.server.location"}) +@Presubmit +public class GnssBatchingProviderTest { + + private static final long PERIOD_NANOS = (long) 1e9; + private static final boolean WAKE_ON_FIFO_FULL = true; + private static final int BATCH_SIZE = 3; + @Mock + private GnssBatchingProviderNative mMockNative; + private GnssBatchingProvider mTestProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mMockNative.initBatching()).thenReturn(true); + when(mMockNative.startBatch(anyLong(), anyBoolean())).thenReturn(true); + when(mMockNative.stopBatch()).thenReturn(true); + when(mMockNative.getBatchSize()).thenReturn(BATCH_SIZE); + mTestProvider = new GnssBatchingProvider(mMockNative); + mTestProvider.enable(); + mTestProvider.start(PERIOD_NANOS, WAKE_ON_FIFO_FULL); + } + + @Test + public void start_nativeStarted() { + verify(mMockNative).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL)); + } + + @Test + public void stop_nativeStopped() { + mTestProvider.stop(); + verify(mMockNative).stopBatch(); + } + + @Test + public void flush_nativeFlushed() { + mTestProvider.flush(); + verify(mMockNative).flushBatch(); + } + + @Test + public void getBatchSize_nativeGetBatchSize() { + assertThat(mTestProvider.getBatchSize()).isEqualTo(BATCH_SIZE); + } + + @Test + public void started_resume_started() { + mTestProvider.resumeIfStarted(); + verify(mMockNative, times(2)).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL)); + } + + @Test + public void stopped_resume_notStarted() { + mTestProvider.stop(); + mTestProvider.resumeIfStarted(); + verify(mMockNative, times(1)).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index 08b8af289bd8..9daea1afc505 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -329,4 +330,52 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { REMOVE_TASK_MODE_DESTROYING); assertFalse(pinnedStack.isFocusable()); } + + /** + * Verifies the correct activity is returned when querying the top running activity with an + * empty focused stack. + */ + @Test + public void testNonFocusedTopRunningActivity() throws Exception { + // Create stack to hold focus + final ActivityStack focusedStack = mService.mStackSupervisor.getDefaultDisplay() + .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + + final KeyguardController keyguard = mSupervisor.getKeyguardController(); + final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(stack).build(); + + mSupervisor.mFocusedStack = focusedStack; + + doAnswer((InvocationOnMock invocationOnMock) -> { + final SparseIntArray displayIds = invocationOnMock.<SparseIntArray>getArgument(0); + displayIds.put(0, mSupervisor.getDefaultDisplay().mDisplayId); + return null; + }).when(mSupervisor.mWindowManager).getDisplaysInFocusOrder(any()); + + // Make sure the top running activity is not affected when keyguard is not locked + assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked()); + assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked( + true /* considerKeyguardState */)); + + // Check to make sure activity not reported when it cannot show on lock and lock is on. + doReturn(true).when(keyguard).isKeyguardLocked(); + assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked()); + assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked( + true /* considerKeyguardState */)); + + // Add activity that should be shown on the keyguard. + final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService) + .setCreateTask(true) + .setStack(stack) + .setActivityFlags(FLAG_SHOW_WHEN_LOCKED) + .build(); + + // Ensure the show when locked activity is returned. + assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked()); + assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked( + true /* considerKeyguardState */)); + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index f5e61a1db341..1cd111fce0ec 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -132,6 +132,7 @@ public class ActivityTestsBase { private int mUid; private boolean mCreateTask; private ActivityStack mStack; + private int mActivityFlags; ActivityBuilder(ActivityManagerService service) { mService = service; @@ -152,6 +153,11 @@ public class ActivityTestsBase { return this; } + ActivityBuilder setActivityFlags(int flags) { + mActivityFlags = flags; + return this; + } + ActivityBuilder setStack(ActivityStack stack) { mStack = stack; return this; @@ -186,6 +192,8 @@ public class ActivityTestsBase { aInfo.applicationInfo = new ApplicationInfo(); aInfo.applicationInfo.packageName = mComponent.getPackageName(); aInfo.applicationInfo.uid = mUid; + aInfo.flags |= mActivityFlags; + final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, 0 /* launchedFromPid */, 0, null, intent, null, aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */, diff --git a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java index c91e22f84a07..057fdc8c10bb 100644 --- a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java @@ -17,6 +17,9 @@ package com.android.server.am; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -62,7 +65,7 @@ import java.util.Comparator; * Tests for exercising {@link TaskRecord}. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.am.TaskRecordTests + * atest FrameworksServicesTests:com.android.server.am.TaskRecordTests */ @MediumTest @Presubmit @@ -113,6 +116,18 @@ public class TaskRecordTests extends ActivityTestsBase { assertTrue(factory.mCreated); } + @Test + public void testReturnsToHomeStack() throws Exception { + final TaskRecord task = createTaskRecord(1); + assertFalse(task.returnsToHomeStack()); + task.intent = null; + assertFalse(task.returnsToHomeStack()); + task.intent = new Intent(); + assertFalse(task.returnsToHomeStack()); + task.intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME); + assertTrue(task.returnsToHomeStack()); + } + private File serializeToFile(TaskRecord r) throws IOException, XmlPullParserException { final File tmpFile = File.createTempFile(r.taskId + "_task_", "xml"); diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java index 80cbf2aae3f0..13478dfded34 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -164,8 +166,10 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa @Test public void testIsRealSnapshotPersistAndLoadSnapshot() { - TaskSnapshot a = createSnapshot(1f /* scale */, true /* isRealSnapshot */); - TaskSnapshot b = createSnapshot(1f /* scale */, false /* isRealSnapshot */); + TaskSnapshot a = createSnapshot(1f /* scale */, true /* isRealSnapshot */, + WINDOWING_MODE_FULLSCREEN); + TaskSnapshot b = createSnapshot(1f /* scale */, false /* isRealSnapshot */, + WINDOWING_MODE_FULLSCREEN); assertTrue(a.isRealSnapshot()); assertFalse(b.isRealSnapshot()); mPersister.persistSnapshot(1, mTestUserId, a); @@ -180,6 +184,25 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa } @Test + public void testWindowingModePersistAndLoadSnapshot() { + TaskSnapshot a = createSnapshot(1f /* scale */, true /* isRealSnapshot */, + WINDOWING_MODE_FULLSCREEN); + TaskSnapshot b = createSnapshot(1f /* scale */, true /* isRealSnapshot */, + WINDOWING_MODE_PINNED); + assertTrue(a.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); + assertTrue(b.getWindowingMode() == WINDOWING_MODE_PINNED); + mPersister.persistSnapshot(1, mTestUserId, a); + mPersister.persistSnapshot(2, mTestUserId, b); + mPersister.waitForQueueEmpty(); + final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */); + final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */); + assertNotNull(snapshotA); + assertNotNull(snapshotB); + assertTrue(snapshotA.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); + assertTrue(snapshotB.getWindowingMode() == WINDOWING_MODE_PINNED); + } + + @Test public void testRemoveObsoleteFiles() { mPersister.persistSnapshot(1, mTestUserId, createSnapshot()); mPersister.persistSnapshot(2, mTestUserId, createSnapshot()); diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index 2ad5bf404052..6a4acbe47beb 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE; import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY; @@ -84,16 +85,16 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { } TaskSnapshot createSnapshot(float scale) { - return createSnapshot(scale, true /* isRealSnapshot */); + return createSnapshot(scale, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN); } - TaskSnapshot createSnapshot(float scale, boolean isRealSnapshot) { + TaskSnapshot createSnapshot(float scale, boolean isRealSnapshot, int windowingMode) { final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); Canvas c = buffer.lockCanvas(); c.drawColor(Color.RED); buffer.unlockCanvasAndPost(c); return new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, TEST_INSETS, - scale < 1f /* reducedResolution */, scale, isRealSnapshot); + scale < 1f /* reducedResolution */, scale, isRealSnapshot, windowingMode); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index d5334babc1a6..54d02d4f2ad2 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static org.junit.Assert.assertEquals; @@ -60,7 +61,8 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888, GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER); final TaskSnapshot snapshot = new TaskSnapshot(buffer, - ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */); + ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */, + WINDOWING_MODE_FULLSCREEN); mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test", Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds, ORIENTATION_PORTRAIT); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java index 8446d252323f..6c7830e5cf79 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java @@ -17,6 +17,8 @@ package com.android.server.wm; import android.support.test.filters.FlakyTest; +import android.view.SurfaceControl; +import android.view.SurfaceSession; import org.junit.Test; import org.junit.runner.RunWith; @@ -43,6 +45,9 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyFloat; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -108,6 +113,21 @@ public class WindowContainerTests extends WindowTestsBase { } @Test + public void testAddChildSetsSurfacePosition() throws Exception { + MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(); + + final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class); + sWm.mTransactionFactory = () -> transaction; + + WindowContainer child = new WindowContainer(sWm); + child.setBounds(1, 1, 10, 10); + + verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat()); + top.addChild(child, 0); + verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f)); + } + + @Test public void testAdd_AlreadyHasParent() throws Exception { final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); final TestWindowContainer root = builder.setLayer(0).build(); @@ -825,4 +845,28 @@ public class WindowContainerTests extends WindowTestsBase { return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible, mOrientation); } } + + private class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer> { + final SurfaceSession mSession = new SurfaceSession(); + + MockSurfaceBuildingContainer() { + super(sWm); + } + + class MockSurfaceBuilder extends SurfaceControl.Builder { + MockSurfaceBuilder(SurfaceSession ss) { + super(ss); + } + + @Override + public SurfaceControl build() { + return mock(SurfaceControl.class); + } + } + + @Override + SurfaceControl.Builder makeChildSurface(WindowContainer child) { + return new MockSurfaceBuilder(mSession); + } + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java index 9ef0ec7ac99b..4668ed42b11e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java @@ -267,6 +267,32 @@ public class ManagedServicesTest extends UiServiceTestCase { } @Test + public void testReadXml_appendsListOfApprovedComponents() throws Exception { + for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { + ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, + mIpm, approvalLevel); + + String preApprovedPackage = "some.random.package"; + String preApprovedComponent = "some.random.package/C1"; + + List<String> packages = new ArrayList<>(); + packages.add(preApprovedPackage); + addExpectedServices(service, packages, 0); + + service.setPackageOrComponentEnabled(preApprovedComponent, 0, true, true); + + loadXml(service); + + verifyExpectedApprovedEntries(service); + + String verifyValue = (approvalLevel == APPROVAL_BY_COMPONENT) + ? preApprovedComponent + : preApprovedPackage; + assertTrue(service.isPackageOrComponentAllowed(verifyValue, 0)); + } + } + + @Test public void testWriteXml_trimsMissingServices() throws Exception { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 19061f94a6b9..c850004a54d8 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1124,6 +1124,41 @@ public class TelephonyManager { */ public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID"; + /** + * Broadcast intent action indicating that when data stall recovery is attempted by Telephony, + * intended for report every data stall recovery step attempted. + * + * <p> + * The {@link #EXTRA_RECOVERY_ACTION} extra indicates the action associated with the data + * stall recovery. + * The phone id where the data stall recovery is attempted. + * + * <p class="note"> + * Requires the READ_PHONE_STATE permission. + * + * <p class="note"> + * This is a protected intent that can only be sent by the system. + * + * @see #EXTRA_RECOVERY_ACTION + * + * @hide + */ + // TODO(b/78370030) : Restrict this to system applications only + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + public static final String ACTION_DATA_STALL_DETECTED = + "android.intent.action.DATA_STALL_DETECTED"; + + /** + * An int extra used with {@link #ACTION_DATA_STALL_DETECTED} to indicate the + * action associated with the data stall recovery. + * + * @see #ACTION_DATA_STALL_DETECTED + * + * @hide + */ + public static final String EXTRA_RECOVERY_ACTION = "recoveryAction"; + // // // Device Info diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 482d6e1fdb31..5b73bbaa1c73 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -84,6 +84,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.CaptivePortal; import android.net.ConnectivityManager; @@ -201,6 +202,7 @@ public class ConnectivityServiceTest { @Mock DefaultNetworkMetrics mDefaultNetworkMetrics; @Mock INetworkManagementService mNetworkManagementService; @Mock INetworkStatsService mStatsService; + @Mock Vpn mMockVpn; private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class); @@ -505,6 +507,7 @@ public class ConnectivityServiceTest { mWrappedNetworkMonitor.gen204ProbeResult = 204; NetworkRequest request = new NetworkRequest.Builder() .addTransportType(mNetworkCapabilities.getTransportTypes()[0]) + .clearCapabilities() .build(); callback = new NetworkCallback() { public void onCapabilitiesChanged(Network network, @@ -888,6 +891,15 @@ public class ConnectivityServiceTest { return mLastCreatedNetworkMonitor; } + public void mockVpn(int uid) { + synchronized (mVpns) { + // This has no effect unless the VPN is actually connected, because things like + // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN + // netId, and check if that network is actually connected. + mVpns.put(UserHandle.getUserId(Process.myUid()), mMockVpn); + } + } + public void waitForIdle(int timeoutMs) { waitForIdleHandler(mHandlerThread, timeoutMs); } @@ -914,6 +926,7 @@ public class ConnectivityServiceTest { MockitoAnnotations.initMocks(this); when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics); + when(mMockVpn.appliesToUid(Process.myUid())).thenReturn(true); // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. // http://b/25897652 . @@ -935,6 +948,7 @@ public class ConnectivityServiceTest { // getSystemService() correctly. mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService); mService.systemReady(); + mService.mockVpn(Process.myUid()); mCm.bindProcessToNetwork(null); // Ensure that the default setting for Captive Portals is used for most tests @@ -1347,6 +1361,7 @@ public class ConnectivityServiceTest { private final static int TIMEOUT_MS = 100; private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>(); + private Network mLastAvailableNetwork; protected void setLastCallback(CallbackState state, Network network, Object o) { mCallbacks.offer(new CallbackInfo(state, network, o)); @@ -1354,6 +1369,7 @@ public class ConnectivityServiceTest { @Override public void onAvailable(Network network) { + mLastAvailableNetwork = network; setLastCallback(CallbackState.AVAILABLE, network, null); } @@ -1389,9 +1405,14 @@ public class ConnectivityServiceTest { @Override public void onLost(Network network) { + mLastAvailableNetwork = null; setLastCallback(CallbackState.LOST, network, null); } + public Network getLastAvailableNetwork() { + return mLastAvailableNetwork; + } + CallbackInfo nextCallback(int timeoutMs) { CallbackInfo cb = null; try { @@ -1658,6 +1679,7 @@ public class ConnectivityServiceTest { callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mWiFiNetworkAgent.connect(true); // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request. @@ -1668,6 +1690,7 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mEthernetNetworkAgent.connect(true); callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent); @@ -1676,11 +1699,13 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent); defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent); assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mEthernetNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent); defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); for (int i = 0; i < 4; i++) { MockNetworkAgent oldNetwork, newNetwork; @@ -1709,6 +1734,7 @@ public class ConnectivityServiceTest { defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent); defaultCallback.assertNoCallback(); callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Wifi no longer satisfies our listen, which is for an unmetered network. // But because its score is 55, it's still up (and the default network). @@ -1718,8 +1744,11 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.disconnect(); defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mCellNetworkAgent.disconnect(); defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); + waitForIdle(); + assertEquals(null, mCm.getActiveNetwork()); mCm.unregisterNetworkCallback(callback); waitForIdle(); @@ -1736,6 +1765,7 @@ public class ConnectivityServiceTest { callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up wifi with a score of 20. // Cell stays up because it would satisfy the default request if it validated. @@ -1744,12 +1774,14 @@ public class ConnectivityServiceTest { callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up wifi with a score of 70. // Cell is lingered because it would not satisfy any request, even if it validated. @@ -1760,6 +1792,7 @@ public class ConnectivityServiceTest { callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Tear down wifi. mWiFiNetworkAgent.disconnect(); @@ -1767,6 +1800,7 @@ public class ConnectivityServiceTest { defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but // it's arguably correct to linger it, since it was the default network before it validated. @@ -1778,6 +1812,7 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); @@ -1786,12 +1821,15 @@ public class ConnectivityServiceTest { mCellNetworkAgent.disconnect(); callback.expectCallback(CallbackState.LOST, mCellNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); + waitForIdle(); + assertEquals(null, mCm.getActiveNetwork()); // If a network is lingering, and we add and remove a request from it, resume lingering. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); @@ -1799,6 +1837,7 @@ public class ConnectivityServiceTest { // TODO: Investigate sending validated before losing. callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); NetworkRequest cellRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_CELLULAR).build(); @@ -1815,6 +1854,7 @@ public class ConnectivityServiceTest { callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Cell is now the default network. Pin it with a cell-specific request. noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525 @@ -1825,6 +1865,7 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.connect(true); callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // The default request is lingering on cell, but nothing happens to cell, and we send no // callbacks for it, because it's kept up by cellRequest. callback.assertNoCallback(); @@ -1848,6 +1889,7 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent); trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent); defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Let linger run its course. callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs); @@ -2496,23 +2538,27 @@ public class ConnectivityServiceTest { mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up wifi and expect CALLBACK_AVAILABLE. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); cellNetworkCallback.assertNoCallback(); defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring down cell. Expect no default network callback, since it wasn't the default. mCellNetworkAgent.disconnect(); cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); defaultNetworkCallback.assertNoCallback(); + assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring up cell. Expect no default network callback, since it won't be the default. mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); defaultNetworkCallback.assertNoCallback(); + assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); // Bring down wifi. Expect the default network callback to notified of LOST wifi // followed by AVAILABLE cell. @@ -2523,6 +2569,23 @@ public class ConnectivityServiceTest { mCellNetworkAgent.disconnect(); cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); + waitForIdle(); + assertEquals(null, mCm.getActiveNetwork()); + + final int uid = Process.myUid(); + final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet<UidRange> ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId); + vpnNetworkAgent.setUids(ranges); + vpnNetworkAgent.connect(true); + defaultNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); + assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + vpnNetworkAgent.disconnect(); + defaultNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); + waitForIdle(); + assertEquals(null, mCm.getActiveNetwork()); } @Test @@ -4015,6 +4078,7 @@ public class ConnectivityServiceTest { final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback(); final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback(); final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback(); + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build(); final NetworkRequest genericRequest = new NetworkRequest.Builder() .removeCapability(NET_CAPABILITY_NOT_VPN).build(); @@ -4027,6 +4091,8 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback); mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback); mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); + mCm.registerDefaultNetworkCallback(defaultCallback); + defaultCallback.assertNoCallback(); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); @@ -4034,15 +4100,14 @@ public class ConnectivityServiceTest { genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); vpnNetworkCallback.assertNoCallback(); - - // TODO : check callbacks agree with the return value of mCm.getActiveNetwork(). - // Right now this is not possible because establish() is not adequately instrumented - // in this test. + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); final ArraySet<UidRange> ranges = new ArraySet<>(); ranges.add(new UidRange(uid, uid)); + when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId); vpnNetworkAgent.setUids(ranges); vpnNetworkAgent.connect(false); @@ -4050,10 +4115,14 @@ public class ConnectivityServiceTest { genericNotVpnNetworkCallback.assertNoCallback(); wifiNetworkCallback.assertNoCallback(); vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent); + defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); ranges.clear(); vpnNetworkAgent.setUids(ranges); @@ -4063,6 +4132,14 @@ public class ConnectivityServiceTest { wifiNetworkCallback.assertNoCallback(); vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); + // TODO : The default network callback should actually get a LOST call here (also see the + // comment below for AVAILABLE). This is because ConnectivityService does not look at UID + // ranges at all when determining whether a network should be rematched. In practice, VPNs + // can't currently update their UIDs without disconnecting, so this does not matter too + // much, but that is the reason the test here has to check for an update to the + // capabilities instead of the expected LOST then AVAILABLE. + defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent); + ranges.add(new UidRange(uid, uid)); vpnNetworkAgent.setUids(ranges); @@ -4070,6 +4147,9 @@ public class ConnectivityServiceTest { genericNotVpnNetworkCallback.assertNoCallback(); wifiNetworkCallback.assertNoCallback(); vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); + // TODO : Here like above, AVAILABLE would be correct, but because this can't actually + // happen outside of the test, ConnectivityService does not rematch callbacks. + defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent); mWiFiNetworkAgent.disconnect(); @@ -4077,6 +4157,7 @@ public class ConnectivityServiceTest { genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); vpnNetworkCallback.assertNoCallback(); + defaultCallback.assertNoCallback(); vpnNetworkAgent.disconnect(); @@ -4084,9 +4165,61 @@ public class ConnectivityServiceTest { genericNotVpnNetworkCallback.assertNoCallback(); wifiNetworkCallback.assertNoCallback(); vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); + defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); + assertEquals(null, mCm.getActiveNetwork()); mCm.unregisterNetworkCallback(genericNetworkCallback); mCm.unregisterNetworkCallback(wifiNetworkCallback); mCm.unregisterNetworkCallback(vpnNetworkCallback); + mCm.unregisterNetworkCallback(defaultCallback); + } + + @Test + public void testVpnWithAndWithoutInternet() { + final int uid = Process.myUid(); + + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultCallback); + defaultCallback.assertNoCallback(); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet<UidRange> ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId); + vpnNetworkAgent.setUids(ranges); + vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */); + + defaultCallback.assertNoCallback(); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + vpnNetworkAgent.disconnect(); + defaultCallback.assertNoCallback(); + + vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId); + vpnNetworkAgent.setUids(ranges); + vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */); + defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + vpnNetworkAgent.disconnect(); + defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); + defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + + vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId); + ranges.clear(); + vpnNetworkAgent.setUids(ranges); + + vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */); + defaultCallback.assertNoCallback(); + + mCm.unregisterNetworkCallback(defaultCallback); } } diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index a3b766481887..b90e7b3042f9 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -798,35 +798,39 @@ class LinkCommand { return; } - xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionCode"); - if (attr != nullptr) { - Maybe<std::string>& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version; - if (BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get())) { - switch (prim->value.dataType) { - case Res_value::TYPE_INT_DEC: - compile_sdk_version = StringPrintf("%" PRId32, static_cast<int32_t>(prim->value.data)); - break; - case Res_value::TYPE_INT_HEX: - compile_sdk_version = StringPrintf("%" PRIx32, prim->value.data); - break; - default: - break; + if (!options_.manifest_fixer_options.compile_sdk_version) { + xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionCode"); + if (attr != nullptr) { + Maybe<std::string>& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version; + if (BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get())) { + switch (prim->value.dataType) { + case Res_value::TYPE_INT_DEC: + compile_sdk_version = StringPrintf("%" PRId32, static_cast<int32_t>(prim->value.data)); + break; + case Res_value::TYPE_INT_HEX: + compile_sdk_version = StringPrintf("%" PRIx32, prim->value.data); + break; + default: + break; + } + } else if (String* str = ValueCast<String>(attr->compiled_value.get())) { + compile_sdk_version = *str->value; + } else { + compile_sdk_version = attr->value; } - } else if (String* str = ValueCast<String>(attr->compiled_value.get())) { - compile_sdk_version = *str->value; - } else { - compile_sdk_version = attr->value; } } - attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionName"); - if (attr != nullptr) { - Maybe<std::string>& compile_sdk_version_codename = - options_.manifest_fixer_options.compile_sdk_version_codename; - if (String* str = ValueCast<String>(attr->compiled_value.get())) { - compile_sdk_version_codename = *str->value; - } else { - compile_sdk_version_codename = attr->value; + if (!options_.manifest_fixer_options.compile_sdk_version_codename) { + xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionName"); + if (attr != nullptr) { + Maybe<std::string>& compile_sdk_version_codename = + options_.manifest_fixer_options.compile_sdk_version_codename; + if (String* str = ValueCast<String>(attr->compiled_value.get())) { + compile_sdk_version_codename = *str->value; + } else { + compile_sdk_version_codename = attr->value; + } } } } @@ -2102,6 +2106,13 @@ int Link(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) { .OptionalFlag("--version-name", "Version name to inject into the AndroidManifest.xml if none is present.", &options.manifest_fixer_options.version_name_default) + .OptionalFlag("--compile-sdk-version-code", + "Version code (integer) to inject into the AndroidManifest.xml if none is\n" + "present.", + &options.manifest_fixer_options.compile_sdk_version) + .OptionalFlag("--compile-sdk-version-name", + "Version name to inject into the AndroidManifest.xml if none is present.", + &options.manifest_fixer_options.compile_sdk_version_codename) .OptionalSwitch("--shared-lib", "Generates a shared Android runtime library.", &shared_lib) .OptionalSwitch("--static-lib", "Generate a static Android library.", &static_lib) diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py index ec40a2229c33..ffca46696a7c 100755 --- a/tools/fonts/fontchain_linter.py +++ b/tools/fonts/fontchain_linter.py @@ -471,11 +471,20 @@ def parse_ucd(ucd_path): _emoji_zwj_sequences.update(parse_unicode_datafile( path.join(ucd_path, 'additions', 'emoji-zwj-sequences.txt'))) + exclusions = parse_unicode_datafile(path.join(ucd_path, 'additions', 'emoji-exclusions.txt')) + _emoji_sequences = remove_emoji_exclude(_emoji_sequences, exclusions) + _emoji_zwj_sequences = remove_emoji_exclude(_emoji_zwj_sequences, exclusions) + _emoji_variation_sequences = remove_emoji_variation_exclude(_emoji_variation_sequences, exclusions) + +def remove_emoji_variation_exclude(source, items): + return source.difference(items.keys()) + +def remove_emoji_exclude(source, items): + return {k: v for k, v in source.items() if k not in items} def flag_sequence(territory_code): return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code) - UNSUPPORTED_FLAGS = frozenset({ flag_sequence('BL'), flag_sequence('BQ'), flag_sequence('DG'), flag_sequence('EA'), flag_sequence('EH'), flag_sequence('FK'), @@ -522,8 +531,6 @@ LEGACY_ANDROID_EMOJI = { ZWJ_IDENTICALS = { # KISS (0x1F469, 0x200D, 0x2764, 0x200D, 0x1F48B, 0x200D, 0x1F468): 0x1F48F, - # COUPLE WITH HEART - (0x1F469, 0x200D, 0x2764, 0x200D, 0x1F468): 0x1F491, # FAMILY (0x1F468, 0x200D, 0x1F469, 0x200D, 0x1F466): 0x1F46A, } @@ -576,6 +583,8 @@ GENDER_DEFAULTS = [ (0x1F9DD, FEMALE_SIGN), # ELF (0x1F9DE, FEMALE_SIGN), # GENIE (0x1F9DF, FEMALE_SIGN), # ZOMBIE + (0X1F9B8, FEMALE_SIGN), # SUPERVILLAIN + (0x1F9B9, FEMALE_SIGN), # SUPERHERO ] def is_fitzpatrick_modifier(cp): diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh index ebcc2a2f34a2..4e52b8f23399 100755 --- a/wifi/tests/runtests.sh +++ b/wifi/tests/runtests.sh @@ -21,4 +21,5 @@ adb wait-for-device adb install -r -g "$OUT/data/app/FrameworksWifiApiTests/FrameworksWifiApiTests.apk" -adb shell am instrument -w "$@" 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner' +adb shell am instrument --no-hidden-api-checks -w "$@" \ + 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner' |