diff options
12 files changed, 117 insertions, 126 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index e1cb5e4f062a..8bc603d8513c 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -52315,7 +52315,7 @@ package android.view.textservice { method @NonNull public java.util.List<android.view.textservice.SpellCheckerInfo> getEnabledSpellCheckerInfos(); method public boolean isSpellCheckerEnabled(); method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean); - method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable android.os.Bundle, @Nullable java.util.Locale, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener, boolean, int); + method @Nullable public android.view.textservice.SpellCheckerSession newSpellCheckerSession(@Nullable java.util.Locale, boolean, int, @Nullable android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener); } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 579f9126b318..d4d3321d37a4 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6169,13 +6169,22 @@ public class DevicePolicyManager { // STOPSHIP(b/174298501): clarify the expected return value following generateKeyPair call. /** - * Called by a device or profile owner, or delegated certificate installer, to query whether a - * certificate and private key are installed under a given alias. + * This API can be called by the following to query whether a certificate and private key are + * installed under a given alias: + * <ul> + * <li>Device owner</li> + * <li>Profile owner</li> + * <li>Delegated certificate installer</li> + * <li>Credential management app</li> + * </ul> + * + * If called by the credential management app, the alias must exist in the credential + * management app's {@link android.security.AppUriAuthenticationPolicy}. * * @param alias The alias under which the key pair is installed. * @return {@code true} if a key pair with this alias exists, {@code false} otherwise. - * @throws SecurityException if the caller is not a device or profile owner or a delegated - * certificate installer. + * @throws SecurityException if the caller is not a device or profile owner, a delegated + * certificate installer or the credential management app. * @see #setDelegatedScopes * @see #DELEGATION_CERT_INSTALL */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index f0b22a923e0f..13f397912642 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -15835,6 +15835,7 @@ public final class Settings { * * @hide */ + @Readable public static final String BLOCK_UNTRUSTED_TOUCHES_MODE = "block_untrusted_touches"; /** @@ -15860,6 +15861,7 @@ public final class Settings { * * @hide */ + @Readable public static final String MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH = "maximum_obscuring_opacity_for_touch"; diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java index ba58b6525a6d..a449cf1876e1 100644 --- a/core/java/android/view/textservice/SpellCheckerSession.java +++ b/core/java/android/view/textservice/SpellCheckerSession.java @@ -16,6 +16,8 @@ package android.view.textservice; +import android.annotation.BinderThread; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Build; @@ -27,6 +29,7 @@ import android.os.RemoteException; import android.util.Log; import android.view.inputmethod.InputMethodManager; +import com.android.internal.annotations.GuardedBy; import com.android.internal.textservice.ISpellCheckerSession; import com.android.internal.textservice.ISpellCheckerSessionListener; import com.android.internal.textservice.ITextServicesSessionListener; @@ -35,6 +38,7 @@ import dalvik.system.CloseGuard; import java.util.LinkedList; import java.util.Queue; +import java.util.concurrent.Executor; /** * The SpellCheckerSession interface provides the per client functionality of SpellCheckerService. @@ -102,38 +106,26 @@ public class SpellCheckerSession { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private final SpellCheckerSessionListener mSpellCheckerSessionListener; private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl; + private final Executor mExecutor; private final CloseGuard mGuard = CloseGuard.get(); - /** Handler that will execute the main tasks */ - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_ON_GET_SUGGESTION_MULTIPLE: - handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj); - break; - case MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE: - handleOnGetSentenceSuggestionsMultiple((SentenceSuggestionsInfo[]) msg.obj); - break; - } - } - }; - /** * Constructor * @hide */ public SpellCheckerSession( - SpellCheckerInfo info, TextServicesManager tsm, SpellCheckerSessionListener listener) { + SpellCheckerInfo info, TextServicesManager tsm, SpellCheckerSessionListener listener, + Executor executor) { if (info == null || listener == null || tsm == null) { throw new NullPointerException(); } mSpellCheckerInfo = info; - mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler); + mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(this); mInternalListener = new InternalListener(mSpellCheckerSessionListenerImpl); mTextServicesManager = tsm; mSpellCheckerSessionListener = listener; + mExecutor = executor; mGuard.open("finishSession"); } @@ -219,12 +211,13 @@ public class SpellCheckerSession { textInfos, suggestionsLimit, sequentialWords); } - private void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionInfos) { - mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos); + void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionsInfos) { + mExecutor.execute(() -> mSpellCheckerSessionListener.onGetSuggestions(suggestionsInfos)); } - private void handleOnGetSentenceSuggestionsMultiple(SentenceSuggestionsInfo[] suggestionInfos) { - mSpellCheckerSessionListener.onGetSentenceSuggestions(suggestionInfos); + void handleOnGetSentenceSuggestionsMultiple(SentenceSuggestionsInfo[] suggestionsInfos) { + mExecutor.execute(() -> + mSpellCheckerSessionListener.onGetSentenceSuggestions(suggestionsInfos)); } private static final class SpellCheckerSessionListenerImpl @@ -249,7 +242,8 @@ public class SpellCheckerSession { } private final Queue<SpellCheckerParams> mPendingTasks = new LinkedList<>(); - private Handler mHandler; + @GuardedBy("SpellCheckerSessionListenerImpl.this") + private SpellCheckerSession mSpellCheckerSession; private static final int STATE_WAIT_CONNECTION = 0; private static final int STATE_CONNECTED = 1; @@ -270,8 +264,8 @@ public class SpellCheckerSession { private HandlerThread mThread; private Handler mAsyncHandler; - public SpellCheckerSessionListenerImpl(Handler handler) { - mHandler = handler; + SpellCheckerSessionListenerImpl(SpellCheckerSession spellCheckerSession) { + mSpellCheckerSession = spellCheckerSession; } private static class SpellCheckerParams { @@ -349,6 +343,7 @@ public class SpellCheckerSession { } } + @GuardedBy("SpellCheckerSessionListenerImpl.this") private void processCloseLocked() { if (DBG) Log.d(TAG, "entering processCloseLocked:" + " session" + (mISpellCheckerSession != null ? ".hashCode()=#" @@ -358,7 +353,7 @@ public class SpellCheckerSession { if (mThread != null) { mThread.quit(); } - mHandler = null; + mSpellCheckerSession = null; mPendingTasks.clear(); mThread = null; mAsyncHandler = null; @@ -502,23 +497,30 @@ public class SpellCheckerSession { processTask(session, scp, false); } + @BinderThread @Override public void onGetSuggestions(SuggestionsInfo[] results) { - synchronized (this) { - if (mHandler != null) { - mHandler.sendMessage(Message.obtain(mHandler, - MSG_ON_GET_SUGGESTION_MULTIPLE, results)); - } + SpellCheckerSession session = getSpellCheckerSession(); + if (session != null) { + // Lock should not be held when calling callback, in order to avoid deadlock. + session.handleOnGetSuggestionsMultiple(results); } } + @BinderThread @Override public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) { - synchronized (this) { - if (mHandler != null) { - mHandler.sendMessage(Message.obtain(mHandler, - MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE, results)); - } + SpellCheckerSession session = getSpellCheckerSession(); + if (session != null) { + // Lock should not be held when calling callback, in order to avoid deadlock. + session.handleOnGetSentenceSuggestionsMultiple(results); + } + } + + @Nullable + private SpellCheckerSession getSpellCheckerSession() { + synchronized (SpellCheckerSessionListenerImpl.this) { + return mSpellCheckerSession; } } } diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java index 4f6fa272e103..bf91cca85522 100644 --- a/core/java/android/view/textservice/TextServicesManager.java +++ b/core/java/android/view/textservice/TextServicesManager.java @@ -16,6 +16,7 @@ package android.view.textservice; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; @@ -25,6 +26,8 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerExecutor; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; @@ -40,6 +43,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Objects; +import java.util.concurrent.Executor; /** * System API to the overall text services, which arbitrates interaction between applications @@ -161,10 +166,12 @@ public final class TextServicesManager { * {@link SuggestionsInfo#RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS} will be passed to the spell * checker as supported attributes. * - * @see #newSpellCheckerSession(Bundle, Locale, SpellCheckerSessionListener, boolean, int) + * @see #newSpellCheckerSession(Locale, boolean, int, Bundle, Executor, + * SpellCheckerSessionListener) * @param bundle A bundle to pass to the spell checker. * @param locale The locale for the spell checker. * @param listener A spell checker session lister for getting results from the spell checker. + * The listener will be called on the calling thread. * @param referToSpellCheckerLanguageSettings If true, the session for one of enabled * languages in settings will be used. * @return A spell checker session from the spell checker. @@ -174,10 +181,15 @@ public final class TextServicesManager { @Nullable Locale locale, @NonNull SpellCheckerSessionListener listener, boolean referToSpellCheckerLanguageSettings) { - return newSpellCheckerSession(bundle, locale, listener, referToSpellCheckerLanguageSettings, - SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY - | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO - | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS); + // Attributes existed before {@link #newSpellCheckerSession(Locale, boolean, int, Bundle, + // Executor, SpellCheckerSessionListener)} was introduced. + int supportedAttributes = SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY + | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO + | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS; + // Using the implicit looper to preserve the old behavior. + Executor executor = new HandlerExecutor(new Handler()); + return newSpellCheckerSession(locale, referToSpellCheckerLanguageSettings, + supportedAttributes, bundle, executor, listener); } /** @@ -191,25 +203,28 @@ public final class TextServicesManager { * language only (e.g. "en"), the specified locale in Settings (e.g. "en_US") will be * selected. * - * @param bundle A bundle to pass to the spell checker. * @param locale The locale for the spell checker. - * @param listener A spell checker session lister for getting results from a spell checker. * @param referToSpellCheckerLanguageSettings If true, the session for one of enabled * languages in settings will be used. * @param supportedAttributes A union of {@link SuggestionsInfo} attributes that the spell * checker can set in the spell checking results. + * @param bundle A bundle for passing implementation-specific extra parameters for the spell + * checker. You can check the current spell checker package by + * {@link #getCurrentSpellCheckerInfo()}. + * @param executor An executor to call the listener on. + * @param listener A spell checker session lister for getting results from a spell checker. * @return The spell checker session of the spell checker. */ @Nullable public SpellCheckerSession newSpellCheckerSession( - @SuppressLint("NullableCollection") @Nullable Bundle bundle, @SuppressLint("UseIcu") @Nullable Locale locale, - @NonNull SpellCheckerSessionListener listener, - @SuppressLint("ListenerLast") boolean referToSpellCheckerLanguageSettings, - @SuppressLint("ListenerLast") @SuggestionsInfo.ResultAttrs int supportedAttributes) { - if (listener == null) { - throw new NullPointerException(); - } + boolean referToSpellCheckerLanguageSettings, + @SuggestionsInfo.ResultAttrs int supportedAttributes, + @Nullable Bundle bundle, + @NonNull @CallbackExecutor Executor executor, + @NonNull SpellCheckerSessionListener listener) { + Objects.requireNonNull(executor); + Objects.requireNonNull(listener); if (!referToSpellCheckerLanguageSettings && locale == null) { throw new IllegalArgumentException("Locale should not be null if you don't refer" + " settings."); @@ -259,7 +274,7 @@ public final class TextServicesManager { if (subtypeInUse == null) { return null; } - final SpellCheckerSession session = new SpellCheckerSession(sci, this, listener); + final SpellCheckerSession session = new SpellCheckerSession(sci, this, listener, executor); try { mService.getSpellCheckerService(mUserId, sci.getId(), subtypeInUse.getLocale(), session.getTextServicesSessionListener(), diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index 2464b4af23eb..a63305e55e53 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -126,14 +126,14 @@ public class SpellChecker implements SpellCheckerSessionListener { || mTextServicesManager.getCurrentSpellCheckerSubtype(true) == null) { mSpellCheckerSession = null; } else { + int supportedAttributes = SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY + | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO + | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR + | SuggestionsInfo.RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS; mSpellCheckerSession = mTextServicesManager.newSpellCheckerSession( + mCurrentLocale, false, supportedAttributes, null /* Bundle not currently used by the textServicesManager */, - mCurrentLocale, this, - false /* means any available languages from current spell checker */, - SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY - | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO - | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR - | SuggestionsInfo.RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS); + mTextView.getContext().getMainExecutor(), this); } // Restore SpellCheckSpans in pool diff --git a/data/etc/car/com.android.car.messenger.xml b/data/etc/car/com.android.car.messenger.xml index 16595c30c65c..9e5f339a0afa 100644 --- a/data/etc/car/com.android.car.messenger.xml +++ b/data/etc/car/com.android.car.messenger.xml @@ -16,6 +16,7 @@ --> <permissions> <privapp-permissions package="com.android.car.messenger"> + <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/> </privapp-permissions> </permissions> diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml index 8efe0539207a..73b02f4fa481 100644 --- a/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml +++ b/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml @@ -18,33 +18,20 @@ android:paddingMode="stack" > <item android:id="@android:id/background" android:gravity="center_vertical|fill_horizontal"> - <layer-list> - <item> - <shape - android:tint="?android:attr/colorControlActivated" - android:alpha="?android:attr/disabledAlpha"> - <size android:height="@dimen/rounded_slider_height" /> - <solid android:color="@color/white_disabled" /> - <corners android:radius="@dimen/rounded_slider_corner_radius" /> - </shape> - </item> - <item - android:gravity="center_vertical|left" - android:height="@dimen/rounded_slider_icon_size" - android:width="@dimen/rounded_slider_icon_size" - android:left="@dimen/rounded_slider_icon_inset"> - <com.android.systemui.util.AlphaTintDrawableWrapper - android:drawable="@drawable/ic_brightness" - android:tint="?android:attr/colorControlActivated" /> - </item> - </layer-list> + <inset + android:insetLeft="@dimen/rounded_slider_track_inset" + android:insetRight="@dimen/rounded_slider_track_inset" > + <shape> + <size android:height="@dimen/rounded_slider_track_width" /> + <corners android:radius="@dimen/rounded_slider_track_corner_radius" /> + <solid android:color="?android:attr/textColorPrimary" /> + </shape> + </inset> </item> <item android:id="@android:id/progress" android:gravity="center_vertical|fill_horizontal"> - <clip + <com.android.systemui.util.RoundedCornerProgressDrawable android:drawable="@drawable/brightness_progress_full_drawable" - android:clipOrientation="horizontal" - android:gravity="left" /> </item> </layer-list>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml index 5bc2773dc657..41140a7a8c85 100644 --- a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml +++ b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml @@ -26,10 +26,10 @@ </item> <item android:id="@+id/slider_icon" - android:gravity="center_vertical|left" + android:gravity="center_vertical|right" android:height="@dimen/rounded_slider_icon_size" android:width="@dimen/rounded_slider_icon_size" - android:left="@dimen/rounded_slider_icon_inset"> + android:right="@dimen/rounded_slider_icon_inset"> <com.android.systemui.util.AlphaTintDrawableWrapper android:drawable="@drawable/ic_brightness" android:tint="?android:attr/colorBackground" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 2062104be2df..6e270a75a6b9 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1356,11 +1356,15 @@ <dimen name="people_space_image_radius">20dp</dimen> <dimen name="people_space_widget_background_padding">6dp</dimen> - <dimen name="rounded_slider_height">48dp</dimen> + <dimen name="rounded_slider_height">44dp</dimen> <!-- rounded_slider_height / 2 --> - <dimen name="rounded_slider_corner_radius">24dp</dimen> - <!-- rounded_slider_height / 2 --> - <dimen name="rounded_slider_icon_size">24dp</dimen> - <!-- rounded_slider_icon_size / 2 --> + <dimen name="rounded_slider_corner_radius">22dp</dimen> + <dimen name="rounded_slider_icon_size">20dp</dimen> + <!-- (rounded_slider_height - rounded_slider_icon_size) / 2 --> <dimen name="rounded_slider_icon_inset">12dp</dimen> + <!-- rounded_slider_corner_radius - rounded_slider_track_corner_radius --> + <dimen name="rounded_slider_track_inset">18dp</dimen> + <dimen name="rounded_slider_track_width">8dp</dimen> + <!-- rounded_slider_track_width / 2 --> + <dimen name="rounded_slider_track_corner_radius">4dp</dimen> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt index 6aadd1020bce..dc86d5893adb 100644 --- a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt +++ b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt @@ -17,8 +17,6 @@ package com.android.systemui.util import android.content.res.Resources -import android.graphics.Canvas -import android.graphics.Path import android.graphics.Rect import android.graphics.drawable.Drawable import android.graphics.drawable.DrawableWrapper @@ -43,53 +41,25 @@ class RoundedCornerProgressDrawable @JvmOverloads constructor( private const val MAX_LEVEL = 10000 // Taken from Drawable } - private var clipPath: Path = Path() - - init { - setClipPath(Rect()) - } - override fun onLayoutDirectionChanged(layoutDirection: Int): Boolean { onLevelChange(level) return super.onLayoutDirectionChanged(layoutDirection) } override fun onBoundsChange(bounds: Rect) { - setClipPath(bounds) super.onBoundsChange(bounds) onLevelChange(level) } - private fun setClipPath(bounds: Rect) { - clipPath.reset() - clipPath.addRoundRect( - bounds.left.toFloat(), - bounds.top.toFloat(), - bounds.right.toFloat(), - bounds.bottom.toFloat(), - bounds.height().toFloat() / 2, - bounds.height().toFloat() / 2, - Path.Direction.CW - ) - } - override fun onLevelChange(level: Int): Boolean { val db = drawable?.bounds!! - val width = bounds.width() * level / MAX_LEVEL - // Extra space on the left to keep the rounded shape on the right end - val leftBound = bounds.left - bounds.height() - drawable?.setBounds(leftBound, db.top, bounds.left + width, db.bottom) + // On 0, the width is bounds.height (a circle), and on MAX_LEVEL, the width is bounds.width + val width = bounds.height() + (bounds.width() - bounds.height()) * level / MAX_LEVEL + drawable?.setBounds(bounds.left, db.top, bounds.left + width, db.bottom) return super.onLevelChange(level) } - override fun draw(canvas: Canvas) { - canvas.save() - canvas.clipPath(clipPath) - super.draw(canvas) - canvas.restore() - } - - override fun getConstantState(): ConstantState? { + override fun getConstantState(): ConstantState { // This should not be null as it was created with a state in the constructor. return RoundedCornerState(super.getConstantState()!!) } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 10b33b3a2377..f2b452948384 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5482,7 +5482,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public boolean hasKeyPair(String callerPackage, String alias) { final CallerIdentity caller = getCallerIdentity(callerPackage); - Preconditions.checkCallAuthorization(canManageCertificates(caller)); + Preconditions.checkCallAuthorization(canManageCertificates(caller) + || isCredentialManagementApp(caller, alias)); return mInjector.binderWithCleanCallingIdentity(() -> { try (KeyChainConnection keyChainConnection = |