diff options
23 files changed, 713 insertions, 684 deletions
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index a4f7b5bf5e24..b219fd41afec 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -54,6 +54,7 @@ import com.google.android.exoplayer2.video.ColorInfo; import java.io.EOFException; import java.io.IOException; +import java.io.InterruptedIOException; import java.nio.ByteBuffer; import java.util.Collections; import java.util.HashMap; @@ -119,7 +120,7 @@ import java.util.Map; * * @Override * public void onSampleData(int trackIndex, @NonNull InputReader inputReader) - * throws IOException, InterruptedException { + * throws IOException { * int numberOfBytesToRead = (int) inputReader.getLength(); * if (videoTrackIndex != trackIndex) { * // Discard contents. @@ -310,8 +311,7 @@ public final class MediaParser { * of the input has been reached. * @throws java.io.IOException If an error occurs reading from the source. */ - int read(@NonNull byte[] buffer, int offset, int readLength) - throws IOException, InterruptedException; + int read(@NonNull byte[] buffer, int offset, int readLength) throws IOException; /** Returns the current read position (byte offset) in the stream. */ long getPosition(); @@ -373,11 +373,8 @@ public final class MediaParser { * @param trackIndex The index of the track to which the sample data corresponds. * @param inputReader The {@link InputReader} from which to read the data. * @throws IOException If an exception occurs while reading from {@code inputReader}. - * @throws InterruptedException If an interruption occurs while reading from {@code - * inputReader}. */ - void onSampleData(int trackIndex, @NonNull InputReader inputReader) - throws IOException, InterruptedException; + void onSampleData(int trackIndex, @NonNull InputReader inputReader) throws IOException; /** * Called once all the data of a sample has been passed to {@link #onSampleData}. @@ -717,8 +714,7 @@ public final class MediaParser { * @throws UnrecognizedInputFormatException If the format cannot be recognized by any of the * underlying parser implementations. */ - public boolean advance(@NonNull SeekableInputReader seekableInputReader) - throws IOException, InterruptedException { + public boolean advance(@NonNull SeekableInputReader seekableInputReader) throws IOException { if (mExtractorInput == null) { // TODO: For efficiency, the same implementation should be used, by providing a // clearBuffers() method, or similar. @@ -748,8 +744,10 @@ public final class MediaParser { } } catch (EOFException e) { // Do nothing. - } catch (IOException | InterruptedException e) { - throw new IllegalStateException(e); + } catch (InterruptedException e) { + // TODO: Remove this exception replacement once we update the ExoPlayer + // version. + throw new InterruptedIOException(); } finally { mExtractorInput.resetPeekPosition(); } @@ -767,7 +765,13 @@ public final class MediaParser { } mPositionHolder.position = seekableInputReader.getPosition(); - int result = mExtractor.read(mExtractorInput, mPositionHolder); + int result = 0; + try { + result = mExtractor.read(mExtractorInput, mPositionHolder); + } catch (InterruptedException e) { + // TODO: Remove this exception replacement once we update the ExoPlayer version. + throw new InterruptedIOException(); + } if (result == Extractor.RESULT_END_OF_INPUT) { return false; } @@ -853,13 +857,7 @@ public final class MediaParser { @Override public int read(byte[] buffer, int offset, int readLength) throws IOException { - // TODO: Reevaluate interruption in Input. - try { - return mInputReader.read(buffer, offset, readLength); - } catch (InterruptedException e) { - // TODO: Remove. - throw new RuntimeException(); - } + return mInputReader.read(buffer, offset, readLength); } @Override @@ -926,7 +924,7 @@ public final class MediaParser { @Override public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput) - throws IOException, InterruptedException { + throws IOException { mScratchExtractorInputAdapter.setExtractorInput(input, length); long positionBeforeReading = mScratchExtractorInputAdapter.getPosition(); mOutputConsumer.onSampleData(mTrackIndex, mScratchExtractorInputAdapter); @@ -938,7 +936,7 @@ public final class MediaParser { mScratchParsableByteArrayAdapter.resetWithByteArray(data, length); try { mOutputConsumer.onSampleData(mTrackIndex, mScratchParsableByteArrayAdapter); - } catch (IOException | InterruptedException e) { + } catch (IOException e) { // Unexpected. throw new RuntimeException(e); } @@ -967,9 +965,14 @@ public final class MediaParser { // Input implementation. @Override - public int read(byte[] buffer, int offset, int readLength) - throws IOException, InterruptedException { - int readBytes = mExtractorInput.read(buffer, offset, readLength); + public int read(byte[] buffer, int offset, int readLength) throws IOException { + int readBytes = 0; + try { + readBytes = mExtractorInput.read(buffer, offset, readLength); + } catch (InterruptedException e) { + // TODO: Remove this exception replacement once we update the ExoPlayer version. + throw new InterruptedIOException(); + } mCurrentPosition += readBytes; return readBytes; } diff --git a/api/current.txt b/api/current.txt index 7acbdb4929f8..9c2007ce1c0f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -26403,7 +26403,7 @@ package android.media { } public final class MediaParser { - method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException, java.lang.InterruptedException; + method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException; method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...); method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer); method @Nullable public String getParserName(); @@ -26435,12 +26435,12 @@ package android.media { public static interface MediaParser.InputReader { method public long getLength(); method public long getPosition(); - method public int read(@NonNull byte[], int, int) throws java.io.IOException, java.lang.InterruptedException; + method public int read(@NonNull byte[], int, int) throws java.io.IOException; } public static interface MediaParser.OutputConsumer { method public void onSampleCompleted(int, long, int, int, int, @Nullable android.media.MediaCodec.CryptoInfo); - method public void onSampleData(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException, java.lang.InterruptedException; + method public void onSampleData(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException; method public void onSeekMap(@NonNull android.media.MediaParser.SeekMap); method public void onTrackData(int, @NonNull android.media.MediaParser.TrackData); method public void onTracksFound(int); diff --git a/api/system-current.txt b/api/system-current.txt index 379ae579e8b7..9f2953cc9a1e 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -11523,7 +11523,7 @@ package android.telephony { public class SmsMessage { method @Nullable public static android.telephony.SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[], boolean); method @Nullable public static android.telephony.SmsMessage.SubmitPdu getSmsPdu(int, int, @Nullable String, @NonNull String, @NonNull String, long); - method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, int, int, int, int, int); + method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0, to=255) int, @IntRange(from=1, to=255) int, @IntRange(from=1, to=255) int); } public class SubscriptionInfo implements android.os.Parcelable { diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index e9cdbf28e9cb..8c3eef27dd58 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -748,5 +748,4 @@ interface IPackageManager { void clearMimeGroup(String packageName, String group); List<String> getMimeGroup(String packageName, String group); - } diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java new file mode 100644 index 000000000000..1daa5052a565 --- /dev/null +++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.common; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Collection of common constants for accessibility shortcut. + */ +public final class ShortcutConstants { + private ShortcutConstants() {} + + public static final char SERVICES_SEPARATOR = ':'; + public static final float DISABLED_ALPHA = 0.5f; + public static final float ENABLED_ALPHA = 1.0f; + + /** + * Annotation for different user shortcut type UI type. + * + * {@code DEFAULT} for displaying default value. + * {@code SOFTWARE} for displaying specifying the accessibility services or features which + * choose accessibility button in the navigation bar as preferred shortcut. + * {@code HARDWARE} for displaying specifying the accessibility services or features which + * choose accessibility shortcut as preferred shortcut. + * {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly + * tapping screen 3 times as preferred shortcut. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + UserShortcutType.DEFAULT, + UserShortcutType.SOFTWARE, + UserShortcutType.HARDWARE, + UserShortcutType.TRIPLETAP, + }) + public @interface UserShortcutType { + int DEFAULT = 0; + int SOFTWARE = 1; // 1 << 0 + int HARDWARE = 2; // 1 << 1 + int TRIPLETAP = 4; // 1 << 2 + } + + /** + * Annotation for different accessibilityService fragment UI type. + * + * {@code LEGACY} for displaying appearance aligned with sdk version Q accessibility service + * page, but only hardware shortcut allowed and under service in version Q or early. + * {@code INVISIBLE} for displaying appearance without switch bar. + * {@code INTUITIVE} for displaying appearance with version R accessibility design. + * {@code BOUNCE} for displaying appearance with pop-up action. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + AccessibilityServiceFragmentType.LEGACY, + AccessibilityServiceFragmentType.INVISIBLE, + AccessibilityServiceFragmentType.INTUITIVE, + AccessibilityServiceFragmentType.BOUNCE, + }) + public @interface AccessibilityServiceFragmentType { + int LEGACY = 0; + int INVISIBLE = 1; + int INTUITIVE = 2; + int BOUNCE = 3; + } + + /** + * Annotation for different shortcut menu mode. + * + * {@code LAUNCH} for clicking list item to trigger the service callback. + * {@code EDIT} for clicking list item and save button to disable the service. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + ShortcutMenuMode.LAUNCH, + ShortcutMenuMode.EDIT, + }) + public @interface ShortcutMenuMode { + int LAUNCH = 0; + int EDIT = 1; + } + + /** + * Annotation for align the element index of white listing feature + * {@code WHITE_LISTING_FEATURES}. + * + * {@code COMPONENT_ID} is to get the service component name. + * {@code LABEL_ID} is to get the service label text. + * {@code ICON_ID} is to get the service icon. + * {@code FRAGMENT_TYPE} is to get the service fragment type. + * {@code SETTINGS_KEY} is to get the service settings key. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + WhiteListingFeatureElementIndex.COMPONENT_ID, + WhiteListingFeatureElementIndex.LABEL_ID, + WhiteListingFeatureElementIndex.ICON_ID, + WhiteListingFeatureElementIndex.FRAGMENT_TYPE, + WhiteListingFeatureElementIndex.SETTINGS_KEY, + }) + public @interface WhiteListingFeatureElementIndex { + int COMPONENT_ID = 0; + int LABEL_ID = 1; + int ICON_ID = 2; + int FRAGMENT_TYPE = 3; + int SETTINGS_KEY = 4; + } +} diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java new file mode 100644 index 000000000000..d0ead5e3b6ce --- /dev/null +++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.util; +import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityServiceFragmentType; +import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.ComponentName; +import android.content.Context; +import android.os.Build; +import android.os.UserHandle; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.ArraySet; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Collection of utilities for accessibility service. + */ +public final class AccessibilityUtils { + private AccessibilityUtils() {} + + /** + * Returns the set of enabled accessibility services for userId. If there are no + * services, it returns the unmodifiable {@link Collections#emptySet()}. + */ + public static Set<ComponentName> getEnabledServicesFromSettings(Context context, int userId) { + final String enabledServicesSetting = Settings.Secure.getStringForUser( + context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + userId); + if (TextUtils.isEmpty(enabledServicesSetting)) { + return Collections.emptySet(); + } + + final Set<ComponentName> enabledServices = new HashSet<>(); + final TextUtils.StringSplitter colonSplitter = + new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR); + colonSplitter.setString(enabledServicesSetting); + + for (String componentNameString : colonSplitter) { + final ComponentName enabledService = ComponentName.unflattenFromString( + componentNameString); + if (enabledService != null) { + enabledServices.add(enabledService); + } + } + + return enabledServices; + } + + /** + * Changes an accessibility component's state. + */ + public static void setAccessibilityServiceState(Context context, ComponentName componentName, + boolean enabled) { + setAccessibilityServiceState(context, componentName, enabled, UserHandle.myUserId()); + } + + /** + * Changes an accessibility component's state for {@param userId}. + */ + public static void setAccessibilityServiceState(Context context, ComponentName componentName, + boolean enabled, int userId) { + Set<ComponentName> enabledServices = getEnabledServicesFromSettings( + context, userId); + + if (enabledServices.isEmpty()) { + enabledServices = new ArraySet<>(/* capacity= */ 1); + } + + if (enabled) { + enabledServices.add(componentName); + } else { + enabledServices.remove(componentName); + } + + final StringBuilder enabledServicesBuilder = new StringBuilder(); + for (ComponentName enabledService : enabledServices) { + enabledServicesBuilder.append(enabledService.flattenToString()); + enabledServicesBuilder.append( + SERVICES_SEPARATOR); + } + + final int enabledServicesBuilderLength = enabledServicesBuilder.length(); + if (enabledServicesBuilderLength > 0) { + enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1); + } + + Settings.Secure.putStringForUser(context.getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, + enabledServicesBuilder.toString(), userId); + } + + /** + * Gets the corresponding fragment type of a given accessibility service. + * + * @param accessibilityServiceInfo The accessibilityService's info. + * @return int from {@link AccessibilityServiceFragmentType}. + */ + public static @AccessibilityServiceFragmentType int getAccessibilityServiceFragmentType( + AccessibilityServiceInfo accessibilityServiceInfo) { + final int targetSdk = accessibilityServiceInfo.getResolveInfo() + .serviceInfo.applicationInfo.targetSdkVersion; + final boolean requestA11yButton = (accessibilityServiceInfo.flags + & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; + + if (targetSdk <= Build.VERSION_CODES.Q) { + return AccessibilityServiceFragmentType.LEGACY; + } + return requestA11yButton + ? AccessibilityServiceFragmentType.INVISIBLE + : AccessibilityServiceFragmentType.INTUITIVE; + } +} diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java new file mode 100644 index 000000000000..7df712fbcf7b --- /dev/null +++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2020 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.internal.accessibility.util; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; + +import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; + +import android.annotation.NonNull; +import android.content.Context; +import android.provider.Settings; +import android.text.TextUtils; +import android.view.accessibility.AccessibilityManager.ShortcutType; + +import java.util.StringJoiner; + +/** + * Collection of utilities for accessibility shortcut. + */ +public final class ShortcutUtils { + private ShortcutUtils() {} + + private static final TextUtils.SimpleStringSplitter sStringColonSplitter = + new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR); + + /** + * Opts out component name into colon-separated {@code shortcutType} key's string in Settings. + * + * @param context The current context. + * @param shortcutType The preferred shortcut type user selected. + * @param componentId The component id that need to be opted out from Settings. + */ + public static void optOutValueFromSettings( + Context context, @UserShortcutType int shortcutType, String componentId) { + final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR)); + final String targetsKey = convertToKey(shortcutType); + final String targetsValue = Settings.Secure.getString(context.getContentResolver(), + targetsKey); + + if (TextUtils.isEmpty(targetsValue)) { + return; + } + + sStringColonSplitter.setString(targetsValue); + while (sStringColonSplitter.hasNext()) { + final String id = sStringColonSplitter.next(); + if (TextUtils.isEmpty(id) || componentId.equals(id)) { + continue; + } + joiner.add(id); + } + + Settings.Secure.putString(context.getContentResolver(), targetsKey, joiner.toString()); + } + + /** + * Returns if component name existed in one of {@code shortcutTypes} string in Settings. + * + * @param context The current context. + * @param shortcutTypes A combination of {@link UserShortcutType}. + * @param componentId The component name that need to be checked existed in Settings. + * @return {@code true} if componentName existed in Settings. + */ + public static boolean hasValuesInSettings(Context context, int shortcutTypes, + @NonNull String componentId) { + boolean exist = false; + if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { + exist = hasValueInSettings(context, UserShortcutType.SOFTWARE, componentId); + } + if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) { + exist |= hasValueInSettings(context, UserShortcutType.HARDWARE, componentId); + } + return exist; + } + + + /** + * Returns if component name existed in Settings. + * + * @param context The current context. + * @param shortcutType The preferred shortcut type user selected. + * @param componentId The component id that need to be checked existed in Settings. + * @return {@code true} if componentName existed in Settings. + */ + public static boolean hasValueInSettings(Context context, @UserShortcutType int shortcutType, + @NonNull String componentId) { + final String targetKey = convertToKey(shortcutType); + final String targetString = Settings.Secure.getString(context.getContentResolver(), + targetKey); + + if (TextUtils.isEmpty(targetString)) { + return false; + } + + sStringColonSplitter.setString(targetString); + while (sStringColonSplitter.hasNext()) { + final String id = sStringColonSplitter.next(); + if (componentId.equals(id)) { + return true; + } + } + + return false; + } + + /** + * Converts {@link UserShortcutType} to key in Settings. + * + * @param type The shortcut type. + * @return Mapping key in Settings. + */ + public static String convertToKey(@UserShortcutType int type) { + switch (type) { + case UserShortcutType.SOFTWARE: + return Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT; + case UserShortcutType.HARDWARE: + return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; + case UserShortcutType.TRIPLETAP: + return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED; + default: + throw new IllegalArgumentException( + "Unsupported user shortcut type: " + type); + } + } + + /** + * Converts {@link ShortcutType} to {@link UserShortcutType}. + * + * @param type The shortcut type. + * @return {@link UserShortcutType}. + */ + public static @UserShortcutType int convertToUserType(@ShortcutType int type) { + switch (type) { + case ACCESSIBILITY_BUTTON: + return UserShortcutType.SOFTWARE; + case ACCESSIBILITY_SHORTCUT_KEY: + return UserShortcutType.HARDWARE; + default: + throw new IllegalArgumentException( + "Unsupported shortcut type:" + type); + } + } +} diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java index 86d2ed6c15c0..852deb208ea6 100644 --- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java +++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java @@ -22,16 +22,25 @@ import static android.view.accessibility.AccessibilityManager.ShortcutType; import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; -import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.COMPONENT_ID; -import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.FRAGMENT_TYPE; -import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.ICON_ID; -import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.LABEL_ID; -import static com.android.internal.app.AccessibilityButtonChooserActivity.WhiteListingFeatureElementIndex.SETTINGS_KEY; +import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityServiceFragmentType; +import static com.android.internal.accessibility.common.ShortcutConstants.DISABLED_ALPHA; +import static com.android.internal.accessibility.common.ShortcutConstants.ENABLED_ALPHA; +import static com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode; +import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; +import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.COMPONENT_ID; +import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.FRAGMENT_TYPE; +import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.ICON_ID; +import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.LABEL_ID; +import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.SETTINGS_KEY; +import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType; +import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState; +import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType; +import static com.android.internal.accessibility.util.ShortcutUtils.hasValuesInSettings; +import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings; import static com.android.internal.util.Preconditions.checkArgument; import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityShortcutInfo; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; @@ -44,12 +53,8 @@ import android.content.res.TypedArray; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.drawable.Drawable; -import android.os.Build; import android.os.Bundle; -import android.os.UserHandle; import android.provider.Settings; -import android.text.TextUtils; -import android.util.ArraySet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -64,24 +69,14 @@ import android.widget.TextView; import com.android.internal.R; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; -import java.util.StringJoiner; /** * Activity used to display and persist a service or feature target for the Accessibility button. */ public class AccessibilityButtonChooserActivity extends Activity { - private static final char SERVICES_SEPARATOR = ':'; - private static final float DISABLED_ALPHA = 0.5f; - private static final float ENABLED_ALPHA = 1.0f; - private static final TextUtils.SimpleStringSplitter sStringColonSplitter = - new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR); @ShortcutType private int mShortcutType; @UserShortcutType @@ -90,97 +85,6 @@ public class AccessibilityButtonChooserActivity extends Activity { private AlertDialog mAlertDialog; private TargetAdapter mTargetAdapter; - /** - * Annotation for different user shortcut type UI type. - * - * {@code DEFAULT} for displaying default value. - * {@code SOFTWARE} for displaying specifying the accessibility services or features which - * choose accessibility button in the navigation bar as preferred shortcut. - * {@code HARDWARE} for displaying specifying the accessibility services or features which - * choose accessibility shortcut as preferred shortcut. - * {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly - * tapping screen 3 times as preferred shortcut. - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - UserShortcutType.DEFAULT, - UserShortcutType.SOFTWARE, - UserShortcutType.HARDWARE, - UserShortcutType.TRIPLETAP, - }) - /** Denotes the user shortcut type. */ - private @interface UserShortcutType { - int DEFAULT = 0; - int SOFTWARE = 1; // 1 << 0 - int HARDWARE = 2; // 1 << 1 - int TRIPLETAP = 4; // 1 << 2 - } - - /** - * Annotation for different accessibilityService fragment UI type. - * - * {@code LEGACY} for displaying appearance aligned with sdk version Q accessibility service - * page, but only hardware shortcut allowed and under service in version Q or early. - * {@code INVISIBLE} for displaying appearance without switch bar. - * {@code INTUITIVE} for displaying appearance with version R accessibility design. - * {@code BOUNCE} for displaying appearance with pop-up action. - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - AccessibilityServiceFragmentType.LEGACY, - AccessibilityServiceFragmentType.INVISIBLE, - AccessibilityServiceFragmentType.INTUITIVE, - AccessibilityServiceFragmentType.BOUNCE, - }) - private @interface AccessibilityServiceFragmentType { - int LEGACY = 0; - int INVISIBLE = 1; - int INTUITIVE = 2; - int BOUNCE = 3; - } - - /** - * Annotation for different shortcut menu mode. - * - * {@code LAUNCH} for clicking list item to trigger the service callback. - * {@code EDIT} for clicking list item and save button to disable the service. - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - ShortcutMenuMode.LAUNCH, - ShortcutMenuMode.EDIT, - }) - private @interface ShortcutMenuMode { - int LAUNCH = 0; - int EDIT = 1; - } - - /** - * Annotation for align the element index of white listing feature - * {@code WHITE_LISTING_FEATURES}. - * - * {@code COMPONENT_ID} is to get the service component name. - * {@code LABEL_ID} is to get the service label text. - * {@code ICON_ID} is to get the service icon. - * {@code FRAGMENT_TYPE} is to get the service fragment type. - * {@code SETTINGS_KEY} is to get the service settings key. - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - WhiteListingFeatureElementIndex.COMPONENT_ID, - WhiteListingFeatureElementIndex.LABEL_ID, - WhiteListingFeatureElementIndex.ICON_ID, - WhiteListingFeatureElementIndex.FRAGMENT_TYPE, - WhiteListingFeatureElementIndex.SETTINGS_KEY, - }) - @interface WhiteListingFeatureElementIndex { - int COMPONENT_ID = 0; - int LABEL_ID = 1; - int ICON_ID = 2; - int FRAGMENT_TYPE = 3; - int SETTINGS_KEY = 4; - } - private static final String[][] WHITE_LISTING_FEATURES = { { COLOR_INVERSION_COMPONENT_NAME.flattenToString(), @@ -224,8 +128,11 @@ public class AccessibilityButtonChooserActivity extends Activity { mTargets.addAll(getServiceTargets(this, mShortcutType)); + final String selectDialogTitle = + getString(R.string.accessibility_select_shortcut_menu_title); mTargetAdapter = new TargetAdapter(mTargets, mShortcutType); mAlertDialog = new AlertDialog.Builder(this) + .setTitle(selectDialogTitle) .setAdapter(mTargetAdapter, /* listener= */ null) .setPositiveButton( getString(R.string.edit_accessibility_shortcut_menu_button), @@ -242,27 +149,6 @@ public class AccessibilityButtonChooserActivity extends Activity { super.onDestroy(); } - /** - * Gets the corresponding fragment type of a given accessibility service. - * - * @param accessibilityServiceInfo The accessibilityService's info. - * @return int from {@link AccessibilityServiceFragmentType}. - */ - private static @AccessibilityServiceFragmentType int getAccessibilityServiceFragmentType( - AccessibilityServiceInfo accessibilityServiceInfo) { - final int targetSdk = accessibilityServiceInfo.getResolveInfo() - .serviceInfo.applicationInfo.targetSdkVersion; - final boolean requestA11yButton = (accessibilityServiceInfo.flags - & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; - - if (targetSdk <= Build.VERSION_CODES.Q) { - return AccessibilityServiceFragmentType.LEGACY; - } - return requestA11yButton - ? AccessibilityServiceFragmentType.INVISIBLE - : AccessibilityServiceFragmentType.INTUITIVE; - } - private static List<AccessibilityButtonTarget> getServiceTargets(@NonNull Context context, @ShortcutType int shortcutType) { final List<AccessibilityButtonTarget> targets = new ArrayList<>(); @@ -761,193 +647,17 @@ public class AccessibilityButtonChooserActivity extends Activity { private void updateDialogListeners() { final boolean isEditMenuMode = (mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT); + final int selectDialogTitleId = R.string.accessibility_select_shortcut_menu_title; + final int editDialogTitleId = + (mShortcutType == ACCESSIBILITY_BUTTON) + ? R.string.accessibility_edit_shortcut_menu_button_title + : R.string.accessibility_edit_shortcut_menu_volume_title; + + mAlertDialog.setTitle(getString(isEditMenuMode ? editDialogTitleId : selectDialogTitleId)); mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener( isEditMenuMode ? view -> onCancelButtonClicked() : view -> onEditButtonClicked()); mAlertDialog.getListView().setOnItemClickListener( isEditMenuMode ? this::onTargetDeleted : this::onTargetSelected); } - - /** - * @return the set of enabled accessibility services for {@param userId}. If there are no - * services, it returns the unmodifiable {@link Collections#emptySet()}. - */ - private Set<ComponentName> getEnabledServicesFromSettings(Context context, int userId) { - final String enabledServicesSetting = Settings.Secure.getStringForUser( - context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - userId); - if (TextUtils.isEmpty(enabledServicesSetting)) { - return Collections.emptySet(); - } - - final Set<ComponentName> enabledServices = new HashSet<>(); - final TextUtils.StringSplitter colonSplitter = - new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR); - colonSplitter.setString(enabledServicesSetting); - - for (String componentNameString : colonSplitter) { - final ComponentName enabledService = ComponentName.unflattenFromString( - componentNameString); - if (enabledService != null) { - enabledServices.add(enabledService); - } - } - - return enabledServices; - } - - /** - * Changes an accessibility component's state. - */ - private void setAccessibilityServiceState(Context context, ComponentName componentName, - boolean enabled) { - setAccessibilityServiceState(context, componentName, enabled, UserHandle.myUserId()); - } - - /** - * Changes an accessibility component's state for {@param userId}. - */ - private void setAccessibilityServiceState(Context context, ComponentName componentName, - boolean enabled, int userId) { - Set<ComponentName> enabledServices = getEnabledServicesFromSettings( - context, userId); - - if (enabledServices.isEmpty()) { - enabledServices = new ArraySet<>(/* capacity= */ 1); - } - - if (enabled) { - enabledServices.add(componentName); - } else { - enabledServices.remove(componentName); - } - - final StringBuilder enabledServicesBuilder = new StringBuilder(); - for (ComponentName enabledService : enabledServices) { - enabledServicesBuilder.append(enabledService.flattenToString()); - enabledServicesBuilder.append( - SERVICES_SEPARATOR); - } - - final int enabledServicesBuilderLength = enabledServicesBuilder.length(); - if (enabledServicesBuilderLength > 0) { - enabledServicesBuilder.deleteCharAt(enabledServicesBuilderLength - 1); - } - - Settings.Secure.putStringForUser(context.getContentResolver(), - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - enabledServicesBuilder.toString(), userId); - } - - /** - * Opts out component name into colon-separated {@code shortcutType} key's string in Settings. - * - * @param context The current context. - * @param shortcutType The preferred shortcut type user selected. - * @param componentId The component id that need to be opted out from Settings. - */ - private void optOutValueFromSettings( - Context context, @UserShortcutType int shortcutType, String componentId) { - final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR)); - final String targetsKey = convertToKey(shortcutType); - final String targetsValue = Settings.Secure.getString(context.getContentResolver(), - targetsKey); - - if (TextUtils.isEmpty(targetsValue)) { - return; - } - - sStringColonSplitter.setString(targetsValue); - while (sStringColonSplitter.hasNext()) { - final String id = sStringColonSplitter.next(); - if (TextUtils.isEmpty(id) || componentId.equals(id)) { - continue; - } - joiner.add(id); - } - - Settings.Secure.putString(context.getContentResolver(), targetsKey, joiner.toString()); - } - - /** - * Returns if component name existed in one of {@code shortcutTypes} string in Settings. - * - * @param context The current context. - * @param shortcutTypes A combination of {@link UserShortcutType}. - * @param componentId The component name that need to be checked existed in Settings. - * @return {@code true} if componentName existed in Settings. - */ - private boolean hasValuesInSettings(Context context, int shortcutTypes, - @NonNull String componentId) { - boolean exist = false; - if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { - exist = hasValueInSettings(context, UserShortcutType.SOFTWARE, componentId); - } - if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) { - exist |= hasValueInSettings(context, UserShortcutType.HARDWARE, componentId); - } - return exist; - } - - - /** - * Returns if component name existed in Settings. - * - * @param context The current context. - * @param shortcutType The preferred shortcut type user selected. - * @param componentId The component id that need to be checked existed in Settings. - * @return {@code true} if componentName existed in Settings. - */ - private boolean hasValueInSettings(Context context, @UserShortcutType int shortcutType, - @NonNull String componentId) { - final String targetKey = convertToKey(shortcutType); - final String targetString = Settings.Secure.getString(context.getContentResolver(), - targetKey); - - if (TextUtils.isEmpty(targetString)) { - return false; - } - - sStringColonSplitter.setString(targetString); - while (sStringColonSplitter.hasNext()) { - final String id = sStringColonSplitter.next(); - if (componentId.equals(id)) { - return true; - } - } - - return false; - } - - /** - * Converts {@link UserShortcutType} to key in Settings. - * - * @param type The shortcut type. - * @return Mapping key in Settings. - */ - private String convertToKey(@UserShortcutType int type) { - switch (type) { - case UserShortcutType.SOFTWARE: - return Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT; - case UserShortcutType.HARDWARE: - return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; - case UserShortcutType.TRIPLETAP: - return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED; - default: - throw new IllegalArgumentException( - "Unsupported user shortcut type: " + type); - } - } - - private static @UserShortcutType int convertToUserType(@ShortcutType int type) { - switch (type) { - case ACCESSIBILITY_BUTTON: - return UserShortcutType.SOFTWARE; - case ACCESSIBILITY_SHORTCUT_KEY: - return UserShortcutType.HARDWARE; - default: - throw new IllegalArgumentException( - "Unsupported shortcut type:" + type); - } - } } diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java index 2b08a773b6e7..fbef027ac37f 100644 --- a/core/java/com/android/internal/content/om/OverlayConfig.java +++ b/core/java/com/android/internal/content/om/OverlayConfig.java @@ -21,7 +21,6 @@ import android.annotation.Nullable; import android.content.pm.PackagePartitions; import android.content.pm.parsing.ParsingPackageRead; import android.os.Build; -import android.os.Process; import android.os.Trace; import android.util.ArrayMap; import android.util.Log; @@ -186,13 +185,6 @@ public class OverlayConfig { */ @NonNull public static OverlayConfig getZygoteInstance() { - if (Process.myUid() != Process.ROOT_UID) { - // Scan the overlays in the zygote process to generate configuration settings for - // overlays on the system image. Do not cache this instance so OverlayConfig will not - // be present in applications by default. - throw new IllegalStateException("Can only be invoked in the root process"); - } - Trace.traceBegin(Trace.TRACE_TAG_RRO, "OverlayConfig#getZygoteInstance"); try { return new OverlayConfig(null /* rootDirectory */, OverlayScanner::new, @@ -209,13 +201,12 @@ public class OverlayConfig { */ @NonNull public static OverlayConfig initializeSystemInstance(PackageProvider packageProvider) { - if (Process.myUid() != Process.SYSTEM_UID) { - throw new IllegalStateException("Can only be invoked in the system process"); - } - Trace.traceBegin(Trace.TRACE_TAG_RRO, "OverlayConfig#initializeSystemInstance"); - sInstance = new OverlayConfig(null, null, packageProvider); - Trace.traceEnd(Trace.TRACE_TAG_RRO); + try { + sInstance = new OverlayConfig(null, null, packageProvider); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RRO); + } return sInstance; } @@ -379,10 +370,6 @@ public class OverlayConfig { */ @NonNull public String[] createImmutableFrameworkIdmapsInZygote() { - if (Process.myUid() != Process.ROOT_UID) { - throw new IllegalStateException("This method can only be called from the root process"); - } - final String targetPath = "/system/framework/framework-res.apk"; final ArrayList<String> idmapPaths = new ArrayList<>(); final ArrayList<IdmapInvocation> idmapInvocations = diff --git a/core/res/res/layout/accessibility_button_chooser_item.xml b/core/res/res/layout/accessibility_button_chooser_item.xml index d19e313055ae..c01766b2c748 100644 --- a/core/res/res/layout/accessibility_button_chooser_item.xml +++ b/core/res/res/layout/accessibility_button_chooser_item.xml @@ -38,7 +38,9 @@ android:layout_height="wrap_content" android:layout_marginStart="14dp" android:layout_weight="1" - android:textColor="?attr/textColorPrimary"/> + android:textSize="20sp" + android:textColor="?attr/textColorPrimary" + android:fontFamily="sans-serif-medium"/> <FrameLayout android:id="@+id/accessibility_button_target_item_container" diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d83236c46f36..2356b1737acd 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4403,6 +4403,21 @@ accessibility feature. </string> + <!-- Title for accessibility select shortcut menu dialog. [CHAR LIMIT=100] --> + <string name="accessibility_select_shortcut_menu_title">Tap the accessibility app you want to use</string> + + <!-- Title for accessibility edit shortcut selection menu dialog, and dialog is triggered + from accessibility button. [CHAR LIMIT=100] --> + <string name="accessibility_edit_shortcut_menu_button_title">Choose apps you want to use with + accessibility button + </string> + + <!-- Title for accessibility edit shortcut selection menu dialog, and dialog is triggered + from volume key shortcut. [CHAR LIMIT=100] --> + <string name="accessibility_edit_shortcut_menu_volume_title">Choose apps you want to use with + volume key shortcut + </string> + <!-- Text in button that edit the accessibility shortcut menu, user can delete any service item in the menu list. [CHAR LIMIT=100] --> <string name="edit_accessibility_shortcut_menu_button">Edit shortcuts</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f3174d3132f8..92e7fcda863b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3237,6 +3237,10 @@ <java-symbol type="string" name="config_defaultAccessibilityService" /> <java-symbol type="string" name="accessibility_shortcut_spoken_feedback" /> + <java-symbol type="string" name="accessibility_select_shortcut_menu_title" /> + <java-symbol type="string" name="accessibility_edit_shortcut_menu_button_title" /> + <java-symbol type="string" name="accessibility_edit_shortcut_menu_volume_title" /> + <!-- Accessibility Button --> <java-symbol type="layout" name="accessibility_button_chooser_item" /> <java-symbol type="id" name="accessibility_button_target_icon" /> diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 60c1a940d2c6..1ae3d4f482f4 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -225,8 +225,8 @@ public class PipBoundsHandler { */ Rect getDestinationBounds(float aspectRatio, Rect bounds) { final Rect destinationBounds; + final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize); if (bounds == null) { - final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize); destinationBounds = new Rect(defaultBounds); } else { destinationBounds = new Rect(bounds); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 6b3b7481b9c9..8ada3c393222 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -168,7 +168,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio // bounds. We want to restore to the unexpanded bounds when re-entering pip, // so we save the bounds before expansion (normal) instead of the current // bounds. - mReentryBounds.set(mTouchHandler.getMinBounds()); + mReentryBounds.set(mTouchHandler.getNormalBounds()); // Apply the snap fraction of the current bounds to the normal bounds. float snapFraction = mPipBoundsHandler.getSnapFraction(bounds); mPipBoundsHandler.applySnapFraction(mReentryBounds, snapFraction); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java index 5926b8922173..8fff419af5a1 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java @@ -65,7 +65,6 @@ public class PipResizeGestureHandler { private final PointF mDownPoint = new PointF(); private final Point mMaxSize = new Point(); private final Point mMinSize = new Point(); - private final Rect mLastResizeBounds = new Rect(); private final Rect mTmpBounds = new Rect(); private final int mDelta; @@ -194,7 +193,11 @@ public class PipResizeGestureHandler { } } else if (mAllowGesture) { - + final Rect currentPipBounds = mMotionHelper.getBounds(); + Rect newSize = TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(), mDownPoint.x, + mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x, mMinSize.y, mMaxSize, + true, true); + mPipBoundsHandler.transformBoundsToAspectRatio(newSize); switch (action) { case MotionEvent.ACTION_POINTER_DOWN: // We do not support multi touch for resizing via drag @@ -203,18 +206,12 @@ public class PipResizeGestureHandler { case MotionEvent.ACTION_MOVE: // Capture inputs mInputMonitor.pilferPointers(); - final Rect currentPipBounds = mMotionHelper.getBounds(); - mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(), - mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x, - mMinSize.y, mMaxSize, true, true)); - mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds); - mPipTaskOrganizer.resizePip(mLastResizeBounds); - + //TODO: Actually do resize here. break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - mPipTaskOrganizer.finishResize(mLastResizeBounds); - mLastResizeBounds.setEmpty(); + //TODO: Finish resize operation here. + mMotionHelper.synchronizePinnedStackBounds(); mCtrlType = CTRL_NONE; mAllowGesture = false; break; @@ -226,7 +223,7 @@ public class PipResizeGestureHandler { mMaxSize.set(maxX, maxY); } - void updateMinSize(int minX, int minY) { + void updateMiniSize(int minX, int minY) { mMinSize.set(minX, minY); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index bd224800e858..c3212b8b8078 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -41,7 +41,6 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.systemui.R; import com.android.systemui.pip.PipBoundsHandler; @@ -74,7 +73,7 @@ public class PipTouchHandler { private final Context mContext; private final IActivityManager mActivityManager; private final PipBoundsHandler mPipBoundsHandler; - private PipResizeGestureHandler mPipResizeGestureHandler; + private final PipResizeGestureHandler mPipResizeGestureHandler; private IPinnedStackController mPinnedStackController; private final PipMenuActivityController mMenuController; @@ -85,22 +84,14 @@ public class PipTouchHandler { // The current movement bounds private Rect mMovementBounds = new Rect(); - // The current resized bounds, changed by user resize. - // Note that this is not necessarily the same as PipMotionHelper#getBounds, since it's possible - // that PIP is currently is in a expanded state (max size) but we still need mResizeBounds to - // know what size to restore to once expand animation times out. - @VisibleForTesting Rect mResizedBounds = new Rect(); // The reference inset bounds, used to determine the dismiss fraction private Rect mInsetBounds = new Rect(); - - // The reference bounds used to calculate the minimum/maximum target bounds - // The bound in which PIP enters is the starting/minimum bound, while the expanded/auto-resized - // bound is the maximum bound. - private Rect mMinBounds = new Rect(); - @VisibleForTesting Rect mMinMovementBounds = new Rect(); - private Rect mMaxBounds = new Rect(); - @VisibleForTesting Rect mMaxMovementBounds = new Rect(); + // The reference bounds used to calculate the normal/expanded target bounds + private Rect mNormalBounds = new Rect(); + private Rect mNormalMovementBounds = new Rect(); + private Rect mExpandedBounds = new Rect(); + private Rect mExpandedMovementBounds = new Rect(); private int mExpandedShortestEdgeSize; // Used to workaround an issue where the WM rotation happens before we are notified, allowing @@ -135,7 +126,7 @@ public class PipTouchHandler { private final PipTouchState mTouchState; private final FlingAnimationUtils mFlingAnimationUtils; private final FloatingContentCoordinator mFloatingContentCoordinator; - private PipMotionHelper mMotionHelper; + private final PipMotionHelper mMotionHelper; private PipTouchGesture mGesture; // Temp vars @@ -244,16 +235,14 @@ public class PipTouchHandler { mFloatingContentCoordinator.onContentRemoved(mMotionHelper); } - mResizedBounds.setEmpty(); mPipResizeGestureHandler.onActivityUnpinned(); } public void onPinnedStackAnimationEnded() { // Always synchronize the motion helper bounds once PiP animations finish mMotionHelper.synchronizePinnedStackBounds(); - - updateMovementBounds(); - mResizedBounds.set(mMinBounds); + mPipResizeGestureHandler.updateMiniSize(mMotionHelper.getBounds().width(), + mMotionHelper.getBounds().height()); if (mShowPipMenuOnAnimationEnd) { mMenuController.showMenu(MENU_STATE_CLOSE, mMotionHelper.getBounds(), @@ -277,10 +266,7 @@ public class PipTouchHandler { mShelfHeight = shelfHeight; } - /** - * Update all the cached bounds (movement, min, max, etc.) - */ - public void onMovementBoundsChanged(Rect insetBounds, Rect minBounds, Rect curBounds, + public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect curBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation) { final int bottomOffset = mIsImeShowing ? mImeHeight : 0; final boolean fromDisplayRotationChanged = (mDisplayRotation != displayRotation); @@ -289,25 +275,23 @@ public class PipTouchHandler { } // Re-calculate the expanded bounds - mMinBounds.set(minBounds); - Rect minMovementBounds = new Rect(); - mSnapAlgorithm.getMovementBounds(mMinBounds, insetBounds, minMovementBounds, + mNormalBounds = normalBounds; + Rect normalMovementBounds = new Rect(); + mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds, bottomOffset); // Calculate the expanded size - float aspectRatio = (float) minBounds.width() / minBounds.height(); + float aspectRatio = (float) normalBounds.width() / normalBounds.height(); Point displaySize = new Point(); mContext.getDisplay().getRealSize(displaySize); - Size maxSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, + Size expandedSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mExpandedShortestEdgeSize, displaySize.x, displaySize.y); - mMaxBounds.set(0, 0, maxSize.getWidth(), maxSize.getHeight()); - Rect maxMovementBounds = new Rect(); - mSnapAlgorithm.getMovementBounds(mMaxBounds, insetBounds, maxMovementBounds, + mExpandedBounds.set(0, 0, expandedSize.getWidth(), expandedSize.getHeight()); + mPipResizeGestureHandler.updateMaxSize(expandedSize.getWidth(), expandedSize.getHeight()); + Rect expandedMovementBounds = new Rect(); + mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds, bottomOffset); - mPipResizeGestureHandler.updateMinSize(minBounds.width(), minBounds.height()); - mPipResizeGestureHandler.updateMaxSize(mMaxBounds.width(), mMaxBounds.height()); - // The extra offset does not really affect the movement bounds, but are applied based on the // current state (ime showing, or shelf offset) when we need to actually shift int extraOffset = Math.max( @@ -324,8 +308,8 @@ public class PipTouchHandler { final float offsetBufferPx = BOTTOM_OFFSET_BUFFER_DP * mContext.getResources().getDisplayMetrics().density; final Rect toMovementBounds = mMenuState == MENU_STATE_FULL && willResizeMenu() - ? new Rect(maxMovementBounds) - : new Rect(minMovementBounds); + ? new Rect(expandedMovementBounds) + : new Rect(normalMovementBounds); final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets; final int toBottom = toMovementBounds.bottom < toMovementBounds.top ? toMovementBounds.bottom @@ -339,17 +323,17 @@ public class PipTouchHandler { // Update the movement bounds after doing the calculations based on the old movement bounds // above - mMinMovementBounds = minMovementBounds; - mMaxMovementBounds = maxMovementBounds; + mNormalMovementBounds = normalMovementBounds; + mExpandedMovementBounds = expandedMovementBounds; mDisplayRotation = displayRotation; mInsetBounds.set(insetBounds); - updateMovementBounds(); + updateMovementBounds(mMenuState); mMovementBoundsExtraOffsets = extraOffset; // If we have a deferred resize, apply it now if (mDeferResizeToNormalBoundsUntilRotation == displayRotation) { - mMotionHelper.animateToUnexpandedState(minBounds, mSavedSnapFraction, - mMinMovementBounds, mMovementBounds, true /* immediate */); + mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction, + mNormalMovementBounds, mMovementBounds, true /* immediate */); mSavedSnapFraction = -1f; mDeferResizeToNormalBoundsUntilRotation = -1; } @@ -403,7 +387,7 @@ public class PipTouchHandler { case MotionEvent.ACTION_UP: { // Update the movement bounds again if the state has changed since the user started // dragging (ie. when the IME shows) - updateMovementBounds(); + updateMovementBounds(mMenuState); if (mGesture.onUp(mTouchState)) { break; @@ -501,13 +485,11 @@ public class PipTouchHandler { if (menuState == MENU_STATE_FULL && mMenuState != MENU_STATE_FULL) { // Save the current snap fraction and if we do not drag or move the PiP, then // we store back to this snap fraction. Otherwise, we'll reset the snap - // fraction and snap to the closest edge. - // Also save the current resized bounds so when the menu disappears, we can restore it. + // fraction and snap to the closest edge + Rect expandedBounds = new Rect(mExpandedBounds); if (resize) { - mResizedBounds.set(mMotionHelper.getBounds()); - Rect expandedBounds = new Rect(mMaxBounds); mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds, - mMovementBounds, mMaxMovementBounds); + mMovementBounds, mExpandedMovementBounds); } } else if (menuState == MENU_STATE_NONE && mMenuState == MENU_STATE_FULL) { // Try and restore the PiP to the closest edge, using the saved snap fraction @@ -533,9 +515,9 @@ public class PipTouchHandler { } if (mDeferResizeToNormalBoundsUntilRotation == -1) { - Rect normalBounds = new Rect(mResizedBounds); + Rect normalBounds = new Rect(mNormalBounds); mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction, - mMinMovementBounds, mMovementBounds, false /* immediate */); + mNormalMovementBounds, mMovementBounds, false /* immediate */); mSavedSnapFraction = -1f; } } else { @@ -546,7 +528,7 @@ public class PipTouchHandler { } } mMenuState = menuState; - updateMovementBounds(); + updateMovementBounds(menuState); // If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip // as well, or it can't handle a11y focus and pip menu can't perform any action. onRegistrationChanged(menuState == MENU_STATE_NONE); @@ -562,26 +544,11 @@ public class PipTouchHandler { return mMotionHelper; } - @VisibleForTesting - PipResizeGestureHandler getPipResizeGestureHandler() { - return mPipResizeGestureHandler; - } - - @VisibleForTesting - void setPipResizeGestureHandler(PipResizeGestureHandler pipResizeGestureHandler) { - mPipResizeGestureHandler = pipResizeGestureHandler; - } - - @VisibleForTesting - void setPipMotionHelper(PipMotionHelper pipMotionHelper) { - mMotionHelper = pipMotionHelper; - } - /** * @return the unexpanded bounds. */ - public Rect getMinBounds() { - return mMinBounds; + public Rect getNormalBounds() { + return mNormalBounds; } /** @@ -734,17 +701,17 @@ public class PipTouchHandler { }; /** - * Updates the current movement bounds based on the current PIP size. + * Updates the current movement bounds based on whether the menu is currently visible and + * resized. */ - private void updateMovementBounds() { - Rect movementBounds = new Rect(); - mSnapAlgorithm.getMovementBounds(mMotionHelper.getBounds(), mInsetBounds, - movementBounds, mIsImeShowing ? mImeHeight : 0); - mMotionHelper.setCurrentMovementBounds(movementBounds); - - boolean isMenuExpanded = mMenuState == MENU_STATE_FULL; + private void updateMovementBounds(int menuState) { + boolean isMenuExpanded = menuState == MENU_STATE_FULL; + mMovementBounds = isMenuExpanded && willResizeMenu() + ? mExpandedMovementBounds + : mNormalMovementBounds; mPipBoundsHandler.setMinEdgeSize( - isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0); + isMenuExpanded ? mExpandedShortestEdgeSize : 0); + mMotionHelper.setCurrentMovementBounds(mMovementBounds); } /** @@ -762,18 +729,18 @@ public class PipTouchHandler { if (!mEnableResize) { return false; } - return mMaxBounds.width() != mMinBounds.width() - || mMaxBounds.height() != mMinBounds.height(); + return mExpandedBounds.width() != mNormalBounds.width() + || mExpandedBounds.height() != mNormalBounds.height(); } public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); pw.println(innerPrefix + "mMovementBounds=" + mMovementBounds); - pw.println(innerPrefix + "mMinBounds=" + mMinBounds); - pw.println(innerPrefix + "mMinMovementBounds=" + mMinMovementBounds); - pw.println(innerPrefix + "mMaxBounds=" + mMaxBounds); - pw.println(innerPrefix + "mMaxMovementBounds=" + mMaxMovementBounds); + pw.println(innerPrefix + "mNormalBounds=" + mNormalBounds); + pw.println(innerPrefix + "mNormalMovementBounds=" + mNormalMovementBounds); + pw.println(innerPrefix + "mExpandedBounds=" + mExpandedBounds); + pw.println(innerPrefix + "mExpandedMovementBounds=" + mExpandedMovementBounds); pw.println(innerPrefix + "mMenuState=" + mMenuState); pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing); pw.println(innerPrefix + "mImeHeight=" + mImeHeight); diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java deleted file mode 100644 index 35abb14070bf..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.pip.phone; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.app.IActivityManager; -import android.app.IActivityTaskManager; -import android.graphics.Point; -import android.graphics.Rect; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.util.Size; -import android.view.DisplayInfo; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.pip.PipBoundsHandler; -import com.android.systemui.pip.PipSnapAlgorithm; -import com.android.systemui.pip.PipTaskOrganizer; -import com.android.systemui.shared.system.InputConsumerController; -import com.android.systemui.util.DeviceConfigProxy; -import com.android.systemui.util.FloatingContentCoordinator; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -/** - * Unit tests against {@link PipTouchHandler}, including but not limited to: - * - Update movement bounds based on new bounds - * - Update movement bounds based on IME/shelf - * - Update movement bounds to PipResizeHandler - */ -@RunWith(AndroidTestingRunner.class) -@SmallTest -@TestableLooper.RunWithLooper(setAsMainLooper = true) -public class PipTouchHandlerTest extends SysuiTestCase { - private static final int ROUNDING_ERROR_MARGIN = 10; - private static final float DEFAULT_ASPECT_RATIO = 1f; - private static final Rect EMPTY_CURRENT_BOUNDS = null; - - private PipTouchHandler mPipTouchHandler; - private DisplayInfo mDefaultDisplayInfo; - - @Mock - private IActivityManager mActivityManager; - - @Mock - private IActivityTaskManager mIActivityTaskManager; - - @Mock - private PipMenuActivityController mPipMenuActivityController; - - @Mock - private InputConsumerController mInputConsumerController; - - @Mock - private PipBoundsHandler mPipBoundsHandler; - - @Mock - private PipTaskOrganizer mPipTaskOrganizer; - - @Mock - private FloatingContentCoordinator mFloatingContentCoordinator; - - @Mock - private DeviceConfigProxy mDeviceConfigProxy; - - private PipSnapAlgorithm mPipSnapAlgorithm; - private PipMotionHelper mMotionHelper; - private PipResizeGestureHandler mPipResizeGestureHandler; - - Rect mInsetBounds; - Rect mMinBounds; - Rect mCurBounds; - boolean mFromImeAdjustment; - boolean mFromShelfAdjustment; - int mDisplayRotation; - - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager, mIActivityTaskManager, - mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler, - mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy); - mPipSnapAlgorithm = new PipSnapAlgorithm(mContext); - mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper()); - mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler()); - mPipTouchHandler.setPipMotionHelper(mMotionHelper); - mPipTouchHandler.setPipResizeGestureHandler(mPipResizeGestureHandler); - - // Assume a display of 1000 x 1000 - // inset of 10 - mInsetBounds = new Rect(10, 10, 990, 990); - // minBounds of 100x100 bottom right corner - mMinBounds = new Rect(890, 890, 990, 990); - mCurBounds = new Rect(); - mFromImeAdjustment = false; - mFromShelfAdjustment = false; - mDisplayRotation = 0; - } - - @Test - public void updateMovementBounds_minBounds() { - Rect expectedMinMovementBounds = new Rect(); - mPipSnapAlgorithm.getMovementBounds(mMinBounds, mInsetBounds, expectedMinMovementBounds, 0); - - mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds, - mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation); - - assertEquals(expectedMinMovementBounds, mPipTouchHandler.mMinMovementBounds); - verify(mPipResizeGestureHandler, times(1)) - .updateMinSize(mMinBounds.width(), mMinBounds.height()); - } - - @Test - public void updateMovementBounds_maxBounds() { - Point displaySize = new Point(); - mContext.getDisplay().getRealSize(displaySize); - Size maxSize = mPipSnapAlgorithm.getSizeForAspectRatio(1, - mContext.getResources().getDimensionPixelSize( - R.dimen.pip_expanded_shortest_edge_size), displaySize.x, displaySize.y); - Rect maxBounds = new Rect(0, 0, maxSize.getWidth(), maxSize.getHeight()); - Rect expectedMaxMovementBounds = new Rect(); - mPipSnapAlgorithm.getMovementBounds(maxBounds, mInsetBounds, expectedMaxMovementBounds, 0); - - mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds, - mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation); - - assertEquals(expectedMaxMovementBounds, mPipTouchHandler.mMaxMovementBounds); - verify(mPipResizeGestureHandler, times(1)) - .updateMaxSize(maxBounds.width(), maxBounds.height()); - } - - @Test - public void updateMovementBounds_withImeAdjustment_movesPip() { - mFromImeAdjustment = true; - mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds, - mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation); - - verify(mMotionHelper, times(1)).animateToOffset(any(), anyInt()); - } -} diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 485127a79c27..31044d0f0085 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -986,4 +986,11 @@ public abstract class PackageManagerInternal { * Returns MIME types contained in {@code mimeGroup} from {@code packageName} package */ public abstract List<String> getMimeGroup(String packageName, String mimeGroup); + + /** + * Toggles visibility logging to help in debugging the app enumeration feature. + * @param packageName the package name that should begin logging + * @param enabled true if visibility blocks should be logged + */ + public abstract void setVisibilityLogging(String packageName, boolean enabled); } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 0ad0b2373a79..b90681de3518 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -43,6 +43,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.util.SparseSetArray; import com.android.internal.R; @@ -123,6 +124,7 @@ public class AppsFilter { } public interface FeatureConfig { + /** Called when the system is ready and components can be queried. */ void onSystemReady(); @@ -132,11 +134,21 @@ public class AppsFilter { /** @return true if the feature is enabled for the given package. */ boolean packageIsEnabled(AndroidPackage pkg); + /** @return true if debug logging is enabled for the given package. */ + boolean isLoggingEnabled(int appId); + + /** + * Turns on logging for the given appId + * @param enable true if logging should be enabled, false if disabled. + */ + void enableLogging(int appId, boolean enable); + /** * Initializes the package enablement state for the given package. This gives opportunity * to do any expensive operations ahead of the actual checks. + * @param removed true if adding, false if removing */ - void initializePackageState(String packageName); + void updatePackageState(PackageSetting setting, boolean removed); } private static class FeatureConfigImpl implements FeatureConfig, CompatChange.ChangeListener { @@ -147,6 +159,9 @@ public class AppsFilter { PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT; private final ArraySet<String> mDisabledPackages = new ArraySet<>(); + @Nullable + private SparseBooleanArray mLoggingEnabled = null; + private FeatureConfigImpl( PackageManagerInternal pmInternal, PackageManagerService.Injector injector) { mPmInternal = pmInternal; @@ -192,39 +207,65 @@ public class AppsFilter { } } - private boolean fetchPackageIsEnabled(AndroidPackage pkg) { + @Override + public boolean isLoggingEnabled(int uid) { + return mLoggingEnabled != null && mLoggingEnabled.indexOfKey(uid) >= 0; + } + + @Override + public void enableLogging(int appId, boolean enable) { + if (enable) { + if (mLoggingEnabled == null) { + mLoggingEnabled = new SparseBooleanArray(); + } + mLoggingEnabled.put(appId, true); + } else { + if (mLoggingEnabled != null) { + final int index = mLoggingEnabled.indexOfKey(appId); + if (index >= 0) { + mLoggingEnabled.removeAt(index); + if (mLoggingEnabled.size() == 0) { + mLoggingEnabled = null; + } + } + } + } + } + + @Override + public void onCompatChange(String packageName) { + updateEnabledState(mPmInternal.getPackage(packageName)); + } + + private void updateEnabledState(AndroidPackage pkg) { final long token = Binder.clearCallingIdentity(); try { // TODO(b/135203078): Do not use toAppInfo - final boolean changeEnabled = + final boolean enabled = mInjector.getCompatibility().isChangeEnabled( PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState()); - return changeEnabled; + if (enabled) { + mDisabledPackages.remove(pkg.getPackageName()); + } else { + mDisabledPackages.add(pkg.getPackageName()); + } } finally { Binder.restoreCallingIdentity(token); } } @Override - public void onCompatChange(String packageName) { - final AndroidPackage pkg = mPmInternal.getPackage(packageName); - if (pkg == null) { - mDisabledPackages.remove(packageName); - return; - } - boolean enabled = fetchPackageIsEnabled(pkg); - if (enabled) { - mDisabledPackages.remove(packageName); + public void updatePackageState(PackageSetting setting, boolean removed) { + final boolean enableLogging = + !removed && (setting.pkg.isTestOnly() || setting.pkg.isDebuggable()); + enableLogging(setting.appId, enableLogging); + if (removed) { + mDisabledPackages.remove(setting.pkg.getPackageName()); } else { - mDisabledPackages.add(packageName); + updateEnabledState(setting.pkg); } } - - @Override - public void initializePackageState(String packageName) { - onCompatChange(packageName); - } } /** Builder method for an AppsFilter */ @@ -250,6 +291,10 @@ public class AppsFilter { forceSystemAppsQueryable, null); } + public FeatureConfig getFeatureConfig() { + return mFeatureConfig; + } + /** Returns true if the querying package may query for the potential target package */ private static boolean canQueryViaComponents(AndroidPackage querying, AndroidPackage potentialTarget) { @@ -447,7 +492,7 @@ public class AppsFilter { } } mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); - mFeatureConfig.initializePackageState(newPkgSetting.pkg.getPackageName()); + mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -499,7 +544,7 @@ public class AppsFilter { } mOverlayReferenceMapper.removePkg(setting.name); - mFeatureConfig.initializePackageState(setting.pkg.getPackageName()); + mFeatureConfig.updatePackageState(setting, true /*removed*/); } /** @@ -516,13 +561,13 @@ public class AppsFilter { PackageSetting targetPkgSetting, int userId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication"); try { - if (!shouldFilterApplicationInternal(callingUid, callingSetting, targetPkgSetting, - userId)) { + + if (!shouldFilterApplicationInternal( + callingUid, callingSetting, targetPkgSetting, userId)) { return false; } - if (DEBUG_LOGGING) { - log(callingSetting, targetPkgSetting, - DEBUG_ALLOW_ALL ? "ALLOWED" : "BLOCKED", new RuntimeException()); + if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(UserHandle.getAppId(callingUid))) { + log(callingSetting, targetPkgSetting, "BLOCKED"); } return !DEBUG_ALLOW_ALL; } finally { @@ -737,17 +782,11 @@ public class AppsFilter { } } - private static void log(SettingBase callingPkgSetting, PackageSetting targetPkgSetting, + private static void log(SettingBase callingSetting, PackageSetting targetPkgSetting, String description) { - log(callingPkgSetting, targetPkgSetting, description, null); - } - - private static void log(SettingBase callingPkgSetting, PackageSetting targetPkgSetting, - String description, Throwable throwable) { - Slog.wtf(TAG, - "interaction: " + callingPkgSetting - + " -> " + targetPkgSetting + " " - + description, throwable); + Slog.i(TAG, + "interaction: " + (callingSetting == null ? "system" : callingSetting) + " -> " + + targetPkgSetting + " " + description); } public void dumpQueries( diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index a8996d5cfea4..3a0daf13b1d3 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -6838,7 +6838,7 @@ public class PackageManagerService extends IPackageManager.Stub || (matchVisibleToInstantAppOnly && isCallerInstantApp && isTargetHiddenFromInstantApp)); final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp - && !resolveForStart && shouldFilterApplicationLocked( + && shouldFilterApplicationLocked( getPackageSettingInternal(ai.applicationInfo.packageName, Process.SYSTEM_UID), filterCallingUid, userId); if (!blockInstantResolution && !blockNormalResolution) { @@ -24152,6 +24152,18 @@ public class PackageManagerService extends IPackageManager.Stub public List<String> getMimeGroup(String packageName, String mimeGroup) { return PackageManagerService.this.getMimeGroup(packageName, mimeGroup); } + + @Override + public void setVisibilityLogging(String packageName, boolean enable) { + final PackageSetting pkg; + synchronized (mLock) { + pkg = mSettings.getPackageLPr(packageName); + } + if (pkg == null) { + throw new IllegalStateException("No package found for " + packageName); + } + mAppsFilter.getFeatureConfig().enableLogging(pkg.appId, enable); + } } @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 0f06c186b9ff..be17dd8989a3 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -295,6 +295,8 @@ class PackageManagerShellCommand extends ShellCommand { return runRollbackApp(); case "get-moduleinfo": return runGetModuleInfo(); + case "log-visibility": + return runLogVisibility(); default: { String nextArg = getNextArg(); if (nextArg == null) { @@ -360,6 +362,36 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } + private int runLogVisibility() { + final PrintWriter pw = getOutPrintWriter(); + boolean enable = true; + + String opt; + while ((opt = getNextOption()) != null) { + switch (opt) { + case "--disable": + enable = false; + break; + case "--enable": + enable = true; + break; + default: + pw.println("Error: Unknown option: " + opt); + return -1; + } + } + + String packageName = getNextArg(); + if (packageName != null) { + LocalServices.getService(PackageManagerInternal.class) + .setVisibilityLogging(packageName, enable); + } else { + getErrPrintWriter().println("Error: no package specified"); + return -1; + } + return 1; + } + private int uninstallSystemUpdates() { final PrintWriter pw = getOutPrintWriter(); List<String> failedUninstalls = new LinkedList<>(); @@ -3715,6 +3747,11 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" --all: show all module info"); pw.println(" --installed: show only installed modules"); pw.println(""); + pw.println(" log-visibility [--enable|--disable] <PACKAGE>"); + pw.println(" Turns on debug logging when visibility is blocked for the given package."); + pw.println(" --enable: turn on debug logging (default)"); + pw.println(" --disable: turn off debug logging"); + pw.println(""); Intent.printIntentArgsHelp(pw , ""); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index eed3d9d51e56..2a34bbe4ed23 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3297,22 +3297,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } - public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle, + public DeviceAdminInfo findAdmin(final ComponentName adminName, final int userHandle, boolean throwForMissingPermission) { if (!mHasFeature) { return null; } enforceFullCrossUsersPermission(userHandle); - ActivityInfo ai = null; - try { - ai = mIPackageManager.getReceiverInfo(adminName, - PackageManager.GET_META_DATA | - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS | - PackageManager.MATCH_DIRECT_BOOT_AWARE | - PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); - } catch (RemoteException e) { - // shouldn't happen. - } + final ActivityInfo ai = mInjector.binderWithCleanCallingIdentity(() -> { + try { + return mIPackageManager.getReceiverInfo(adminName, + PackageManager.GET_META_DATA + | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); + } catch (RemoteException e) { + // shouldn't happen. + return null; + } + }); if (ai == null) { throw new IllegalArgumentException("Unknown admin: " + adminName); } diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index 37d3d32efc34..bc5cc9601e05 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -20,6 +20,7 @@ import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; import android.Manifest; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -719,9 +720,9 @@ public class SmsMessage { * 23.040 9.2.3.24.16 * @param languageShiftTable GSM national language shift table to use, specified by 3GPP * 23.040 9.2.3.24.15 - * @param refNumber parameter to create SmsHeader - * @param seqNumber parameter to create SmsHeader - * @param msgCount parameter to create SmsHeader + * @param refNumber reference number of concatenated SMS, specified by 3GPP 23.040 9.2.3.24.1 + * @param seqNumber sequence number of concatenated SMS, specified by 3GPP 23.040 9.2.3.24.1 + * @param msgCount count of messages of concatenated SMS, specified by 3GPP 23.040 9.2.3.24.2 * @return a byte[] containing the encoded message * * @hide @@ -730,11 +731,14 @@ public class SmsMessage { @SystemApi @NonNull public static byte[] getSubmitPduEncodedMessage(boolean isTypeGsm, - @NonNull String destinationAddress, - @NonNull String message, - @EncodingSize int encoding, int languageTable, - int languageShiftTable, int refNumber, - int seqNumber, int msgCount) { + @NonNull String destinationAddress, + @NonNull String message, + @EncodingSize int encoding, + @IntRange(from = 0) int languageTable, + @IntRange(from = 0) int languageShiftTable, + @IntRange(from = 0, to = 255) int refNumber, + @IntRange(from = 1, to = 255) int seqNumber, + @IntRange(from = 1, to = 255) int msgCount) { byte[] data; SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); concatRef.refNumber = refNumber; |