diff options
22 files changed, 249 insertions, 224 deletions
diff --git a/api/current.txt b/api/current.txt index e3a20f5fee28..31ec76ec571c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -35147,6 +35147,7 @@ package android.os.storage { public final class StorageVolume implements android.os.Parcelable { method public deprecated android.content.Intent createAccessIntent(java.lang.String); + method public android.content.Intent createOpenDocumentTreeIntent(); method public int describeContents(); method public java.lang.String getDescription(android.content.Context); method public java.lang.String getState(); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index a2784237247c..791f3da0d5e8 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -3078,7 +3078,7 @@ public class AppOpsManager { */ public int unsafeCheckOpRaw(String op, int uid, String packageName) { try { - return mService.checkOperation(strOpToOp(op), uid, packageName); + return mService.checkOperationRaw(strOpToOp(op), uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 7fe21b23738c..139a39fe3a1d 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -37,10 +37,11 @@ public abstract class AppOpsManagerInternal { * @param uid The UID for which to check. * @param packageName The package for which to check. * @param superImpl The super implementation. + * @param raw Whether to check the raw op i.e. not interpret the mode based on UID state. * @return The app op check result. */ - int checkOperation(int code, int uid, String packageName, - TriFunction<Integer, Integer, String, Integer> superImpl); + int checkOperation(int code, int uid, String packageName, boolean raw, + QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl); /** * Allows overriding check audio operation behavior. diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java index 8a03e9eb7507..df1a7131a7ae 100644 --- a/core/java/android/os/storage/StorageVolume.java +++ b/core/java/android/os/storage/StorageVolume.java @@ -16,6 +16,7 @@ package android.os.storage; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; @@ -348,6 +349,32 @@ public final class StorageVolume implements Parcelable { return intent; } + /** + * Builds an {@link Intent#ACTION_OPEN_DOCUMENT_TREE} to allow the user to grant access to any + * directory subtree (or entire volume) from the {@link android.provider.DocumentsProvider}s + * available on the device. The initial location of the document navigation will be the root of + * this {@link StorageVolume}. + * + * Note that the returned {@link Intent} simply suggests that the user picks this {@link + * StorageVolume} by default, but the user may select a different location. Callers must respect + * the user's chosen location, even if it is different from the originally requested location. + * + * @return intent to {@link Intent#ACTION_OPEN_DOCUMENT_TREE} initially showing the contents + * of this {@link StorageVolume} + * @see Intent#ACTION_OPEN_DOCUMENT_TREE + */ + @NonNull public Intent createOpenDocumentTreeIntent() { + final String rootId = isEmulated() + ? DocumentsContract.EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID + : mFsUuid; + final Uri rootUri = DocumentsContract.buildRootUri( + DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY, rootId); + final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + .putExtra(DocumentsContract.EXTRA_INITIAL_URI, rootUri) + .putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true); + return intent; + } + @Override public boolean equals(Object obj) { if (obj instanceof StorageVolume && mPath != null) { diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index cd991cc0d6fc..a323ed1a51cb 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -238,6 +238,9 @@ public final class DocumentsContract { "com.android.externalstorage.documents"; /** {@hide} */ + public static final String EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID = "primary"; + + /** {@hide} */ public static final String PACKAGE_DOCUMENTS_UI = "com.android.documentsui"; /** @@ -857,16 +860,6 @@ public final class DocumentsContract { } /** - * Builds URI for user home directory on external (local) storage. - * {@hide} - */ - public static Uri buildHomeUri() { - // TODO: Avoid this type of interpackage copying. Added here to avoid - // direct coupling, but not ideal. - return DocumentsContract.buildRootUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY, "home"); - } - - /** * Build URI representing the recently modified documents of a specific root * in a document provider. When queried, a provider will return zero or more * rows with columns defined by {@link Document}. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 9f019f778167..d93985c8ec3d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -12820,6 +12820,17 @@ public final class Settings { "privileged_device_identifier_3p_check_relaxed"; /** + * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE + * permission check for preloaded non-privileged apps. + * + * STOPSHIP: Remove this once we ship with the new device identifier check enabled. + * + * @hide + */ + public static final String PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED = + "privileged_device_identifier_non_priv_check_relaxed"; + + /** * If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored * and restoring to lower version of platform API will be skipped. * diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index e571656b9135..e59bee42c21c 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -65,4 +65,6 @@ interface IAppOpsService { void startWatchingNoted(in int[] ops, IAppOpsNotedCallback callback); void stopWatchingNoted(IAppOpsNotedCallback callback); + + int checkOperationRaw(int code, int uid, String packageName); } diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 6d1aae12d858..f8bd4e33ec75 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -384,6 +384,7 @@ public class SettingsBackupTest { Settings.Global.PRIV_APP_OOB_LIST, Settings.Global.PRIVATE_DNS_DEFAULT_MODE, Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, + Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED, Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED, Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS, diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 1eb4b7494085..8d04702ea5f6 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -67,7 +67,7 @@ public class ExternalStorageProvider extends FileSystemProvider { private static final boolean DEBUG = false; - public static final String AUTHORITY = "com.android.externalstorage.documents"; + public static final String AUTHORITY = DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY; private static final Uri BASE_URI = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY).build(); @@ -96,7 +96,8 @@ public class ExternalStorageProvider extends FileSystemProvider { public boolean reportAvailableBytes = true; } - private static final String ROOT_ID_PRIMARY_EMULATED = "primary"; + private static final String ROOT_ID_PRIMARY_EMULATED = + DocumentsContract.EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID; private static final String ROOT_ID_HOME = "home"; private StorageManager mStorageManager; diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java index 89ebf4d1300a..d400159984a6 100644 --- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java +++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java @@ -31,7 +31,7 @@ import androidx.preference.PreferenceViewHolder; import java.util.Arrays; /** - * This BarChartPreference shows four bar views in this preference at most. + * This BarChartPreference shows up to four bar views in this preference at most. * * <p>The following code sample shows a typical use, with an XML layout and code to initialize the * contents of the BarChartPreference: @@ -74,71 +74,28 @@ public class BarChartPreference extends Preference { }; private int mMaxBarHeight; - private @StringRes int mTitleId; - private @StringRes int mDetailsId; + @StringRes + private int mTitleId; + @StringRes + private int mDetailsId; private BarViewInfo[] mBarViewsInfo; private View.OnClickListener mDetailsOnClickListener; - /** - * Constructs a new BarChartPreference with the given context's theme. - * It sets a layout with settings bar chart style - * - * @param context The Context the view is running in, through which it can - * access the current theme, resources, etc. - */ public BarChartPreference(Context context) { super(context); init(); } - /** - * Constructs a new BarChartPreference with the given context's theme and the supplied - * attribute set. - * It sets a layout with settings bar chart style - * - * @param context the Context the view is running in - * @param attrs the attributes of the XML tag that is inflating the view. - */ public BarChartPreference(Context context, AttributeSet attrs) { super(context, attrs); init(); } - /** - * Constructs a new BarChartPreference with the given context's theme, the supplied - * attribute set, and default style attribute. - * It sets a layout with settings bar chart style - * - * @param context The Context the view is running in, through which it can - * access the current theme, resources, etc. - * @param attrs The attributes of the XML tag that is inflating the view. - * @param defStyleAttr An attribute in the current theme that contains a - * reference to a style resource that supplies default - * values for the view. Can be 0 to not look for - * defaults. - */ public BarChartPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } - /** - * Constructs a new BarChartPreference with the given context's theme, the supplied - * attribute set, and default styles. - * It sets a layout with settings bar chart style - * - * @param context The Context the view is running in, through which it can - * access the current theme, resources, etc. - * @param attrs The attributes of the XML tag that is inflating the view. - * @param defStyleAttr An attribute in the current theme that contains a - * reference to a style resource that supplies default - * values for the view. Can be 0 to not look for - * defaults. - * @param defStyleRes A resource identifier of a style resource that - * supplies default values for the view, used only if - * defStyleAttr is 0 or can not be found in the theme. - * Can be 0 to not look for defaults. - */ public BarChartPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); @@ -172,8 +129,6 @@ public class BarChartPreference extends Preference { /** * Set all bar view information which you'd like to show in preference. * - * <p>This method helps you do a sort by {@linkBarViewInfo#mBarNumber} in descending order. - * * @param barViewsInfo the barViewsInfo contain at least one {@link BarViewInfo}. */ public void setAllBarViewsInfo(@NonNull BarViewInfo[] barViewsInfo) { @@ -181,7 +136,7 @@ public class BarChartPreference extends Preference { // Do a sort in descending order, the first element would have max {@link // BarViewInfo#mBarNumber} Arrays.sort(mBarViewsInfo); - caculateAllBarViewsHeight(); + calculateAllBarViewHeights(); notifyChanged(); } @@ -224,19 +179,19 @@ public class BarChartPreference extends Preference { continue; } barView.setVisibility(View.VISIBLE); - barView.updateBarViewUI(mBarViewsInfo[index]); + barView.updateView(mBarViewsInfo[index]); } } - private void caculateAllBarViewsHeight() { + private void calculateAllBarViewHeights() { // Since we sorted this array in advance, the first element must have the max {@link - // BarViewInfo#mBarNumber}. - final int maxBarViewNumber = mBarViewsInfo[0].getBarNumber(); - // If the max number of bar view is zero, then we don't caculate the unit for bar height. - final int unit = maxBarViewNumber == 0 ? 0 : mMaxBarHeight / maxBarViewNumber; + // BarViewInfo#mHeight}. + final int maxBarHeight = mBarViewsInfo[0].getHeight(); + // If the max number of bar view is zero, then we don't calculate the unit for bar height. + final int unit = maxBarHeight == 0 ? 0 : mMaxBarHeight / maxBarHeight; for (BarViewInfo barView : mBarViewsInfo) { - barView.setBarHeight(barView.getBarNumber() * unit); + barView.setNormalizedHeight(barView.getHeight() * unit); } } } diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java index 6243a2de387a..6bf61ae70312 100644 --- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java +++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java @@ -30,7 +30,7 @@ import androidx.annotation.ColorInt; import androidx.annotation.VisibleForTesting; /** - * A extension view for bar chart. + * {@link View} for a single vertical bar with icon and summary. */ public class BarView extends LinearLayout { @@ -41,24 +41,11 @@ public class BarView extends LinearLayout { private TextView mBarTitle; private TextView mBarSummary; - /** - * Constructs a new BarView with the given context's theme. - * - * @param context The Context the view is running in, through which it can - * access the current theme, resources, etc. - */ public BarView(Context context) { super(context); init(); } - /** - * Constructs a new BarView with the given context's theme and the supplied - * attribute set. - * - * @param context the Context the view is running in - * @param attrs the attributes of the XML tag that is inflating the view. - */ public BarView(Context context, AttributeSet attrs) { super(context, attrs); init(); @@ -77,17 +64,16 @@ public class BarView extends LinearLayout { } /** - * This helps update the bar view UI with a {@link BarViewInfo}. - * - * @param barViewInfo A {@link BarViewInfo} saves bar view status. + * Updates the view with a {@link BarViewInfo}. */ - public void updateBarViewUI(BarViewInfo barViewInfo) { + void updateView(BarViewInfo barViewInfo) { + setOnClickListener(barViewInfo.getClickListener()); //Set height of bar view - mBarView.getLayoutParams().height = barViewInfo.getBarHeight(); + mBarView.getLayoutParams().height = barViewInfo.getNormalizedHeight(); mIcon.setImageDrawable(barViewInfo.getIcon()); // For now, we use the bar number as title. - mBarTitle.setText(Integer.toString(barViewInfo.getBarNumber())); - mBarSummary.setText(barViewInfo.getSummaryRes()); + mBarTitle.setText(Integer.toString(barViewInfo.getHeight())); + mBarSummary.setText(barViewInfo.getSummary()); } @VisibleForTesting @@ -106,9 +92,9 @@ public class BarView extends LinearLayout { setGravity(Gravity.CENTER); mBarView = findViewById(R.id.bar_view); - mIcon = (ImageView) findViewById(R.id.icon_view); - mBarTitle = (TextView) findViewById(R.id.bar_title); - mBarSummary = (TextView) findViewById(R.id.bar_summary); + mIcon = findViewById(R.id.icon_view); + mBarTitle = findViewById(R.id.bar_title); + mBarSummary = findViewById(R.id.bar_summary); } private void setOnClickListner(View.OnClickListener listener) { diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java index aa83ce99d200..409f9ea05889 100644 --- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java +++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java @@ -31,116 +31,71 @@ import java.util.Comparator; public class BarViewInfo implements Comparable<BarViewInfo> { private final Drawable mIcon; - private View.OnClickListener mListener; - private @StringRes int mSummaryRes; + private View.OnClickListener mClickListener; + @StringRes + private int mSummary; // A number indicates this bar's height. The larger number shows a higher bar view. - private int mBarNumber; + private int mHeight; // A real height of bar view. - private int mBarHeight; + private int mNormalizedHeight; /** * Construct a BarViewInfo instance. * - * @param icon the icon of bar view. - * @param barNumber the number of bar view. The larger number show a more height of bar view. - * @param summaryRes the resource identifier of the string resource to be displayed - * @return BarViewInfo object. + * @param icon The icon of bar view. + * @param barHeight The height of bar view. Larger number shows a higher bar view. + * @param summary The string resource id for summary. */ - public BarViewInfo(Drawable icon, @IntRange(from = 0) int barNumber, - @StringRes int summaryRes) { + public BarViewInfo(Drawable icon, @IntRange(from = 0) int barHeight, @StringRes int summary) { mIcon = icon; - mBarNumber = barNumber; - mSummaryRes = summaryRes; + mHeight = barHeight; + mSummary = summary; } /** - * Set number for bar view. - * - * @param barNumber the number of bar view. The larger number shows a higher bar view. + * Set a click listener for bar view. */ - public void setBarNumber(@IntRange(from = 0) int barNumber) { - mBarNumber = barNumber; + public void setClickListener(@Nullable View.OnClickListener listener) { + mClickListener = listener; } - /** - * Set summary resource for bar view - * - * @param resId the resource identifier of the string resource to be displayed - */ - public void setSummary(@StringRes int resId) { - mSummaryRes = resId; + @Override + public int compareTo(BarViewInfo other) { + // Descending order + return Comparator.comparingInt((BarViewInfo barViewInfo) -> barViewInfo.mHeight) + .compare(other, this); } - /** - * Set a click listner for bar view. - * - * @param listener the click listner is attached on bar view. - */ - public void setClickListener(@Nullable View.OnClickListener listener) { - mListener = listener; + void setHeight(@IntRange(from = 0) int height) { + mHeight = height; } - /** - * Get the icon of bar view. - * - * @return Drawable the icon of bar view. - */ - public Drawable getIcon() { - return mIcon; + void setSummary(@StringRes int resId) { + mSummary = resId; } - /** - * Get the OnClickListener of bar view. - * - * @return View.OnClickListener the click listner of bar view. - */ - public View.OnClickListener getListener() { - return mListener; + Drawable getIcon() { + return mIcon; } - /** - * Get the real height of bar view. - * - * @return the real height of bar view. - */ - public int getBarHeight() { - return mBarHeight; + int getHeight() { + return mHeight; } - /** - * Get summary resource of bar view. - * - * @return summary resource of bar view. - */ - public int getSummaryRes() { - return mSummaryRes; + View.OnClickListener getClickListener() { + return mClickListener; } - /** - * Get the number of app uses this permisssion. - * - * @return the number of app uses this permission. - */ - public int getBarNumber() { - return mBarNumber; + @StringRes + int getSummary() { + return mSummary; } - @Override - public int compareTo(BarViewInfo other) { - // Descending order - return Comparator.comparingInt((BarViewInfo barViewInfo) -> barViewInfo.mBarNumber) - .compare(other, this); + void setNormalizedHeight(@IntRange(from = 0) int barHeight) { + mNormalizedHeight = barHeight; } - /** - * Set a real height for bar view. - * - * <p>This method should not be called by outside. It usually should be called by - * {@link BarChartPreference#caculateAllBarViewsHeight} - * - * @param barHeight the real bar height for bar view. - */ - void setBarHeight(@IntRange(from = 0) int barHeight) { - mBarHeight = barHeight; + int getNormalizedHeight() { + return mNormalizedHeight; } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java index 371c3d46dfb4..d4e74810ea3f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java @@ -208,4 +208,18 @@ public class BarChartPreferenceTest { assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mBarView1.getSummary()).isEqualTo(mContext.getText(R.string.debug_app)); } + + @Test + public void setAllBarViewsInfo_setClickListenerForBarView_barViewAttachClickListener() { + final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app); + viewInfo.setClickListener(v -> { + }); + final BarViewInfo[] barViewsInfo = new BarViewInfo[]{viewInfo}; + + mPreference.setAllBarViewsInfo(barViewsInfo); + mPreference.onBindViewHolder(mHolder); + + assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mBarView1.hasOnClickListeners()).isTrue(); + } } diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index f0ec69f488b1..f027253651ee 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -65,7 +65,6 @@ import android.os.ServiceManager; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; -import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; @@ -1646,29 +1645,40 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override + public int checkOperationRaw(int code, int uid, String packageName) { + return checkOperationInternal(code, uid, packageName, true /*raw*/); + } + + @Override public int checkOperation(int code, int uid, String packageName) { + return checkOperationInternal(code, uid, packageName, false /*raw*/); + } + + private int checkOperationInternal(int code, int uid, String packageName, boolean raw) { final CheckOpsDelegate delegate; synchronized (this) { delegate = mCheckOpsDelegate; } if (delegate == null) { - return checkOperationImpl(code, uid, packageName); + return checkOperationImpl(code, uid, packageName, raw); } - return delegate.checkOperation(code, uid, packageName, + return delegate.checkOperation(code, uid, packageName, raw, AppOpsService.this::checkOperationImpl); } - private int checkOperationImpl(int code, int uid, String packageName) { + private int checkOperationImpl(int code, int uid, String packageName, + boolean raw) { verifyIncomingUid(uid); verifyIncomingOp(code); String resolvedPackageName = resolvePackageName(uid, packageName); if (resolvedPackageName == null) { return AppOpsManager.MODE_IGNORED; } - return checkOperationUnchecked(code, uid, resolvedPackageName); + return checkOperationUnchecked(code, uid, resolvedPackageName, raw); } - private int checkOperationUnchecked(int code, int uid, String packageName) { + private int checkOperationUnchecked(int code, int uid, String packageName, + boolean raw) { synchronized (this) { if (isOpRestrictedLocked(uid, code, packageName)) { return AppOpsManager.MODE_IGNORED; @@ -1677,7 +1687,8 @@ public class AppOpsService extends IAppOpsService.Stub { UidState uidState = getUidStateLocked(uid, false); if (uidState != null && uidState.opModes != null && uidState.opModes.indexOfKey(code) >= 0) { - return uidState.evalMode(uidState.opModes.get(code)); + final int rawMode = uidState.opModes.get(code); + return raw ? rawMode : uidState.evalMode(rawMode); } Op op = getOpLocked(code, uid, packageName, false, true, false); if (op == null) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3bfd363de836..983ec4be328d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -20117,18 +20117,18 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public int checkOperation(int code, int uid, String packageName, - TriFunction<Integer, Integer, String, Integer> superImpl) { + public int checkOperation(int code, int uid, String packageName, boolean raw, + QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) { if (uid == mTargetUid && isTargetOp(code)) { final long identity = Binder.clearCallingIdentity(); try { return superImpl.apply(code, Process.SHELL_UID, - "com.android.shell"); + "com.android.shell", raw); } finally { Binder.restoreCallingIdentity(identity); } } - return superImpl.apply(code, uid, packageName); + return superImpl.apply(code, uid, packageName, raw); } @Override diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index a51b0183b905..4a32f75ea677 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -4305,14 +4305,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } final File subtypeFile = new File(inputMethodDir, ADDITIONAL_SUBTYPES_FILE_NAME); mAdditionalInputMethodSubtypeFile = new AtomicFile(subtypeFile, "input-subtypes"); - if (!subtypeFile.exists()) { - // If "subtypes.xml" doesn't exist, create a blank file. - writeAdditionalInputMethodSubtypes( - mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, methodMap); - } else { - readAdditionalInputMethodSubtypes( - mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile); - } + readAdditionalInputMethodSubtypes(mAdditionalSubtypesMap, + mAdditionalInputMethodSubtypeFile); } private void deleteAllInputMethodSubtypes(String imiId) { @@ -4352,6 +4346,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private static void writeAdditionalInputMethodSubtypes( ArrayMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile, ArrayMap<String, InputMethodInfo> methodMap) { + if (allSubtypes.isEmpty()) { + if (subtypesFile.exists()) { + subtypesFile.delete(); + } + return; + } + // Safety net for the case that this function is called before methodMap is set. final boolean isSetMethodMap = methodMap != null && methodMap.size() > 0; FileOutputStream fos = null; @@ -4408,6 +4409,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub ArrayMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile) { if (allSubtypes == null || subtypesFile == null) return; allSubtypes.clear(); + if (!subtypesFile.exists()) { + // Not having the file means there is no additional subtype. + return; + } try (final FileInputStream fis = subtypesFile.openRead()) { final XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, StandardCharsets.UTF_8.name()); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 53ee16b1b585..2359c2a02863 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1952,9 +1952,11 @@ public class NotificationManagerService extends SystemService { */ @GuardedBy("mNotificationLock") protected void reportSeen(NotificationRecord r) { - mAppUsageStats.reportEvent(r.sbn.getPackageName(), - getRealUserId(r.sbn.getUserId()), - UsageEvents.Event.NOTIFICATION_SEEN); + if (!r.isProxied()) { + mAppUsageStats.reportEvent(r.sbn.getPackageName(), + getRealUserId(r.sbn.getUserId()), + UsageEvents.Event.NOTIFICATION_SEEN); + } } protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy, @@ -4056,7 +4058,7 @@ public class NotificationManagerService extends SystemService { final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i); for (int j = 0; j < listeners.size(); j++) { - final ComponentName componentName = listeners.valueAt(i); + final ComponentName componentName = listeners.valueAt(j); componentName.writeToProto(proto, ListenersDisablingEffectsProto.LISTENER_COMPONENTS); } @@ -4201,8 +4203,8 @@ public class NotificationManagerService extends SystemService { final int listenerSize = listeners.size(); for (int j = 0; j < listenerSize; j++) { - if (i > 0) pw.print(','); - final ComponentName listener = listeners.valueAt(i); + if (j > 0) pw.print(','); + final ComponentName listener = listeners.valueAt(j); if (listener != null) { pw.print(listener); } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 1f8893c56874..e2c64ca459a8 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -151,7 +151,6 @@ public final class NotificationRecord { private int mSuppressedVisualEffects = 0; private String mUserExplanation; - private String mPeopleExplanation; private boolean mPreChannelsNotification = true; private Uri mSound; private long[] mVibration; @@ -1191,6 +1190,13 @@ public final class NotificationRecord { } /** + * Returns whether this notification was posted by a secondary app + */ + public boolean isProxied() { + return !Objects.equals(sbn.getPackageName(), sbn.getOpPkg()); + } + + /** * @return all {@link Uri} that should have permission granted to whoever * will be rendering it. This list has already been vetted to only * include {@link Uri} that the enqueuing app can grant. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 28fb01d6d958..6453db5db1b6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -888,7 +888,7 @@ public class PackageManagerService extends IPackageManager.Stub volatile boolean mSystemReady; volatile boolean mSafeMode; volatile boolean mHasSystemUidErrors; - private volatile boolean mWebInstantAppsDisabled; + private volatile SparseBooleanArray mWebInstantAppsDisabled = new SparseBooleanArray(); ApplicationInfo mAndroidApplication; final ActivityInfo mResolveActivity = new ActivityInfo(); @@ -5904,8 +5904,8 @@ public class PackageManagerService extends IPackageManager.Stub /** * Returns whether or not instant apps have been disabled remotely. */ - private boolean areWebInstantAppsDisabled() { - return mWebInstantAppsDisabled; + private boolean areWebInstantAppsDisabled(int userId) { + return mWebInstantAppsDisabled.get(userId); } private boolean isInstantAppResolutionAllowed( @@ -5936,7 +5936,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) { return false; - } else if (areWebInstantAppsDisabled()) { + } else if (areWebInstantAppsDisabled(userId)) { return false; } } @@ -6816,7 +6816,7 @@ public class PackageManagerService extends IPackageManager.Stub private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos, String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, boolean resolveForStart, int userId, Intent intent) { - final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(); + final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled(userId); for (int i = resolveInfos.size() - 1; i >= 0; i--) { final ResolveInfo info = resolveInfos.get(i); // remove locally resolved instant app web results when disabled @@ -20124,16 +20124,21 @@ public class PackageManagerService extends IPackageManager.Stub ContentObserver co = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange) { - mWebInstantAppsDisabled = - (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) || - (Secure.getInt(resolver, Secure.INSTANT_APPS_ENABLED, 1) == 0); + boolean ephemeralFeatureDisabled = + Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0; + for (int userId : UserManagerService.getInstance().getUserIds()) { + boolean instantAppsDisabledForUser = + ephemeralFeatureDisabled || Secure.getIntForUser(resolver, + Secure.INSTANT_APPS_ENABLED, 1, userId) == 0; + mWebInstantAppsDisabled.put(userId, instantAppsDisabledForUser); + } } }; mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global .getUriFor(Global.ENABLE_EPHEMERAL_FEATURE), - false, co, UserHandle.USER_SYSTEM); + false, co, UserHandle.USER_ALL); mContext.getContentResolver().registerContentObserver(android.provider.Settings.Secure - .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM); + .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL); co.onChange(true); // Disable any carrier apps. We do this very early in boot to prevent the apps from being diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 2aed35f32d6c..371e8f4db9de 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -232,11 +232,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Override - protected void reportSeen(NotificationRecord r) { - return; - } - - @Override protected void reportUserInteraction(NotificationRecord r) { return; } @@ -3823,7 +3818,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); - NotificationVisibility[] notificationVisibility = new NotificationVisibility[] { + NotificationVisibility[] notificationVisibility = new NotificationVisibility[]{ NotificationVisibility.obtain(r.getKey(), 0, 0, true) }; mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility, @@ -3831,4 +3826,27 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(0, mService.countLogSmartSuggestionsVisible); } + + public void testReportSeen_delegated() { + Notification.Builder nb = + new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setContentTitle("foo") + .setSmallIcon(android.R.drawable.sym_def_app_icon); + + StatusBarNotification sbn = new StatusBarNotification(PKG, "opPkg", 0, "tag", mUid, 0, + nb.build(), new UserHandle(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.reportSeen(r); + verify(mAppUsageStats, never()).reportEvent(anyString(), anyInt(), anyInt()); + + } + + @Test + public void testReportSeen_notDelegated() { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); + + mService.reportSeen(r); + verify(mAppUsageStats, times(1)).reportEvent(anyString(), anyInt(), anyInt()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java index 522ab9ffb291..04e433e98678 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java @@ -164,6 +164,7 @@ public class WindowManagerServiceRule implements TestRule { } private void tearDown() { + cancelAllPendingAnimations(); waitUntilWindowManagerHandlersIdle(); destroyAllSurfaceTransactions(); destroyAllSurfaceControls(); @@ -178,6 +179,15 @@ public class WindowManagerServiceRule implements TestRule { return mService; } + private void cancelAllPendingAnimations() { + for (final WeakReference<SurfaceControl> reference : mSurfaceControls) { + final SurfaceControl sc = reference.get(); + if (sc != null) { + mService.mSurfaceAnimationRunner.onAnimationCancelled(sc); + } + } + } + void waitUntilWindowManagerHandlersIdle() { final WindowManagerService wm = getWindowManagerService(); if (wm == null) { diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index 553e3fb9d219..0edc0026722b 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -284,8 +284,6 @@ public final class TelephonyPermissions { */ private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid, int uid, String callingPackage, String message) { - Log.wtf(LOG_TAG, - "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message); // If the device identifier check is enabled then enforce the new access requirements for // both 1P and 3P apps. boolean enableDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(), @@ -295,17 +293,40 @@ public final class TelephonyPermissions { boolean relax3PDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(), Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED, 0) == 1; boolean is3PApp = true; + // Also check if the application is a preloaded non-privileged app; if so there is a + // separate setting to relax the check for these apps to ensure users can relax the check + // for 3P or non-priv apps as needed while continuing to test the other. + boolean relaxNonPrivDeviceIdentifierCheck = Settings.Global.getInt( + context.getContentResolver(), + Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED, 0) == 1; + boolean isNonPrivApp = false; ApplicationInfo callingPackageInfo = null; try { callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0); - if (callingPackageInfo.isSystemApp()) { + if (callingPackageInfo.isPrivilegedApp()) { is3PApp = false; + } else if (callingPackageInfo.isSystemApp()) { + is3PApp = false; + isNonPrivApp = true; } } catch (PackageManager.NameNotFoundException e) { // If the application info for the calling package could not be found then assume the // calling app is a 3P app to detect any issues with the check + Log.e(LOG_TAG, "Exception caught obtaining package info for package " + callingPackage, + e); } - if (enableDeviceIdentifierCheck || (is3PApp && !relax3PDeviceIdentifierCheck)) { + Log.wtf(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message + + ":is3PApp=" + is3PApp + ":isNonPrivApp=" + isNonPrivApp); + // The new Q restrictions for device identifier access will be enforced if any of the + // following are true: + // - The PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED setting has been set. + // - The app requesting a device identifier is not a preloaded app (3P), and the + // PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED setting has not been set. + // - The app requesting a device identifier is a preloaded app but is not a privileged app, + // and the PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED setting has not been set. + if (enableDeviceIdentifierCheck + || (is3PApp && !relax3PDeviceIdentifierCheck) + || (isNonPrivApp && !relaxNonPrivDeviceIdentifierCheck)) { boolean targetQBehaviorDisabled = Settings.Global.getInt(context.getContentResolver(), Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, 0) == 0; if (callingPackage != null) { |