Merge "Address API feedback" into rvc-dev
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index a4f7b5b..b219fd41 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -54,6 +54,7 @@
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 @@
*
* @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 @@
* 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 @@
* @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 @@
* @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 @@
}
} 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 @@
}
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 @@
@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 @@
@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 @@
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 @@
// 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 7acbdb4..9c2007c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26403,7 +26403,7 @@
}
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 @@
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 379ae57..9f2953c 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -11523,7 +11523,7 @@
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 e9cdbf28..8c3eef2 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -748,5 +748,4 @@
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 0000000..1daa505
--- /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 0000000..d0ead5e
--- /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 0000000..7df712f
--- /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 86d2ed6..852deb2 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 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.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 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 @@
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 @@
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 @@
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 @@
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 2b08a77..fbef027 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.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 @@
*/
@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 @@
*/
@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 @@
*/
@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 d19e313..c01766b 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 d83236c..2356b17 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 f3174d3..92e7fcd 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 60c1a94..1ae3d4f 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 @@
*/
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 6b3b748..8ada3c3 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 @@
// 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 5926b89..8fff419 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 @@
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 @@
}
} 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 @@
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 @@
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 bd22480..c3212b8 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.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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
}
// 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 @@
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 @@
// 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 @@
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 @@
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 @@
}
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 @@
}
}
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 @@
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 @@
};
/**
- * 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 @@
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 35abb14..0000000
--- 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 485127a..31044d0 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -986,4 +986,11 @@
* 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 0ad0b23..b90681d 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.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 interface FeatureConfig {
+
/** Called when the system is ready and components can be queried. */
void onSystemReady();
@@ -132,11 +134,21 @@
/** @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 @@
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 @@
}
}
- 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 @@
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 @@
}
}
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 @@
}
mOverlayReferenceMapper.removePkg(setting.name);
- mFeatureConfig.initializePackageState(setting.pkg.getPackageName());
+ mFeatureConfig.updatePackageState(setting, true /*removed*/);
}
/**
@@ -516,13 +561,13 @@
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 @@
}
}
- 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 a8996d5..3a0daf1 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 @@
|| (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 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 0f06c18..be17dd8 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 @@
return runRollbackApp();
case "get-moduleinfo":
return runGetModuleInfo();
+ case "log-visibility":
+ return runLogVisibility();
default: {
String nextArg = getNextArg();
if (nextArg == null) {
@@ -360,6 +362,36 @@
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 @@
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 eed3d9d..2a34bbe 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 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 37d3d32..bc5cc96 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -20,6 +20,7 @@
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 @@
* 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 @@
@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;