diff options
81 files changed, 1357 insertions, 697 deletions
diff --git a/Android.bp b/Android.bp index add6117895e0..e120efd2bf03 100644 --- a/Android.bp +++ b/Android.bp @@ -1039,6 +1039,7 @@ droiddoc { ], api_filename: "public_api.txt", removed_api_filename: "removed.txt", + removed_dex_api_filename: "removed-dex.txt", args: framework_docs_args + " -referenceonly -nodocs", } diff --git a/api/test-current.txt b/api/test-current.txt index 73b72fae08ce..50aaa0a22c91 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -965,13 +965,6 @@ package android.telephony { method public void setCarrierTestOverride(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String); field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff } - - public class TelephonyManager { - method public int getCarrierIdListVersion(); - method public void setCarrierTestOverride(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String); - field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff - } - } package android.telephony.mbms { diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 71f126f3245f..a1219ea28546 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -229,6 +229,7 @@ Landroid/app/AppOpsManager;->OP_WIFI_SCAN:I Landroid/app/AppOpsManager;->OP_WRITE_CONTACTS:I Landroid/app/AppOpsManager;->OP_WRITE_SMS:I Landroid/app/AppOpsManager;->permissionToOpCode(Ljava/lang/String;)I +Landroid/app/AppOpsManager;->setRestriction(III[Ljava/lang/String;)V Landroid/app/AppOpsManager;->sOpPerms:[Ljava/lang/String; Landroid/app/AppOpsManager;->strOpToOp(Ljava/lang/String;)I Landroid/app/backup/BackupDataInput$EntityHeader;->dataSize:I @@ -420,6 +421,7 @@ Landroid/app/NotificationManager;->sService:Landroid/app/INotificationManager; Landroid/app/PendingIntent;->getActivityAsUser(Landroid/content/Context;ILandroid/content/Intent;ILandroid/os/Bundle;Landroid/os/UserHandle;)Landroid/app/PendingIntent; Landroid/app/PendingIntent;->getIntent()Landroid/content/Intent; Landroid/app/PendingIntent;->isActivity()Z +Landroid/app/PictureInPictureParams;->getAspectRatio()F Landroid/app/Presentation;->createPresentationContext(Landroid/content/Context;Landroid/view/Display;I)Landroid/content/Context; Landroid/app/ProgressDialog;->mProgressNumber:Landroid/widget/TextView; Landroid/app/QueuedWork;->addFinisher(Ljava/lang/Runnable;)V @@ -695,6 +697,7 @@ Landroid/content/pm/IPackageDataObserver$Stub$Proxy;-><init>(Landroid/os/IBinder Landroid/content/pm/IPackageDataObserver$Stub$Proxy;->mRemote:Landroid/os/IBinder; Landroid/content/pm/IPackageDataObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDataObserver; Landroid/content/pm/IPackageDataObserver;->onRemoveCompleted(Ljava/lang/String;Z)V +Landroid/content/pm/IPackageDeleteObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDeleteObserver; Landroid/content/pm/IPackageDeleteObserver2$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/content/pm/IPackageDeleteObserver2$Stub$Proxy;->mRemote:Landroid/os/IBinder; Landroid/content/pm/IPackageDeleteObserver2;->onPackageDeleted(Ljava/lang/String;ILjava/lang/String;)V @@ -738,6 +741,7 @@ Landroid/content/pm/IPackageMoveObserver$Stub;->asInterface(Landroid/os/IBinder; Landroid/content/pm/IPackageStatsObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/content/pm/IPackageStatsObserver$Stub$Proxy;->mRemote:Landroid/os/IBinder; Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V +Landroid/content/pm/IPackageStatsObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageStatsObserver; Landroid/content/pm/IShortcutService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/content/pm/IShortcutService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IShortcutService; Landroid/content/pm/LauncherActivityInfo;->mActivityInfo:Landroid/content/pm/ActivityInfo; @@ -796,6 +800,7 @@ Landroid/content/pm/PackageParser$Package;->applicationInfo:Landroid/content/pm/ Landroid/content/pm/PackageParser$Package;->configPreferences:Ljava/util/ArrayList; Landroid/content/pm/PackageParser$Package;->instrumentation:Ljava/util/ArrayList; Landroid/content/pm/PackageParser$Package;->mAppMetaData:Landroid/os/Bundle; +Landroid/content/pm/PackageParser$Package;->mKeySetMapping:Landroid/util/ArrayMap; Landroid/content/pm/PackageParser$Package;->mPreferredOrder:I Landroid/content/pm/PackageParser$Package;->mSharedUserId:Ljava/lang/String; Landroid/content/pm/PackageParser$Package;->mSharedUserLabel:I @@ -891,6 +896,7 @@ 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/ResourcesImpl;->getAssets()Landroid/content/res/AssetManager; +Landroid/content/res/ResourcesImpl;->getValue(ILandroid/util/TypedValue;Z)V Landroid/content/res/ResourcesImpl;->mAccessLock:Ljava/lang/Object; Landroid/content/res/ResourcesImpl;->mAnimatorCache:Landroid/content/res/ConfigurationBoundResourceCache; Landroid/content/res/ResourcesImpl;->mAssets:Landroid/content/res/AssetManager; @@ -1262,6 +1268,7 @@ Landroid/icu/text/SpoofChecker$ScriptSet;->isFull()Z Landroid/icu/text/SpoofChecker$ScriptSet;->setAll()V Landroid/icu/text/TimeZoneNames$DefaultTimeZoneNames$FactoryImpl;-><init>()V Landroid/icu/text/Transliterator;->createFromRules(Ljava/lang/String;Ljava/lang/String;I)Landroid/icu/text/Transliterator; +Landroid/icu/text/Transliterator;->getInstance(Ljava/lang/String;)Landroid/icu/text/Transliterator; Landroid/icu/text/Transliterator;->transliterate(Ljava/lang/String;)Ljava/lang/String; Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale; Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale; @@ -2093,6 +2100,7 @@ Landroid/R$styleable;->CheckedTextView:[I Landroid/R$styleable;->CheckedTextView_checkMark:I Landroid/R$styleable;->CompoundButton:[I Landroid/R$styleable;->CompoundButton_button:I +Landroid/R$styleable;->DrawableStates:[I Landroid/R$styleable;->ImageView:[I Landroid/R$styleable;->ImageView_adjustViewBounds:I Landroid/R$styleable;->ImageView_baselineAlignBottom:I @@ -2355,6 +2363,7 @@ Landroid/telephony/CellSignalStrengthLte;->mRsrp:I Landroid/telephony/CellSignalStrengthLte;->mRsrq:I Landroid/telephony/CellSignalStrengthLte;->mRssnr:I Landroid/telephony/CellSignalStrengthLte;->mSignalStrength:I +Landroid/telephony/CellSignalStrengthLte;->mTimingAdvance:I Landroid/telephony/CellSignalStrengthWcdma;->mBitErrorRate:I Landroid/telephony/CellSignalStrengthWcdma;->mSignalStrength:I Landroid/telephony/PhoneNumberUtils;->isLocalEmergencyNumber(Landroid/content/Context;ILjava/lang/String;)Z @@ -2364,6 +2373,7 @@ Landroid/telephony/SignalStrength;-><init>()V Landroid/telephony/SignalStrength;->getAsuLevel()I Landroid/telephony/SignalStrength;->getCdmaLevel()I Landroid/telephony/SignalStrength;->getDbm()I +Landroid/telephony/SignalStrength;->getGsmDbm()I Landroid/telephony/SignalStrength;->getLteDbm()I Landroid/telephony/SignalStrength;->getLteRsrp()I Landroid/telephony/SignalStrength;->getLteRsrq()I @@ -2428,6 +2438,7 @@ Landroid/telephony/TelephonyManager;->getSubscriberInfo()Lcom/android/internal/t Landroid/telephony/TelephonyManager;->hasIccCard(I)Z Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z Landroid/telephony/TelephonyManager;->isNetworkRoaming(I)Z +Landroid/telephony/TelephonyManager;->isVideoTelephonyAvailable()Z Landroid/telephony/TelephonyManager;->isVolteAvailable()Z Landroid/telephony/TelephonyManager;->isWifiCallingAvailable()Z Landroid/telephony/TelephonyManager;->mSubscriptionManager:Landroid/telephony/SubscriptionManager; @@ -2606,6 +2617,7 @@ Landroid/view/inputmethod/InputMethodInfo;->mSubtypes:Landroid/view/inputmethod/ Landroid/view/inputmethod/InputMethodManager;->finishInputLocked()V Landroid/view/inputmethod/InputMethodManager;->focusIn(Landroid/view/View;)V Landroid/view/inputmethod/InputMethodManager;->focusOut(Landroid/view/View;)V +Landroid/view/inputmethod/InputMethodManager;->getClient()Lcom/android/internal/view/IInputMethodClient; Landroid/view/inputmethod/InputMethodManager;->getInputMethodWindowVisibleHeight()I Landroid/view/inputmethod/InputMethodManager;->getInstance()Landroid/view/inputmethod/InputMethodManager; Landroid/view/inputmethod/InputMethodManager;->mCurId:Ljava/lang/String; @@ -2782,6 +2794,7 @@ Landroid/view/View;->getWindowDisplayFrame(Landroid/graphics/Rect;)V Landroid/view/View;->includeForAccessibility()Z Landroid/view/View;->initializeScrollbars(Landroid/content/res/TypedArray;)V Landroid/view/View;->internalSetPadding(IIII)V +Landroid/view/View;->invalidateParentIfNeeded()V Landroid/view/View;->isPaddingResolved()Z Landroid/view/View;->isRootNamespace()Z Landroid/view/View;->isVisibleToUser()Z @@ -3066,6 +3079,7 @@ Landroid/widget/ImageView;->mAlpha:I Landroid/widget/ImageView;->mDrawMatrix:Landroid/graphics/Matrix; Landroid/widget/ImageView;->mMaxHeight:I Landroid/widget/ImageView;->mMaxWidth:I +Landroid/widget/ImageView;->mRecycleableBitmapDrawable:Landroid/graphics/drawable/BitmapDrawable; Landroid/widget/ImageView;->mResource:I Landroid/widget/ImageView;->mUri:Landroid/net/Uri; Landroid/widget/ImageView;->updateDrawable(Landroid/graphics/drawable/Drawable;)V @@ -3570,11 +3584,13 @@ Lcom/android/internal/telephony/ITelephony;->dial(Ljava/lang/String;)V Lcom/android/internal/telephony/ITelephony;->disableDataConnectivity()Z Lcom/android/internal/telephony/ITelephony;->enableDataConnectivity()Z Lcom/android/internal/telephony/ITelephony;->endCall()Z +Lcom/android/internal/telephony/ITelephony;->endCallForSubscriber(I)Z Lcom/android/internal/telephony/ITelephony;->getCallState()I Lcom/android/internal/telephony/ITelephony;->getDataState()I Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z Lcom/android/internal/telephony/ITelephony;->setRadio(Z)Z Lcom/android/internal/telephony/ITelephony;->silenceRinger()V +Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Lcom/android/internal/telephony/ITelephonyRegistry$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephonyRegistry; Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCallState(ILjava/lang/String;)V Lcom/android/internal/telephony/SmsHeader$ConcatRef;->msgCount:I @@ -3711,6 +3727,7 @@ Ldalvik/system/VMDebug;->dumpReferenceTables()V Ldalvik/system/VMDebug;->isDebuggerConnected()Z Ldalvik/system/VMRuntime;->addressOf(Ljava/lang/Object;)J Ldalvik/system/VMRuntime;->clearGrowthLimit()V +Ldalvik/system/VMRuntime;->gcSoftReferences()V Ldalvik/system/VMRuntime;->getCurrentInstructionSet()Ljava/lang/String; Ldalvik/system/VMRuntime;->getExternalBytesAllocated()J Ldalvik/system/VMRuntime;->getInstructionSet(Ljava/lang/String;)Ljava/lang/String; diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index a44bd0305875..07b4b9c39e1e 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -16,8 +16,6 @@ package android.app; -import com.android.internal.app.AlertController; - import android.annotation.ArrayRes; import android.annotation.AttrRes; import android.annotation.DrawableRes; @@ -30,17 +28,19 @@ import android.database.Cursor; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Message; +import android.text.Layout; +import android.text.method.MovementMethod; import android.util.TypedValue; import android.view.ContextThemeWrapper; import android.view.KeyEvent; import android.view.View; -import android.view.WindowManager; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListAdapter; import android.widget.ListView; import com.android.internal.R; +import com.android.internal.app.AlertController; /** * A subclass of Dialog that can display one, two or three buttons. If you only want to @@ -54,7 +54,7 @@ import com.android.internal.R; * </pre> * * <p>The AlertDialog class takes care of automatically setting - * {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM + * {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} for you based on whether * any views in the dialog return true from {@link View#onCheckIsTextEditor() * View.onCheckIsTextEditor()}. Generally you want this set for a Dialog @@ -266,6 +266,17 @@ public class AlertDialog extends Dialog implements DialogInterface { mAlert.setMessage(message); } + /** @hide */ + public void setMessageMovementMethod(MovementMethod movementMethod) { + mAlert.setMessageMovementMethod(movementMethod); + } + + /** @hide */ + public void setMessageHyphenationFrequency( + @Layout.HyphenationFrequency int hyphenationFrequency) { + mAlert.setMessageHyphenationFrequency(hyphenationFrequency); + } + /** * Set the view to display in that dialog. */ diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 30451c247650..583f060f2e0c 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -93,6 +93,8 @@ public final class Trace { public static final long TRACE_TAG_VIBRATOR = 1L << 23; /** @hide */ public static final long TRACE_TAG_AIDL = 1L << 24; + /** @hide */ + public static final long TRACE_TAG_NNAPI = 1L << 25; private static final long TRACE_TAG_NOT_READY = 1L << 63; private static final int MAX_SECTION_NAME_LEN = 127; diff --git a/core/java/android/printservice/recommendation/RecommendationService.java b/core/java/android/printservice/recommendation/RecommendationService.java index 733629aa3564..968a62585d8e 100644 --- a/core/java/android/printservice/recommendation/RecommendationService.java +++ b/core/java/android/printservice/recommendation/RecommendationService.java @@ -119,14 +119,16 @@ public abstract class RecommendationService extends Service { mCallbacks = null; break; case MSG_UPDATE: - // Note that there might be a connection change in progress. In this case the - // message is handled as before the change. This is acceptable as the caller of - // the connection change has not guarantee when the connection change binder - // transaction is actually processed. - try { - mCallbacks.onRecommendationsUpdated((List<RecommendationInfo>) msg.obj); - } catch (RemoteException | NullPointerException e) { - Log.e(LOG_TAG, "Could not update recommended services", e); + if (mCallbacks != null) { + // Note that there might be a connection change in progress. In this case + // the message is handled as before the change. This is acceptable as the + // caller of the connection change has not guarantee when the connection + // change binder transaction is actually processed. + try { + mCallbacks.onRecommendationsUpdated((List<RecommendationInfo>) msg.obj); + } catch (RemoteException | NullPointerException e) { + Log.e(LOG_TAG, "Could not update recommended services", e); + } } break; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 9751b7f9ddf2..da452697c219 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10804,16 +10804,29 @@ public final class Settings { public static final String SYNC_MANAGER_CONSTANTS = "sync_manager_constants"; /** - * Whether or not App Standby feature is enabled. This controls throttling of apps - * based on usage patterns and predictions. + * Whether or not App Standby feature is enabled by system. This controls throttling of apps + * based on usage patterns and predictions. Platform will turn on this feature if both this + * flag and {@link #ADAPTIVE_BATTERY_MANAGEMENT_ENABLED} is on. * Type: int (0 for false, 1 for true) * Default: 1 * @hide + * @see #ADAPTIVE_BATTERY_MANAGEMENT_ENABLED */ @SystemApi public static final String APP_STANDBY_ENABLED = "app_standby_enabled"; /** + * Whether or not adaptive battery feature is enabled by user. Platform will turn on this + * feature if both this flag and {@link #APP_STANDBY_ENABLED} is on. + * Type: int (0 for false, 1 for true) + * Default: 1 + * @hide + * @see #APP_STANDBY_ENABLED + */ + public static final String ADAPTIVE_BATTERY_MANAGEMENT_ENABLED = + "adaptive_battery_management_enabled"; + + /** * Whether or not app auto restriction is enabled. When it is enabled, settings app will * auto restrict the app if it has bad behavior(e.g. hold wakelock for long time). * diff --git a/core/java/android/service/autofill/BatchUpdates.java b/core/java/android/service/autofill/BatchUpdates.java index 90acc881e171..2ba03762ec29 100644 --- a/core/java/android/service/autofill/BatchUpdates.java +++ b/core/java/android/service/autofill/BatchUpdates.java @@ -82,6 +82,9 @@ public final class BatchUpdates implements Parcelable { * {@link #transformChild(int, Transformation) transformations} are applied to the children * views. * + * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color + * or background color: Autofill on different platforms may have different themes. + * * @param updates a {@link RemoteViews} with the updated actions to be applied in the * underlying presentation template. * diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java index ccec483d046b..521176797657 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -336,6 +336,9 @@ public final class Dataset implements Parcelable { * higher, datasets that require authentication can be also be filtered by passing a * {@link AutofillValue#forText(CharSequence) text value} as the {@code value} parameter. * + * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color + * or background color: Autofill on different platforms may have different themes. + * * @param id id returned by {@link * android.app.assist.AssistStructure.ViewNode#getAutofillId()}. * @param value the value to be autofilled. Pass {@code null} if you do not have the value diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index 2bc4b8f7baf2..7bf1f83f6bd8 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -241,6 +241,9 @@ public final class FillResponse implements Parcelable { * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the * platform needs to fill in the authentication arguments. * + * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color + * or background color: Autofill on different platforms may have different themes. + * * @param authentication Intent to an activity with your authentication flow. * @param presentation The presentation to visualize the response. * @param ids id of Views that when focused will display the authentication UI. @@ -449,6 +452,9 @@ public final class FillResponse implements Parcelable { * authentication (as the header could have been set directly in the main presentation in * these cases). * + * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color + * or background color: Autofill on different platforms may have different themes. + * * @param header a presentation to represent the header. This presentation is not clickable * —calling * {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would @@ -477,6 +483,9 @@ public final class FillResponse implements Parcelable { * authentication (as the footer could have been set directly in the main presentation in * these cases). * + * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color + * or background color: Autofill on different platforms may have different themes. + * * @param footer a presentation to represent the footer. This presentation is not clickable * —calling * {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java index a6495d154941..826620710b18 100644 --- a/core/java/android/view/autofill/AutofillPopupWindow.java +++ b/core/java/android/view/autofill/AutofillPopupWindow.java @@ -19,6 +19,7 @@ package android.view.autofill; import static android.view.autofill.Helper.sVerbose; import android.annotation.NonNull; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.IBinder; @@ -79,11 +80,6 @@ public class AutofillPopupWindow extends PopupWindow { public AutofillPopupWindow(@NonNull IAutofillWindowPresenter presenter) { mWindowPresenter = new WindowPresenter(presenter); - // We want to show the window as system controlled one so it covers app windows, but it has - // to be an application type (so it's contained inside the application area). - // Hence, we set it to the application type with the highest z-order, which currently - // is TYPE_APPLICATION_ABOVE_SUB_PANEL. - setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL); setTouchModal(false); setOutsideTouchable(true); setInputMethodMode(INPUT_METHOD_NOT_NEEDED); @@ -110,7 +106,16 @@ public class AutofillPopupWindow extends PopupWindow { */ public void update(View anchor, int offsetX, int offsetY, int width, int height, Rect virtualBounds) { - mFullScreen = width == LayoutParams.MATCH_PARENT && height == LayoutParams.MATCH_PARENT; + mFullScreen = width == LayoutParams.MATCH_PARENT; + // For no fullscreen autofill window, we want to show the window as system controlled one + // so it covers app windows, but it has to be an application type (so it's contained inside + // the application area). Hence, we set it to the application type with the highest z-order, + // which currently is TYPE_APPLICATION_ABOVE_SUB_PANEL. + // For fullscreen mode, autofill window is at the bottom of screen, it should not be + // clipped by app activity window. Fullscreen autofill window does not need to follow app + // anchor view position. + setWindowLayoutType(mFullScreen ? WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG + : WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL); // If we are showing the popup for a virtual view we use a fake view which // delegates to the anchor but present itself with the same bounds as the // virtual view. This ensures that the location logic in popup works @@ -119,6 +124,15 @@ public class AutofillPopupWindow extends PopupWindow { if (mFullScreen) { offsetX = 0; offsetY = 0; + // If it is not fullscreen height, put window at bottom. Computes absolute position. + // Note that we cannot easily change default gravity from Gravity.TOP to + // Gravity.BOTTOM because PopupWindow base class does not expose computeGravity(). + final Point outPoint = new Point(); + anchor.getContext().getDisplay().getSize(outPoint); + width = outPoint.x; + if (height != LayoutParams.MATCH_PARENT) { + offsetY = outPoint.y - height; + } actualAnchor = anchor; } else if (virtualBounds != null) { final int[] mLocationOnScreen = new int[] {virtualBounds.left, virtualBounds.top}; @@ -202,6 +216,16 @@ public class AutofillPopupWindow extends PopupWindow { actualAnchor = anchor; } + if (!mFullScreen) { + // No fullscreen window animation is controlled by PopupWindow. + setAnimationStyle(-1); + } else if (height == LayoutParams.MATCH_PARENT) { + // Complete fullscreen autofill window has no animation. + setAnimationStyle(0); + } else { + // Slide half screen height autofill window from bottom. + setAnimationStyle(com.android.internal.R.style.AutofillHalfScreenAnimation); + } if (!isShowing()) { setWidth(width); setHeight(height); @@ -223,7 +247,12 @@ public class AutofillPopupWindow extends PopupWindow { protected boolean findDropDownPosition(View anchor, LayoutParams outParams, int xOffset, int yOffset, int width, int height, int gravity, boolean allowScroll) { if (mFullScreen) { - // Do not patch LayoutParams if force full screen + // In fullscreen mode, don't need consider the anchor view. + outParams.x = xOffset; + outParams.y = yOffset; + outParams.width = width; + outParams.height = height; + outParams.gravity = gravity; return false; } return super.findDropDownPosition(anchor, outParams, xOffset, yOffset, @@ -316,11 +345,6 @@ public class AutofillPopupWindow extends PopupWindow { } @Override - public void setAnimationStyle(int animationStyle) { - throw new IllegalStateException("You can't call this!"); - } - - @Override public void setBackgroundDrawable(Drawable background) { throw new IllegalStateException("You can't call this!"); } diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index cb362e65911d..f1a1457e9d5c 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -170,7 +170,7 @@ public final class Magnifier { if (mWindow == null) { synchronized (mLock) { mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(), - getValidViewSurface(), + getValidParentSurfaceForMagnifier(), mWindowWidth, mWindowHeight, mWindowElevation, mWindowCornerRadius, Handler.getMain() /* draw the magnifier on the UI thread */, mLock, mCallback); @@ -245,18 +245,20 @@ public final class Magnifier { } @Nullable - private Surface getValidViewSurface() { - // TODO: deduplicate this against the first part of #performPixelCopy - final Surface surface; + private Surface getValidParentSurfaceForMagnifier() { + if (mView.getViewRootImpl() != null) { + final Surface mainWindowSurface = mView.getViewRootImpl().mSurface; + if (mainWindowSurface != null && mainWindowSurface.isValid()) { + return mainWindowSurface; + } + } if (mView instanceof SurfaceView) { - surface = ((SurfaceView) mView).getHolder().getSurface(); - } else if (mView.getViewRootImpl() != null) { - surface = mView.getViewRootImpl().mSurface; - } else { - surface = null; + final Surface surfaceViewSurface = ((SurfaceView) mView).getHolder().getSurface(); + if (surfaceViewSurface != null && surfaceViewSurface.isValid()) { + return surfaceViewSurface; + } } - - return (surface != null && surface.isValid()) ? surface : null; + return null; } private void configureCoordinates(final float xPosInView, final float yPosInView) { @@ -264,12 +266,12 @@ public final class Magnifier { // magnifier. These are relative to the surface the content is copied from. final float posX; final float posY; + mView.getLocationInSurface(mViewCoordinatesInSurface); if (mView instanceof SurfaceView) { // No offset required if the backing Surface matches the size of the SurfaceView. posX = xPosInView; posY = yPosInView; } else { - mView.getLocationInSurface(mViewCoordinatesInSurface); posX = xPosInView + mViewCoordinatesInSurface[0]; posY = yPosInView + mViewCoordinatesInSurface[1]; } @@ -282,6 +284,14 @@ public final class Magnifier { R.dimen.magnifier_offset); mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2; mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset; + if (mView instanceof SurfaceView && mView.getViewRootImpl() != null) { + // TODO: deduplicate against the first part of #getValidParentSurfaceForMagnifier() + final Surface mainWindowSurface = mView.getViewRootImpl().mSurface; + if (mainWindowSurface != null && mainWindowSurface.isValid()) { + mWindowCoords.x += mViewCoordinatesInSurface[0]; + mWindowCoords.y += mViewCoordinatesInSurface[1]; + } + } } private void performPixelCopy(final int startXInSurface, final int startYInSurface, @@ -361,6 +371,9 @@ public final class Magnifier { // The alpha set on the magnifier's content, which defines how // prominent the white background is. private static final int CONTENT_BITMAP_ALPHA = 242; + // The z of the magnifier surface, defining its z order in the list of + // siblings having the same parent surface (usually the main app surface). + private static final int SURFACE_Z = 5; // Display associated to the view the magnifier is attached to. private final Display mDisplay; @@ -602,6 +615,7 @@ public final class Magnifier { mSurfaceControl.setPosition(pendingX, pendingY); } if (firstDraw) { + mSurfaceControl.setLayer(SURFACE_Z); mSurfaceControl.show(); } SurfaceControl.closeTransaction(); diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 5ecbf90a4eca..4865dab6056a 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.ColorInt; import android.annotation.DimenRes; import android.annotation.NonNull; +import android.annotation.StyleRes; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; @@ -56,6 +57,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; +import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.LayoutInflater.Filter; import android.view.RemotableViewMethod; @@ -182,6 +184,12 @@ public class RemoteViews implements Parcelable, Filter { private boolean mIsRoot = true; /** + * Optional theme resource id applied in inflateView(). When 0, Theme.DeviceDefault will be + * used. + */ + private int mApplyThemeResId; + + /** * Whether reapply is disallowed on this remoteview. This maybe be true if some actions modify * the layout in a way that isn't recoverable, since views are being removed. */ @@ -3267,6 +3275,14 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Set the theme used in apply() and applyASync(). + * @hide + */ + public void setApplyTheme(@StyleRes int themeResId) { + mApplyThemeResId = themeResId; + } + + /** * Inflates the view hierarchy represented by this object and applies * all of the actions. * @@ -3301,6 +3317,10 @@ public class RemoteViews implements Parcelable, Filter { final Context contextForResources = getContextForResources(context); Context inflationContext = new RemoteViewsContextWrapper(context, contextForResources); + // If mApplyThemeResId is not given, Theme.DeviceDefault will be used. + if (mApplyThemeResId != 0) { + inflationContext = new ContextThemeWrapper(inflationContext, mApplyThemeResId); + } LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 46cb5461b682..732172111b80 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -30,7 +30,10 @@ import android.database.Cursor; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Message; +import android.text.Layout; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.method.MovementMethod; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; @@ -101,6 +104,9 @@ public class AlertController { private ImageView mIconView; private TextView mTitleView; protected TextView mMessageView; + private MovementMethod mMessageMovementMethod; + @Layout.HyphenationFrequency + private Integer mMessageHyphenationFrequency; private View mCustomTitleView; private boolean mForceInverseBackground; @@ -290,6 +296,21 @@ public class AlertController { } } + public void setMessageMovementMethod(MovementMethod movementMethod) { + mMessageMovementMethod = movementMethod; + if (mMessageView != null) { + mMessageView.setMovementMethod(movementMethod); + } + } + + public void setMessageHyphenationFrequency( + @Layout.HyphenationFrequency int hyphenationFrequency) { + mMessageHyphenationFrequency = hyphenationFrequency; + if (mMessageView != null) { + mMessageView.setHyphenationFrequency(hyphenationFrequency); + } + } + /** * Set the view resource to display in the dialog. */ @@ -676,6 +697,12 @@ public class AlertController { if (mMessage != null) { mMessageView.setText(mMessage); + if (mMessageMovementMethod != null) { + mMessageView.setMovementMethod(mMessageMovementMethod); + } + if (mMessageHyphenationFrequency != null) { + mMessageView.setHyphenationFrequency(mMessageHyphenationFrequency); + } } else { mMessageView.setVisibility(View.GONE); mScrollView.removeView(mMessageView); diff --git a/core/res/res/layout-television/autofill_save.xml b/core/res/res/layout-television/autofill_save.xml new file mode 100644 index 000000000000..ebd2dec3fc0f --- /dev/null +++ b/core/res/res/layout-television/autofill_save.xml @@ -0,0 +1,100 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- NOTE: outer layout is required to provide proper shadow. --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:orientation="horizontal" + android:id="@+id/autofill_save" + android:background="?android:attr/colorBackground" + android:layout_marginTop="32dp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="40dp" + android:paddingEnd="40dp" + android:paddingTop="40dp" + android:paddingBottom="40dp"> + + <LinearLayout + android:orientation="vertical" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginEnd="32dp"> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="6dp"> + + <ImageView + android:id="@+id/autofill_save_icon" + android:scaleType="fitStart" + android:layout_marginEnd="10dp" + android:layout_gravity="center_vertical" + android:layout_width="48dp" + android:layout_height="48dp"/> + <TextView + android:id="@+id/autofill_save_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/autofill_save_title" + android:layout_gravity="center_vertical" + android:textSize="24sp" /> + </LinearLayout> + + <com.android.server.autofill.ui.CustomScrollView + android:id="@+id/autofill_save_custom_subtitle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:visibility="gone"/> + + </LinearLayout> + + <LinearLayout + android:layout_width="304dp" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <Button + android:id="@+id/autofill_save_no" + style="?attr/borderlessButtonStyle" + android:textAlignment="viewStart" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/autofill_save_no"> + </Button> + + <Button + android:id="@+id/autofill_save_yes" + style="?attr/borderlessButtonStyle" + android:textAlignment="viewStart" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/autofill_save_yes"> + </Button> + </LinearLayout> + + </LinearLayout> + +</LinearLayout> diff --git a/core/res/res/layout/autofill_dataset_picker.xml b/core/res/res/layout/autofill_dataset_picker.xml index ef19f870006f..a88836eff5a0 100644 --- a/core/res/res/layout/autofill_dataset_picker.xml +++ b/core/res/res/layout/autofill_dataset_picker.xml @@ -14,8 +14,7 @@ limitations under the License. --> -<view xmlns:android="http://schemas.android.com/apk/res/android" - class="com.android.server.autofill.ui.FillUi$AutofillFrameLayout" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/autofill_dataset_picker" android:layout_width="fill_parent" android:layout_height="fill_parent" @@ -31,4 +30,4 @@ android:visibility="gone"> </ListView> -</view> +</FrameLayout> diff --git a/core/res/res/layout/autofill_dataset_picker_fullscreen.xml b/core/res/res/layout/autofill_dataset_picker_fullscreen.xml index 07298c182269..1d2b5e5d6543 100644 --- a/core/res/res/layout/autofill_dataset_picker_fullscreen.xml +++ b/core/res/res/layout/autofill_dataset_picker_fullscreen.xml @@ -14,35 +14,73 @@ limitations under the License. --> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/autofill_dataset_picker" - style="@style/AutofillDatasetPicker" - android:layout_width="fill_parent" - android:layout_height="fill_parent"> - - <TextView - android:layout_width="wrap_content" +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:background="?android:attr/windowBackground" + android:paddingStart="40dp" + android:paddingEnd="40dp" + android:paddingTop="40dp" + android:paddingBottom="40dp"> + + <LinearLayout + android:orientation="vertical" + android:layout_width="0dp" android:layout_height="wrap_content" - android:text="@string/autofill_window_title" - android:layout_above="@+id/autofill_dataset_container" - android:layout_alignStart="@+id/autofill_dataset_container" - android:textSize="16sp"/> + android:layout_weight="1" + android:layout_marginEnd="32dp"> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="6dp" + > + <ImageView + android:id="@+id/autofill_dataset_icon" + android:scaleType="fitStart" + android:layout_marginEnd="10dp" + android:layout_gravity="center_vertical" + android:layout_width="48dp" + android:layout_height="48dp"/> + <TextView + android:id="@+id/autofill_dataset_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:textSize="24sp" /> + </LinearLayout> + + <LinearLayout + android:id="@+id/autofill_dataset_header" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"/> + + </LinearLayout> <!-- autofill_container is the common parent for inserting authentication item or - autofill_dataset_list--> - <FrameLayout - android:id="@+id/autofill_dataset_container" - android:layout_width="wrap_content" + autofill_dataset_list, autofill_dataset_foolter--> + <LinearLayout + android:layout_width="304dp" android:layout_height="wrap_content" - android:layout_centerInParent="true"> + android:id="@+id/autofill_dataset_picker" + android:orientation="vertical"> <ListView android:id="@+id/autofill_dataset_list" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:divider="@null" android:drawSelectorOnTop="true" android:visibility="gone"/> - </FrameLayout> + <LinearLayout + android:id="@+id/autofill_dataset_footer" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"/> + </LinearLayout> -</RelativeLayout> +</LinearLayout>
\ No newline at end of file diff --git a/core/res/res/layout/autofill_dataset_picker_header_footer.xml b/core/res/res/layout/autofill_dataset_picker_header_footer.xml index 048494ac8f29..093f035ec1ea 100644 --- a/core/res/res/layout/autofill_dataset_picker_header_footer.xml +++ b/core/res/res/layout/autofill_dataset_picker_header_footer.xml @@ -14,8 +14,7 @@ limitations under the License. --> -<view xmlns:android="http://schemas.android.com/apk/res/android" - class="com.android.server.autofill.ui.FillUi$AutofillFrameLayout" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/autofill_dataset_picker" android:layout_width="fill_parent" android:layout_height="fill_parent" @@ -54,4 +53,4 @@ </LinearLayout> -</view> +</FrameLayout> diff --git a/core/res/res/layout/autofill_dataset_picker_header_footer_fullscreen.xml b/core/res/res/layout/autofill_dataset_picker_header_footer_fullscreen.xml deleted file mode 100644 index 24b14a061d90..000000000000 --- a/core/res/res/layout/autofill_dataset_picker_header_footer_fullscreen.xml +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/autofill_dataset_picker" - style="@style/AutofillDatasetPicker" - android:layout_width="fill_parent" - android:layout_height="fill_parent"> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/autofill_window_title" - android:layout_above="@+id/autofill_dataset_container" - android:layout_alignStart="@+id/autofill_dataset_container" - android:textSize="16sp"/> - - <!-- autofill_container is the common parent for inserting authentication item or - autofill_dataset_list--> - <FrameLayout - android:id="@+id/autofill_dataset_container" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerInParent="true"> - - <LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - - <LinearLayout - android:id="@+id/autofill_dataset_header" - android:visibility="gone" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="vertical"/> - - <ListView - android:id="@+id/autofill_dataset_list" - android:layout_weight="1" - android:layout_width="fill_parent" - android:layout_height="0dp" - android:clickable="true" - android:divider="@null" - android:drawSelectorOnTop="true" - android:visibility="gone"/> - - <LinearLayout - android:id="@+id/autofill_dataset_footer" - android:visibility="gone" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="vertical"/> - - </LinearLayout> - - </FrameLayout> - -</RelativeLayout> diff --git a/core/res/res/values-television/dimens.xml b/core/res/res/values-television/dimens.xml index aa5625124f29..4c25225dd50c 100644 --- a/core/res/res/values-television/dimens.xml +++ b/core/res/res/values-television/dimens.xml @@ -20,8 +20,4 @@ <item type="dimen" format="float" name="ambient_shadow_alpha">0.15</item> <item type="dimen" format="float" name="spot_shadow_alpha">0.3</item> - <!-- Max width/height of the autofill data set picker as a fraction of the screen width/height --> - <dimen name="autofill_dataset_picker_max_width">60%</dimen> - <dimen name="autofill_dataset_picker_max_height">70%</dimen> - </resources> diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml index e01caa31ef4f..e380a7bb88a6 100644 --- a/core/res/res/values-television/themes_device_defaults.xml +++ b/core/res/res/values-television/themes_device_defaults.xml @@ -16,4 +16,6 @@ <resources> <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" /> <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" /> + <style name="Theme.DeviceDefault.Autofill" parent="Theme.Material.Autofill" /> + <style name="Theme.DeviceDefault.Autofill.Save" parent="Theme.Material.Autofill.Save" /> </resources> diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml index 3609fb82669a..2966aff6a9da 100644 --- a/core/res/res/values/colors_material.xml +++ b/core/res/res/values/colors_material.xml @@ -145,4 +145,8 @@ <color name="datepicker_default_view_animator_color_material_light">#fff2f2f2</color> <color name="datepicker_default_view_animator_color_material_dark">#ff303030</color> + <!-- Autofill colors --> + <color name="autofill_background_material_dark">@color/material_blue_grey_900</color> + <color name="autofill_background_material_light">@color/material_grey_50</color> + </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 395b26935838..b92052b9ebde 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2196,8 +2196,8 @@ <!-- Text to show in the auto complete drop down list on a text view when the WebView can auto fill the entire form but the user has not configured an AutoFill profile [CHAR-LIMIT=19] --> <string name="setup_autofill">Set up Autofill</string> - <!-- Title of fullscreen autofill window [CHAR-LIMIT=80] --> - <string name="autofill_window_title">Autofill</string> + <!-- Title of fullscreen autofill window, including the name of which autofill service it is using [CHAR-LIMIT=NONE] --> + <string name="autofill_window_title">Autofill with <xliff:g id="serviceName" example="MyPass">%1$s</xliff:g></string> <!-- String used to separate FirstName and LastName when writing out a local name e.g. John<separator>Smith [CHAR-LIMIT=NONE]--> @@ -4514,7 +4514,10 @@ <!-- Notification shown when device owner silently deletes a package [CHAR LIMIT=NONE] --> <string name="package_deleted_device_owner">Deleted by your admin</string> - <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description --> + <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description, with a "learn more" link. --> + <string name="battery_saver_description_with_learn_more">To extend your battery life, Battery Saver turns off some device features and restricts apps. <annotation id="url">Learn More</annotation></string> + + <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description, without a "learn more" link. --> <string name="battery_saver_description">To extend your battery life, Battery Saver turns off some device features and restricts apps.</string> <!-- [CHAR_LIMIT=NONE] Data saver: Feature description --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 984461b06624..50a6ff313f9b 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1487,13 +1487,19 @@ please see styles_device_defaults.xml. <item name="successColor">@color/lock_pattern_view_success_color</item> </style> - <!-- @hide --> + <!-- @hide Autofill background for popup window (not for fullscreen) --> <style name="AutofillDatasetPicker"> <item name="elevation">4dp</item> <item name="background">@drawable/autofill_dataset_picker_background</item> </style> <!-- @hide --> + <style name="AutofillHalfScreenAnimation"> + <item name="android:windowEnterAnimation">@anim/slide_in_up</item> + <item name="android:windowExitAnimation">@anim/slide_out_down</item> + </style> + + <!-- @hide --> <style name="AutofillSaveAnimation"> <item name="android:windowEnterAnimation">@anim/slide_in_up</item> <item name="android:windowExitAnimation">@anim/slide_out_down</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7cc88e8d8f35..d7a1ecc4921b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -663,6 +663,7 @@ <java-symbol type="string" name="autofill_state_re" /> <java-symbol type="string" name="autofill_this_form" /> <java-symbol type="string" name="autofill_username_re" /> + <java-symbol type="string" name="autofill_window_title" /> <java-symbol type="string" name="autofill_zip_4_re" /> <java-symbol type="string" name="autofill_zip_code" /> <java-symbol type="string" name="autofill_zip_code_re" /> @@ -3055,13 +3056,13 @@ <java-symbol type="layout" name="autofill_dataset_picker"/> <java-symbol type="layout" name="autofill_dataset_picker_fullscreen"/> <java-symbol type="layout" name="autofill_dataset_picker_header_footer"/> - <java-symbol type="layout" name="autofill_dataset_picker_header_footer_fullscreen"/> <java-symbol type="id" name="autofill" /> - <java-symbol type="id" name="autofill_dataset_container"/> <java-symbol type="id" name="autofill_dataset_footer"/> <java-symbol type="id" name="autofill_dataset_header"/> + <java-symbol type="id" name="autofill_dataset_icon" /> <java-symbol type="id" name="autofill_dataset_list"/> <java-symbol type="id" name="autofill_dataset_picker"/> + <java-symbol type="id" name="autofill_dataset_title" /> <java-symbol type="id" name="autofill_save_custom_subtitle" /> <java-symbol type="id" name="autofill_save_icon" /> <java-symbol type="id" name="autofill_save_no" /> @@ -3086,6 +3087,7 @@ <java-symbol type="string" name="autofill_save_type_email_address" /> <java-symbol type="drawable" name="autofill_dataset_picker_background" /> <java-symbol type="style" name="AutofillDatasetPicker" /> + <java-symbol type="style" name="AutofillHalfScreenAnimation" /> <java-symbol type="style" name="AutofillSaveAnimation" /> <java-symbol type="dimen" name="autofill_dataset_picker_max_width"/> <java-symbol type="dimen" name="autofill_dataset_picker_max_height"/> @@ -3093,6 +3095,9 @@ <java-symbol type="dimen" name="autofill_save_icon_max_size"/> <java-symbol type="integer" name="autofill_max_visible_datasets" /> + <java-symbol type="style" name="Theme.DeviceDefault.Autofill" /> + <java-symbol type="style" name="Theme.DeviceDefault.Autofill.Save" /> + <java-symbol type="dimen" name="notification_big_picture_max_height"/> <java-symbol type="dimen" name="notification_big_picture_max_width"/> <java-symbol type="dimen" name="notification_media_image_max_width"/> @@ -3373,4 +3378,5 @@ <java-symbol type="id" name="user_loading_avatar" /> <java-symbol type="id" name="user_loading" /> + <java-symbol type="string" name="battery_saver_description_with_learn_more" /> </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index 92b2f3341ddd..14e5082bdebb 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -1673,6 +1673,15 @@ easier. <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> </style> + + <!-- @hide DeviceDefault theme for the autofill FillUi --> + <style name="Theme.DeviceDefault.Autofill" parent="Theme.Material.Autofill.Light"> + </style> + + <!-- @hide DeviceDefault theme for the autofill SaveUi --> + <style name="Theme.DeviceDefault.Autofill.Save" parent="Theme.Material.Autofill.Save.Light"> + </style> + <!-- DeviceDefault theme for the default system theme. --> <style name="Theme.DeviceDefault.System" parent="Theme.DeviceDefault.Light.DarkActionBar" /> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index 9b633fc94a8f..b3e33d5c4ee4 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -1417,4 +1417,25 @@ please see themes_device_defaults.xml. <item name="colorPrimaryDark">@color/primary_dark_material_settings</item> <item name="colorSecondary">@color/secondary_material_settings</item> </style> + + <!-- @hide --> + <style name="Theme.Material.Autofill" parent="Theme.Material"> + <item name="colorBackground">@color/autofill_background_material_dark</item> + </style> + + <!-- @hide --> + <style name="Theme.Material.Autofill.Light" parent="Theme.Material.Light"> + <item name="colorBackground">@color/autofill_background_material_light</item> + </style> + + <!-- @hide --> + <style name="Theme.Material.Autofill.Save" parent="Theme.Material.Panel"> + <item name="colorBackground">@color/autofill_background_material_dark</item> + </style> + + <!-- @hide --> + <style name="Theme.Material.Autofill.Save.Light" parent="Theme.Material.Light.Panel"> + <item name="colorBackground">@color/autofill_background_material_light</item> + </style> + </resources> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 542266f0a069..cfc7f9faf272 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -99,6 +99,7 @@ public class SettingsBackupTest { private static final Set<String> BACKUP_BLACKLISTED_GLOBAL_SETTINGS = newHashSet( Settings.Global.ACTIVITY_MANAGER_CONSTANTS, + Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, Settings.Global.ADB_ENABLED, Settings.Global.ADD_USERS_WHEN_LOCKED, Settings.Global.AIRPLANE_MODE_ON, diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp index dba30f514d1f..14b2e4131acb 100644 --- a/libs/protoutil/Android.bp +++ b/libs/protoutil/Android.bp @@ -33,6 +33,7 @@ cc_library { export_include_dirs: ["include"], shared_libs: [ + "libbase", "libcutils", "liblog", ], diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp index 22b9709ef066..3fee7e42338d 100644 --- a/libs/protoutil/src/ProtoOutputStream.cpp +++ b/libs/protoutil/src/ProtoOutputStream.cpp @@ -17,6 +17,7 @@ #include <inttypes.h> +#include <android-base/file.h> #include <android/util/protobuf.h> #include <android/util/ProtoOutputStream.h> #include <cutils/log.h> @@ -467,19 +468,6 @@ ProtoOutputStream::size() return mBuffer.size(); } -static bool write_all(int fd, uint8_t const* buf, size_t size) -{ - while (size > 0) { - ssize_t amt = ::write(fd, buf, size); - if (amt < 0) { - return false; - } - size -= amt; - buf += amt; - } - return true; -} - bool ProtoOutputStream::flush(int fd) { @@ -488,7 +476,7 @@ ProtoOutputStream::flush(int fd) EncodedBuffer::iterator it = mBuffer.begin(); while (it.readBuffer() != NULL) { - if (!write_all(fd, it.readBuffer(), it.currentToRead())) return false; + if (!android::base::WriteFully(fd, it.readBuffer(), it.currentToRead())) return false; it.rp()->move(it.currentToRead()); } return true; diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index 491f71eea5e7..db776c63178a 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -321,6 +321,7 @@ public class CaptivePortalLoginActivity extends Activity { // TODO: reuse NetworkMonitor facilities for consistent captive portal detection. new Thread(new Runnable() { public void run() { + final Network network = ResolvUtil.makeNetworkWithPrivateDnsBypass(mNetwork); // Give time for captive portal to open. try { Thread.sleep(1000); @@ -329,7 +330,7 @@ public class CaptivePortalLoginActivity extends Activity { HttpURLConnection urlConnection = null; int httpResponseCode = 500; try { - urlConnection = (HttpURLConnection) mNetwork.openConnection(mUrl); + urlConnection = (HttpURLConnection) network.openConnection(mUrl); urlConnection.setInstanceFollowRedirects(false); urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/PrinterHashMap.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/PrinterHashMap.java deleted file mode 100644 index 61956f694245..000000000000 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/PrinterHashMap.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package com.android.printservice.recommendation.plugin.hp; - -import android.net.nsd.NsdServiceInfo; - -import java.util.HashMap; - -final class PrinterHashMap extends HashMap<String, NsdServiceInfo> { - public static String getKey(NsdServiceInfo serviceInfo) { - return serviceInfo.getServiceName(); - } - public NsdServiceInfo addPrinter(NsdServiceInfo device) { - return put(getKey(device), device); - } - public NsdServiceInfo removePrinter(NsdServiceInfo device) { - return remove(getKey(device)); - } -} diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java index 600af1ff6da4..9535ef06f888 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java @@ -24,6 +24,7 @@ import android.text.TextUtils; import com.android.printservice.recommendation.R; import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer; +import com.android.printservice.recommendation.util.PrinterHashMap; import java.net.InetAddress; import java.util.ArrayList; @@ -183,9 +184,7 @@ public class ServiceListener implements ServiceResolveQueue.ResolveCallback { ArrayList<InetAddress> printerAddressess = new ArrayList<>(); for (PrinterHashMap oneVendorPrinters : mVendorHashMap.values()) { - for (NsdServiceInfo printer : oneVendorPrinters.values()) { - printerAddressess.add(printer.getHost()); - } + printerAddressess.addAll(oneVendorPrinters.getPrinterAddresses()); } return printerAddressess; diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/PrinterHashMap.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/PrinterHashMap.java deleted file mode 100755 index b88c7c725349..000000000000 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/PrinterHashMap.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 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. - */ -package com.android.printservice.recommendation.plugin.xerox; - -import android.net.nsd.NsdServiceInfo; - -import java.util.HashMap; - -final class PrinterHashMap extends HashMap<String, NsdServiceInfo> { - public static String getKey(NsdServiceInfo serviceInfo) { - return serviceInfo.getServiceName(); - } - - public NsdServiceInfo addPrinter(NsdServiceInfo device) { - return put(getKey(device), device); - } - - public NsdServiceInfo removePrinter(NsdServiceInfo device) { - return remove(getKey(device)); - } -} diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java index 4d0efd8be23d..9ada969c84c9 100755 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/ServiceResolver.java @@ -22,6 +22,7 @@ import android.text.TextUtils; import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer; import com.android.printservice.recommendation.util.NsdResolveQueue; +import com.android.printservice.recommendation.util.PrinterHashMap; import java.net.InetAddress; import java.util.ArrayList; @@ -195,12 +196,7 @@ class ServiceResolver { } public ArrayList<InetAddress> getPrinters() { - ArrayList<InetAddress> printerAddresses = new ArrayList<>(); - for (NsdServiceInfo printer : mPrinterHashMap.values()) { - printerAddresses.add(printer.getHost()); - } - - return printerAddresses; + return mPrinterHashMap.getPrinterAddresses(); } } diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java index c08ca6ef591f..65cef9441fdc 100644 --- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/MDNSFilteredDiscovery.java @@ -18,6 +18,7 @@ package com.android.printservice.recommendation.util; import android.content.Context; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; +import android.text.TextUtils; import android.util.Log; import androidx.annotation.GuardedBy; @@ -27,9 +28,8 @@ import androidx.core.util.Preconditions; import com.android.printservice.recommendation.PrintServicePlugin; -import java.net.InetAddress; -import java.util.ArrayList; import java.util.HashSet; +import java.util.Objects; import java.util.Set; /** @@ -55,9 +55,9 @@ public class MDNSFilteredDiscovery implements NsdManager.DiscoveryListener { boolean matchesCriteria(NsdServiceInfo nsdServiceInfo); } - /** Printer identifiers of the mPrinters found. */ + /** Printers found. */ @GuardedBy("mLock") - private final @NonNull HashSet<InetAddress> mPrinters; + private final @NonNull PrinterHashMap mPrinters; /** Service types discovered by this plugin */ private final @NonNull HashSet<String> mServiceTypes; @@ -97,7 +97,7 @@ public class MDNSFilteredDiscovery implements NsdManager.DiscoveryListener { mPrinterFilter = Preconditions.checkNotNull(printerFilter, "printerFilter"); mResolveQueue = NsdResolveQueue.getInstance(); - mPrinters = new HashSet<>(); + mPrinters = new PrinterHashMap(); } /** @@ -107,6 +107,12 @@ public class MDNSFilteredDiscovery implements NsdManager.DiscoveryListener { return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE); } + private void onChanged() { + if (mCallback != null) { + mCallback.onChanged(mPrinters.getPrinterAddresses()); + } + } + /** * Start the discovery. * @@ -114,7 +120,8 @@ public class MDNSFilteredDiscovery implements NsdManager.DiscoveryListener { */ public void start(@NonNull PrintServicePlugin.PrinterDiscoveryCallback callback) { mCallback = callback; - mCallback.onChanged(new ArrayList<>(mPrinters)); + + onChanged(); for (String serviceType : mServiceTypes) { DiscoveryListenerMultiplexer.addListener(getNDSManager(), serviceType, this); @@ -167,11 +174,12 @@ public class MDNSFilteredDiscovery implements NsdManager.DiscoveryListener { @Override public void onServiceResolved(NsdServiceInfo serviceInfo) { - if (mPrinterFilter.matchesCriteria(serviceInfo)) { + if (!TextUtils.isEmpty(PrinterHashMap.getKey(serviceInfo)) + && mPrinterFilter.matchesCriteria(serviceInfo)) { if (mCallback != null) { - boolean added = mPrinters.add(serviceInfo.getHost()); - if (added) { - mCallback.onChanged(new ArrayList<>(mPrinters)); + NsdServiceInfo old = mPrinters.addPrinter(serviceInfo); + if (!Objects.equals(old, serviceInfo)) { + onChanged(); } } } @@ -181,26 +189,9 @@ public class MDNSFilteredDiscovery implements NsdManager.DiscoveryListener { @Override public void onServiceLost(NsdServiceInfo serviceInfo) { - mResolveQueue.resolve(getNDSManager(), serviceInfo, - new NsdManager.ResolveListener() { - @Override - public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { - Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": " - + errorCode); - } - - @Override - public void onServiceResolved(NsdServiceInfo serviceInfo) { - if (mPrinterFilter.matchesCriteria(serviceInfo)) { - if (mCallback != null) { - boolean removed = mPrinters.remove(serviceInfo.getHost()); - - if (removed) { - mCallback.onChanged(new ArrayList<>(mPrinters)); - } - } - } - } - }); + NsdServiceInfo oldAddress = mPrinters.removePrinter(serviceInfo); + if (oldAddress != null) { + onChanged(); + } } -}
\ No newline at end of file +} diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/PrinterHashMap.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/PrinterHashMap.java new file mode 100644 index 000000000000..ee35edb3956d --- /dev/null +++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/util/PrinterHashMap.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 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. + */ + +package com.android.printservice.recommendation.util; + +import android.net.nsd.NsdServiceInfo; +import android.util.ArrayMap; + +import java.net.InetAddress; +import java.util.ArrayList; + +/** + * Map to store {@link NsdServiceInfo} belonging to printers. If two infos have the same + * {@link PrinterHashMap#getKey(NsdServiceInfo) key} they are considered the same. + */ +public class PrinterHashMap { + private final ArrayMap<String, NsdServiceInfo> mPrinters = new ArrayMap<>(); + + /** + * Key uniquely identifying a printer. + * + * @param serviceInfo The service info describing the printer + * + * @return The key + */ + public static String getKey(NsdServiceInfo serviceInfo) { + return serviceInfo.getServiceName(); + } + + /** + * Add a printer. + * + * @param device The service info of the printer + * + * @return The service info of the printer that was previously registered for the same key + */ + public NsdServiceInfo addPrinter(NsdServiceInfo device) { + return mPrinters.put(getKey(device), device); + } + + /** + * Remove a printer. + * + * @param device The service info of the printer + * + * @return The service info of the printer that was previously registered for the same key + */ + public NsdServiceInfo removePrinter(NsdServiceInfo device) { + return mPrinters.remove(getKey(device)); + } + + /** + * @return the addresses of printers + */ + public ArrayList<InetAddress> getPrinterAddresses() { + int numPrinters = mPrinters.size(); + ArrayList<InetAddress> printerAddressess = new ArrayList<>(numPrinters); + for (int i = 0; i < numPrinters; i++) { + printerAddressess.add(mPrinters.valueAt(i).getHost()); + } + + return printerAddressess; + } + + /** + * Remove all printers + */ + public void clear() { + mPrinters.clear(); + } + + /** + * @return {@code} true iff the map is empty + */ + public boolean isEmpty() { + return mPrinters.isEmpty(); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java index b976dd66cb76..7f518c1d71d3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java @@ -46,6 +46,7 @@ import android.widget.TextView; import com.android.internal.widget.LockPatternUtils; import java.util.List; +import java.util.Objects; /** * Utility class to host methods usable in adding a restricted padlock icon and showing admin @@ -90,29 +91,29 @@ public class RestrictedLockUtils { // Restriction is not enforced. return null; } else if (enforcingUsers.size() > 1) { - return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; + return EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction); } final int restrictionSource = enforcingUsers.get(0).getUserRestrictionSource(); final int adminUserId = enforcingUsers.get(0).getUserHandle().getIdentifier(); - if (restrictionSource == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) { // Check if it is a profile owner of the user under consideration. if (adminUserId == userId) { - return getProfileOwner(context, adminUserId); + return getProfileOwner(context, userRestriction, adminUserId); } else { // Check if it is a profile owner of a managed profile of the current user. // Otherwise it is in a separate user and we return a default EnforcedAdmin. final UserInfo parentUser = um.getProfileParent(adminUserId); return (parentUser != null && parentUser.id == userId) - ? getProfileOwner(context, adminUserId) - : EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; + ? getProfileOwner(context, userRestriction, adminUserId) + : EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction); } } else if (restrictionSource == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) { // When the restriction is enforced by device owner, return the device owner admin only // if the admin is for the {@param userId} otherwise return a default EnforcedAdmin. return adminUserId == userId - ? getDeviceOwner(context) : EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN; + ? getDeviceOwner(context, userRestriction) + : EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction); } // If the restriction is enforced by system then return null. @@ -406,7 +407,6 @@ public class RestrictedLockUtils { * or {@code null} if no quality requirements are set. If the requirements are set by * multiple device admins, then the admin component will be set to {@code null} and userId to * {@link UserHandle#USER_NULL}. - * */ public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context, int userId) { final LockSettingCheck check = @@ -518,6 +518,11 @@ public class RestrictedLockUtils { } public static EnforcedAdmin getProfileOrDeviceOwner(Context context, int userId) { + return getProfileOrDeviceOwner(context, null, userId); + } + + public static EnforcedAdmin getProfileOrDeviceOwner( + Context context, String enforcedRestriction, int userId) { if (userId == UserHandle.USER_NULL) { return null; } @@ -528,18 +533,22 @@ public class RestrictedLockUtils { } ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId); if (adminComponent != null) { - return new EnforcedAdmin(adminComponent, userId); + return new EnforcedAdmin(adminComponent, enforcedRestriction, userId); } if (dpm.getDeviceOwnerUserId() == userId) { adminComponent = dpm.getDeviceOwnerComponentOnAnyUser(); if (adminComponent != null) { - return new EnforcedAdmin(adminComponent, userId); + return new EnforcedAdmin(adminComponent, enforcedRestriction, userId); } } return null; } public static EnforcedAdmin getDeviceOwner(Context context) { + return getDeviceOwner(context, null); + } + + private static EnforcedAdmin getDeviceOwner(Context context, String enforcedRestriction) { final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( Context.DEVICE_POLICY_SERVICE); if (dpm == null) { @@ -547,12 +556,18 @@ public class RestrictedLockUtils { } ComponentName adminComponent = dpm.getDeviceOwnerComponentOnAnyUser(); if (adminComponent != null) { - return new EnforcedAdmin(adminComponent, dpm.getDeviceOwnerUserId()); + return new EnforcedAdmin( + adminComponent, enforcedRestriction, dpm.getDeviceOwnerUserId()); } return null; } private static EnforcedAdmin getProfileOwner(Context context, int userId) { + return getProfileOwner(context, null, userId); + } + + private static EnforcedAdmin getProfileOwner( + Context context, String enforcedRestriction, int userId) { if (userId == UserHandle.USER_NULL) { return null; } @@ -563,7 +578,7 @@ public class RestrictedLockUtils { } ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId); if (adminComponent != null) { - return new EnforcedAdmin(adminComponent, userId); + return new EnforcedAdmin(adminComponent, enforcedRestriction, userId); } return null; } @@ -626,6 +641,7 @@ public class RestrictedLockUtils { && isCurrentUserOrProfile(context, admin.userId)) { targetUserId = admin.userId; } + intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, admin.enforcedRestriction); context.startActivityAsUser(intent, new UserHandle(targetUserId)); } @@ -700,53 +716,71 @@ public class RestrictedLockUtils { } public static class EnforcedAdmin { + @Nullable public ComponentName component = null; + /** + * The restriction enforced by admin. It could be any user restriction or policy like + * {@link DevicePolicyManager#POLICY_DISABLE_CAMERA}. + */ + @Nullable + public String enforcedRestriction = null; public int userId = UserHandle.USER_NULL; // We use this to represent the case where a policy is enforced by multiple admins. public final static EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin(); + public static EnforcedAdmin createDefaultEnforcedAdminWithRestriction( + String enforcedRestriction) { + EnforcedAdmin enforcedAdmin = new EnforcedAdmin(); + enforcedAdmin.enforcedRestriction = enforcedRestriction; + return enforcedAdmin; + } + public EnforcedAdmin(ComponentName component, int userId) { this.component = component; this.userId = userId; } + public EnforcedAdmin(ComponentName component, String enforcedRestriction, int userId) { + this.component = component; + this.enforcedRestriction = enforcedRestriction; + this.userId = userId; + } + public EnforcedAdmin(EnforcedAdmin other) { if (other == null) { throw new IllegalArgumentException(); } this.component = other.component; + this.enforcedRestriction = other.enforcedRestriction; this.userId = other.userId; } - public EnforcedAdmin() {} + public EnforcedAdmin() { + } @Override - public boolean equals(Object object) { - if (object == this) return true; - if (!(object instanceof EnforcedAdmin)) return false; - EnforcedAdmin other = (EnforcedAdmin) object; - if (userId != other.userId) { - return false; - } - if ((component == null && other.component == null) || - (component != null && component.equals(other.component))) { - return true; - } - return false; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EnforcedAdmin that = (EnforcedAdmin) o; + return userId == that.userId && + Objects.equals(component, that.component) && + Objects.equals(enforcedRestriction, that.enforcedRestriction); } @Override - public String toString() { - return "EnforcedAdmin{component=" + component + ",userId=" + userId + "}"; + public int hashCode() { + return Objects.hash(component, enforcedRestriction, userId); } - public void copyTo(EnforcedAdmin other) { - if (other == null) { - throw new IllegalArgumentException(); - } - other.component = component; - other.userId = userId; + @Override + public String toString() { + return "EnforcedAdmin{" + + "component=" + component + + ", enforcedRestriction='" + enforcedRestriction + + ", userId=" + userId + + '}'; } } diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java b/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java index 246ca474da32..afc08f451623 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java @@ -40,18 +40,18 @@ public class DefaultAppInfo extends CandidateInfo { public final ComponentName componentName; public final PackageItemInfo packageItemInfo; public final String summary; - protected final PackageManagerWrapper mPm; + protected final PackageManager mPm; private final Context mContext; - public DefaultAppInfo(Context context, PackageManagerWrapper pm, int uid, ComponentName cn) { + public DefaultAppInfo(Context context, PackageManager pm, int uid, ComponentName cn) { this(context, pm, uid, cn, null /* summary */, true /* enabled */); } - public DefaultAppInfo(Context context, PackageManagerWrapper pm, PackageItemInfo info) { + public DefaultAppInfo(Context context, PackageManager pm, PackageItemInfo info) { this(context, pm, info, null /* summary */, true /* enabled */); } - public DefaultAppInfo(Context context, PackageManagerWrapper pm, int uid, ComponentName cn, + public DefaultAppInfo(Context context, PackageManager pm, int uid, ComponentName cn, String summary, boolean enabled) { super(enabled); mContext = context; @@ -62,7 +62,7 @@ public class DefaultAppInfo extends CandidateInfo { this.summary = summary; } - public DefaultAppInfo(Context context, PackageManagerWrapper pm, PackageItemInfo info, + public DefaultAppInfo(Context context, PackageManager pm, PackageItemInfo info, String summary, boolean enabled) { super(enabled); mContext = context; @@ -79,17 +79,17 @@ public class DefaultAppInfo extends CandidateInfo { try { final ComponentInfo componentInfo = getComponentInfo(); if (componentInfo != null) { - return componentInfo.loadLabel(mPm.getPackageManager()); + return componentInfo.loadLabel(mPm); } else { final ApplicationInfo appInfo = mPm.getApplicationInfoAsUser( componentName.getPackageName(), 0, userId); - return appInfo.loadLabel(mPm.getPackageManager()); + return appInfo.loadLabel(mPm); } } catch (PackageManager.NameNotFoundException e) { return null; } } else if (packageItemInfo != null) { - return packageItemInfo.loadLabel(mPm.getPackageManager()); + return packageItemInfo.loadLabel(mPm); } else { return null; } diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java index 3c3c70ac364e..454d1dce0b2f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ServiceListing.java @@ -32,8 +32,6 @@ import android.os.Handler; import android.provider.Settings; import android.util.Slog; -import com.android.settingslib.wrapper.PackageManagerWrapper; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -127,8 +125,7 @@ public class ServiceListing { mServices.clear(); final int user = ActivityManager.getCurrentUser(); - final PackageManagerWrapper pmWrapper = - new PackageManagerWrapper(mContext.getPackageManager()); + final PackageManager pmWrapper = mContext.getPackageManager(); List<ResolveInfo> installedServices = pmWrapper.queryIntentServicesAsUser( new Intent(mIntentAction), PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index 6b9902425bcb..62729549ff4d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -20,7 +20,6 @@ import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothCodecConfig; -import android.bluetooth.BluetoothCodecStatus; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; @@ -28,9 +27,7 @@ import android.content.Context; import android.os.ParcelUuid; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.R; -import com.android.settingslib.wrapper.BluetoothA2dpWrapper; import java.util.ArrayList; import java.util.Arrays; @@ -43,7 +40,6 @@ public class A2dpProfile implements LocalBluetoothProfile { private Context mContext; private BluetoothA2dp mService; - private BluetoothA2dpWrapper mServiceWrapper; private boolean mIsProfileReady; private final LocalBluetoothAdapter mLocalAdapter; @@ -67,7 +63,6 @@ public class A2dpProfile implements LocalBluetoothProfile { public void onServiceConnected(int profile, BluetoothProfile proxy) { if (V) Log.d(TAG,"Bluetooth service connected"); mService = (BluetoothA2dp) proxy; - mServiceWrapper = new BluetoothA2dpWrapper(mService); // We just bound to the service, so refresh the UI for any connected A2DP devices. List<BluetoothDevice> deviceList = mService.getConnectedDevices(); while (!deviceList.isEmpty()) { @@ -105,11 +100,6 @@ public class A2dpProfile implements LocalBluetoothProfile { BluetoothProfile.A2DP); } - @VisibleForTesting - void setBluetoothA2dpWrapper(BluetoothA2dpWrapper wrapper) { - mServiceWrapper = wrapper; - } - public boolean isConnectable() { return true; } @@ -203,12 +193,12 @@ public class A2dpProfile implements LocalBluetoothProfile { } public boolean supportsHighQualityAudio(BluetoothDevice device) { - int support = mServiceWrapper.supportsOptionalCodecs(device); + int support = mService.supportsOptionalCodecs(device); return support == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED; } public boolean isHighQualityAudioEnabled(BluetoothDevice device) { - int enabled = mServiceWrapper.getOptionalCodecsEnabled(device); + int enabled = mService.getOptionalCodecsEnabled(device); if (enabled != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN) { return enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED; } else if (getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED && @@ -219,8 +209,8 @@ public class A2dpProfile implements LocalBluetoothProfile { return true; } BluetoothCodecConfig codecConfig = null; - if (mServiceWrapper.getCodecStatus(device) != null) { - codecConfig = mServiceWrapper.getCodecStatus(device).getCodecConfig(); + if (mService.getCodecStatus(device) != null) { + codecConfig = mService.getCodecStatus(device).getCodecConfig(); } if (codecConfig != null) { return !codecConfig.isMandatoryCodec(); @@ -233,7 +223,7 @@ public class A2dpProfile implements LocalBluetoothProfile { int prefValue = enabled ? BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED : BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED; - mServiceWrapper.setOptionalCodecsEnabled(device, prefValue); + mService.setOptionalCodecsEnabled(device, prefValue); if (getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) { return; } @@ -253,8 +243,8 @@ public class A2dpProfile implements LocalBluetoothProfile { // We want to get the highest priority codec, since that's the one that will be used with // this device, and see if it is high-quality (ie non-mandatory). BluetoothCodecConfig[] selectable = null; - if (mServiceWrapper.getCodecStatus(device) != null) { - selectable = mServiceWrapper.getCodecStatus(device).getCodecsSelectableCapabilities(); + if (mService.getCodecStatus(device) != null) { + selectable = mService.getCodecStatus(device).getCodecsSelectableCapabilities(); // To get the highest priority, we sort in reverse. Arrays.sort(selectable, (a, b) -> { diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java index 113256ff929b..e2faf6a01197 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java @@ -354,20 +354,15 @@ public final class UserManagerHelper { return; } - if (userInfo.isGuest()) { - switchToGuest(userInfo.name); - return; - } - switchToUserId(userInfo.id); } /** - * Creates a guest session and switches into the guest session. + * Creates a new guest session and switches into the guest session. * * @param guestName Username for the guest user. */ - public void switchToGuest(String guestName) { + public void startNewGuestSession(String guestName) { UserInfo guest = mUserManager.createGuest(mContext, guestName); if (guest == null) { // Couldn't create user, most likely because there are too many, but we haven't @@ -375,6 +370,7 @@ public final class UserManagerHelper { Log.w(TAG, "can't create user."); return; } + assignDefaultIcon(guest); switchToUserId(guest.id); } @@ -417,6 +413,27 @@ public final class UserManagerHelper { mUserManager.setUserName(user.id, name); } + /** + * Gets a bitmap representing the user's default avatar. + * + * @param userInfo User whose avatar should be returned. + * @return Default user icon + */ + public Bitmap getUserDefaultIcon(UserInfo userInfo) { + return UserIcons.convertToBitmap( + UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false)); + } + + /** + * Gets a bitmap representing the default icon for a Guest user. + * + * @return Degault guest icon + */ + public Bitmap getGuestDefaultIcon() { + return UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon( + mContext.getResources(), UserHandle.USER_NULL, false)); + } + private void registerReceiver() { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_REMOVED); @@ -435,8 +452,7 @@ public final class UserManagerHelper { * @return Bitmap that has been assigned to the user. */ private Bitmap assignDefaultIcon(UserInfo userInfo) { - Bitmap bitmap = UserIcons.convertToBitmap( - UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false)); + Bitmap bitmap = userInfo.isGuest() ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo); mUserManager.setUserIcon(userInfo.id, bitmap); return bitmap; } diff --git a/packages/SettingsLib/src/com/android/settingslib/wrapper/BluetoothA2dpWrapper.java b/packages/SettingsLib/src/com/android/settingslib/wrapper/BluetoothA2dpWrapper.java deleted file mode 100644 index 17e34016a53b..000000000000 --- a/packages/SettingsLib/src/com/android/settingslib/wrapper/BluetoothA2dpWrapper.java +++ /dev/null @@ -1,70 +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. - */ - -package com.android.settingslib.wrapper; - -import android.bluetooth.BluetoothA2dp; -import android.bluetooth.BluetoothCodecStatus; -import android.bluetooth.BluetoothDevice; - -/** - * This class replicates some methods of android.bluetooth.BluetoothA2dp that are new and not - * yet available in our current version of Robolectric. It provides a thin wrapper to call the real - * methods in production and a mock in tests. - */ -public class BluetoothA2dpWrapper { - - private BluetoothA2dp mService; - - public BluetoothA2dpWrapper(BluetoothA2dp service) { - mService = service; - } - - /** - * @return the real {@code BluetoothA2dp} object - */ - public BluetoothA2dp getService() { - return mService; - } - - /** - * Wraps {@code BluetoothA2dp.getCodecStatus} - */ - public BluetoothCodecStatus getCodecStatus(BluetoothDevice device) { - return mService.getCodecStatus(device); - } - - /** - * Wraps {@code BluetoothA2dp.supportsOptionalCodecs} - */ - public int supportsOptionalCodecs(BluetoothDevice device) { - return mService.supportsOptionalCodecs(device); - } - - /** - * Wraps {@code BluetoothA2dp.getOptionalCodecsEnabled} - */ - public int getOptionalCodecsEnabled(BluetoothDevice device) { - return mService.getOptionalCodecsEnabled(device); - } - - /** - * Wraps {@code BluetoothA2dp.setOptionalCodecsEnabled} - */ - public void setOptionalCodecsEnabled(BluetoothDevice device, int value) { - mService.setOptionalCodecsEnabled(device, value); - } -} diff --git a/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java b/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java index 235daf23a664..4e22473a8c87 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java +++ b/packages/SettingsLib/src/com/android/settingslib/wrapper/PackageManagerWrapper.java @@ -35,6 +35,8 @@ import java.util.List; * and the PackageManager. This class only provides access to the minimum number of functions from * the PackageManager needed for DeletionHelper to work. */ +@Deprecated +// Please replace with android.content.pm.PackageManager public class PackageManagerWrapper { private final PackageManager mPm; diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java index 15f77703054d..54510b27e58d 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java @@ -247,13 +247,13 @@ public class UserManagerHelperTest { } @Test - public void switchToGuest() { - mHelper.switchToGuest("Test Guest"); + public void startNewGuestSession() { + mHelper.startNewGuestSession("Test Guest"); verify(mUserManager).createGuest(mContext, "Test Guest"); UserInfo guestInfo = new UserInfo(21, "Test Guest", UserInfo.FLAG_GUEST); when(mUserManager.createGuest(mContext, "Test Guest")).thenReturn(guestInfo); - mHelper.switchToGuest("Test Guest"); + mHelper.startNewGuestSession("Test Guest"); verify(mActivityManager).switchUser(21); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java index 5f6086897d76..710dbc221f07 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java @@ -32,6 +32,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.os.UserHandle; import android.os.UserManager; import org.junit.Before; @@ -42,6 +43,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Arrays; +import java.util.Collections; @RunWith(SettingsLibRobolectricTestRunner.class) public class RestrictedLockUtilsTest { @@ -77,6 +79,42 @@ public class RestrictedLockUtilsTest { } @Test + public void checkIfRestrictionEnforced_deviceOwner() { + UserManager.EnforcingUser enforcingUser = new UserManager.EnforcingUser(mUserId, + UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + when(mUserManager.getUserRestrictionSources(userRestriction, + UserHandle.of(mUserId))). + thenReturn(Collections.singletonList(enforcingUser)); + setUpDeviceOwner(mAdmin1); + + EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext, + userRestriction, mUserId); + + assertThat(enforcedAdmin).isNotNull(); + assertThat(enforcedAdmin.enforcedRestriction).isEqualTo(userRestriction); + assertThat(enforcedAdmin.component).isEqualTo(mAdmin1); + } + + @Test + public void checkIfRestrictionEnforced_profileOwner() { + UserManager.EnforcingUser enforcingUser = new UserManager.EnforcingUser(mUserId, + UserManager.RESTRICTION_SOURCE_PROFILE_OWNER); + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + when(mUserManager.getUserRestrictionSources(userRestriction, + UserHandle.of(mUserId))). + thenReturn(Collections.singletonList(enforcingUser)); + setUpProfileOwner(mAdmin1, mUserId); + + EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext, + userRestriction, mUserId); + + assertThat(enforcedAdmin).isNotNull(); + assertThat(enforcedAdmin.enforcedRestriction).isEqualTo(userRestriction); + assertThat(enforcedAdmin.component).isEqualTo(mAdmin1); + } + + @Test public void checkIfDevicePolicyServiceDisabled_noEnforceAdminForManagedProfile() { when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(null); final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled( @@ -263,4 +301,12 @@ public class RestrictedLockUtilsTest { when(mDevicePolicyManager.getActiveAdminsAsUser(userId)) .thenReturn(Arrays.asList(activeAdmins)); } + + private void setUpDeviceOwner(ComponentName admin) { + when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(admin); + } + + private void setUpProfileOwner(ComponentName admin, int userId) { + when(mDevicePolicyManager.getProfileOwnerAsUser(userId)).thenReturn(admin); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java index 6a161d0a645c..01f0d78ede1a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java @@ -33,7 +33,6 @@ import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import com.android.settingslib.SettingsLibRobolectricTestRunner; -import com.android.settingslib.wrapper.PackageManagerWrapper; import org.junit.Before; import org.junit.Test; @@ -41,7 +40,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; @RunWith(SettingsLibRobolectricTestRunner.class) public class DefaultAppInfoTest { @@ -53,8 +51,6 @@ public class DefaultAppInfoTest { @Mock private PackageManager mPackageManager; @Mock - private PackageManagerWrapper mPackageManagerWrapper; - @Mock private ApplicationInfo mApplicationInfo; @Mock private Drawable mIcon; @@ -67,8 +63,7 @@ public class DefaultAppInfoTest { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); doReturn(mPackageManager).when(mContext).getPackageManager(); - when(mPackageManagerWrapper.getPackageManager()).thenReturn(mPackageManager); - when(mPackageManagerWrapper.getApplicationInfoAsUser(anyString(), anyInt(), + when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())).thenReturn(mApplicationInfo); when(mPackageManager.loadUnbadgedItemIcon(mPackageItemInfo, mApplicationInfo)).thenReturn( mIcon); @@ -77,7 +72,7 @@ public class DefaultAppInfoTest { @Test public void initInfoWithActivityInfo_shouldLoadInfo() { mPackageItemInfo.packageName = "test"; - mInfo = new DefaultAppInfo(mContext, mPackageManagerWrapper, mPackageItemInfo); + mInfo = new DefaultAppInfo(mContext, mPackageManager, mPackageItemInfo); mInfo.loadLabel(); Drawable icon = mInfo.loadIcon(); @@ -90,7 +85,7 @@ public class DefaultAppInfoTest { public void initInfoWithComponent_shouldLoadInfo() { when(mComponentName.getPackageName()).thenReturn("com.android.settings"); - mInfo = new DefaultAppInfo(mContext, mPackageManagerWrapper, 0 /* uid */, mComponentName); + mInfo = new DefaultAppInfo(mContext, mPackageManager, 0 /* uid */, mComponentName); mInfo.getKey(); verify(mComponentName).flattenToString(); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java index 334ea16d608e..ef13a5faa11c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java @@ -31,7 +31,6 @@ import android.content.Context; import android.content.res.Resources; import com.android.settingslib.R; -import com.android.settingslib.wrapper.BluetoothA2dpWrapper; import org.junit.Before; import org.junit.Test; @@ -49,7 +48,6 @@ public class A2dpProfileTest { @Mock LocalBluetoothProfileManager mProfileManager; @Mock BluetoothDevice mDevice; @Mock BluetoothA2dp mBluetoothA2dp; - @Mock BluetoothA2dpWrapper mBluetoothA2dpWrapper; BluetoothProfile.ServiceListener mServiceListener; A2dpProfile mProfile; @@ -68,31 +66,30 @@ public class A2dpProfileTest { mProfile = new A2dpProfile(mContext, mAdapter, mDeviceManager, mProfileManager); mServiceListener.onServiceConnected(BluetoothProfile.A2DP, mBluetoothA2dp); - mProfile.setBluetoothA2dpWrapper(mBluetoothA2dpWrapper); } @Test public void supportsHighQualityAudio() { - when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn( + when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED); assertThat(mProfile.supportsHighQualityAudio(mDevice)).isTrue(); - when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn( + when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED); assertThat(mProfile.supportsHighQualityAudio(mDevice)).isFalse(); - when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn( + when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN); assertThat(mProfile.supportsHighQualityAudio(mDevice)).isFalse(); } @Test public void isHighQualityAudioEnabled() { - when(mBluetoothA2dpWrapper.getOptionalCodecsEnabled(any())).thenReturn( + when(mBluetoothA2dp.getOptionalCodecsEnabled(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED); assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isTrue(); - when(mBluetoothA2dpWrapper.getOptionalCodecsEnabled(any())).thenReturn( + when(mBluetoothA2dp.getOptionalCodecsEnabled(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED); assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isFalse(); @@ -100,23 +97,23 @@ public class A2dpProfileTest { // then isHighQualityAudioEnabled() should return true or false based on whether optional // codecs are supported. If the device is connected then we should ask it directly, but if // the device isn't connected then rely on the stored pref about such support. - when(mBluetoothA2dpWrapper.getOptionalCodecsEnabled(any())).thenReturn( + when(mBluetoothA2dp.getOptionalCodecsEnabled(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN); when(mBluetoothA2dp.getConnectionState(any())).thenReturn( BluetoothProfile.STATE_DISCONNECTED); - when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn( + when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED); assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isFalse(); - when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn( + when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED); assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isTrue(); when(mBluetoothA2dp.getConnectionState(any())).thenReturn( BluetoothProfile.STATE_CONNECTED); BluetoothCodecStatus status = mock(BluetoothCodecStatus.class); - when(mBluetoothA2dpWrapper.getCodecStatus(mDevice)).thenReturn(status); + when(mBluetoothA2dp.getCodecStatus(mDevice)).thenReturn(status); BluetoothCodecConfig config = mock(BluetoothCodecConfig.class); when(status.getCodecConfig()).thenReturn(config); when(config.isMandatoryCodec()).thenReturn(false); @@ -151,14 +148,14 @@ public class A2dpProfileTest { // Most tests want to simulate optional codecs being supported by the device, so do that // by default here. - when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn( + when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED); } @Test public void getLableCodecsNotSupported() { setupLabelTest(); - when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn( + when(mBluetoothA2dp.supportsOptionalCodecs(any())).thenReturn( BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED); assertThat(mProfile.getHighQualityAudioOptionLabel(mDevice)).isEqualTo(UNKNOWN_CODEC_LABEL); } @@ -179,7 +176,7 @@ public class A2dpProfileTest { BluetoothCodecStatus status = mock(BluetoothCodecStatus.class); BluetoothCodecConfig config = mock(BluetoothCodecConfig.class); BluetoothCodecConfig[] configs = {config}; - when(mBluetoothA2dpWrapper.getCodecStatus(mDevice)).thenReturn(status); + when(mBluetoothA2dp.getCodecStatus(mDevice)).thenReturn(status); when(status.getCodecsSelectableCapabilities()).thenReturn(configs); when(config.isMandatoryCodec()).thenReturn(true); @@ -194,7 +191,7 @@ public class A2dpProfileTest { BluetoothCodecStatus status = mock(BluetoothCodecStatus.class); BluetoothCodecConfig config = mock(BluetoothCodecConfig.class); BluetoothCodecConfig[] configs = {config}; - when(mBluetoothA2dpWrapper.getCodecStatus(mDevice)).thenReturn(status); + when(mBluetoothA2dp.getCodecStatus(mDevice)).thenReturn(status); when(status.getCodecsSelectableCapabilities()).thenReturn(configs); when(config.isMandatoryCodec()).thenReturn(false); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java index f2ea3a4a3d87..890abefddd73 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java @@ -185,12 +185,7 @@ public class UserManagerHelperRoboTest { mHelper.switchToUser(createUserInfoForId(20)); assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isFalse(); - // Switching to Guest calls createGuest. - UserInfo guestInfo = new UserInfo(21, "Test Guest", UserInfo.FLAG_GUEST); - mHelper.switchToUser(guestInfo); - verify(mUserManager).createGuest(mContext, "Test Guest"); - - // Switching to non-current, non-guest user, simply calls switchUser. + // Switching to non-foreground user, simply calls switchUser. UserInfo userToSwitchTo = new UserInfo(22, "Test User", 0); mHelper.switchToUser(userToSwitchTo); assertThat(ShadowActivityManager.getShadow().getSwitchUserCalled()).isTrue(); diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk index db57fd162362..ccde5716ef93 100644 --- a/packages/SettingsProvider/Android.mk +++ b/packages/SettingsProvider/Android.mk @@ -3,6 +3,8 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + LOCAL_SRC_FILES := $(call all-java-files-under, src) \ src/com/android/providers/settings/EventLogTags.logtags diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index 4c98bb8cc2e8..7a994a894a86 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -17,7 +17,6 @@ package com.android.providers.settings; import android.os.Process; -import com.android.internal.R; import com.android.internal.app.LocalePicker; import com.android.internal.annotations.VisibleForTesting; @@ -30,13 +29,11 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; -import android.hardware.display.DisplayManager; import android.icu.util.ULocale; import android.location.LocationManager; import android.media.AudioManager; import android.media.RingtoneManager; import android.net.Uri; -import android.os.IPowerManager; import android.os.LocaleList; import android.os.RemoteException; import android.os.ServiceManager; @@ -46,16 +43,16 @@ import android.provider.Settings; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArraySet; -import android.util.Slog; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Locale; public class SettingsHelper { private static final String TAG = "SettingsHelper"; private static final String SILENT_RINGTONE = "_silent"; + private static final float FLOAT_TOLERANCE = 0.01f; + private Context mContext; private AudioManager mAudioManager; private TelephonyManager mTelephonyManager; @@ -259,9 +256,14 @@ public class SettingsHelper { case Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES: case Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES: case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER: - case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE: return !TextUtils.isEmpty(Settings.Secure.getString( mContext.getContentResolver(), name)); + case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE: + float defaultScale = mContext.getResources().getFraction( + R.fraction.def_accessibility_display_magnification_scale, 1, 1); + float currentScale = Settings.Secure.getFloat( + mContext.getContentResolver(), name, defaultScale); + return Math.abs(currentScale - defaultScale) >= FLOAT_TOLERANCE; case Settings.System.FONT_SCALE: return Settings.System.getFloat(mContext.getContentResolver(), name, 1.0f) != 1.0f; default: diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk index bd5b1f2c64ef..0d681ed0f37a 100644 --- a/packages/SettingsProvider/test/Android.mk +++ b/packages/SettingsProvider/test/Android.mk @@ -14,6 +14,10 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-test LOCAL_JAVA_LIBRARIES := android.test.base +LOCAL_RESOURCE_DIR := frameworks/base/packages/SettingsProvider/res + +LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages com.android.providers.settings + LOCAL_PACKAGE_NAME := SettingsProviderTest LOCAL_PRIVATE_PLATFORM_APIS := true diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java new file mode 100644 index 000000000000..b5324e5509ab --- /dev/null +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.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.providers.settings; + +import static junit.framework.Assert.assertEquals; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.net.Uri; +import android.os.Build; +import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link SettingsHelper#restoreValue(Context, ContentResolver, ContentValues, Uri, + * String, String, int)}. Specifically verifies that we restore critical accessibility settings only + * if the user has not already configured these in SUW. + */ +@RunWith(AndroidJUnit4.class) +public class SettingsHelperRestoreTest { + private static final float FLOAT_TOLERANCE = 0.01f; + + private Context mContext; + private ContentResolver mContentResolver; + private SettingsHelper mSettingsHelper; + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getContext(); + mContentResolver = mContext.getContentResolver(); + mSettingsHelper = new SettingsHelper(mContext); + } + + /** Tests for {@link Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}. */ + @Test + public void + testRestoreAccessibilityDisplayMagnificationScale_alreadyConfigured_doesNotRestoreValue() + throws Exception { + float defaultSettingValue = setDefaultAccessibilityDisplayMagnificationScale(); + String settingName = Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE; + float restoreSettingValue = defaultSettingValue + 0.5f; + + // Simulate already configuring setting via SUW. + float configuredSettingValue = defaultSettingValue + 1.0f; + Settings.Secure.putFloat(mContentResolver, settingName, configuredSettingValue); + + mSettingsHelper.restoreValue( + mContext, + mContentResolver, + new ContentValues(2), + Settings.Secure.getUriFor(settingName), + settingName, + String.valueOf(restoreSettingValue), + Build.VERSION.SDK_INT); + + assertEquals( + configuredSettingValue, + Settings.Secure.getFloat(mContentResolver, settingName), + FLOAT_TOLERANCE); + } + + @Test + public void + testRestoreAccessibilityDisplayMagnificationScale_notAlreadyConfigured_restoresValue() + throws Exception { + float defaultSettingValue = setDefaultAccessibilityDisplayMagnificationScale(); + String settingName = Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE; + float restoreSettingValue = defaultSettingValue + 0.5f; + + mSettingsHelper.restoreValue( + mContext, + mContentResolver, + new ContentValues(2), + Settings.Secure.getUriFor(settingName), + settingName, + String.valueOf(restoreSettingValue), + Build.VERSION.SDK_INT); + + assertEquals( + restoreSettingValue, + Settings.Secure.getFloat(mContentResolver, settingName), + FLOAT_TOLERANCE); + } + + /** + * Simulate {@link Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE} value at boot by + * loading the default. + * + * @return the default value. + */ + private float setDefaultAccessibilityDisplayMagnificationScale() { + float defaultSettingValue = + mContext.getResources() + .getFraction( + R.fraction.def_accessibility_display_magnification_scale, 1, 1); + Settings.Secure.putFloat( + mContentResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, + defaultSettingValue); + return defaultSettingValue; + } +} diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml index 5f73beff92e4..4301fdb96234 100644 --- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml +++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml @@ -18,13 +18,15 @@ 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_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="14dp" - android:layout_marginStart="8dp" - android:layout_marginEnd="@dimen/notification_side_paddings" + android:layout_marginStart="@dimen/status_bar_padding_start" + android:layout_marginEnd="@dimen/status_bar_padding_end" android:layout_below="@id/quick_status_bar_system_icons" - android:paddingEnd="@dimen/status_bar_padding_end" > + android:clipChildren="false" + android:clipToPadding="false" + android:minHeight="20dp" > <com.android.systemui.statusbar.policy.DateView android:id="@+id/date" diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml index 54baa4a82a0b..0892f731e9d6 100644 --- a/packages/SystemUI/res/layout/quick_settings_header_info.xml +++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml @@ -45,14 +45,16 @@ android:layout_width="@dimen/qs_header_alarm_icon_size" android:layout_height="@dimen/qs_header_alarm_icon_size" android:src="@drawable/stat_sys_alarm" - android:tint="?android:attr/textColorPrimary" /> + android:tint="?android:attr/textColorPrimary" + android:visibility="gone"/> <TextView android:id="@+id/next_alarm_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start" - android:textAppearance="@style/TextAppearance.QS.TileLabel" /> + android:textAppearance="@style/TextAppearance.QS.TileLabel" + android:visibility="gone"/> <View android:id="@+id/status_separator" @@ -61,20 +63,23 @@ android:layout_marginStart="10dp" android:layout_marginEnd="10dp" android:background="@android:color/white" - android:backgroundTint="?android:attr/textColorPrimary" /> + android:backgroundTint="?android:attr/textColorPrimary" + android:visibility="gone"/> <ImageView android:id="@+id/ringer_mode_icon" android:layout_width="@dimen/qs_header_alarm_icon_size" android:layout_height="@dimen/qs_header_alarm_icon_size" - android:tint="?android:attr/textColorPrimary" /> + android:tint="?android:attr/textColorPrimary" + android:visibility="gone"/> <TextView android:id="@+id/ringer_mode_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start" - android:textAppearance="@style/TextAppearance.QS.TileLabel" /> + android:textAppearance="@style/TextAppearance.QS.TileLabel" + android:visibility="gone"/> </LinearLayout> 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 a9fe8620cf48..d40534edf0ad 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 @@ -20,15 +20,12 @@ android:id="@+id/quick_status_bar_system_icons" android:layout_width="match_parent" android:layout_height="@*android:dimen/quick_qs_offset_height" - android:layout_marginRight="@dimen/notification_side_paddings" - android:layout_marginLeft="@dimen/notification_side_paddings" - android:layout_alignParentEnd="true" android:clipChildren="false" android:clipToPadding="false" android:gravity="center" + android:orientation="horizontal" android:paddingStart="@dimen/status_bar_padding_start" - android:paddingEnd="@dimen/status_bar_padding_end" - android:orientation="horizontal"> + android:paddingEnd="@dimen/status_bar_padding_end" > <com.android.systemui.statusbar.policy.Clock android:id="@+id/clock" diff --git a/packages/SystemUI/res/layout/volume_dnd_icon.xml b/packages/SystemUI/res/layout/volume_dnd_icon.xml index acf9aedd5a3c..215b2300992a 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="@dimen/volume_dialog_panel_width" - android:layout_height="wrap_content"> + android:layout_width="14dp" + android:layout_height="14dp" + android:layout_marginTop="6dp" + android:layout_marginRight="6dp" + android:layout_gravity="right|top"> <ImageView android:id="@+id/dnd_icon" - android:layout_width="14dp" - android:layout_height="14dp" - android:layout_marginTop="6dp" - android:layout_marginRight="6dp" - android:layout_gravity="right|top" + android:layout_width="match_parent" + android:layout_height="match_parent" android:src="@drawable/ic_dnd" android:tint="?android:attr/textColorTertiary"/> </FrameLayout> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 26c7858971a0..ac9fb2b8afa0 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -326,7 +326,7 @@ <dimen name="pull_span_min">25dp</dimen> <dimen name="qs_tile_height">106dp</dimen> - <dimen name="qs_tile_layout_margin_side">9dp</dimen> + <dimen name="qs_tile_layout_margin_side">6dp</dimen> <dimen name="qs_tile_margin_horizontal">18dp</dimen> <dimen name="qs_tile_margin_vertical">24dp</dimen> <dimen name="qs_tile_margin_top_bottom">12dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index d82b00c316a8..697ab06afb19 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2223,4 +2223,6 @@ <!-- An action on the dialog that tells that scheduled (i.e. automatic) battery saver: user acknowledges and closes the dialog. [CHAR LIMIT=NONE]--> <string name="auto_saver_okay_action">Got it</string> + <!-- URl of the webpage that explains battery saver. --> + <string name="help_uri_battery_saver_learn_more_link_target" translatable="false"></string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index 8cc47eba0a9c..5b76627d9d3c 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -19,17 +19,29 @@ package com.android.systemui.power; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioAttributes; +import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.UserHandle; -import androidx.annotation.VisibleForTesting; +import android.text.Annotation; +import android.text.Layout; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.URLSpan; +import android.util.Log; import android.util.Slog; +import android.view.View; +import androidx.annotation.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.settingslib.Utils; @@ -42,6 +54,8 @@ import com.android.systemui.util.NotificationChannels; import java.io.PrintWriter; import java.text.NumberFormat; +import java.util.Locale; +import java.util.Objects; public class PowerNotificationWarnings implements PowerUI.WarningsUI { private static final String TAG = PowerUI.TAG + ".Notification"; @@ -87,6 +101,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private static final String SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING = "android.settings.BATTERY_SAVER_SETTINGS"; + private static final String BATTERY_SAVER_DESCRIPTION_URL_KEY = "url"; + private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) @@ -463,7 +479,16 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { if (mSaverConfirmation != null) return; final SystemUIDialog d = new SystemUIDialog(mContext); d.setTitle(R.string.battery_saver_confirmation_title); - d.setMessage(com.android.internal.R.string.battery_saver_description); + d.setMessage(getBatterySaverDescription()); + + // Sad hack for http://b/78261259 and http://b/78298335. Otherwise "Battery" may be split + // into "Bat-tery". + if (isEnglishLocale()) { + d.setMessageHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE); + } + // We need to set LinkMovementMethod to make the link clickable. + d.setMessageMovementMethod(LinkMovementMethod.getInstance()); + d.setNegativeButton(android.R.string.cancel, null); d.setPositiveButton(R.string.battery_saver_confirmation_ok, (dialog, which) -> setSaverMode(true, false)); @@ -473,6 +498,79 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { mSaverConfirmation = d; } + private boolean isEnglishLocale() { + return Objects.equals(Locale.getDefault().getLanguage(), + Locale.ENGLISH.getLanguage()); + } + + /** + * Generates the message for the "want to start battery saver?" dialog with a "learn more" link. + */ + private CharSequence getBatterySaverDescription() { + final String learnMoreUrl = mContext.getText( + R.string.help_uri_battery_saver_learn_more_link_target).toString(); + + // If there's no link, use the string with no "learn more". + if (TextUtils.isEmpty(learnMoreUrl)) { + return mContext.getText( + com.android.internal.R.string.battery_saver_description); + } + + // If we have a link, use the string with the "learn more" link. + final CharSequence rawText = mContext.getText( + com.android.internal.R.string.battery_saver_description_with_learn_more); + final SpannableString message = new SpannableString(rawText); + final SpannableStringBuilder builder = new SpannableStringBuilder(message); + + // Look for the "learn more" part of the string, and set a URL span on it. + // We use a customized URLSpan to add FLAG_RECEIVER_FOREGROUND to the intent, and + // also to close the dialog. + for (Annotation annotation : message.getSpans(0, message.length(), Annotation.class)) { + final String key = annotation.getValue(); + + if (!BATTERY_SAVER_DESCRIPTION_URL_KEY.equals(key)) { + continue; + } + final int start = message.getSpanStart(annotation); + final int end = message.getSpanEnd(annotation); + + // Replace the "learn more" with a custom URL span, with + // - No underline. + // - When clicked, close the dialog and the notification shade. + final URLSpan urlSpan = new URLSpan(learnMoreUrl) { + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + + @Override + public void onClick(View widget) { + // Close the parent dialog. + if (mSaverConfirmation != null) { + mSaverConfirmation.dismiss(); + } + // Also close the notification shade, if it's open. + mContext.sendBroadcast( + new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) + .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)); + + final Uri uri = Uri.parse(getURL()); + Context context = widget.getContext(); + Intent intent = new Intent(Intent.ACTION_VIEW, uri) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "Activity was not found for intent, " + intent.toString()); + } + } + }; + builder.setSpan(urlSpan, start, end, message.getSpanFlags(urlSpan)); + } + return builder; + } + private void showAutoSaverEnabledConfirmation() { if (mSaverEnabledConfirmation != null) return; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index a44f9433b20a..d8bf990f6465 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -40,7 +40,7 @@ public class QSContainerImpl extends FrameLayout { private int mHeightOverride = -1; private QSPanel mQSPanel; private View mQSDetail; - private View mHeader; + private QuickStatusBarHeader mHeader; private float mQsExpansion; private QSCustomizer mQSCustomizer; private View mQSFooter; @@ -178,7 +178,7 @@ public class QSContainerImpl extends FrameLayout { setMargins(mBackground); setMargins(mQSFooter); mQSPanel.setMargins(mSideMargins); - setMargins(mHeader); + mHeader.setMargins(mSideMargins); } private void setMargins(View view) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 7a24a6086ea4..3d326aecfc93 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -41,6 +41,7 @@ import android.util.Pair; import android.view.View; import android.view.WindowInsets; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; @@ -592,4 +593,16 @@ public class QuickStatusBarHeader extends RelativeLayout implements public static float getColorIntensity(@ColorInt int color) { return color == Color.WHITE ? 0 : 1; } + + public void setMargins(int sideMargins) { + for (int i = 0; i < getChildCount(); i++) { + View v = getChildAt(i); + if (v == mSystemIconsView || v == mQuickQsStatusIcons || v == mHeaderQsPanel) { + continue; + } + RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams(); + lp.leftMargin = sideMargins; + lp.rightMargin = sideMargins; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java index a950cd5f0ca8..a54c778343ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java @@ -207,7 +207,7 @@ public class UserGridRecyclerView extends PagedListView implements // If the user selects Guest, start the guest session. if (userRecord.mIsStartGuestSession) { - mUserManagerHelper.switchToGuest(mGuestName); + mUserManagerHelper.startNewGuestSession(mGuestName); return; } @@ -241,8 +241,7 @@ public class UserGridRecyclerView extends PagedListView implements private Bitmap getUserRecordIcon(UserRecord userRecord) { if (userRecord.mIsStartGuestSession) { - return UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon( - mContext.getResources(), UserHandle.USER_NULL, false)); + return mUserManagerHelper.getGuestDefaultIcon(); } if (userRecord.mIsAddUser) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index f6ec4938885f..bba271b90a2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -521,7 +521,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { // Clear any pending suggestion flag as it has either been nullified or is being shown mPendingRotationSuggestion = false; - getView().removeCallbacks(mCancelPendingRotationProposal); + if (getView() != null) getView().removeCallbacks(mCancelPendingRotationProposal); // Handle the visibility change and animation if (visible) { // Appear and change (cannot force) @@ -1141,6 +1141,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private final Runnable mRipple = new Runnable() { @Override public void run() { // Cause the ripple to fire via false presses + if (!mRoot.isAttachedToWindow()) return; mRoot.setPressed(true); mRoot.setPressed(false); } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 0038e8987d98..bd59ec0390e8 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2079,7 +2079,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } getUiForShowing().showFillUi(filledId, response, filterText, - mService.getServicePackageName(), mComponentName.getPackageName(), this); + mService.getServicePackageName(), mComponentName.getPackageName(), + mService.getServiceLabel(), mService.getServiceIcon(), this); synchronized (mLock) { if (mUiShownTime == 0) { diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index 21a39e483986..ee18dc2e5824 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -163,11 +163,14 @@ public final class AutoFillUI { * @param filterText text of the view to be filled * @param servicePackageName package name of the autofill service filling the activity * @param packageName package name of the activity that is filled + * @param serviceLabel label of autofill service + * @param serviceIcon icon of autofill service * @param callback Identifier for the caller */ public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response, @Nullable String filterText, @Nullable String servicePackageName, - @NonNull String packageName, @NonNull AutoFillUiCallback callback) { + @NonNull String packageName, @NonNull CharSequence serviceLabel, + @NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback) { if (sDebug) { final int size = filterText == null ? 0 : filterText.length(); Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars"); @@ -185,7 +188,7 @@ public final class AutoFillUI { } hideAllUiThread(callback); mFillUi = new FillUi(mContext, response, focusedId, - filterText, mOverlayControl, new FillUi.Callback() { + filterText, mOverlayControl, serviceLabel, serviceIcon, new FillUi.Callback() { @Override public void onResponsePicked(FillResponse response) { log.setType(MetricsEvent.TYPE_DETAIL); diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java index d29ca051ad94..1aeb3b914813 100644 --- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java @@ -26,6 +26,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.ContextThemeWrapper; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; @@ -53,9 +55,11 @@ import android.widget.BaseAdapter; import android.widget.Filter; import android.widget.Filterable; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RemoteViews; +import android.widget.TextView; import com.android.internal.R; import com.android.server.UiThread; @@ -72,29 +76,9 @@ import java.util.stream.Collectors; final class FillUi { private static final String TAG = "FillUi"; - private static final TypedValue sTempTypedValue = new TypedValue(); - - public static final class AutofillFrameLayout extends FrameLayout { - - OnKeyListener mUnhandledListener; + private static final int THEME_ID = com.android.internal.R.style.Theme_DeviceDefault_Autofill; - public AutofillFrameLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public AutofillFrameLayout(Context context, AttributeSet attrs, @AttrRes int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - boolean handled = super.dispatchKeyEvent(event); - if (!handled) { - handled = mUnhandledListener.onKey(this, event.getKeyCode(), event); - } - return handled; - } - } + private static final TypedValue sTempTypedValue = new TypedValue(); interface Callback { void onResponsePicked(@NonNull FillResponse response); @@ -146,51 +130,64 @@ final class FillUi { FillUi(@NonNull Context context, @NonNull FillResponse response, @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText, - @NonNull OverlayControl overlayControl, @NonNull Callback callback) { - mContext = context; + @NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel, + @NonNull Drawable serviceIcon, @NonNull Callback callback) { mCallback = callback; mFullScreen = isFullScreen(context); - - final LayoutInflater inflater = LayoutInflater.from(context); + mContext = new ContextThemeWrapper(context, THEME_ID); + final LayoutInflater inflater = LayoutInflater.from(mContext); final RemoteViews headerPresentation = response.getHeader(); final RemoteViews footerPresentation = response.getFooter(); final ViewGroup decor; - if (headerPresentation != null || footerPresentation != null) { - decor = (ViewGroup) inflater.inflate( - mFullScreen ? R.layout.autofill_dataset_picker_header_footer_fullscreen - : R.layout.autofill_dataset_picker_header_footer, null); + if (mFullScreen) { + decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null); + } else if (headerPresentation != null || footerPresentation != null) { + decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_header_footer, + null); } else { - decor = (ViewGroup) inflater.inflate( - mFullScreen ? R.layout.autofill_dataset_picker_fullscreen - : R.layout.autofill_dataset_picker, null); - } - - // if autofill ui is not fullscreen, send unhandled keyevent to app window. - if (!mFullScreen) { - if (decor instanceof AutofillFrameLayout) { - ((AutofillFrameLayout) decor).mUnhandledListener = - (View view, int keyCode, KeyEvent event) -> { - switch (keyCode) { - case KeyEvent.KEYCODE_BACK: - case KeyEvent.KEYCODE_ESCAPE: - case KeyEvent.KEYCODE_ENTER: - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_DPAD_LEFT: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_DOWN: - return false; - default: - mCallback.dispatchUnhandledKey(event); - return true; - } - }; - } else { - Slog.wtf(TAG, "Unable to send unhandled key"); - } + decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker, null); + } + final TextView titleView = decor.findViewById(R.id.autofill_dataset_title); + if (titleView != null) { + titleView.setText(mContext.getString(R.string.autofill_window_title, serviceLabel)); + } + final ImageView iconView = decor.findViewById(R.id.autofill_dataset_icon); + if (iconView != null) { + iconView.setImageDrawable(serviceIcon); } + // In full screen we only initialize size once assuming screen size never changes + if (mFullScreen) { + final Point outPoint = mTempPoint; + mContext.getDisplay().getSize(outPoint); + // full with of screen and half height of screen + mContentWidth = LayoutParams.MATCH_PARENT; + mContentHeight = outPoint.y / 2; + if (sVerbose) { + Slog.v(TAG, "initialized fillscreen LayoutParams " + + mContentWidth + "," + mContentHeight); + } + } + + // Send unhandled keyevent to app window. + decor.addOnUnhandledKeyEventListener((View view, KeyEvent event) -> { + switch (event.getKeyCode() ) { + case KeyEvent.KEYCODE_BACK: + case KeyEvent.KEYCODE_ESCAPE: + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_RIGHT: + case KeyEvent.KEYCODE_DPAD_DOWN: + return false; + default: + mCallback.dispatchUnhandledKey(event); + return true; + } + }); + if (sVisibleDatasetsMaxCount > 0) { mVisibleDatasetsMaxCount = sVisibleDatasetsMaxCount; if (sVerbose) { @@ -218,14 +215,12 @@ final class FillUi { mFooter = null; mAdapter = null; - // insert authentication item under autofill_dataset_container or decor - ViewGroup container = decor.findViewById(R.id.autofill_dataset_container); - if (container == null) { - container = decor; - } + // insert authentication item under autofill_dataset_picker + ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker); final View content; try { - content = response.getPresentation().apply(context, decor, interceptionHandler); + response.getPresentation().setApplyTheme(THEME_ID); + content = response.getPresentation().apply(mContext, decor, interceptionHandler); container.addView(content); } catch (RuntimeException e) { callback.onCanceled(); @@ -236,20 +231,22 @@ final class FillUi { decor.setFocusable(true); decor.setOnClickListener(v -> mCallback.onResponsePicked(response)); - final Point maxSize = mTempPoint; - resolveMaxWindowSize(context, maxSize); - // fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width - content.getLayoutParams().width = mFullScreen ? maxSize.x - : ViewGroup.LayoutParams.WRAP_CONTENT; - content.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; - final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.x, - MeasureSpec.AT_MOST); - final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y, - MeasureSpec.AT_MOST); - - decor.measure(widthMeasureSpec, heightMeasureSpec); - mContentWidth = content.getMeasuredWidth(); - mContentHeight = content.getMeasuredHeight(); + if (!mFullScreen) { + final Point maxSize = mTempPoint; + resolveMaxWindowSize(mContext, maxSize); + // fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width + content.getLayoutParams().width = mFullScreen ? maxSize.x + : ViewGroup.LayoutParams.WRAP_CONTENT; + content.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; + final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.x, + MeasureSpec.AT_MOST); + final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y, + MeasureSpec.AT_MOST); + + decor.measure(widthMeasureSpec, heightMeasureSpec); + mContentWidth = content.getMeasuredWidth(); + mContentHeight = content.getMeasuredHeight(); + } mWindow = new AnchoredWindow(decor, overlayControl); requestShowFillUi(); @@ -263,7 +260,8 @@ final class FillUi { RemoteViews.OnClickHandler clickBlocker = null; if (headerPresentation != null) { clickBlocker = newClickBlocker(); - mHeader = headerPresentation.apply(context, null, clickBlocker); + headerPresentation.setApplyTheme(THEME_ID); + mHeader = headerPresentation.apply(mContext, null, clickBlocker); final LinearLayout headerContainer = decor.findViewById(R.id.autofill_dataset_header); if (sVerbose) Slog.v(TAG, "adding header"); @@ -274,15 +272,21 @@ final class FillUi { } if (footerPresentation != null) { - if (clickBlocker == null) { // already set for header - clickBlocker = newClickBlocker(); - } - mFooter = footerPresentation.apply(context, null, clickBlocker); final LinearLayout footerContainer = decor.findViewById(R.id.autofill_dataset_footer); - if (sVerbose) Slog.v(TAG, "adding footer"); - footerContainer.addView(mFooter); - footerContainer.setVisibility(View.VISIBLE); + if (footerContainer != null) { + if (clickBlocker == null) { // already set for header + clickBlocker = newClickBlocker(); + } + footerPresentation.setApplyTheme(THEME_ID); + mFooter = footerPresentation.apply(mContext, null, clickBlocker); + // Footer not supported on some platform e.g. TV + if (sVerbose) Slog.v(TAG, "adding footer"); + footerContainer.addView(mFooter); + footerContainer.setVisibility(View.VISIBLE); + } else { + mFooter = null; + } } else { mFooter = null; } @@ -301,7 +305,8 @@ final class FillUi { final View view; try { if (sVerbose) Slog.v(TAG, "setting remote view for " + focusedViewId); - view = presentation.apply(context, null, interceptionHandler); + presentation.setApplyTheme(THEME_ID); + view = presentation.apply(mContext, null, interceptionHandler); } catch (RuntimeException e) { Slog.e(TAG, "Error inflating remote views", e); continue; @@ -352,12 +357,7 @@ final class FillUi { } void requestShowFillUi() { - if (mFullScreen) { - mCallback.requestShowFillUi(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, - mWindowPresenter); - } else { - mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter); - } + mCallback.requestShowFillUi(mContentWidth, mContentHeight, mWindowPresenter); } /** @@ -388,12 +388,6 @@ final class FillUi { mCallback.requestHideFillUi(); } else { if (updateContentSize()) { - if (mFullScreen) { - LayoutParams lp = mListView.getLayoutParams(); - lp.width = mContentWidth; - lp.height = mContentHeight; - mListView.setLayoutParams(lp); - } requestShowFillUi(); } if (mAdapter.getCount() > mVisibleDatasetsMaxCount) { @@ -452,6 +446,10 @@ final class FillUi { if (mAdapter == null) { return false; } + if (mFullScreen) { + // always request show fill window with fixed size for fullscreen + return true; + } boolean changed = false; if (mAdapter.getCount() <= 0) { if (mContentWidth != 0) { @@ -476,11 +474,6 @@ final class FillUi { final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y, MeasureSpec.AT_MOST); final int itemCount = mAdapter.getCount(); - if (mFullScreen) { - // fullScreen mode occupy the full width defined by autofill_dataset_picker_max_width - changed = true; - mContentWidth = maxSize.x; - } if (mHeader != null) { mHeader.measure(widthMeasureSpec, heightMeasureSpec); @@ -491,20 +484,9 @@ final class FillUi { for (int i = 0; i < itemCount; i++) { final View view = mAdapter.getItem(i).view; view.measure(widthMeasureSpec, heightMeasureSpec); - if (mFullScreen) { - // for fullscreen, add up all children height until hit max height. - final int newContentHeight = mContentHeight + view.getMeasuredHeight(); - final int clampedNewHeight = Math.min(newContentHeight, maxSize.y); - if (clampedNewHeight != mContentHeight) { - mContentHeight = clampedNewHeight; - } else if (view.getMeasuredHeight() > 0) { - break; - } - } else { - changed |= updateWidth(view, maxSize); - if (i < mVisibleDatasetsMaxCount) { - changed |= updateHeight(view, maxSize); - } + changed |= updateWidth(view, maxSize); + if (i < mVisibleDatasetsMaxCount) { + changed |= updateHeight(view, maxSize); } } diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index f96fa7c237f7..80903c1a1fe4 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -42,6 +42,7 @@ import android.text.Html; import android.util.ArraySet; import android.util.Pair; import android.util.Slog; +import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -70,6 +71,9 @@ final class SaveUi { private static final String TAG = "AutofillSaveUi"; + private static final int THEME_ID = + com.android.internal.R.style.Theme_DeviceDefault_Autofill_Save; + public interface OnSaveListener { void onSave(); void onCancel(IntentSender listener); @@ -144,6 +148,7 @@ final class SaveUi { mServicePackageName = servicePackageName; mPackageName = packageName; + context = new ContextThemeWrapper(context, THEME_ID); final LayoutInflater inflater = LayoutInflater.from(context); final View view = inflater.inflate(R.layout.autofill_save, null); @@ -222,7 +227,7 @@ final class SaveUi { final View yesButton = view.findViewById(R.id.autofill_save_yes); yesButton.setOnClickListener((v) -> mListener.onSave()); - mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel); + mDialog = new Dialog(context, THEME_ID); mDialog.setContentView(view); // Dialog can be dismissed when touched outside, but the negative listener should not be @@ -309,6 +314,7 @@ final class SaveUi { try { // Create the remote view peer. + template.setApplyTheme(THEME_ID); final View customSubtitleView = template.apply(context, null, handler); // And apply batch updates (if any). diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index ae14dfaa4db1..1cd853ff3efe 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -56,7 +56,10 @@ public class BinderCallsStatsService extends Binder { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (args != null) { for (final String arg : args) { - if ("--reset".equals(arg)) { + if ("-a".equals(arg)) { + // We currently dump all information by default + continue; + } else if ("--reset".equals(arg)) { reset(); pw.println("binder_calls_stats reset."); return; @@ -78,7 +81,6 @@ public class BinderCallsStatsService extends Binder { return; } else { pw.println("Unknown option: " + arg); - return; } } } diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java index 676f0c7dd28e..1149e8703a4f 100644 --- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java @@ -23,6 +23,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; +import android.os.UserManager; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; @@ -59,11 +60,14 @@ final class CarUserSwitchingDialog extends UserSwitchingDialog { View view = LayoutInflater.from(getContext()).inflate(R.layout.car_user_switching_dialog, null); - FileDescriptor fileDescriptor = UserManagerService.getInstance() - .getUserIcon(mNewUser.id).getFileDescriptor(); - Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor); - ((ImageView) view.findViewById(R.id.user_loading_avatar)) - .setImageBitmap(bitmap); + UserManager userManager = + (UserManager) getContext().getSystemService(Context.USER_SERVICE); + Bitmap bitmap = userManager.getUserIcon(mNewUser.id); + if (bitmap != null) { + ((ImageView) view.findViewById(R.id.user_loading_avatar)) + .setImageBitmap(bitmap); + } + ((TextView) view.findViewById(R.id.user_loading)) .setText(res.getString(R.string.car_loading_profile)); setView(view); diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 550c37af5db2..483fec67a429 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -219,6 +219,9 @@ final class PendingIntentRecord extends IIntentSender.Stub { } public void unregisterCancelListenerLocked(IResultReceiver receiver) { + if (mCancelCallbacks == null) { + return; // Already unregistered or detached. + } mCancelCallbacks.unregister(receiver); if (mCancelCallbacks.getRegisteredCallbackCount() <= 0) { mCancelCallbacks = null; diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 312b21ce30fa..03046b6b4eb0 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -818,37 +818,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt } }; - mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) { - @Override - public boolean isAvailableInPlatform() { - return native_is_measurement_supported(); - } - - @Override - protected int registerWithService() { - int devOptions = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Global.DEVELOPMENT_SETTINGS_ENABLED , 0); - int fullTrackingToggled = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING , 0); - boolean result = false; - if (devOptions == 1 /* Developer Mode enabled */ - && fullTrackingToggled == 1 /* Raw Measurements Full Tracking enabled */) { - result = native_start_measurement_collection(true /* enableFullTracking */); - } else { - result = native_start_measurement_collection(false /* enableFullTracking */); - } - if (result) { - return RemoteListenerHelper.RESULT_SUCCESS; - } else { - return RemoteListenerHelper.RESULT_INTERNAL_ERROR; - } - } - - @Override - protected void unregisterFromService() { - native_stop_measurement_collection(); - } - + mGnssMeasurementsProvider = new GnssMeasurementsProvider(mContext, mHandler) { @Override protected boolean isGpsEnabled() { return isEnabled(); @@ -1032,7 +1002,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus); } } - + private void handleRequestLocation(boolean independentFromGnss) { if (isRequestLocationRateLimited()) { if (DEBUG) { @@ -2790,13 +2760,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt private native void native_update_network_state(boolean connected, int type, boolean roaming, boolean available, String extraInfo, String defaultAPN); - // Gps Hal measurements support. - private static native boolean native_is_measurement_supported(); - - private native boolean native_start_measurement_collection(boolean enableFullTracking); - - private native boolean native_stop_measurement_collection(); - // Gps Navigation message support. private static native boolean native_is_navigation_message_supported(); diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java index 477dae65c651..0add86315487 100644 --- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java @@ -16,12 +16,16 @@ package com.android.server.location; +import android.content.Context; import android.location.GnssMeasurementsEvent; import android.location.IGnssMeasurementsListener; import android.os.Handler; import android.os.RemoteException; +import android.provider.Settings; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + /** * An base implementation for GPS measurements provider. * It abstracts out the responsibility of handling listeners, while still allowing technology @@ -29,22 +33,73 @@ import android.util.Log; * * @hide */ -public abstract class GnssMeasurementsProvider - extends RemoteListenerHelper<IGnssMeasurementsListener> { +public abstract class GnssMeasurementsProvider extends + RemoteListenerHelper<IGnssMeasurementsListener> { private static final String TAG = "GnssMeasurementsProvider"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final Context mContext; + private final GnssMeasurementProviderNative mNative; + + private boolean mIsCollectionStarted; + private boolean mEnableFullTracking; + + protected GnssMeasurementsProvider(Context context, Handler handler) { + this(context, handler, new GnssMeasurementProviderNative()); + } - protected GnssMeasurementsProvider(Handler handler) { + @VisibleForTesting + GnssMeasurementsProvider(Context context, Handler handler, + GnssMeasurementProviderNative aNative) { super(handler, TAG); + mContext = context; + mNative = aNative; + } + + // TODO(b/37460011): Use this with death recovery logic. + void resumeIfStarted() { + if (DEBUG) { + Log.d(TAG, "resumeIfStarted"); + } + if (mIsCollectionStarted) { + mNative.startMeasurementCollection(mEnableFullTracking); + } + } + + @Override + public boolean isAvailableInPlatform() { + return mNative.isMeasurementSupported(); + } + + @Override + protected int registerWithService() { + int devOptions = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0); + int fullTrackingToggled = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, 0); + boolean enableFullTracking = (devOptions == 1 /* Developer Mode enabled */) + && (fullTrackingToggled == 1 /* Raw Measurements Full Tracking enabled */); + boolean result = mNative.startMeasurementCollection(enableFullTracking); + if (result) { + mIsCollectionStarted = true; + mEnableFullTracking = enableFullTracking; + return RemoteListenerHelper.RESULT_SUCCESS; + } else { + return RemoteListenerHelper.RESULT_INTERNAL_ERROR; + } + } + + @Override + protected void unregisterFromService() { + boolean stopped = mNative.stopMeasurementCollection(); + if (stopped) { + mIsCollectionStarted = false; + } } public void onMeasurementsAvailable(final GnssMeasurementsEvent event) { ListenerOperation<IGnssMeasurementsListener> operation = - new ListenerOperation<IGnssMeasurementsListener>() { - @Override - public void execute(IGnssMeasurementsListener listener) throws RemoteException { - listener.onGnssMeasurementsReceived(event); - } - }; + listener -> listener.onGnssMeasurementsReceived(event); foreach(operation); } @@ -98,4 +153,25 @@ public abstract class GnssMeasurementsProvider listener.onStatusChanged(mStatus); } } + + @VisibleForTesting + static class GnssMeasurementProviderNative { + public boolean isMeasurementSupported() { + return native_is_measurement_supported(); + } + + public boolean startMeasurementCollection(boolean enableFullTracking) { + return native_start_measurement_collection(enableFullTracking); + } + + public boolean stopMeasurementCollection() { + return native_stop_measurement_collection(); + } + } + + private static native boolean native_is_measurement_supported(); + + private static native boolean native_start_measurement_collection(boolean enableFullTracking); + + private static native boolean native_stop_measurement_collection(); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2b4f34e24573..4d8718f9ad5b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -4227,6 +4227,11 @@ public class PackageManagerService extends IPackageManager.Stub || appId == Process.ROOT_UID) { return false; } + // Installer gets to see all static libs. + if (PackageManager.PERMISSION_GRANTED + == checkUidPermission(Manifest.permission.INSTALL_PACKAGES, uid)) { + return false; + } } // No package means no static lib as it is always on internal storage diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java index a9cdafd9aeaa..507f0a8b7bb8 100644 --- a/services/core/java/com/android/server/slice/SliceManagerService.java +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -155,11 +155,10 @@ public class SliceManagerService extends ISliceManager.Stub { enforceAccess(pkg, uri); int user = Binder.getCallingUserHandle().getIdentifier(); uri = maybeAddUserId(uri, user); - getOrCreatePinnedSlice(uri, pkg).pin(pkg, specs, token); + String slicePkg = getProviderPkg(uri, user); + getOrCreatePinnedSlice(uri, slicePkg).pin(pkg, specs, token); - Uri finalUri = uri; mHandler.post(() -> { - String slicePkg = getProviderPkg(finalUri, user); if (slicePkg != null && !Objects.equals(pkg, slicePkg)) { mAppUsageStats.reportEvent(slicePkg, user, isAssistant(pkg, user) || isDefaultHomeApp(pkg, user) diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index eab391ed74ce..19c5a3d6452a 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -922,6 +922,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * @return Whether this WindowContainer should be magnified by the accessibility magnifier. */ boolean shouldMagnify() { + if (mSurfaceControl == null) { + return false; + } + for (int i = 0; i < mChildren.size(); i++) { if (!mChildren.get(i).shouldMagnify()) { return false; diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 3a9bbe4d976e..b3b37d6de564 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -1799,7 +1799,7 @@ static jboolean android_location_GnssGeofenceProvider_resume_geofence(JNIEnv* /* return JNI_FALSE; } -static jboolean android_location_GnssLocationProvider_is_measurement_supported( +static jboolean android_location_GnssMeasurementsProvider_is_measurement_supported( JNIEnv* env, jclass clazz) { if (gnssMeasurementIface != nullptr) { return JNI_TRUE; @@ -1808,7 +1808,7 @@ static jboolean android_location_GnssLocationProvider_is_measurement_supported( return JNI_FALSE; } -static jboolean android_location_GnssLocationProvider_start_measurement_collection( +static jboolean android_location_GnssMeasurementsProvider_start_measurement_collection( JNIEnv* /* env */, jobject /* obj */, jboolean enableFullTracking) { @@ -1842,7 +1842,7 @@ static jboolean android_location_GnssLocationProvider_start_measurement_collecti return JNI_TRUE; } -static jboolean android_location_GnssLocationProvider_stop_measurement_collection( +static jboolean android_location_GnssMeasurementsProvider_stop_measurement_collection( JNIEnv* env, jobject obj) { if (gnssMeasurementIface == nullptr) { @@ -2178,18 +2178,6 @@ static const JNINativeMethod sMethods[] = { {"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void *>(android_location_GnssLocationProvider_update_network_state)}, - {"native_is_measurement_supported", - "()Z", - reinterpret_cast<void *>( - android_location_GnssLocationProvider_is_measurement_supported)}, - {"native_start_measurement_collection", - "(Z)Z", - reinterpret_cast<void *>( - android_location_GnssLocationProvider_start_measurement_collection)}, - {"native_stop_measurement_collection", - "()Z", - reinterpret_cast<void *>( - android_location_GnssLocationProvider_stop_measurement_collection)}, {"native_is_navigation_message_supported", "()Z", reinterpret_cast<void *>( @@ -2269,6 +2257,22 @@ static const JNINativeMethod sGeofenceMethods[] = { reinterpret_cast<void *>(android_location_GnssGeofenceProvider_resume_geofence)}, }; +static const JNINativeMethod sMeasurementMethods[] = { + /* name, signature, funcPtr */ + {"native_is_measurement_supported", + "()Z", + reinterpret_cast<void *>( + android_location_GnssMeasurementsProvider_is_measurement_supported)}, + {"native_start_measurement_collection", + "(Z)Z", + reinterpret_cast<void *>( + android_location_GnssMeasurementsProvider_start_measurement_collection)}, + {"native_stop_measurement_collection", + "()Z", + reinterpret_cast<void *>( + android_location_GnssMeasurementsProvider_stop_measurement_collection)}, +}; + int register_android_server_location_GnssLocationProvider(JNIEnv* env) { jniRegisterNativeMethods( env, @@ -2280,6 +2284,11 @@ int register_android_server_location_GnssLocationProvider(JNIEnv* env) { "com/android/server/location/GnssGeofenceProvider", sGeofenceMethods, NELEM(sGeofenceMethods)); + jniRegisterNativeMethods( + env, + "com/android/server/location/GnssMeasurementsProvider", + sMeasurementMethods, + NELEM(sMeasurementMethods)); return jniRegisterNativeMethods( env, "com/android/server/location/GnssLocationProvider", diff --git a/services/net/java/android/net/dns/ResolvUtil.java b/services/net/java/android/net/dns/ResolvUtil.java index 97d20f4b2922..a2a6615e5f48 100644 --- a/services/net/java/android/net/dns/ResolvUtil.java +++ b/services/net/java/android/net/dns/ResolvUtil.java @@ -62,4 +62,13 @@ public class ResolvUtil { final long netidForResolv = NETID_USE_LOCAL_NAMESERVERS | (long) network.netId; return new Network((int) netidForResolv); } + + public static Network makeNetworkWithPrivateDnsBypass(Network network) { + return new Network(network) { + @Override + public InetAddress[] getAllByName(String host) throws UnknownHostException { + return blockingResolveAllLocally(network, host); + } + }; + } } diff --git a/services/robotests/src/com/android/server/location/GnssMeasurementsProviderTest.java b/services/robotests/src/com/android/server/location/GnssMeasurementsProviderTest.java new file mode 100644 index 000000000000..23d6cf69edc6 --- /dev/null +++ b/services/robotests/src/com/android/server/location/GnssMeasurementsProviderTest.java @@ -0,0 +1,90 @@ +package com.android.server.location; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.os.Handler; +import android.os.Looper; +import android.platform.test.annotations.Presubmit; + +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.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +/** + * Unit tests for {@link GnssMeasurementsProvider}. + */ +@RunWith(FrameworkRobolectricTestRunner.class) +@Config( + manifest = Config.NONE, + sdk = 27 +) +@SystemLoaderPackages({"com.android.server.location"}) +@Presubmit +public class GnssMeasurementsProviderTest { + @Mock + private GnssMeasurementsProvider.GnssMeasurementProviderNative mMockNative; + private GnssMeasurementsProvider mTestProvider; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mMockNative.startMeasurementCollection(anyBoolean())).thenReturn(true); + when(mMockNative.stopMeasurementCollection()).thenReturn(true); + + mTestProvider = new GnssMeasurementsProvider(RuntimeEnvironment.application, + new Handler(Looper.myLooper()), mMockNative) { + @Override + public boolean isGpsEnabled() { + return true; + } + }; + } + + @Test + public void register_nativeStarted() { + mTestProvider.registerWithService(); + verify(mMockNative).startMeasurementCollection(anyBoolean()); + } + + @Test + public void unregister_nativeStopped() { + mTestProvider.registerWithService(); + mTestProvider.unregisterFromService(); + verify(mMockNative).stopMeasurementCollection(); + } + + @Test + public void isSupported_nativeIsSupported() { + when(mMockNative.isMeasurementSupported()).thenReturn(true); + assertThat(mTestProvider.isAvailableInPlatform()).isTrue(); + + when(mMockNative.isMeasurementSupported()).thenReturn(false); + assertThat(mTestProvider.isAvailableInPlatform()).isFalse(); + } + + @Test + public void register_resume_started() { + mTestProvider.registerWithService(); + mTestProvider.resumeIfStarted(); + verify(mMockNative, times(2)).startMeasurementCollection(anyBoolean()); + } + + @Test + public void unregister_resume_notStarted() { + mTestProvider.registerWithService(); + mTestProvider.unregisterFromService(); + mTestProvider.resumeIfStarted(); + verify(mMockNative, times(1)).startMeasurementCollection(anyBoolean()); + } +} diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java index d49ba3ea3b4d..43a4e277a582 100644 --- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java @@ -93,7 +93,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase { mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken); mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken); - verify(mService, times(1)).createPinnedSlice(eq(TEST_URI), eq("pkg")); + verify(mService, times(1)).createPinnedSlice(eq(TEST_URI), anyString()); } @Test @@ -126,4 +126,4 @@ public class SliceManagerServiceTest extends UiServiceTestCase { verify(mContextSpy).checkPermission(eq("perm2"), eq(Process.myPid()), eq(Process.myUid())); } -}
\ No newline at end of file +} diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 920a6059f10c..97c5ac911563 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -81,7 +81,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; -import android.provider.Settings; +import android.provider.Settings.Global; import android.telephony.TelephonyManager; import android.util.ArraySet; import android.util.KeyValueListParser; @@ -1439,8 +1439,10 @@ public class AppStandbyController { boolean isAppIdleEnabled() { final boolean buildFlag = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableAutoPowerModes); - final boolean runtimeFlag = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.APP_STANDBY_ENABLED, 1) == 1; + final boolean runtimeFlag = Global.getInt(mContext.getContentResolver(), + Global.APP_STANDBY_ENABLED, 1) == 1 + && Global.getInt(mContext.getContentResolver(), + Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 1; return buildFlag && runtimeFlag; } @@ -1489,8 +1491,8 @@ public class AppStandbyController { } String getAppIdleSettings() { - return Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.APP_IDLE_CONSTANTS); + return Global.getString(mContext.getContentResolver(), + Global.APP_IDLE_CONSTANTS); } } @@ -1610,7 +1612,7 @@ public class AppStandbyController { }; /** - * Observe settings changes for {@link Settings.Global#APP_IDLE_CONSTANTS}. + * Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}. */ private class SettingsObserver extends ContentObserver { /** @@ -1650,10 +1652,11 @@ public class AppStandbyController { } void registerObserver() { - mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( - Settings.Global.APP_IDLE_CONSTANTS), false, this); - mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( - Settings.Global.APP_STANDBY_ENABLED), false, this); + final ContentResolver cr = mContext.getContentResolver(); + cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this); + cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this); + cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED), + false, this); } @Override @@ -1665,11 +1668,14 @@ public class AppStandbyController { void updateSettings() { if (DEBUG) { Slog.d(TAG, - "appidle=" + Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.APP_STANDBY_ENABLED)); - Slog.d(TAG, "appidleconstants=" + Settings.Global.getString( + "appidle=" + Global.getString(mContext.getContentResolver(), + Global.APP_STANDBY_ENABLED)); + Slog.d(TAG, + "adaptivebat=" + Global.getString(mContext.getContentResolver(), + Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED)); + Slog.d(TAG, "appidleconstants=" + Global.getString( mContext.getContentResolver(), - Settings.Global.APP_IDLE_CONSTANTS)); + Global.APP_IDLE_CONSTANTS)); } // Check if app_idle_enabled has changed setAppIdleEnabled(mInjector.isAppIdleEnabled()); |