diff options
546 files changed, 26054 insertions, 8586 deletions
diff --git a/Android.bp b/Android.bp index b715b7336d23..10b92f3189b3 100644 --- a/Android.bp +++ b/Android.bp @@ -181,6 +181,7 @@ java_defaults { "core/java/android/hardware/input/IInputManager.aidl", "core/java/android/hardware/input/IInputDevicesChangedListener.aidl", "core/java/android/hardware/input/ITabletModeChangedListener.aidl", + "core/java/android/hardware/iris/IIrisService.aidl", "core/java/android/hardware/location/IActivityRecognitionHardware.aidl", "core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl", "core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl", @@ -286,6 +287,8 @@ java_defaults { "core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl", "core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl", "core/java/android/service/gatekeeper/IGateKeeperService.aidl", + "core/java/android/service/intelligence/IIntelligenceService.aidl", + "core/java/android/service/notification/INotificationListener.aidl", "core/java/android/service/notification/IStatusBarNotificationHolder.aidl", "core/java/android/service/notification/IConditionListener.aidl", @@ -342,6 +345,7 @@ java_defaults { "core/java/android/view/autofill/IAutoFillManager.aidl", "core/java/android/view/autofill/IAutoFillManagerClient.aidl", "core/java/android/view/autofill/IAutofillWindowPresenter.aidl", + "core/java/android/view/intelligence/IIntelligenceManager.aidl", "core/java/android/view/IApplicationToken.aidl", "core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl", "core/java/android/view/IDockedStackListener.aidl", @@ -594,6 +598,8 @@ java_defaults { "telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl", "telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl", "telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl", + "wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl", + "wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl", "wifi/java/android/net/wifi/ISoftApCallback.aidl", "wifi/java/android/net/wifi/ITrafficStateCallback.aidl", "wifi/java/android/net/wifi/IWifiManager.aidl", @@ -692,6 +698,7 @@ java_defaults { ], static_libs: [ + "apex_aidl_interface-java", "framework-protos", "mediaplayer2-protos", "android.hidl.base-V1.0-java", @@ -699,6 +706,8 @@ java_defaults { "android.hardware.contexthub-V1.0-java", "android.hardware.health-V1.0-java-constants", "android.hardware.thermal-V1.0-java-constants", + "android.hardware.thermal-V1.1-java", + "android.hardware.thermal-V2.0-java", "android.hardware.tv.input-V1.0-java-constants", "android.hardware.usb-V1.0-java-constants", "android.hardware.usb-V1.1-java-constants", @@ -1567,6 +1576,10 @@ droidstubs { droidstubs { name: "hiddenapi-mappings", defaults: ["metalava-api-stubs-default"], + srcs: [ + ":openjdk_java_files", + ":non_openjdk_java_files", + ], arg_files: [ "core/res/AndroidManifest.xml", ], diff --git a/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java b/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java new file mode 100644 index 000000000000..0c1f2899690d --- /dev/null +++ b/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.support.test.filters.LargeTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.function.Predicate; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class ArraySetPerfTest { + private static final int NUM_ITERATIONS = 100; + private static final int SET_SIZE_SMALL = 10; + private static final int SET_SIZE_LARGE = 50; + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Test + public void testValueAt_InBounds() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + ArraySet<Integer> set = new ArraySet<>(); + set.add(0); + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + set.valueAt(0); + } + } + } + + @Test + public void testValueAt_OutOfBounds_Negative() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + ArraySet<Integer> set = new ArraySet<>(); + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + try { + set.valueAt(-1); + } catch (ArrayIndexOutOfBoundsException expected) { + // expected + } + } + } + } + + /** + * Tests the case where ArraySet could index into its array even though the index is out of + * bounds. + */ + @Test + public void testValueAt_OutOfBounds_EdgeCase() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + ArraySet<Integer> set = new ArraySet<>(); + set.add(0); + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + try { + set.valueAt(1); + } catch (ArrayIndexOutOfBoundsException expected) { + // expected + } + } + } + } + + /** + * This is the same code as testRemoveIf_Small_* without the removeIf in order to measure + * the performance of the rest of the code in the loop. + */ + @Test + public void testRemoveIf_Small_Base() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + Predicate<Integer> predicate = (i) -> i % 2 == 0; + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + ArraySet<Integer> set = new ArraySet<>(); + for (int j = 0; j < SET_SIZE_SMALL; ++j) { + set.add(j); + } + } + } + } + + @Test + public void testRemoveIf_Small_RemoveNothing() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + Predicate<Integer> predicate = (i) -> false; + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + ArraySet<Integer> set = new ArraySet<>(); + for (int j = 0; j < SET_SIZE_SMALL; ++j) { + set.add(j); + } + set.removeIf(predicate); + } + } + } + + @Test + public void testRemoveIf_Small_RemoveAll() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + Predicate<Integer> predicate = (i) -> true; + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + ArraySet<Integer> set = new ArraySet<>(); + for (int j = 0; j < SET_SIZE_SMALL; j++) { + set.add(j); + } + set.removeIf(predicate); + } + } + } + + @Test + public void testRemoveIf_Small_RemoveHalf() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + Predicate<Integer> predicate = (i) -> i % 2 == 0; + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + ArraySet<Integer> set = new ArraySet<>(); + for (int j = 0; j < SET_SIZE_SMALL; ++j) { + set.add(j); + } + set.removeIf(predicate); + } + } + } + + /** + * This is the same code as testRemoveIf_Large_* without the removeIf in order to measure + * the performance of the rest of the code in the loop. + */ + @Test + public void testRemoveIf_Large_Base() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + Predicate<Integer> predicate = (i) -> i % 2 == 0; + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + ArraySet<Integer> set = new ArraySet<>(); + for (int j = 0; j < SET_SIZE_LARGE; ++j) { + set.add(j); + } + } + } + } + + @Test + public void testRemoveIf_Large_RemoveNothing() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + Predicate<Integer> predicate = (i) -> false; + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + ArraySet<Integer> set = new ArraySet<>(); + for (int j = 0; j < SET_SIZE_LARGE; ++j) { + set.add(j); + } + set.removeIf(predicate); + } + } + } + + @Test + public void testRemoveIf_Large_RemoveAll() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + Predicate<Integer> predicate = (i) -> true; + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + ArraySet<Integer> set = new ArraySet<>(); + for (int j = 0; j < SET_SIZE_LARGE; ++j) { + set.add(j); + } + set.removeIf(predicate); + } + } + } + + @Test + public void testRemoveIf_Large_RemoveHalf() { + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + Predicate<Integer> predicate = (i) -> i % 2 == 0; + while (state.keepRunning()) { + for (int i = 0; i < NUM_ITERATIONS; ++i) { + ArraySet<Integer> set = new ArraySet<>(); + for (int j = 0; j < SET_SIZE_LARGE; ++j) { + set.add(j); + } + set.removeIf(predicate); + } + } + } +} diff --git a/api/current.txt b/api/current.txt index 903959a2f7d6..6258adef338f 100755 --- a/api/current.txt +++ b/api/current.txt @@ -13434,6 +13434,7 @@ package android.graphics { method public boolean clipRect(float, float, float, float); method public boolean clipRect(int, int, int, int); method public void concat(android.graphics.Matrix); + method public void disableZ(); method public void drawARGB(int, int, int, int); method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint); method public void drawArc(float, float, float, float, float, float, boolean, android.graphics.Paint); @@ -13468,6 +13469,7 @@ package android.graphics { method public void drawRect(android.graphics.RectF, android.graphics.Paint); method public void drawRect(android.graphics.Rect, android.graphics.Paint); method public void drawRect(float, float, float, float, android.graphics.Paint); + method public void drawRenderNode(android.graphics.RenderNode); method public void drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint); method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint); method public void drawText(char[], int, int, float, float, android.graphics.Paint); @@ -13479,6 +13481,7 @@ package android.graphics { method public void drawTextRun(char[], int, int, int, int, float, float, boolean, android.graphics.Paint); method public void drawTextRun(java.lang.CharSequence, int, int, int, int, float, float, boolean, android.graphics.Paint); method public void drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint); + method public void enableZ(); method public boolean getClipBounds(android.graphics.Rect); method public final android.graphics.Rect getClipBounds(); method public int getDensity(); @@ -13875,6 +13878,7 @@ package android.graphics { field public static final int RAW_SENSOR = 32; // 0x20 field public static final int RGB_565 = 4; // 0x4 field public static final int UNKNOWN = 0; // 0x0 + field public static final int Y8 = 538982489; // 0x20203859 field public static final int YUV_420_888 = 35; // 0x23 field public static final int YUV_422_888 = 39; // 0x27 field public static final int YUV_444_888 = 40; // 0x28 @@ -14468,6 +14472,9 @@ package android.graphics { ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode); } + public final class RecordingCanvas extends android.graphics.Canvas { + } + public final class Rect implements android.os.Parcelable { ctor public Rect(); ctor public Rect(int, int, int, int); @@ -14604,6 +14611,77 @@ package android.graphics { method public final boolean next(android.graphics.Rect); } + public class RenderNode { + method public int computeApproximateMemoryUsage(); + method public static android.graphics.RenderNode create(java.lang.String); + method public void discardDisplayList(); + method public void endRecording(); + method public float getAlpha(); + method public int getAmbientShadowColor(); + method public int getBottom(); + method public float getCameraDistance(); + method public boolean getClipToOutline(); + method public float getElevation(); + method public int getHeight(); + method public void getInverseMatrix(android.graphics.Matrix); + method public int getLeft(); + method public void getMatrix(android.graphics.Matrix); + method public float getPivotX(); + method public float getPivotY(); + method public int getRight(); + method public float getRotation(); + method public float getRotationX(); + method public float getRotationY(); + method public float getScaleX(); + method public float getScaleY(); + method public int getSpotShadowColor(); + method public int getTop(); + method public float getTranslationX(); + method public float getTranslationY(); + method public float getTranslationZ(); + method public int getWidth(); + method public boolean hasDisplayList(); + method public boolean hasIdentityMatrix(); + method public boolean hasOverlappingRendering(); + method public boolean hasShadow(); + method public boolean isForceDarkAllowed(); + method public boolean isPivotExplicitlySet(); + method public boolean offsetLeftAndRight(int); + method public boolean offsetTopAndBottom(int); + method public boolean resetPivot(); + method public boolean setAlpha(float); + method public boolean setAmbientShadowColor(int); + method public boolean setBottom(int); + method public boolean setCameraDistance(float); + method public boolean setClipBounds(android.graphics.Rect); + method public boolean setClipToBounds(boolean); + method public boolean setClipToOutline(boolean); + method public boolean setElevation(float); + method public boolean setForceDarkAllowed(boolean); + method public boolean setHasOverlappingRendering(boolean); + method public boolean setLeft(int); + method public boolean setLeftTopRightBottom(int, int, int, int); + method public boolean setOutline(android.graphics.Outline); + method public boolean setPivotX(float); + method public boolean setPivotY(float); + method public boolean setProjectBackwards(boolean); + method public boolean setProjectionReceiver(boolean); + method public boolean setRight(int); + method public boolean setRotation(float); + method public boolean setRotationX(float); + method public boolean setRotationY(float); + method public boolean setScaleX(float); + method public boolean setScaleY(float); + method public boolean setSpotShadowColor(int); + method public boolean setTop(int); + method public boolean setTranslationX(float); + method public boolean setTranslationY(float); + method public boolean setTranslationZ(float); + method public boolean setUseCompositingLayer(boolean, android.graphics.Paint); + method public android.graphics.RecordingCanvas startRecording(int, int); + method public android.graphics.RecordingCanvas startRecording(); + } + public class Shader { ctor public deprecated Shader(); method public boolean getLocalMatrix(android.graphics.Matrix); @@ -14692,10 +14770,10 @@ package android.graphics { public static class Typeface.CustomFallbackBuilder { ctor public Typeface.CustomFallbackBuilder(android.graphics.fonts.FontFamily); + method public android.graphics.Typeface.CustomFallbackBuilder addCustomFallback(android.graphics.fonts.FontFamily); method public android.graphics.Typeface build(); - method public android.graphics.Typeface.CustomFallbackBuilder setFallback(java.lang.String); - method public android.graphics.Typeface.CustomFallbackBuilder setItalic(boolean); - method public android.graphics.Typeface.CustomFallbackBuilder setWeight(int); + method public android.graphics.Typeface.CustomFallbackBuilder setStyle(android.graphics.fonts.FontStyle); + method public android.graphics.Typeface.CustomFallbackBuilder setSystemFallback(java.lang.String); } public class Xfermode { @@ -15340,9 +15418,8 @@ package android.graphics.fonts { method public java.nio.ByteBuffer getBuffer(); method public java.io.File getFile(); method public android.os.LocaleList getLocaleList(); - method public int getSlant(); + method public android.graphics.fonts.FontStyle getStyle(); method public int getTtcIndex(); - method public int getWeight(); } public static class Font.Builder { @@ -16216,6 +16293,7 @@ package android.hardware.camera2 { method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys(); method public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission(); method public java.util.Set<java.lang.String> getPhysicalCameraIds(); + method public android.hardware.camera2.params.RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(int); field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES; field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES; field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_MODES; @@ -16878,6 +16956,33 @@ package android.hardware.camera2.params { field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff } + public final class RecommendedStreamConfigurationMap { + method public java.util.Set<android.util.Size> getHighResolutionOutputSizes(int); + method public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRanges(); + method public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRangesFor(android.util.Size); + method public java.util.Set<android.util.Size> getHighSpeedVideoSizes(); + method public java.util.Set<android.util.Size> getHighSpeedVideoSizesFor(android.util.Range<java.lang.Integer>); + method public java.util.Set<java.lang.Integer> getInputFormats(); + method public java.util.Set<android.util.Size> getInputSizes(int); + method public java.util.Set<java.lang.Integer> getOutputFormats(); + method public long getOutputMinFrameDuration(int, android.util.Size); + method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size); + method public java.util.Set<android.util.Size> getOutputSizes(int); + method public <T> java.util.Set<android.util.Size> getOutputSizes(java.lang.Class<T>); + method public long getOutputStallDuration(int, android.util.Size); + method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size); + method public int getRecommendedUseCase(); + method public java.util.Set<java.lang.Integer> getValidOutputFormatsForInput(int); + method public boolean isOutputSupportedFor(int); + method public boolean isOutputSupportedFor(android.view.Surface); + field public static final int USECASE_PREVIEW = 0; // 0x0 + field public static final int USECASE_RAW = 5; // 0x5 + field public static final int USECASE_RECORD = 1; // 0x1 + field public static final int USECASE_SNAPSHOT = 3; // 0x3 + field public static final int USECASE_VIDEO_SNAPSHOT = 2; // 0x2 + field public static final int USECASE_ZSL = 4; // 0x4 + } + public final class RggbChannelVector { ctor public RggbChannelVector(float, float, float, float); method public void copyTo(float[], int); @@ -22714,6 +22819,7 @@ package android.media { field public static final int ENCODING_AC3 = 5; // 0x5 field public static final int ENCODING_AC4 = 17; // 0x11 field public static final int ENCODING_DEFAULT = 1; // 0x1 + field public static final int ENCODING_DOLBY_MAT = 19; // 0x13 field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe field public static final int ENCODING_DTS = 7; // 0x7 field public static final int ENCODING_DTS_HD = 8; // 0x8 @@ -28614,7 +28720,7 @@ package android.net.wifi { enum_constant public static final android.net.wifi.SupplicantState UNINITIALIZED; } - public class WifiConfiguration implements android.os.Parcelable { + public deprecated class WifiConfiguration implements android.os.Parcelable { ctor public WifiConfiguration(); method public int describeContents(); method public android.net.ProxyInfo getHttpProxy(); @@ -28626,9 +28732,11 @@ package android.net.wifi { field public java.lang.String SSID; field public java.util.BitSet allowedAuthAlgorithms; field public java.util.BitSet allowedGroupCiphers; + field public java.util.BitSet allowedGroupMgmtCiphers; field public java.util.BitSet allowedKeyManagement; field public java.util.BitSet allowedPairwiseCiphers; field public java.util.BitSet allowedProtocols; + field public java.util.BitSet allowedSuiteBCiphers; field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig; field public boolean hiddenSSID; field public boolean isHomeProviderNetwork; @@ -28652,6 +28760,7 @@ package android.net.wifi { public static class WifiConfiguration.GroupCipher { field public static final int CCMP = 3; // 0x3 + field public static final int GCMP_256 = 5; // 0x5 field public static final int TKIP = 2; // 0x2 field public static final deprecated int WEP104 = 1; // 0x1 field public static final deprecated int WEP40 = 0; // 0x0 @@ -28659,9 +28768,18 @@ package android.net.wifi { field public static final java.lang.String varName = "group"; } + public static class WifiConfiguration.GroupMgmtCipher { + field public static final int BIP_CMAC_256 = 0; // 0x0 + field public static final int BIP_GMAC_128 = 1; // 0x1 + field public static final int BIP_GMAC_256 = 2; // 0x2 + } + public static class WifiConfiguration.KeyMgmt { field public static final int IEEE8021X = 3; // 0x3 field public static final int NONE = 0; // 0x0 + field public static final int OWE = 9; // 0x9 + field public static final int SAE = 8; // 0x8 + field public static final int SUITE_B_192 = 10; // 0xa field public static final int WPA_EAP = 2; // 0x2 field public static final int WPA_PSK = 1; // 0x1 field public static final java.lang.String[] strings; @@ -28670,6 +28788,7 @@ package android.net.wifi { public static class WifiConfiguration.PairwiseCipher { field public static final int CCMP = 2; // 0x2 + field public static final int GCMP_256 = 3; // 0x3 field public static final int NONE = 0; // 0x0 field public static final deprecated int TKIP = 1; // 0x1 field public static final java.lang.String[] strings; @@ -28768,7 +28887,8 @@ package android.net.wifi { } public class WifiManager { - method public int addNetwork(android.net.wifi.WifiConfiguration); + method public deprecated int addNetwork(android.net.wifi.WifiConfiguration); + method public boolean addNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>, android.app.PendingIntent); method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration); method public static int calculateSignalLevel(int, int); method public deprecated void cancelWps(android.net.wifi.WifiManager.WpsCallback); @@ -28776,10 +28896,10 @@ package android.net.wifi { method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String); method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String); method public android.net.wifi.WifiManager.WifiLock createWifiLock(java.lang.String); - method public boolean disableNetwork(int); - method public boolean disconnect(); - method public boolean enableNetwork(int, boolean); - method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks(); + method public deprecated boolean disableNetwork(int); + method public deprecated boolean disconnect(); + method public deprecated boolean enableNetwork(int, boolean); + method public deprecated java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks(); method public android.net.wifi.WifiInfo getConnectionInfo(); method public android.net.DhcpInfo getDhcpInfo(); method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations(); @@ -28790,22 +28910,23 @@ package android.net.wifi { method public boolean isEnhancedPowerReportingSupported(); method public boolean isP2pSupported(); method public boolean isPreferredNetworkOffloadSupported(); - method public boolean isScanAlwaysAvailable(); + method public deprecated boolean isScanAlwaysAvailable(); method public boolean isTdlsSupported(); method public boolean isWifiEnabled(); method public deprecated boolean pingSupplicant(); - method public boolean reassociate(); - method public boolean reconnect(); - method public boolean removeNetwork(int); + method public deprecated boolean reassociate(); + method public deprecated boolean reconnect(); + method public deprecated boolean removeNetwork(int); + method public boolean removeNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>); method public void removePasspointConfiguration(java.lang.String); method public deprecated boolean saveConfiguration(); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); - method public boolean setWifiEnabled(boolean); + method public deprecated boolean setWifiEnabled(boolean); method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler); method public deprecated boolean startScan(); method public deprecated void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback); - method public int updateNetwork(android.net.wifi.WifiConfiguration); + method public deprecated int updateNetwork(android.net.wifi.WifiConfiguration); field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE"; field public static final deprecated int ERROR_AUTHENTICATING = 1; // 0x1 @@ -28879,6 +29000,29 @@ package android.net.wifi { method public abstract deprecated void onSucceeded(); } + public class WifiNetworkConfigBuilder { + ctor public WifiNetworkConfigBuilder(); + method public android.net.NetworkSpecifier buildNetworkSpecifier(); + method public android.net.wifi.WifiNetworkSuggestion buildNetworkSuggestion(); + method public android.net.wifi.WifiNetworkConfigBuilder setBssid(android.net.MacAddress); + method public android.net.wifi.WifiNetworkConfigBuilder setBssidPattern(android.net.MacAddress, android.net.MacAddress); + method public android.net.wifi.WifiNetworkConfigBuilder setEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig); + method public android.net.wifi.WifiNetworkConfigBuilder setIsAppInteractionRequired(); + method public android.net.wifi.WifiNetworkConfigBuilder setIsHiddenSsid(); + method public android.net.wifi.WifiNetworkConfigBuilder setIsMetered(); + method public android.net.wifi.WifiNetworkConfigBuilder setIsUserInteractionRequired(); + method public android.net.wifi.WifiNetworkConfigBuilder setPriority(int); + method public android.net.wifi.WifiNetworkConfigBuilder setPskPassphrase(java.lang.String); + method public android.net.wifi.WifiNetworkConfigBuilder setSsid(java.lang.String); + method public android.net.wifi.WifiNetworkConfigBuilder setSsidPattern(android.os.PatternMatcher); + } + + public final class WifiNetworkSuggestion implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSuggestion> CREATOR; + } + public deprecated class WpsInfo implements android.os.Parcelable { ctor public deprecated WpsInfo(); ctor public deprecated WpsInfo(android.net.wifi.WpsInfo); @@ -33189,6 +33333,7 @@ package android.os { field public static java.lang.String DIRECTORY_PICTURES; field public static java.lang.String DIRECTORY_PODCASTS; field public static java.lang.String DIRECTORY_RINGTONES; + field public static java.lang.String DIRECTORY_SCREENSHOTS; field public static final java.lang.String MEDIA_BAD_REMOVAL = "bad_removal"; field public static final java.lang.String MEDIA_CHECKING = "checking"; field public static final java.lang.String MEDIA_EJECTING = "ejecting"; @@ -34040,6 +34185,7 @@ package android.os { field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps"; field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources"; field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY = "no_install_unknown_sources_globally"; + field public static final java.lang.String DISALLOW_INTELLIGENCE_CAPTURE = "no_intelligence_capture"; field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts"; field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media"; field public static final java.lang.String DISALLOW_NETWORK_RESET = "no_network_reset"; @@ -36917,12 +37063,15 @@ package android.provider { public final class MediaStore { ctor public MediaStore(); + method public static android.net.Uri createPending(android.content.Context, android.provider.MediaStore.PendingParams); method public static java.util.Set<java.lang.String> getAllVolumeNames(android.content.Context); method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri); method public static android.net.Uri getMediaScannerUri(); method public static android.net.Uri getMediaUri(android.content.Context, android.net.Uri); method public static java.lang.String getVersion(android.content.Context); method public static java.lang.String getVolumeName(android.net.Uri); + method public static android.provider.MediaStore.PendingSession openPending(android.content.Context, android.net.Uri); + method public static android.net.Uri setIncludePending(android.net.Uri); field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE"; field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE"; field public static final java.lang.String ACTION_REVIEW = "android.provider.action.REVIEW"; @@ -37180,12 +37329,29 @@ package android.provider { field public static final java.lang.String DISPLAY_NAME = "_display_name"; field public static final java.lang.String HASH = "_hash"; field public static final java.lang.String HEIGHT = "height"; + field public static final java.lang.String IS_PENDING = "is_pending"; field public static final java.lang.String MIME_TYPE = "mime_type"; + field public static final java.lang.String OWNER_PACKAGE_NAME = "owner_package_name"; field public static final java.lang.String SIZE = "_size"; field public static final java.lang.String TITLE = "title"; field public static final java.lang.String WIDTH = "width"; } + public static class MediaStore.PendingParams { + ctor public MediaStore.PendingParams(android.net.Uri, java.lang.String, java.lang.String); + method public void setPrimaryDirectory(java.lang.String); + method public void setSecondaryDirectory(java.lang.String); + } + + public static class MediaStore.PendingSession implements java.lang.AutoCloseable { + method public void abandon(); + method public void close(); + method public void notifyProgress(int); + method public android.os.ParcelFileDescriptor open() throws java.io.FileNotFoundException; + method public java.io.OutputStream openOutputStream() throws java.io.FileNotFoundException; + method public android.net.Uri publish(); + } + public static final class MediaStore.Video { ctor public MediaStore.Video(); method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[]); @@ -37270,6 +37436,7 @@ package android.provider { field public static final java.lang.String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS"; field public static final java.lang.String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS"; field public static final java.lang.String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS"; + field public static final java.lang.String ACTION_APP_USAGE_SETTINGS = "android.settings.action.APP_USAGE_SETTINGS"; field public static final java.lang.String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS"; field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS"; field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS"; @@ -42295,6 +42462,7 @@ package android.telecom { method public java.lang.String getVoiceMailNumber(android.telecom.PhoneAccountHandle); method public boolean handleMmi(java.lang.String); method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle); + method public boolean isDefaultCallScreeningApp(android.content.ComponentName); method public boolean isInCall(); method public boolean isInManagedCall(); method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle); @@ -42303,12 +42471,14 @@ package android.telecom { method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String); method public void placeCall(android.net.Uri, android.os.Bundle); method public void registerPhoneAccount(android.telecom.PhoneAccount); + method public void requestChangeDefaultCallScreeningApp(android.content.ComponentName); method public void showInCallScreen(boolean); method public void silenceRinger(); method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle); field public static final java.lang.String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER"; field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS"; field public static final java.lang.String ACTION_CONFIGURE_PHONE_ACCOUNT = "android.telecom.action.CONFIGURE_PHONE_ACCOUNT"; + field public static final java.lang.String ACTION_DEFAULT_CALL_SCREENING_APP_CHANGED = "android.telecom.action.DEFAULT_CALL_SCREENING_APP_CHANGED"; field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED"; field public static final deprecated java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL"; field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED"; @@ -42325,9 +42495,11 @@ package android.telecom { field public static final java.lang.String EXTRA_CALL_NETWORK_TYPE = "android.telecom.extra.CALL_NETWORK_TYPE"; field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT"; field public static final java.lang.String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME"; + field public static final java.lang.String EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME = "android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME"; field public static final java.lang.String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS"; field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS"; field public static final java.lang.String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE"; + field public static final java.lang.String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP"; field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT"; field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER"; field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS"; @@ -48355,6 +48527,7 @@ package android.view { ctor public TouchDelegate(android.graphics.Rect, android.view.View); method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo(); method public boolean onTouchEvent(android.view.MotionEvent); + method public boolean onTouchExplorationHoverEvent(android.view.MotionEvent); field public static final int ABOVE = 1; // 0x1 field public static final int BELOW = 2; // 0x2 field public static final int TO_LEFT = 4; // 0x4 @@ -50013,17 +50186,29 @@ package android.view { method public int getStableInsetLeft(); method public int getStableInsetRight(); method public int getStableInsetTop(); + method public android.graphics.Insets getStableInsets(); method public int getSystemWindowInsetBottom(); method public int getSystemWindowInsetLeft(); method public int getSystemWindowInsetRight(); method public int getSystemWindowInsetTop(); + method public android.graphics.Insets getSystemWindowInsets(); method public boolean hasInsets(); method public boolean hasStableInsets(); method public boolean hasSystemWindowInsets(); + method public android.view.WindowInsets inset(int, int, int, int); method public boolean isConsumed(); method public boolean isRound(); - method public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int); - method public android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect); + method public deprecated android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int); + method public deprecated android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect); + } + + public static class WindowInsets.Builder { + ctor public WindowInsets.Builder(); + ctor public WindowInsets.Builder(android.view.WindowInsets); + method public android.view.WindowInsets build(); + method public android.view.WindowInsets.Builder setDisplayCutout(android.view.DisplayCutout); + method public android.view.WindowInsets.Builder setStableInsets(android.graphics.Insets); + method public android.view.WindowInsets.Builder setSystemWindowInsets(android.graphics.Insets); } public abstract interface WindowManager implements android.view.ViewManager { @@ -51456,6 +51641,17 @@ package android.view.inputmethod { } +package android.view.intelligence { + + public final class IntelligenceManager { + method public void disableContentCapture(); + method public android.content.ComponentName getIntelligenceServiceComponentName(); + method public boolean isContentCaptureEnabled(); + field public static final int FLAG_USER_INPUT = 1; // 0x1 + } + +} + package android.view.textclassifier { public final class ConversationActions implements android.os.Parcelable { @@ -55052,6 +55248,9 @@ package android.widget { method public android.os.LocaleList getTextLocales(); method public android.text.PrecomputedText.Params getTextMetricsParams(); method public float getTextScaleX(); + method public android.graphics.drawable.Drawable getTextSelectHandle(); + method public android.graphics.drawable.Drawable getTextSelectHandleLeft(); + method public android.graphics.drawable.Drawable getTextSelectHandleRight(); method public float getTextSize(); method public int getTotalPaddingBottom(); method public int getTotalPaddingEnd(); @@ -55180,6 +55379,12 @@ package android.widget { method public void setTextLocales(android.os.LocaleList); method public void setTextMetricsParams(android.text.PrecomputedText.Params); method public void setTextScaleX(float); + method public void setTextSelectHandle(android.graphics.drawable.Drawable); + method public void setTextSelectHandle(int); + method public void setTextSelectHandleLeft(android.graphics.drawable.Drawable); + method public void setTextSelectHandleLeft(int); + method public void setTextSelectHandleRight(android.graphics.drawable.Drawable); + method public void setTextSelectHandleRight(int); method public void setTextSize(float); method public void setTextSize(int, float); method public final void setTransformationMethod(android.text.method.TransformationMethod); diff --git a/api/system-current.txt b/api/system-current.txt index 10cf633a0b50..d8f7f4a1ad10 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -24,6 +24,7 @@ package android { field public static final java.lang.String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH"; field public static final java.lang.String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE"; field public static final java.lang.String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE"; + field public static final java.lang.String BIND_INTELLIGENCE_SERVICE = "android.permission.BIND_INTELLIGENCE_SERVICE"; field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET"; field public static final java.lang.String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE"; field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"; @@ -294,10 +295,13 @@ package android.app { } public class AppOpsManager { + method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long); + method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long); method public static java.lang.String[] getOpStrs(); method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]); + method public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOpStrs(java.lang.String[]); + method public static int opToDefaultMode(java.lang.String); method public static java.lang.String opToPermission(java.lang.String); - method public void resetUidMode(java.lang.String, int, boolean); method public void setMode(java.lang.String, int, java.lang.String, int); method public void setUidMode(java.lang.String, int, int); field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover"; @@ -343,6 +347,39 @@ package android.app { field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms"; field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms"; field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper"; + field public static final int UID_STATE_BACKGROUND = 4; // 0x4 + field public static final int UID_STATE_CACHED = 5; // 0x5 + field public static final int UID_STATE_FOREGROUND = 3; // 0x3 + field public static final int UID_STATE_FOREGROUND_SERVICE = 2; // 0x2 + field public static final int UID_STATE_PERSISTENT = 0; // 0x0 + field public static final int UID_STATE_TOP = 1; // 0x1 + } + + public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable { + method public int describeContents(); + method public long getAccessCount(int); + method public long getAccessDuration(int); + method public long getBackgroundAccessCount(); + method public long getBackgroundAccessDuration(); + method public long getBackgroundRejectCount(); + method public long getForegroundAccessCount(); + method public long getForegroundAccessDuration(); + method public long getForegroundRejectCount(); + method public java.lang.String getOp(); + method public long getRejectCount(int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR; + } + + public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable { + method public int describeContents(); + method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String); + method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int); + method public int getEntryCount(); + method public java.lang.String getPackageName(); + method public int getUid(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR; } public static final class AppOpsManager.OpEntry implements android.os.Parcelable { @@ -578,6 +615,14 @@ package android.app.admin { } +package android.app.assist { + + public static class AssistStructure.ViewNode { + ctor public AssistStructure.ViewNode(); + } + +} + package android.app.backup { public class BackupDataInput { @@ -3570,7 +3615,7 @@ package android.net.wifi { field public byte id; } - public class WifiConfiguration implements android.os.Parcelable { + public deprecated class WifiConfiguration implements android.os.Parcelable { method public boolean hasNoInternetAccess(); method public boolean isEphemeral(); method public boolean isNoInternetAccessExpected(); @@ -3596,11 +3641,16 @@ package android.net.wifi { method public int getWifiApState(); method public boolean isDeviceToApRttSupported(); method public boolean isDeviceToDeviceRttSupported(); + method public boolean isOweSupported(); method public boolean isPortableHotspotSupported(); method public boolean isWifiApEnabled(); method public boolean isWifiScannerSupported(); + method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler); + method public boolean isWpa3SaeSupported(); + method public boolean isWpa3SuiteBSupported(); method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration); method public boolean startScan(android.os.WorkSource); + method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback); field public static final int CHANGE_REASON_ADDED = 0; // 0x0 field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2 field public static final int CHANGE_REASON_REMOVED = 1; // 0x1 @@ -3628,6 +3678,18 @@ package android.net.wifi { method public abstract void onSuccess(); } + public static abstract interface WifiManager.NetworkRequestMatchCallback { + method public abstract void onMatch(java.util.List<android.net.wifi.WifiConfiguration>); + method public abstract void onUserSelectionCallbackRegistration(android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback); + method public abstract void onUserSelectionConnectFailure(android.net.wifi.WifiConfiguration); + method public abstract void onUserSelectionConnectSuccess(android.net.wifi.WifiConfiguration); + } + + public static abstract interface WifiManager.NetworkRequestUserSelectionCallback { + method public abstract void reject(); + method public abstract void select(android.net.wifi.WifiConfiguration); + } + public class WifiNetworkConnectionStatistics implements android.os.Parcelable { ctor public WifiNetworkConnectionStatistics(int, int); ctor public WifiNetworkConnectionStatistics(); @@ -4825,6 +4887,36 @@ package android.service.euicc { } +package android.service.intelligence { + + public abstract class IntelligenceService extends android.app.Service { + ctor public IntelligenceService(); + method public abstract void onContentCaptureEvent(android.service.intelligence.InteractionSessionId, java.util.List<android.view.intelligence.ContentCaptureEvent>); + method public void onCreateInteractionSession(android.service.intelligence.InteractionContext, android.service.intelligence.InteractionSessionId); + method public void onDestroyInteractionSession(android.service.intelligence.InteractionSessionId); + field public static final java.lang.String SERVICE_INTERFACE = "android.service.intelligence.IntelligenceService"; + } + + public final class InteractionContext implements android.os.Parcelable { + method public int describeContents(); + method public android.content.ComponentName getActivityComponent(); + method public int getDisplayId(); + method public int getFlags(); + method public int getTaskId(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.intelligence.InteractionContext> CREATOR; + field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1 + field public static final int FLAG_DISABLED_BY_FLAG_SECURE = 2; // 0x2 + } + + public final class InteractionSessionId implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.service.intelligence.InteractionSessionId> CREATOR; + } + +} + package android.service.notification { public final class Adjustment implements android.os.Parcelable { @@ -5468,8 +5560,12 @@ package android.telephony { method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>); field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS"; field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS"; - field public static final android.net.Uri ENHANCED_4G_ENABLED_CONTENT_URI; + field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI; + field public static final android.net.Uri VT_ENABLED_CONTENT_URI; field public static final android.net.Uri WFC_ENABLED_CONTENT_URI; + field public static final android.net.Uri WFC_MODE_CONTENT_URI; + field public static final android.net.Uri WFC_ROAMING_ENABLED_CONTENT_URI; + field public static final android.net.Uri WFC_ROAMING_MODE_CONTENT_URI; } public final class SubscriptionPlan implements android.os.Parcelable { @@ -5828,6 +5924,7 @@ package android.telephony.euicc { field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2 field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1 field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4 + field public static final int RESULT_CALLER_NOT_ALLOWED = -3; // 0xfffffffd field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe field public static final int RESULT_OK = 0; // 0x0 field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff @@ -5952,6 +6049,7 @@ package android.telephony.ims { method public void setCallExtra(java.lang.String, java.lang.String); method public void setCallExtraBoolean(java.lang.String, boolean); method public void setCallExtraInt(java.lang.String, int); + method public void setCallRestrictCause(int); method public void updateCallExtras(android.telephony.ims.ImsCallProfile); method public void updateCallType(android.telephony.ims.ImsCallProfile); method public void updateMediaProfile(android.telephony.ims.ImsCallProfile); @@ -6862,6 +6960,40 @@ package android.view.accessibility { } +package android.view.intelligence { + + public final class ContentCaptureEvent implements android.os.Parcelable { + method public int describeContents(); + method public long getEventTime(); + method public int getFlags(); + method public android.view.autofill.AutofillId getId(); + method public java.lang.CharSequence getText(); + method public int getType(); + method public android.view.intelligence.ViewNode getViewNode(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.view.intelligence.ContentCaptureEvent> CREATOR; + field public static final int TYPE_ACTIVITY_PAUSED = 3; // 0x3 + field public static final int TYPE_ACTIVITY_RESUMED = 2; // 0x2 + field public static final int TYPE_ACTIVITY_STARTED = 1; // 0x1 + field public static final int TYPE_ACTIVITY_STOPPED = 4; // 0x4 + field public static final int TYPE_VIEW_ADDED = 5; // 0x5 + field public static final int TYPE_VIEW_REMOVED = 6; // 0x6 + field public static final int TYPE_VIEW_TEXT_CHANGED = 7; // 0x7 + } + + public final class IntelligenceManager { + method public java.util.Set<android.content.ComponentName> getContentCaptureDisabledActivities(); + method public java.util.Set<java.lang.String> getContentCaptureDisabledPackages(); + method public void setActivityContentCaptureEnabled(android.content.ComponentName, boolean); + method public void setPackageContentCaptureEnabled(java.lang.String, boolean); + } + + public final class ViewNode extends android.app.assist.AssistStructure.ViewNode { + method public android.view.autofill.AutofillId getParentAutofillId(); + } + +} + package android.webkit { public abstract class CookieManager { diff --git a/api/test-current.txt b/api/test-current.txt index b59eaccf7823..b2cf4c897e07 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -78,6 +78,8 @@ package android.app { } public class AppOpsManager { + method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long); + method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long); method public static int getNumOps(); method public static java.lang.String[] getOpStrs(); method public boolean isOperationActive(int, int, java.lang.String); @@ -135,6 +137,33 @@ package android.app { field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18 } + public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable { + method public int describeContents(); + method public long getAccessCount(int); + method public long getAccessDuration(int); + method public long getBackgroundAccessCount(); + method public long getBackgroundAccessDuration(); + method public long getBackgroundRejectCount(); + method public long getForegroundAccessCount(); + method public long getForegroundAccessDuration(); + method public long getForegroundRejectCount(); + method public java.lang.String getOp(); + method public long getRejectCount(int); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR; + } + + public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable { + method public int describeContents(); + method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String); + method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int); + method public int getEntryCount(); + method public java.lang.String getPackageName(); + method public int getUid(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR; + } + public static abstract interface AppOpsManager.OnOpActiveChangedListener { method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean); } @@ -179,10 +208,12 @@ package android.app { method public int getActivityType(); method public android.graphics.Rect getAppBounds(); method public android.graphics.Rect getBounds(); + method public int getRotation(); method public int getWindowingMode(); method public void setActivityType(int); method public void setAppBounds(android.graphics.Rect); method public void setBounds(android.graphics.Rect); + method public void setRotation(int); method public void setTo(android.app.WindowConfiguration); method public void setWindowingMode(int); method public void writeToParcel(android.os.Parcel, int); @@ -191,6 +222,7 @@ package android.app { field public static final int ACTIVITY_TYPE_RECENTS = 3; // 0x3 field public static final int ACTIVITY_TYPE_STANDARD = 1; // 0x1 field public static final int ACTIVITY_TYPE_UNDEFINED = 0; // 0x0 + field public static final int ROTATION_UNDEFINED = -1; // 0xffffffff field public static final int WINDOWING_MODE_FREEFORM = 5; // 0x5 field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1 field public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = 4; // 0x4 @@ -1323,6 +1355,14 @@ package android.transition { } +package android.util { + + public final class ArraySet<E> implements java.util.Collection java.util.Set { + method public E valueAtUnchecked(int); + } + +} + package android.util.proto { public final class EncodedBuffer { diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp index fc1a61cac558..80ed80776829 100644 --- a/cmds/statsd/src/FieldValue.cpp +++ b/cmds/statsd/src/FieldValue.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include "FieldValue.h" #include "HashableDimensionKey.h" +#include "math.h" namespace android { namespace os { @@ -174,6 +175,25 @@ std::string Value::toString() const { } } +bool Value::isZero() const { + switch (type) { + case INT: + return int_value == 0; + case LONG: + return long_value == 0; + case FLOAT: + return fabs(float_value) <= std::numeric_limits<float>::epsilon(); + case DOUBLE: + return fabs(double_value) <= std::numeric_limits<double>::epsilon(); + case STRING: + return str_value.size() == 0; + case STORAGE: + return storage_value.size() == 0; + default: + return false; + } +} + bool Value::operator==(const Value& that) const { if (type != that.getType()) return false; diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h index 77163f9d8619..a5d00ac4e72b 100644 --- a/cmds/statsd/src/FieldValue.h +++ b/cmds/statsd/src/FieldValue.h @@ -331,6 +331,8 @@ struct Value { std::string toString() const; + bool isZero() const; + Type getType() const { return type; } diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 12e2560a43b5..f0f599317352 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -272,26 +272,25 @@ void StatsLogProcessor::dumpStates(int out, bool verbose) { } /* - * onDumpReport dumps serialized ConfigMetricsReportList into outData. + * onDumpReport dumps serialized ConfigMetricsReportList into proto. */ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs, const bool include_current_partial_bucket, + const bool erase_data, const DumpReportReason dumpReportReason, - vector<uint8_t>* outData) { + ProtoOutputStream* proto) { std::lock_guard<std::mutex> lock(mMetricsMutex); - ProtoOutputStream proto; - // Start of ConfigKey. - uint64_t configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY); - proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid()); - proto.write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId()); - proto.end(configKeyToken); + uint64_t configKeyToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY); + proto->write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid()); + proto->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId()); + proto->end(configKeyToken); // End of ConfigKey. // Then, check stats-data directory to see there's any file containing // ConfigMetricsReport from previous shutdowns to concatenate to reports. - StorageManager::appendConfigMetricsReport(key, &proto); + StorageManager::appendConfigMetricsReport(key, proto); auto it = mMetricsManagers.find(key); if (it != mMetricsManagers.end()) { @@ -301,14 +300,27 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTim // Start of ConfigMetricsReport (reports). uint64_t reportsToken = - proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS); + proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS); onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket, - dumpReportReason, &proto); - proto.end(reportsToken); + erase_data, dumpReportReason, proto); + proto->end(reportsToken); // End of ConfigMetricsReport (reports). } else { ALOGW("Config source %s does not exist", key.ToString().c_str()); } +} + +/* + * onDumpReport dumps serialized ConfigMetricsReportList into outData. + */ +void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs, + const bool include_current_partial_bucket, + const bool erase_data, + const DumpReportReason dumpReportReason, + vector<uint8_t>* outData) { + ProtoOutputStream proto; + onDumpReport(key, dumpTimeStampNs, include_current_partial_bucket, erase_data, + dumpReportReason, &proto); if (outData != nullptr) { outData->clear(); @@ -332,6 +344,7 @@ void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTim void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs, const bool include_current_partial_bucket, + const bool erase_data, const DumpReportReason dumpReportReason, ProtoOutputStream* proto) { // We already checked whether key exists in mMetricsManagers in @@ -348,7 +361,7 @@ void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key, // First, fill in ConfigMetricsReport using current data on memory, which // starts from filling in StatsLogReport's. it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, - &str_set, proto); + erase_data, &str_set, proto); // Fill in UidMap if there is at least one metric to report. // This skips the uid map if it's an empty config. @@ -479,7 +492,7 @@ void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key, } ProtoOutputStream proto; onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/, - dumpReportReason, &proto); + true /* erase_data */, dumpReportReason, &proto); string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR, (long)getWallClockSec(), key.GetUid(), (long long)key.GetId()); android::base::unique_fd fd(open(file_name.c_str(), diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 3e8b9b8d5df5..ecfd819a3399 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -61,8 +61,11 @@ public: size_t GetMetricsSize(const ConfigKey& key) const; void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs, - const bool include_current_partial_bucket, + const bool include_current_partial_bucket, const bool erase_data, const DumpReportReason dumpReportReason, vector<uint8_t>* outData); + void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs, + const bool include_current_partial_bucket, const bool erase_data, + const DumpReportReason dumpReportReason, ProtoOutputStream* proto); /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */ void onAnomalyAlarmFired( @@ -141,6 +144,7 @@ private: void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs, const bool include_current_partial_bucket, + const bool erase_data, const DumpReportReason dumpReportReason, util::ProtoOutputStream* proto); diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index ce2877731882..27685fc108a0 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -46,6 +46,8 @@ using namespace android; using android::base::StringPrintf; +using android::util::FIELD_COUNT_REPEATED; +using android::util::FIELD_TYPE_MESSAGE; namespace android { namespace os { @@ -58,6 +60,9 @@ constexpr const char* kOpUsage = "android:get_usage_stats"; #define STATS_SERVICE_DIR "/data/misc/stats-service" +// for StatsDataDumpProto +const int FIELD_ID_REPORTS_LIST = 1; + static binder::Status ok() { return binder::Status::ok(); } @@ -224,31 +229,48 @@ status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* rep } /** - * Write debugging data about statsd. + * Write data from statsd. + * Format for statsdStats: adb shell dumpsys stats --metadata [-v] [--proto] + * Format for data report: adb shell dumpsys stats [anything other than --metadata] [--proto] + * Anything ending in --proto will be in proto format. + * Anything without --metadata as the first argument will be report information. + * (bugreports call "adb shell dumpsys stats --dump-priority NORMAL -a --proto") + * TODO: Come up with a more robust method of enacting <serviceutils/PriorityDumper.h>. */ status_t StatsService::dump(int fd, const Vector<String16>& args) { if (!checkCallingPermission(String16(kPermissionDump))) { return PERMISSION_DENIED; } - - bool verbose = false; - bool proto = false; - if (args.size() > 0 && !args[0].compare(String16("-v"))) { - verbose = true; + int lastArg = args.size() - 1; + bool asProto = false; + if (lastArg >= 0 && !args[lastArg].compare(String16("--proto"))) { // last argument + asProto = true; + lastArg--; } - if (args.size() > 0 && !args[args.size()-1].compare(String16("--proto"))) { - proto = true; + if (args.size() > 0 && !args[0].compare(String16("--metadata"))) { // first argument + // Request is to dump statsd stats. + bool verbose = false; + if (lastArg >= 0 && !args[lastArg].compare(String16("-v"))) { + verbose = true; + lastArg--; + } + dumpStatsdStats(fd, verbose, asProto); + } else { + // Request is to dump statsd report data. + if (asProto) { + dumpIncidentSection(fd); + } else { + dprintf(fd, "Non-proto format of stats data dump not available; see proto version.\n"); + } } - dump_impl(fd, verbose, proto); - return NO_ERROR; } /** * Write debugging data about statsd in text or proto format. */ -void StatsService::dump_impl(int out, bool verbose, bool proto) { +void StatsService::dumpStatsdStats(int out, bool verbose, bool proto) { if (proto) { vector<uint8_t> data; StatsdStats::getInstance().dumpStats(&data, false); // does not reset statsdStats. @@ -262,6 +284,22 @@ void StatsService::dump_impl(int out, bool verbose, bool proto) { } /** + * Write stats report data in StatsDataDumpProto incident section format. + */ +void StatsService::dumpIncidentSection(int out) { + ProtoOutputStream proto; + for (const ConfigKey& configKey : mConfigManager->GetAllConfigKeys()) { + uint64_t reportsListToken = + proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST); + mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), + true /* includeCurrentBucket */, false /* erase_data */, + ADB_DUMP, &proto); + proto.end(reportsListToken); + proto.flush(out); + } +} + +/** * Implementation of the adb shell cmd stats command. */ status_t StatsService::command(int in, int out, int err, Vector<String8>& args, @@ -283,7 +321,7 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args, } if (!args[0].compare(String8("dump-report"))) { - return cmd_dump_report(out, err, args); + return cmd_dump_report(out, args); } if (!args[0].compare(String8("pull-source")) && args.size() > 1) { @@ -546,7 +584,7 @@ status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& arg return UNKNOWN_ERROR; } -status_t StatsService::cmd_dump_report(int out, int err, const Vector<String8>& args) { +status_t StatsService::cmd_dump_report(int out, const Vector<String8>& args) { if (mProcessor != nullptr) { int argCount = args.size(); bool good = false; @@ -589,14 +627,13 @@ status_t StatsService::cmd_dump_report(int out, int err, const Vector<String8>& if (good) { vector<uint8_t> data; mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(), - includeCurrentBucket, ADB_DUMP, &data); + includeCurrentBucket, true /* erase_data */, ADB_DUMP, &data); if (proto) { for (size_t i = 0; i < data.size(); i ++) { dprintf(out, "%c", data[i]); } } else { - dprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str()); - dprintf(out, "See the StatsLogReport in logcat...\n"); + dprintf(out, "Non-proto stats data dump not currently supported.\n"); } return android::OK; } else { @@ -888,7 +925,7 @@ Status StatsService::getData(int64_t key, const String16& packageName, vector<ui VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid()); ConfigKey configKey(ipc->getCallingUid(), key); mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/, - GET_DATA_CALLED, output); + true /* erase_data */, GET_DATA_CALLED, output); return Status::ok(); } diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index cbf34292c1d4..4a5f05fef034 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -213,9 +213,14 @@ private: uint32_t serial); /** - * Text or proto output of dumpsys. + * Proto output of statsd report data dumpsys, wrapped in a StatsDataDumpProto. */ - void dump_impl(int outFd, bool verbose, bool proto); + void dumpIncidentSection(int outFd); + + /** + * Text or proto output of statsdStats dumpsys. + */ + void dumpStatsdStats(int outFd, bool verbose, bool proto); /** * Print usage information for the commands @@ -240,7 +245,7 @@ private: /** * Print the event log. */ - status_t cmd_dump_report(int outFd, int err, const Vector<String8>& args); + status_t cmd_dump_report(int outFd, const Vector<String8>& args); /** * Print the mapping of uids to package names. diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index d2919c51a65e..a0d77d6f922d 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -362,11 +362,17 @@ void StatsdStats::notePullDelay(int pullAtomId, int64_t pullDelayNs) { lock_guard<std::mutex> lock(mLock); auto& pullStats = mPulledAtomStats[pullAtomId]; pullStats.maxPullDelayNs = std::max(pullStats.maxPullDelayNs, pullDelayNs); - pullStats.avgPullDelayNs = (pullStats.avgPullDelayNs * pullStats.numPullDelay + pullDelayNs) / - (pullStats.numPullDelay + 1); + pullStats.avgPullDelayNs = + (pullStats.avgPullDelayNs * pullStats.numPullDelay + pullDelayNs) / + (pullStats.numPullDelay + 1); pullStats.numPullDelay += 1; } +void StatsdStats::notePullDataError(int pullAtomId) { + lock_guard<std::mutex> lock(mLock); + mPulledAtomStats[pullAtomId].dataError++; +} + void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) { lock_guard<std::mutex> lock(mLock); @@ -422,6 +428,7 @@ void StatsdStats::resetInternalLocked() { pullStats.second.avgPullDelayNs = 0; pullStats.second.maxPullDelayNs = 0; pullStats.second.numPullDelay = 0; + pullStats.second.dataError = 0; } } @@ -530,11 +537,11 @@ void StatsdStats::dumpStats(int out) const { dprintf(out, "Atom %d->(total pull)%ld, (pull from cache)%ld, (min pull interval)%ld, (average " "pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay nanos)%lld, " - "(max pull delay nanos)%lld\n", + "(max pull delay nanos)%lld, (data error)%ld\n", (int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache, (long)pair.second.minPullIntervalSec, (long long)pair.second.avgPullTimeNs, (long long)pair.second.maxPullTimeNs, (long long)pair.second.avgPullDelayNs, - (long long)pair.second.maxPullDelayNs); + (long long)pair.second.maxPullDelayNs, pair.second.dataError); } if (mAnomalyAlarmRegisteredStats > 0) { diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 777d8652d2b6..2008abdb2345 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -279,6 +279,11 @@ public: void notePullFromCache(int pullAtomId); /* + * Notify data error for pulled atom. + */ + void notePullDataError(int pullAtomId); + + /* * Records time for actual pulling, not including those served from cache and not including * statsd processing delays. */ @@ -329,6 +334,7 @@ public: int64_t avgPullDelayNs = 0; int64_t maxPullDelayNs = 0; long numPullDelay = 0; + long dataError = 0; } PulledAtomStats; private: diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp index 6b8c12a893e8..eddc86eca798 100644 --- a/cmds/statsd/src/main.cpp +++ b/cmds/statsd/src/main.cpp @@ -82,7 +82,9 @@ int main(int /*argc*/, char** /*argv*/) { // Create the service gStatsService = new StatsService(looper); - if (defaultServiceManager()->addService(String16("stats"), gStatsService) != 0) { + if (defaultServiceManager()->addService(String16("stats"), gStatsService, false, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO) + != 0) { ALOGE("Failed to add service as AIDL service"); return -1; } diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp index bd94800a327d..5ca88142f152 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.cpp +++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp @@ -143,6 +143,7 @@ void CountMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, ProtoOutputStream* protoOutput) { if (include_current_partial_bucket) { @@ -230,7 +231,9 @@ void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, protoOutput->end(protoToken); - mPastBuckets.clear(); + if (erase_data) { + mPastBuckets.clear(); + } } void CountMetricProducer::dropDataLocked(const int64_t dropTimeNs) { diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h index 39d4ae2f36a5..1ac4426468d8 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.h +++ b/cmds/statsd/src/metrics/CountMetricProducer.h @@ -56,6 +56,7 @@ private: void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, android::util::ProtoOutputStream* protoOutput) override; diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index dd3402dae2f8..35deffe5db97 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -453,6 +453,7 @@ void DurationMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, ProtoOutputStream* protoOutput) { if (include_current_partial_bucket) { @@ -541,7 +542,9 @@ void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, } protoOutput->end(protoToken); - mPastBuckets.clear(); + if (erase_data) { + mPastBuckets.clear(); + } } void DurationMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) { diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index 12addb8727f1..1b830a3f69f5 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -63,6 +63,7 @@ private: void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, android::util::ProtoOutputStream* protoOutput) override; diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp index afd8ec2212fe..a18e406b74ca 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.cpp +++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp @@ -105,6 +105,7 @@ void EventMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, ProtoOutputStream* protoOutput) { if (mProto->size() <= 0) { @@ -120,7 +121,9 @@ void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS, reinterpret_cast<char*>(buffer.get()->data()), buffer.get()->size()); - mProto->clear(); + if (erase_data) { + mProto->clear(); + } } void EventMetricProducer::onConditionChangedLocked(const bool conditionMet, diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h index 7f7aa3711255..96adfdd48743 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.h +++ b/cmds/statsd/src/metrics/EventMetricProducer.h @@ -47,6 +47,7 @@ private: void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, android::util::ProtoOutputStream* protoOutput) override; void clearPastBucketsLocked(const int64_t dumpTimeNs) override; diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp index f5a16e96fdf5..05103a962c33 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp @@ -182,6 +182,7 @@ void GaugeMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, ProtoOutputStream* protoOutput) { VLOG("Gauge metric %lld report now...", (long long)mMetricId); @@ -226,7 +227,6 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, (long long)(NanoToMillis(pair.second))); protoOutput->end(wrapperToken); } - mSkippedBuckets.clear(); for (const auto& pair : mPastBuckets) { const MetricDimensionKey& dimensionKey = pair.first; @@ -304,7 +304,11 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, } protoOutput->end(protoToken); - mPastBuckets.clear(); + + if (erase_data) { + mPastBuckets.clear(); + mSkippedBuckets.clear(); + } } void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) { diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h index 99827bb2ad2d..5866139047ae 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.h +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h @@ -94,6 +94,7 @@ protected: private: void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, android::util::ProtoOutputStream* protoOutput) override; void clearPastBucketsLocked(const int64_t dumpTimeNs) override; diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index b21fd501c2d0..127cbbde1a3a 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -133,10 +133,12 @@ public: // This method clears all the past buckets. void onDumpReport(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, android::util::ProtoOutputStream* protoOutput) { std::lock_guard<std::mutex> lock(mMutex); - return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, str_set, protoOutput); + return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, erase_data, + str_set, protoOutput); } void clearPastBuckets(const int64_t dumpTimeNs) { @@ -210,6 +212,7 @@ protected: const int64_t eventTime) = 0; virtual void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, android::util::ProtoOutputStream* protoOutput) = 0; virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0; diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index f85ba1f93e8c..4244d5bed23b 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -197,6 +197,7 @@ void MetricsManager::dropData(const int64_t dropTimeNs) { void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, ProtoOutputStream* protoOutput) { VLOG("=========================Metric Reports Start=========================="); @@ -206,11 +207,11 @@ void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs, uint64_t token = protoOutput->start( FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS); if (mHashStringsInReport) { - producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, str_set, - protoOutput); + producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data, + str_set, protoOutput); } else { - producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, nullptr, - protoOutput); + producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data, + nullptr, protoOutput); } protoOutput->end(token); } else { diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index 649222ffef9d..a4672b68f2bc 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -107,6 +107,7 @@ public: virtual void onDumpReport(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, android::util::ProtoOutputStream* protoOutput); diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index 192a54b7e0a3..c8b1cf07eb32 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -92,7 +92,9 @@ ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric : StatsdStats::kDimensionKeySizeHardLimit), mUseAbsoluteValueOnReset(metric.use_absolute_value_on_reset()), mAggregationType(metric.aggregation_type()), - mValueType(metric.aggregation_type() == ValueMetric::AVG ? DOUBLE : LONG) { + mUseDiff(metric.has_use_diff() ? metric.use_diff() : (mIsPulled ? true : false)), + mValueDirection(metric.value_direction()), + mSkipZeroDiffOutput(metric.skip_zero_diff_output()) { int64_t bucketSizeMills = 0; if (metric.has_bucket()) { bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()); @@ -125,24 +127,25 @@ ValueMetricProducer::ValueMetricProducer(const ConfigKey& key, const ValueMetric } mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0); mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what()) || - HasPositionALL(metric.dimensions_in_condition()); + HasPositionALL(metric.dimensions_in_condition()); flushIfNeededLocked(startTimeNs); - // Kicks off the puller immediately. + if (mIsPulled) { mPullerManager->RegisterReceiver(mPullTagId, this, getCurrentBucketEndTimeNs(), mBucketSizeNs); } - // TODO: Only do this for partial buckets like first bucket. All other buckets should use + // Only do this for partial buckets like first bucket. All other buckets should use // flushIfNeeded to adjust start and end to bucket boundaries. // Adjust start for partial bucket mCurrentBucketStartTimeNs = startTimeNs; - if (mIsPulled) { + // Kicks off the puller immediately if condition is true and diff based. + if (mIsPulled && mCondition && mUseDiff) { pullLocked(startTimeNs); } - VLOG("value metric %lld created. bucket size %lld start_time: %lld", - (long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs); + VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(), + (long long)mBucketSizeNs, (long long)mTimeBaseNs); } ValueMetricProducer::~ValueMetricProducer() { @@ -170,6 +173,7 @@ void ValueMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, ProtoOutputStream* protoOutput) { VLOG("metric %lld dump report now...", (long long)mMetricId); @@ -187,14 +191,14 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, // Fills the dimension path if not slicing by ALL. if (!mSliceByPositionALL) { if (!mDimensionsInWhat.empty()) { - uint64_t dimenPathToken = protoOutput->start( - FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT); + uint64_t dimenPathToken = + protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT); writeDimensionPathToProto(mDimensionsInWhat, protoOutput); protoOutput->end(dimenPathToken); } if (!mDimensionsInCondition.empty()) { - uint64_t dimenPathToken = protoOutput->start( - FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION); + uint64_t dimenPathToken = + protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_CONDITION); writeDimensionPathToProto(mDimensionsInCondition, protoOutput); protoOutput->end(dimenPathToken); } @@ -211,7 +215,6 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, (long long)(NanoToMillis(pair.second))); protoOutput->end(wrapperToken); } - mSkippedBuckets.clear(); for (const auto& pair : mPastBuckets) { const MetricDimensionKey& dimensionKey = pair.first; @@ -221,15 +224,15 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, // First fill dimension. if (mSliceByPositionALL) { - uint64_t dimensionToken = protoOutput->start( - FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT); + uint64_t dimensionToken = + protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT); writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput); protoOutput->end(dimensionToken); if (dimensionKey.hasDimensionKeyInCondition()) { - uint64_t dimensionInConditionToken = protoOutput->start( - FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION); - writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), - str_set, protoOutput); + uint64_t dimensionInConditionToken = + protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_CONDITION); + writeDimensionToProto(dimensionKey.getDimensionKeyInCondition(), str_set, + protoOutput); protoOutput->end(dimensionInConditionToken); } } else { @@ -237,8 +240,8 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput); if (dimensionKey.hasDimensionKeyInCondition()) { writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInCondition(), - FIELD_ID_DIMENSION_LEAF_IN_CONDITION, - str_set, protoOutput); + FIELD_ID_DIMENSION_LEAF_IN_CONDITION, str_set, + protoOutput); } } @@ -256,28 +259,34 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM, (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs))); } - if (mValueType == LONG) { + if (bucket.value.getType() == LONG) { protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_LONG, - (long long)bucket.mValueLong); + (long long)bucket.value.long_value); + VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs, + (long long)bucket.mBucketEndNs, (long long)bucket.value.long_value); + } else if (bucket.value.getType() == DOUBLE) { + protoOutput->write(FIELD_TYPE_DOUBLE | FIELD_ID_VALUE_DOUBLE, + bucket.value.double_value); + VLOG("\t bucket [%lld - %lld] count: %.2f", (long long)bucket.mBucketStartNs, + (long long)bucket.mBucketEndNs, bucket.value.double_value); } else { - protoOutput->write(FIELD_TYPE_DOUBLE | FIELD_ID_VALUE_DOUBLE, bucket.mValueDouble); + VLOG("Wrong value type for ValueMetric output: %d", bucket.value.getType()); } protoOutput->end(bucketInfoToken); - VLOG("\t bucket [%lld - %lld] count: %lld, %.2f", (long long)bucket.mBucketStartNs, - (long long)bucket.mBucketEndNs, (long long)bucket.mValueLong, bucket.mValueDouble); } protoOutput->end(wrapperToken); } protoOutput->end(protoToken); VLOG("metric %lld dump report now...", (long long)mMetricId); - mPastBuckets.clear(); + if (erase_data) { + mPastBuckets.clear(); + mSkippedBuckets.clear(); + } } void ValueMetricProducer::onConditionChangedLocked(const bool condition, const int64_t eventTimeNs) { - mCondition = condition; - if (eventTimeNs < mCurrentBucketStartTimeNs) { VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, (long long)mCurrentBucketStartTimeNs); @@ -286,9 +295,19 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition, flushIfNeededLocked(eventTimeNs); - if (mIsPulled) { + // Pull on condition changes. + if (mIsPulled && (mCondition != condition)) { pullLocked(eventTimeNs); } + + // when condition change from true to false, clear diff base + if (mUseDiff && mCondition && !condition) { + for (auto& slice : mCurrentSlicedBucket) { + slice.second.hasBase = false; + } + } + + mCondition = condition; } void ValueMetricProducer::pullLocked(const int64_t timestampNs) { @@ -303,30 +322,33 @@ void ValueMetricProducer::pullLocked(const int64_t timestampNs) { } } +int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) { + return mTimeBaseNs + ((currentTimeNs - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs; +} + void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) { std::lock_guard<std::mutex> lock(mMutex); - if (mCondition == true || mConditionTrackerIndex < 0) { + if (mCondition) { if (allData.size() == 0) { return; } // For scheduled pulled data, the effective event time is snap to the nearest - // bucket boundary to make bucket finalize. + // bucket end. In the case of waking up from a deep sleep state, we will + // attribute to the previous bucket end. If the sleep was long but not very long, we + // will be in the immediate next bucket. Previous bucket may get a larger number as + // we pull at a later time than real bucket end. + // If the sleep was very long, we skip more than one bucket before sleep. In this case, + // if the diff base will be cleared and this new data will serve as new diff base. int64_t realEventTime = allData.at(0)->GetElapsedTimestampNs(); - int64_t eventTime = mTimeBaseNs + - ((realEventTime - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs; - - // close the end of the bucket - mCondition = false; - for (const auto& data : allData) { - data->setElapsedTimestampNs(eventTime - 1); - onMatchedLogEventLocked(0, *data); + int64_t bucketEndTime = calcPreviousBucketEndTime(realEventTime) - 1; + if (bucketEndTime < mCurrentBucketStartTimeNs) { + VLOG("Skip bucket end pull due to late arrival: %lld vs %lld", (long long)bucketEndTime, + (long long)mCurrentBucketStartTimeNs); + return; } - - // start a new bucket - mCondition = true; for (const auto& data : allData) { - data->setElapsedTimestampNs(eventTime); + data->setElapsedTimestampNs(bucketEndTime); onMatchedLogEventLocked(0, *data); } } @@ -360,8 +382,8 @@ bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) { StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount); // 2. Don't add more tuples, we are above the allowed threshold. Drop the data. if (newTupleCount > mDimensionHardLimit) { - ALOGE("ValueMetric %lld dropping data for dimension key %s", - (long long)mMetricId, newKey.toString().c_str()); + ALOGE("ValueMetric %lld dropping data for dimension key %s", (long long)mMetricId, + newKey.toString().c_str()); return true; } } @@ -390,10 +412,10 @@ const Value getDoubleOrLong(const Value& value) { return v; } -void ValueMetricProducer::onMatchedLogEventInternalLocked( - const size_t matcherIndex, const MetricDimensionKey& eventKey, - const ConditionKey& conditionKey, bool condition, - const LogEvent& event) { +void ValueMetricProducer::onMatchedLogEventInternalLocked(const size_t matcherIndex, + const MetricDimensionKey& eventKey, + const ConditionKey& conditionKey, + bool condition, const LogEvent& event) { int64_t eventTimeNs = event.GetElapsedTimestampNs(); if (eventTimeNs < mCurrentBucketStartTimeNs) { VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, @@ -403,6 +425,14 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked( flushIfNeededLocked(eventTimeNs); + // For pulled data, we already check condition when we decide to pull or + // in onDataPulled. So take all of them. + // For pushed data, just check condition. + if (!(mIsPulled || condition)) { + VLOG("ValueMetric skip event because condition is false"); + return; + } + if (hitGuardRailLocked(eventKey)) { return; } @@ -415,71 +445,70 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked( } Value value = getDoubleOrLong(event.getValues()[mField - 1].mValue); - Value diff; - bool hasDiff = false; - if (mIsPulled) { - // Always require condition for pulled events. In the case of no condition, only pull - // on bucket boundaries, in which we fake condition changes. - if (mCondition == true) { - if (!interval.startUpdated) { - interval.start = value; - interval.startUpdated = true; - } else { - // Skip it if there is already value recorded for the start. Happens when puller - // takes too long to finish. In this case we take the previous value. - VLOG("Already recorded value for this dimension %s", eventKey.toString().c_str()); - } - } else { - // Generally we expect value to be monotonically increasing. - // If not, take absolute value or drop it, based on config. - if (interval.startUpdated) { - if (value >= interval.start) { - diff = (value - interval.start); - hasDiff = true; + if (mUseDiff) { + // no base. just update base and return. + if (!interval.hasBase) { + interval.base = value; + interval.hasBase = true; + return; + } + Value diff; + switch (mValueDirection) { + case ValueMetric::INCREASING: + if (value >= interval.base) { + diff = value - interval.base; + } else if (mUseAbsoluteValueOnReset) { + diff = value; } else { - if (mUseAbsoluteValueOnReset) { - diff = value; - hasDiff = true; - } else { - VLOG("Dropping data for atom %d, prev: %s, now: %s", mPullTagId, - interval.start.toString().c_str(), value.toString().c_str()); - } + VLOG("Unexpected decreasing value"); + StatsdStats::getInstance().notePullDataError(mPullTagId); + interval.base = value; + return; } - interval.startUpdated = false; - } else { - VLOG("No start for matching end %s", value.toString().c_str()); - } - } - } else { - // for pushed events, only aggregate when sliced condition is true - if (condition == true || mConditionTrackerIndex < 0) { - diff = value; - hasDiff = true; + break; + case ValueMetric::DECREASING: + if (interval.base >= value) { + diff = interval.base - value; + } else if (mUseAbsoluteValueOnReset) { + diff = value; + } else { + VLOG("Unexpected increasing value"); + StatsdStats::getInstance().notePullDataError(mPullTagId); + interval.base = value; + return; + } + break; + case ValueMetric::ANY: + diff = value - interval.base; + break; + default: + break; } + interval.base = value; + value = diff; } - if (hasDiff) { - if (interval.hasValue) { - switch (mAggregationType) { - case ValueMetric::SUM: + + if (interval.hasValue) { + switch (mAggregationType) { + case ValueMetric::SUM: // for AVG, we add up and take average when flushing the bucket - case ValueMetric::AVG: - interval.value += diff; - break; - case ValueMetric::MIN: - interval.value = diff < interval.value ? diff : interval.value; - break; - case ValueMetric::MAX: - interval.value = diff > interval.value ? diff : interval.value; - break; - default: - break; - } - } else { - interval.value = diff; - interval.hasValue = true; + case ValueMetric::AVG: + interval.value += value; + break; + case ValueMetric::MIN: + interval.value = std::min(value, interval.value); + break; + case ValueMetric::MAX: + interval.value = std::max(value, interval.value); + break; + default: + break; } - interval.sampleSize += 1; + } else { + interval.value = value; + interval.hasValue = true; } + interval.sampleSize += 1; // TODO: propgate proper values down stream when anomaly support doubles long wholeBucketVal = interval.value.long_value; @@ -509,6 +538,10 @@ void ValueMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) { if (numBucketsForward > 1) { VLOG("Skipping forward %lld buckets", (long long)numBucketsForward); + // take base again in future good bucket. + for (auto& slice : mCurrentSlicedBucket) { + slice.second.hasBase = false; + } } VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId, (long long)mCurrentBucketStartTimeNs); @@ -531,8 +564,18 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) { // The current bucket is large enough to keep. for (const auto& slice : mCurrentSlicedBucket) { if (slice.second.hasValue) { - info.mValueLong = slice.second.value.long_value; - info.mValueDouble = (double)slice.second.value.long_value / slice.second.sampleSize; + // skip the output if the diff is zero + if (mSkipZeroDiffOutput && mUseDiff && slice.second.value.isZero()) { + continue; + } + if (mAggregationType != ValueMetric::AVG) { + info.value = slice.second.value; + } else { + double sum = slice.second.value.type == LONG + ? (double)slice.second.value.long_value + : slice.second.value.double_value; + info.value.setDouble(sum / slice.second.sampleSize); + } // it will auto create new vector of ValuebucketInfo if the key is not found. auto& bucketList = mPastBuckets[slice.first]; bucketList.push_back(info); @@ -578,7 +621,10 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) { } // Reset counters - mCurrentSlicedBucket.clear(); + for (auto& slice : mCurrentSlicedBucket) { + slice.second.hasValue = false; + slice.second.sampleSize = 0; + } } size_t ValueMetricProducer::byteSizeLocked() const { diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index b2f0b6ff4d78..3416afe06b81 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -34,8 +34,7 @@ namespace statsd { struct ValueBucket { int64_t mBucketStartNs; int64_t mBucketEndNs; - int64_t mValueLong; - double mValueDouble; + Value value; }; class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver { @@ -54,35 +53,11 @@ public: void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid, const int64_t version) override { std::lock_guard<std::mutex> lock(mMutex); - - if (mIsPulled && (mCondition == true || mConditionTrackerIndex < 0)) { - vector<shared_ptr<LogEvent>> allData; - mPullerManager->Pull(mPullTagId, eventTimeNs, &allData); - if (allData.size() == 0) { - // This shouldn't happen since this valuemetric is not useful now. - } - - // Pretend the pulled data occurs right before the app upgrade event. - mCondition = false; - for (const auto& data : allData) { - data->setElapsedTimestampNs(eventTimeNs - 1); - onMatchedLogEventLocked(0, *data); - } - - flushCurrentBucketLocked(eventTimeNs); - mCurrentBucketStartTimeNs = eventTimeNs; - - mCondition = true; - for (const auto& data : allData) { - data->setElapsedTimestampNs(eventTimeNs); - onMatchedLogEventLocked(0, *data); - } - } else { - // For pushed value metric or pulled metric where condition is not true, - // we simply flush and reset the current bucket start. - flushCurrentBucketLocked(eventTimeNs); - mCurrentBucketStartTimeNs = eventTimeNs; + if (mIsPulled && mCondition) { + pullLocked(eventTimeNs - 1); } + flushCurrentBucketLocked(eventTimeNs); + mCurrentBucketStartTimeNs = eventTimeNs; }; protected: @@ -94,6 +69,7 @@ protected: private: void onDumpReportLocked(const int64_t dumpTimeNs, const bool include_current_partial_bucket, + const bool erase_data, std::set<string> *str_set, android::util::ProtoOutputStream* protoOutput) override; void clearPastBucketsLocked(const int64_t dumpTimeNs) override; @@ -116,6 +92,9 @@ private: void dropDataLocked(const int64_t dropTimeNs) override; + // Calculate previous bucket end time based on current time. + int64_t calcPreviousBucketEndTime(const int64_t currentTimeNs); + sp<StatsPullerManager> mPullerManager; const FieldMatcher mValueField; @@ -130,11 +109,10 @@ private: // internal state of a bucket. typedef struct { - // Pulled data always come in pair of <start, end>. This holds the value - // for start. The diff (end - start) is taken as the real value. - Value start; - // Whether the start data point is updated - bool startUpdated; + // Holds current base value of the dimension. Take diff and update if necessary. + Value base; + // Whether there is a base to diff to. + bool hasBase; // Current value, depending on the aggregation type. Value value; // Number of samples collected. @@ -171,7 +149,11 @@ private: const ValueMetric::AggregationType mAggregationType; - const Type mValueType; + const bool mUseDiff; + + const ValueMetric::ValueDirection mValueDirection; + + const bool mSkipZeroDiffOutput; FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition); FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset); @@ -186,13 +168,13 @@ private: FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition); FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition); FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2); - FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3); FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMin); FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMax); FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateAvg); FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSum); - FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSumSliced); FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket); + FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime); + FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput); }; } // namespace statsd diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 8bfa36059e9a..4da3828ff88d 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -374,6 +374,7 @@ message StatsdStatsReport { optional int64 max_pull_time_nanos = 6; optional int64 average_pull_delay_nanos = 7; optional int64 max_pull_delay_nanos = 8; + optional int64 data_error = 9; } repeated PulledAtomStats pulled_atom_stats = 10; diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index 44fa72e77a0d..504c5864f2ec 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -63,6 +63,7 @@ const int FIELD_ID_AVERAGE_PULL_TIME_NANOS = 5; const int FIELD_ID_MAX_PULL_TIME_NANOS = 6; const int FIELD_ID_AVERAGE_PULL_DELAY_NANOS = 7; const int FIELD_ID_MAX_PULL_DELAY_NANOS = 8; +const int FIELD_ID_DATA_ERROR = 9; namespace { @@ -446,6 +447,7 @@ void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats> (long long)pair.second.avgPullDelayNs); protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_DELAY_NANOS, (long long)pair.second.maxPullDelayNs); + protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DATA_ERROR, (long long)pair.second.dataError); protoOutput->end(token); } diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h index b8f6850ddc29..61f31eb3fa17 100644 --- a/cmds/statsd/src/stats_log_util.h +++ b/cmds/statsd/src/stats_log_util.h @@ -21,6 +21,7 @@ #include "HashableDimensionKey.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "guardrail/StatsdStats.h" +#include "statslog.h" namespace android { namespace os { @@ -87,6 +88,10 @@ bool parseProtoOutputStream(util::ProtoOutputStream& protoOutput, T* message) { // Returns the truncated timestamp. int64_t truncateTimestampNsToFiveMinutes(int64_t timestampNs); +inline bool isPushedAtom(int atomId) { + return atomId <= util::kMaxPushedAtomId && atomId > 1; +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index d5f81a593082..5c46a296b9bf 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -270,6 +270,17 @@ message ValueMetric { optional int64 min_bucket_size_nanos = 10; optional bool use_absolute_value_on_reset = 11 [default = false]; + + optional bool use_diff = 12; + + enum ValueDirection { + INCREASING = 1; + DECREASING = 2; + ANY = 3; + } + optional ValueDirection value_direction = 13 [default = INCREASING]; + + optional bool skip_zero_diff_output = 14 [default = true]; } message Alert { diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index b6f635c6a0cb..8864252bcf4b 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -168,7 +168,7 @@ TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) { // Expect to get no metrics, but snapshot specified above in uidmap. vector<uint8_t> bytes; - p.onDumpReport(key, 1, false, ADB_DUMP, &bytes); + p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes); ConfigMetricsReportList output; output.ParseFromArray(bytes.data(), bytes.size()); @@ -197,7 +197,7 @@ TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) { // Expect to get no metrics, but snapshot specified above in uidmap. vector<uint8_t> bytes; - p.onDumpReport(key, 1, false, ADB_DUMP, &bytes); + p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes); ConfigMetricsReportList output; output.ParseFromArray(bytes.data(), bytes.size()); @@ -227,7 +227,7 @@ TEST(StatsLogProcessorTest, TestReportIncludesSubConfig) { // Expect to get no metrics, but snapshot specified above in uidmap. vector<uint8_t> bytes; - p.onDumpReport(key, 1, false, ADB_DUMP, &bytes); + p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes); ConfigMetricsReportList output; output.ParseFromArray(bytes.data(), bytes.size()); diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp index a8fcc8163656..5c47af797eea 100644 --- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp @@ -144,8 +144,8 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) { } ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -290,8 +290,8 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) { } ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp index 75bd40f67946..a8914da4b7fe 100644 --- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp +++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp @@ -212,7 +212,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondi ConfigMetricsReportList reports; vector<uint8_t> buffer; processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, - ADB_DUMP, &buffer); + true, ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -548,7 +548,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationConditi ConfigMetricsReportList reports; vector<uint8_t> buffer; processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, - ADB_DUMP, &buffer); + true, ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -798,7 +798,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_Combination ConfigMetricsReportList reports; vector<uint8_t> buffer; processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, - ADB_DUMP, &buffer); + true, ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp index c5a8a2eba4ae..621b6ed6ddbf 100644 --- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp +++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp @@ -130,8 +130,8 @@ TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCon ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -346,8 +346,8 @@ TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondi ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -530,8 +530,8 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_OR_CombinationCondit ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -732,8 +732,8 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_OR_CombinationConditio ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp index 5bcc9ee8513d..9f8acaf18422 100644 --- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp +++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp @@ -143,7 +143,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition) { ConfigMetricsReportList reports; vector<uint8_t> buffer; processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, - ADB_DUMP, &buffer); + true, ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -438,7 +438,7 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition) { ConfigMetricsReportList reports; vector<uint8_t> buffer; processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, - ADB_DUMP, &buffer); + true, ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -658,8 +658,8 @@ TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp index d7b9c119b71b..2d090e02a42a 100644 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp @@ -123,8 +123,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) { ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -246,8 +246,8 @@ TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) { ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -350,8 +350,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) { ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp index 5c1ef01dd576..71afedfa6c8f 100644 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp @@ -149,8 +149,8 @@ TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) { } ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp index 0f13a4ac1254..29e86f3f9456 100644 --- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp @@ -167,8 +167,8 @@ TEST(MetricActivationE2eTest, TestCountMetric) { ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp index cc8894bdbca6..9349c857c5b3 100644 --- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp @@ -199,8 +199,8 @@ TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) { } ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -318,8 +318,8 @@ TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) { ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp index 67acd6154176..3cb553fd9a16 100644 --- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp @@ -46,7 +46,7 @@ ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestam IPCThreadState* ipc = IPCThreadState::self(); ConfigKey configKey(ipc->getCallingUid(), kConfigKey); processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/, - ADB_DUMP, &output); + true /* erase_data */, ADB_DUMP, &output); ConfigMetricsReportList reports; reports.ParseFromArray(output.data(), output.size()); EXPECT_EQ(1, reports.reports_size()); diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp index f2e8f58fe763..095b4017b440 100644 --- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp @@ -49,6 +49,7 @@ StatsdConfig CreateStatsdConfig() { CreateDimensions(android::util::TEMPERATURE, {2/* sensor name field */ }); valueMetric->set_bucket(FIVE_MINUTES); valueMetric->set_use_absolute_value_on_reset(true); + valueMetric->set_skip_zero_diff_output(false); return config; } @@ -117,8 +118,8 @@ TEST(ValueMetricE2eTest, TestPulledEvents) { ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -224,8 +225,8 @@ TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) { ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp index b9d0c62cf596..6d1317cb5dee 100644 --- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp @@ -127,8 +127,8 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) FeedEvents(config, processor); vector<uint8_t> buffer; ConfigMetricsReportList reports; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -164,8 +164,8 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) FeedEvents(config, processor); vector<uint8_t> buffer; ConfigMetricsReportList reports; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -215,8 +215,8 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) processor->OnLogEvent(event.get()); } - processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -248,8 +248,8 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) FeedEvents(config, processor); ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); @@ -277,8 +277,8 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) FeedEvents(config, processor); ConfigMetricsReportList reports; vector<uint8_t> buffer; - processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); @@ -323,8 +323,8 @@ TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) processor->OnLogEvent(event.get()); } - processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP, - &buffer); + processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, + ADB_DUMP, &buffer); EXPECT_TRUE(buffer.size() > 0); EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); backfillDimensionPath(&reports); diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index 57aab971eaaa..ffa07081c781 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -47,7 +47,35 @@ const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs; const int64_t bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs; const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs; -const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; +double epsilon = 0.001; + +/* + * Tests that the first bucket works correctly + */ +TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) { + ValueMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.mutable_value_field()->set_field(tagId); + metric.mutable_value_field()->add_child()->set_field(2); + + int64_t startTimeBase = 11; + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + + // statsd started long ago. + // The metric starts in the middle of the bucket + ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + -1, startTimeBase, 22, pullerManager); + + EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10)); + EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10)); + EXPECT_EQ(60 * NS_PER_SEC + startTimeBase, + valueProducer.calcPreviousBucketEndTime(2 * 60 * NS_PER_SEC)); + EXPECT_EQ(2 * 60 * NS_PER_SEC + startTimeBase, + valueProducer.calcPreviousBucketEndTime(3 * 60 * NS_PER_SEC)); +} /* * Tests that the first bucket works correctly @@ -90,7 +118,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs); event->write(tagId); event->write(3); event->init(); @@ -114,12 +142,11 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - // startUpdated:true sum:0 start:11 - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(11, curInterval.start.long_value); - EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); - EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(11, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(8, curInterval.value.long_value); + EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); allData.clear(); event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1); @@ -131,12 +158,14 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - // tartUpdated:false sum:12 - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); + + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(23, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(12, curInterval.value.long_value); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); - EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); + EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second.back().value.long_value); allData.clear(); event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1); @@ -147,12 +176,14 @@ TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) { valueProducer.onDataPulled(allData); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - // startUpdated:false sum:12 - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); + + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(36, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(13, curInterval.value.long_value); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); - EXPECT_EQ(3UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(13, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size()); + EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().value.long_value); } /* @@ -170,7 +201,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(false)); + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(true)); ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); @@ -188,9 +219,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(true, curInterval.startUpdated); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(11, curInterval.base.long_value); EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(11, curInterval.start.long_value); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); allData.clear(); @@ -203,11 +234,11 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); - EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(10, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(10, curInterval.value.long_value); + EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); allData.clear(); event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1); @@ -218,11 +249,13 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) { valueProducer.onDataPulled(allData); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(36, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(26, curInterval.value.long_value); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); - EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); + EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().value.long_value); } /* @@ -257,9 +290,9 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(true, curInterval.startUpdated); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(11, curInterval.base.long_value); EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(11, curInterval.start.long_value); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); allData.clear(); @@ -272,7 +305,8 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(true, curInterval.startUpdated); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(10, curInterval.base.long_value); EXPECT_EQ(false, curInterval.hasValue); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); @@ -285,11 +319,11 @@ TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) { valueProducer.onDataPulled(allData); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); - EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(36, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(26, curInterval.value.long_value); + EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); } /* @@ -309,21 +343,10 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) - // should not take effect - .WillOnce(Invoke([](int tagId, int64_t timeNs, - vector<std::shared_ptr<LogEvent>>* data) { - data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); - event->write(tagId); - event->write(3); - event->init(); - data->push_back(event); - return true; - })) .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8); event->write(tagId); event->write(100); event->init(); @@ -333,7 +356,7 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); event->write(tagId); event->write(120); event->init(); @@ -349,8 +372,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; // startUpdated:false sum:0 start:100 - EXPECT_EQ(100, curInterval.start.long_value); - EXPECT_EQ(true, curInterval.startUpdated); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(100, curInterval.base.long_value); EXPECT_EQ(false, curInterval.hasValue); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); @@ -366,20 +389,20 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - // startUpdated:false sum:0 start:110 - EXPECT_EQ(110, curInterval.start.long_value); - EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); - EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(110, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(10, curInterval.value.long_value); + EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - // startUpdated:false sum:0 start:110 + EXPECT_EQ(true, curInterval.hasValue); EXPECT_EQ(10, curInterval.value.long_value); - EXPECT_EQ(false, curInterval.startUpdated); + EXPECT_EQ(false, curInterval.hasBase); } TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) { @@ -401,9 +424,9 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) { valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + valueProducer.notifyAppUpgrade(bucketStartTimeNs + 150, "ANY.APP", 1, 1); EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); - EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs); shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC); event2->write(1); @@ -411,7 +434,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) { event2->init(); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2); EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); - EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs); // Next value should create a new bucket. shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC); @@ -435,11 +458,11 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) { EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) - .WillOnce(Return(false)) + .WillOnce(Return(true)) .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 149); event->write(tagId); event->write(120); event->init(); @@ -451,7 +474,7 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) { vector<shared_ptr<LogEvent>> allData; allData.clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); event->write(tagId); event->write(100); event->init(); @@ -460,21 +483,21 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) { valueProducer.onDataPulled(allData); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1); EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); - EXPECT_EQ(eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs); - EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValueLong); + EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].value.long_value); allData.clear(); - event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); + event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1); event->write(tagId); event->write(150); event->init(); allData.push_back(event); valueProducer.onDataPulled(allData); - EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); - EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs); - EXPECT_EQ(30L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mValueLong); + EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].value.long_value); } TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) { @@ -490,11 +513,10 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) { EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) - .WillOnce(Return(false)) .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1); event->write(tagId); event->write(100); event->init(); @@ -504,7 +526,7 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) { .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs - 100); event->write(tagId); event->write(120); event->init(); @@ -523,7 +545,7 @@ TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) { EXPECT_EQ(bucket2StartTimeNs-50, valueProducer.mCurrentBucketStartTimeNs); EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); EXPECT_EQ(bucketStartTimeNs, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs); - EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValueLong); + EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].value.long_value); EXPECT_FALSE(valueProducer.mCondition); } @@ -565,7 +587,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { valueProducer.flushIfNeededLocked(bucket3StartTimeNs); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().value.long_value); } TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { @@ -587,9 +609,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { event1->init(); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1); // has 1 slice - EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size()); valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15); shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20); @@ -600,6 +620,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); + ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; EXPECT_EQ(20, curInterval.value.long_value); @@ -629,7 +650,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { valueProducer.flushIfNeededLocked(bucket3StartTimeNs); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().value.long_value); } TEST(ValueMetricProducerTest, TestAnomalyDetection) { @@ -727,7 +748,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(false)); + EXPECT_CALL(*pullerManager, Pull(tagId, _, _)).WillOnce(Return(true)); ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); @@ -747,9 +768,9 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; // startUpdated:true sum:0 start:11 - EXPECT_EQ(true, curInterval.startUpdated); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(11, curInterval.base.long_value); EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(11, curInterval.start.long_value); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); // pull 2 at correct time @@ -764,11 +785,11 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; // tartUpdated:false sum:12 - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); - EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(23, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(12, curInterval.value.long_value); + EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); // pull 3 come late. // The previous bucket gets closed with error. (Has start value 23, no ending) @@ -784,12 +805,12 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; // startUpdated:false sum:12 - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(36, curInterval.start.long_value); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(36, curInterval.base.long_value); EXPECT_EQ(false, curInterval.hasValue); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().value.long_value); } /* @@ -810,12 +831,11 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) - .WillOnce(Return(false)) // condition becomes true .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8); event->write(tagId); event->write(100); event->init(); @@ -826,7 +846,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); event->write(tagId); event->write(120); event->init(); @@ -841,17 +861,17 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - // startUpdated:false sum:0 start:100 - EXPECT_EQ(100, curInterval.start.long_value); - EXPECT_EQ(true, curInterval.startUpdated); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(100, curInterval.base.long_value); EXPECT_EQ(false, curInterval.hasValue); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); // pull on bucket boundary come late, condition change happens before it valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(false, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(false, curInterval.hasBase); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(20, curInterval.value.long_value); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); // Now the alarm is delivered. @@ -866,8 +886,9 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) { valueProducer.onDataPulled(allData); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(false, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(false, curInterval.hasBase); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(20, curInterval.value.long_value); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); } @@ -889,12 +910,11 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) - .WillOnce(Return(false)) // condition becomes true .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8); event->write(tagId); event->write(100); event->init(); @@ -905,7 +925,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 20); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); event->write(tagId); event->write(120); event->init(); @@ -916,7 +936,7 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { .WillOnce(Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) { data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 30); + shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 25); event->write(tagId); event->write(130); event->init(); @@ -932,24 +952,26 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; // startUpdated:false sum:0 start:100 - EXPECT_EQ(100, curInterval.start.long_value); - EXPECT_EQ(true, curInterval.startUpdated); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(100, curInterval.base.long_value); EXPECT_EQ(false, curInterval.hasValue); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); // pull on bucket boundary come late, condition change happens before it valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(false, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(false, curInterval.hasBase); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(20, curInterval.value.long_value); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); // condition changed to true again, before the pull alarm is delivered valueProducer.onConditionChanged(true, bucket2StartTimeNs + 25); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(130, curInterval.start.long_value); - EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(130, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(20, curInterval.value.long_value); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); // Now the alarm is delivered, but it is considered late, it has no effect @@ -963,89 +985,10 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) { valueProducer.onDataPulled(allData); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(130, curInterval.start.long_value); - EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); -} - -/* - * Test pulled event with non sliced condition. The pull on boundary come late because the puller is - * very slow. - */ -TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition3) { - ValueMetric metric; - metric.set_id(metricId); - metric.set_bucket(ONE_MINUTE); - metric.mutable_value_field()->set_field(tagId); - metric.mutable_value_field()->add_child()->set_field(2); - metric.set_condition(StringToId("SCREEN_ON")); - - sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); - EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return()); - - EXPECT_CALL(*pullerManager, Pull(tagId, _, _)) - .WillOnce(Return(false)) - // condition becomes true - .WillOnce(Invoke([](int tagId, int64_t timeNs, - vector<std::shared_ptr<LogEvent>>* data) { - data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); - event->write(tagId); - event->write(100); - event->init(); - data->push_back(event); - return true; - })) - // condition becomes false - .WillOnce(Invoke([](int tagId, int64_t timeNs, - vector<std::shared_ptr<LogEvent>>* data) { - data->clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 20); - event->write(tagId); - event->write(120); - event->init(); - data->push_back(event); - return true; - })); - - ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, tagId, bucketStartTimeNs, - bucketStartTimeNs, pullerManager); - valueProducer.onConditionChanged(true, bucketStartTimeNs + 8); - - // has one slice - EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); - ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - // startUpdated:false sum:0 start:100 - EXPECT_EQ(100, curInterval.start.long_value); - EXPECT_EQ(true, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); - - // pull on bucket boundary come late, condition change happens before it. - // But puller is very slow in this one, so the data come after bucket finish - valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1); - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(false, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); - EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); - - // Alarm is delivered in time, but the pull is very slow, and pullers are called in order, - // so this one comes even later - vector<shared_ptr<LogEvent>> allData; - allData.clear(); - shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 30); - event->write(1); - event->write(110); - event->init(); - allData.push_back(event); - valueProducer.onDataPulled(allData); - - curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(false, curInterval.startUpdated); - EXPECT_EQ(false, curInterval.hasValue); + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(130, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(20, curInterval.value.long_value); EXPECT_EQ(0UL, valueProducer.mPastBuckets.size()); } @@ -1088,7 +1031,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) { valueProducer.flushIfNeededLocked(bucket3StartTimeNs); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().value.long_value); } TEST(ValueMetricProducerTest, TestPushedAggregateMax) { @@ -1130,7 +1073,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) { valueProducer.flushIfNeededLocked(bucket3StartTimeNs); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().value.long_value); } TEST(ValueMetricProducerTest, TestPushedAggregateAvg) { @@ -1175,7 +1118,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) { valueProducer.flushIfNeededLocked(bucket3StartTimeNs); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(12.5, valueProducer.mPastBuckets.begin()->second.back().mValueDouble); + EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().value.double_value - 12.5) < epsilon); } TEST(ValueMetricProducerTest, TestPushedAggregateSum) { @@ -1217,67 +1160,75 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) { valueProducer.flushIfNeededLocked(bucket3StartTimeNs); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(25, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(25, valueProducer.mPastBuckets.begin()->second.back().value.long_value); } -TEST(ValueMetricProducerTest, TestPushedAggregateSumSliced) { - string slicedConditionName = "UID"; - const int conditionTagId = 2; +TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { ValueMetric metric; metric.set_id(metricId); metric.set_bucket(ONE_MINUTE); metric.mutable_value_field()->set_field(tagId); - metric.mutable_value_field()->add_child()->set_field(1); - metric.set_aggregation_type(ValueMetric::SUM); - - metric.set_condition(StringToId(slicedConditionName)); - MetricConditionLink* link = metric.add_links(); - link->set_condition(StringToId(slicedConditionName)); - buildSimpleAtomFieldMatcher(tagId, 2, link->mutable_fields_in_what()); - buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition()); - - LogEvent event1(tagId, bucketStartTimeNs + 10); - event1.write(10); // value - event1.write("111"); // uid - event1.init(); - ConditionKey key1; - key1[StringToId(slicedConditionName)] = - {getMockedDimensionKey(conditionTagId, 2, "111")}; - - LogEvent event2(tagId, bucketStartTimeNs + 20); - event2.write(15); - event2.write("222"); - event2.init(); - ConditionKey key2; - key2[StringToId(slicedConditionName)] = - {getMockedDimensionKey(conditionTagId, 2, "222")}; + metric.mutable_value_field()->add_child()->set_field(2); + metric.set_aggregation_type(ValueMetric::MIN); + metric.set_use_diff(true); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); - EXPECT_CALL(*wizard, query(_, key1, _, _, _, _)).WillOnce(Return(ConditionState::kFalse)); - EXPECT_CALL(*wizard, query(_, key2, _, _, _, _)).WillOnce(Return(ConditionState::kTrue)); - sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); - ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, -1, bucketStartTimeNs, + ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs, bucketStartTimeNs, pullerManager); - valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); - + shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); + event1->write(1); + event1->write(10); + event1->init(); + shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15); + event2->write(1); + event2->write(15); + event2->init(); + valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1); + // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(10, curInterval.base.long_value); EXPECT_EQ(false, curInterval.hasValue); - valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); + valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; - EXPECT_EQ(15, curInterval.value.long_value); + EXPECT_EQ(true, curInterval.hasValue); + EXPECT_EQ(5, curInterval.value.long_value); + + // no change in data. + shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10); + event3->write(1); + event3->write(15); + event3->init(); + valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3); + EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(15, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); + + shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15); + event4->write(1); + event4->write(15); + event4->init(); + valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4); + EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); + curInterval = valueProducer.mCurrentSlicedBucket.begin()->second; + EXPECT_EQ(true, curInterval.hasBase); + EXPECT_EQ(15, curInterval.base.long_value); + EXPECT_EQ(true, curInterval.hasValue); valueProducer.flushIfNeededLocked(bucket3StartTimeNs); EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); - EXPECT_EQ(15, valueProducer.mPastBuckets.begin()->second.back().mValueLong); + EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second.back().value.long_value); } } // namespace statsd diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 7382cd3f5ff1..e396a3d05517 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -1,4 +1,6 @@ Landroid/accessibilityservice/IAccessibilityServiceConnection$Stub;->asInterface(Landroid/os/IBinder;)Landroid/accessibilityservice/IAccessibilityServiceConnection; +Landroid/accounts/AccountManager$AmsTask;-><init>(Landroid/accounts/AccountManager;Landroid/app/Activity;Landroid/os/Handler;Landroid/accounts/AccountManagerCallback;)V +Landroid/accounts/AccountManager$Future2Task;-><init>(Landroid/accounts/AccountManager;Landroid/os/Handler;Landroid/accounts/AccountManagerCallback;)V Landroid/accounts/IAccountAuthenticator$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/accounts/IAccountAuthenticator$Stub$Proxy;->mRemote:Landroid/os/IBinder; Landroid/accounts/IAccountAuthenticator$Stub;-><init>()V @@ -30,6 +32,7 @@ Landroid/accounts/IAccountManagerResponse;->onResult(Landroid/os/Bundle;)V Landroid/app/ActivityManagerNative;-><init>()V Landroid/app/ActivityThread$AppBindData;-><init>()V Landroid/app/ActivityThread$CreateServiceData;-><init>()V +Landroid/app/ActivityThread$H;-><init>(Landroid/app/ActivityThread;)V Landroid/app/admin/IDevicePolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/admin/IDevicePolicyManager; Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I @@ -212,6 +215,7 @@ Landroid/app/job/IJobService;->startJob(Landroid/app/job/JobParameters;)V Landroid/app/job/IJobService;->stopJob(Landroid/app/job/JobParameters;)V Landroid/app/PackageDeleteObserver;-><init>()V Landroid/app/PackageInstallObserver;-><init>()V +Landroid/app/ReceiverRestrictedContext;-><init>(Landroid/content/Context;)V Landroid/app/ResourcesManager$ActivityResources;-><init>()V Landroid/app/ResourcesManager;-><init>()V Landroid/app/TaskStackListener;-><init>()V @@ -262,6 +266,7 @@ Landroid/bluetooth/IBluetoothManager;->unregisterStateChangeCallback(Landroid/bl Landroid/bluetooth/IBluetoothManagerCallback$Stub;-><init>()V Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap; Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V +Landroid/content/ContentProviderProxy;->mRemote:Landroid/os/IBinder; Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard; Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V @@ -415,9 +420,14 @@ Landroid/content/pm/IShortcutService$Stub;->asInterface(Landroid/os/IBinder;)Lan Landroid/content/res/ConfigurationBoundResourceCache;-><init>()V Landroid/content/res/DrawableCache;-><init>()V Landroid/content/UndoManager;-><init>()V +Landroid/database/BulkCursorProxy;->mRemote:Landroid/os/IBinder; Landroid/database/IContentObserver$Stub;-><init>()V Landroid/database/IContentObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/database/IContentObserver; Landroid/database/IContentObserver;->onChange(ZLandroid/net/Uri;I)V +Landroid/database/sqlite/SQLiteConnectionPool;->$assertionsDisabled:Z +Landroid/database/sqlite/SQLiteDatabase;->$assertionsDisabled:Z +Landroid/filterfw/GraphEnvironment;->addReferences([Ljava/lang/Object;)V +Landroid/hardware/camera2/utils/HashCodeHelpers;->hashCode([I)I Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager; Landroid/hardware/display/IDisplayManager;->getDisplayInfo(I)Landroid/view/DisplayInfo; Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V @@ -432,6 +442,9 @@ Landroid/hardware/location/IContextHubService$Stub;->asInterface(Landroid/os/IBi Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/hardware/usb/IUsbManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/usb/IUsbManager; Landroid/icu/impl/CurrencyData;-><init>()V +Landroid/icu/impl/ICUResourceBundle;->getULocale()Landroid/icu/util/ULocale; +Landroid/icu/impl/ICUResourceBundle;->getWithFallback(Ljava/lang/String;)Landroid/icu/impl/ICUResourceBundle; +Landroid/icu/impl/IllegalIcuArgumentException;-><init>(Ljava/lang/String;)V Landroid/icu/text/ArabicShaping;-><init>(I)V Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I @@ -462,6 +475,8 @@ Landroid/icu/util/UResourceBundle;->getString()Ljava/lang/String; Landroid/icu/util/UResourceBundle;->getType()I Landroid/icu/util/UResourceBundleIterator;->hasNext()Z Landroid/icu/util/UResourceBundleIterator;->next()Landroid/icu/util/UResourceBundle; +Landroid/inputmethodservice/IInputMethodSessionWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller; +Landroid/inputmethodservice/IInputMethodWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller; Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryDetector; Landroid/location/ICountryListener$Stub;-><init>()V Landroid/location/IGeocodeProvider$Stub;-><init>()V @@ -479,9 +494,11 @@ Landroid/location/ILocationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager; Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I Landroid/location/ILocationManager;->getAllProviders()Ljava/util/List; +Landroid/location/LocationManager$ListenerTransport;-><init>(Landroid/location/LocationManager;Landroid/location/LocationListener;Landroid/os/Looper;)V Landroid/Manifest$permission;->CAPTURE_SECURE_VIDEO_OUTPUT:Ljava/lang/String; Landroid/Manifest$permission;->CAPTURE_VIDEO_OUTPUT:Ljava/lang/String; Landroid/Manifest$permission;->READ_FRAME_BUFFER:Ljava/lang/String; +Landroid/media/effect/SingleFilterEffect;-><init>(Landroid/media/effect/EffectContext;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V Landroid/media/IAudioFocusDispatcher;->dispatchAudioFocusChange(ILjava/lang/String;)V Landroid/media/IAudioRoutesObserver$Stub;-><init>()V Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V @@ -500,6 +517,7 @@ Landroid/media/IRemoteDisplayCallback;->onStateChanged(Landroid/media/RemoteDisp Landroid/media/IRingtonePlayer;->play(Landroid/os/IBinder;Landroid/net/Uri;Landroid/media/AudioAttributes;FZ)V Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController; Landroid/media/MediaFile;-><init>()V +Landroid/media/MediaScanner$MyMediaScannerClient;-><init>(Landroid/media/MediaScanner;)V Landroid/media/projection/IMediaProjectionManager;->hasProjectionPermission(ILjava/lang/String;)Z Landroid/media/session/ISessionManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/session/ISessionManager; Landroid/net/IConnectivityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V @@ -547,6 +565,7 @@ Landroid/net/INetworkStatsSession;->getSummaryForNetwork(Landroid/net/NetworkTem Landroid/net/MobileLinkQualityInfo;-><init>()V Landroid/net/nsd/INsdManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/nsd/INsdManager; Landroid/net/nsd/INsdManager;->getMessenger()Landroid/os/Messenger; +Landroid/net/sip/ISipSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/sip/ISipSession; Landroid/net/SntpClient;-><init>()V Landroid/net/wifi/IWifiManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Landroid/net/wifi/IWifiManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/IWifiManager; @@ -637,6 +656,7 @@ Landroid/os/BatteryStats;->computeBatteryRealtime(JI)J Landroid/os/BatteryStats;->computeBatteryTimeRemaining(J)J Landroid/os/BatteryStats;->computeBatteryUptime(JI)J Landroid/os/BatteryStats;->computeChargeTimeRemaining(J)J +Landroid/os/BatteryStats;->dumpLine(Ljava/io/PrintWriter;ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V Landroid/os/BatteryStats;->getBatteryUptime(J)J Landroid/os/BatteryStats;->getGlobalWifiRunningTime(JI)J Landroid/os/BatteryStats;->getMobileRadioActiveTime(JI)J @@ -725,6 +745,7 @@ Landroid/os/Environment;->buildExternalStorageAppDataDirs(Ljava/lang/String;)[Lj Landroid/os/Environment;->buildExternalStorageAppFilesDirs(Ljava/lang/String;)[Ljava/io/File; Landroid/os/Environment;->buildExternalStorageAppMediaDirs(Ljava/lang/String;)[Ljava/io/File; Landroid/os/Environment;->buildExternalStorageAppObbDirs(Ljava/lang/String;)[Ljava/io/File; +Landroid/os/Environment;->buildPaths([Ljava/io/File;[Ljava/lang/String;)[Ljava/io/File; Landroid/os/Environment;->getDataSystemDirectory()Ljava/io/File; Landroid/os/Environment;->getLegacyExternalStorageObbDirectory()Ljava/io/File; Landroid/os/Environment;->initForCurrentUser()V @@ -930,6 +951,8 @@ Landroid/os/ServiceManager;->listServices()[Ljava/lang/String; Landroid/os/ServiceManager;->sCache:Ljava/util/Map; Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager; Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager; +Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder; +Landroid/os/ServiceManagerProxy;->mRemote:Landroid/os/IBinder; Landroid/os/ServiceSpecificException;-><init>(ILjava/lang/String;)V Landroid/os/SharedMemory;->getFd()I Landroid/os/ShellCommand;->peekNextArg()Ljava/lang/String; @@ -1064,6 +1087,7 @@ Landroid/os/WorkSource;->sTmpWorkSource:Landroid/os/WorkSource; Landroid/os/WorkSource;->updateLocked(Landroid/os/WorkSource;ZZ)Z Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/String;)V Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/Throwable;)V +Landroid/preference/PreferenceGroupAdapter;->getItem(I)Landroid/preference/Preference; Landroid/R$styleable;->ActionBar:[I Landroid/R$styleable;->ActionBar_background:I Landroid/R$styleable;->ActionBar_backgroundSplit:I @@ -1346,6 +1370,17 @@ Landroid/security/IKeystoreService;->reset()I Landroid/security/IKeystoreService;->sign(Ljava/lang/String;[B)[B Landroid/security/IKeystoreService;->ungrant(Ljava/lang/String;I)I Landroid/security/IKeystoreService;->verify(Ljava/lang/String;[B[B)I +Landroid/security/keymaster/KeymasterBlobArgument;-><init>(ILandroid/os/Parcel;)V +Landroid/security/keymaster/KeymasterBlobArgument;-><init>(I[B)V +Landroid/security/keymaster/KeymasterBlobArgument;->blob:[B +Landroid/security/keymaster/KeymasterBooleanArgument;-><init>(ILandroid/os/Parcel;)V +Landroid/security/keymaster/KeymasterDateArgument;-><init>(ILandroid/os/Parcel;)V +Landroid/security/keymaster/KeymasterIntArgument;-><init>(II)V +Landroid/security/keymaster/KeymasterIntArgument;-><init>(ILandroid/os/Parcel;)V +Landroid/security/keymaster/KeymasterIntArgument;->value:I +Landroid/security/keymaster/KeymasterLongArgument;-><init>(IJ)V +Landroid/security/keymaster/KeymasterLongArgument;-><init>(ILandroid/os/Parcel;)V +Landroid/security/keymaster/KeymasterLongArgument;->value:J Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager; @@ -1383,9 +1418,42 @@ Landroid/service/wallpaper/IWallpaperEngine;->dispatchWallpaperCommand(Ljava/lan Landroid/service/wallpaper/IWallpaperEngine;->setVisibility(Z)V Landroid/service/wallpaper/IWallpaperService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/wallpaper/IWallpaperService; Landroid/speech/IRecognitionListener;->onEvent(ILandroid/os/Bundle;)V +Landroid/telecom/Log;->i(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V +Landroid/telecom/Log;->w(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V Landroid/telephony/CarrierMessagingServiceManager;-><init>()V +Landroid/telephony/JapanesePhoneNumberFormatter;->format(Landroid/text/Editable;)V +Landroid/telephony/SmsCbCmasInfo;->getCategory()I +Landroid/telephony/SmsCbCmasInfo;->getCertainty()I +Landroid/telephony/SmsCbCmasInfo;->getMessageClass()I +Landroid/telephony/SmsCbCmasInfo;->getResponseType()I +Landroid/telephony/SmsCbCmasInfo;->getSeverity()I +Landroid/telephony/SmsCbCmasInfo;->getUrgency()I +Landroid/telephony/SmsCbEtwsInfo;->getWarningType()I +Landroid/telephony/SmsCbLocation;-><init>(Ljava/lang/String;)V +Landroid/telephony/SmsCbLocation;-><init>(Ljava/lang/String;II)V +Landroid/telephony/SmsCbLocation;->getCid()I +Landroid/telephony/SmsCbLocation;->getLac()I +Landroid/telephony/SmsCbLocation;->getPlmn()Ljava/lang/String; +Landroid/telephony/SmsCbMessage;-><init>(Landroid/os/Parcel;)V +Landroid/telephony/SmsCbMessage;->getCmasWarningInfo()Landroid/telephony/SmsCbCmasInfo; +Landroid/telephony/SmsCbMessage;->getEtwsWarningInfo()Landroid/telephony/SmsCbEtwsInfo; +Landroid/telephony/SmsCbMessage;->getGeographicalScope()I +Landroid/telephony/SmsCbMessage;->getLanguageCode()Ljava/lang/String; +Landroid/telephony/SmsCbMessage;->getLocation()Landroid/telephony/SmsCbLocation; +Landroid/telephony/SmsCbMessage;->getMessageBody()Ljava/lang/String; +Landroid/telephony/SmsCbMessage;->getMessageFormat()I +Landroid/telephony/SmsCbMessage;->getSerialNumber()I +Landroid/telephony/SmsCbMessage;->getServiceCategory()I +Landroid/telephony/SmsCbMessage;->isCmasMessage()Z +Landroid/telephony/SmsCbMessage;->isEmergencyMessage()Z Landroid/telephony/TelephonyManager$MultiSimVariants;->values()[Landroid/telephony/TelephonyManager$MultiSimVariants; +Landroid/test/AndroidTestCase;->getTestContext()Landroid/content/Context; +Landroid/test/AndroidTestCase;->setTestContext(Landroid/content/Context;)V +Landroid/test/InstrumentationTestCase;->runMethod(Ljava/lang/reflect/Method;I)V +Landroid/test/RepetitiveTest;->numIterations()I Landroid/util/Singleton;-><init>()V +Landroid/util/XmlPullAttributes;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V +Landroid/util/XmlPullAttributes;->mParser:Lorg/xmlpull/v1/XmlPullParser; Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setFindAccessibilityNodeInfoResult(Landroid/view/accessibility/AccessibilityNodeInfo;I)V Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setFindAccessibilityNodeInfosResult(Ljava/util/List;I)V Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setPerformAccessibilityActionResult(ZI)V @@ -1443,7 +1511,9 @@ Landroid/view/IWindowSession;->setInTouchMode(Z)V Landroid/view/IWindowSession;->setTransparentRegion(Landroid/view/IWindow;Landroid/graphics/Region;)V Landroid/view/IWindowSession;->wallpaperCommandComplete(Landroid/os/IBinder;Landroid/os/Bundle;)V Landroid/view/IWindowSession;->wallpaperOffsetsComplete(Landroid/os/IBinder;)V +Landroid/view/RenderNodeAnimator;->setDuration(J)Landroid/view/RenderNodeAnimator; Landroid/view/View$AttachInfo$InvalidateInfo;-><init>()V +Landroid/view/View$CheckForLongPress;-><init>(Landroid/view/View;)V Landroid/view/View$ListenerInfo;-><init>()V Landroid/view/ViewTreeObserver$InternalInsetsInfo;-><init>()V Landroid/webkit/CacheManager$CacheResult;-><init>()V @@ -1453,9 +1523,102 @@ Landroid/webkit/IWebViewUpdateService$Stub;->asInterface(Landroid/os/IBinder;)La Landroid/webkit/IWebViewUpdateService;->getCurrentWebViewPackageName()Ljava/lang/String; Landroid/webkit/IWebViewUpdateService;->getValidWebViewPackages()[Landroid/webkit/WebViewProviderInfo; Landroid/webkit/IWebViewUpdateService;->isFallbackPackage(Ljava/lang/String;)Z +Landroid/widget/DigitalClock$FormatChangeObserver;-><init>(Landroid/widget/DigitalClock;)V +Landroid/widget/QuickContactBadge$QueryHandler;-><init>(Landroid/widget/QuickContactBadge;Landroid/content/ContentResolver;)V Landroid/widget/RelativeLayout$DependencyGraph$Node;-><init>()V Landroid/widget/ScrollBarDrawable;-><init>()V +Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->clear()V +Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->getRememberedPosition()I +Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->inputDigit(C)Ljava/lang/String; +Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;->inputDigitAndRememberPosition(C)Ljava/lang/String; +Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;->getDescriptionForNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Ljava/util/Locale;)Ljava/lang/String; +Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;->getInstance()Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder; +Lcom/android/i18n/phonenumbers/NumberParseException;->getErrorType()Lcom/android/i18n/phonenumbers/NumberParseException$ErrorType; +Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getDomesticCarrierCodeFormattingRule()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getFormat()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getLeadingDigitsPattern(I)Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getNationalPrefixFormattingRule()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->getPattern()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonemetadata$NumberFormat;->leadingDigitsPatternSize()I +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getCountryCode()I +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getGeneralDesc()Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc; +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNationalPrefixForParsing()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getNationalPrefixTransformRule()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->getPreferredExtnPrefix()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->hasNationalPrefix()Z +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->hasPreferredExtnPrefix()Z +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->intlNumberFormats()Ljava/util/List; +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadata;->numberFormats()Ljava/util/List; +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;-><init>()V +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneMetadataCollection;->getMetadataList()Ljava/util/List; +Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;->getNationalNumberPattern()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_DEFAULT_COUNTRY:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITHOUT_PLUS_SIGN:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITH_IDD:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->FROM_NUMBER_WITH_PLUS_SIGN:Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;->values()[Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->clearCountryCode()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber; +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getCountryCode()I +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getCountryCodeSource()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource; +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getExtension()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->getNationalNumber()J +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->hasCountryCode()Z +Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->hasExtension()Z +Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->end()I +Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->number()Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber; +Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->rawString()Ljava/lang/String; +Lcom/android/i18n/phonenumbers/PhoneNumberMatch;->start()I +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;->POSSIBLE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->EXACT_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NOT_A_NUMBER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NO_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->NSN_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->SHORT_NSN_MATCH:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->E164:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->INTERNATIONAL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->NATIONAL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->RFC3966:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->FIXED_LINE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->FIXED_LINE_OR_MOBILE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->MOBILE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PAGER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PERSONAL_NUMBER:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->PREMIUM_RATE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->SHARED_COST:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->TOLL_FREE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->UAN:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->values()[Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->VOICEMAIL:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType;->VOIP:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;->IS_POSSIBLE:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult;->TOO_LONG:Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->findNumbers(Ljava/lang/CharSequence;Ljava/lang/String;Lcom/android/i18n/phonenumbers/PhoneNumberUtil$Leniency;J)Ljava/lang/Iterable; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->format(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberFormat;)Ljava/lang/String; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->formatInOriginalFormat(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Ljava/lang/String;)Ljava/lang/String; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getAsYouTypeFormatter(Ljava/lang/String;)Lcom/android/i18n/phonenumbers/AsYouTypeFormatter; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getCountryCodeForRegion(Ljava/lang/String;)I +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getInstance()Lcom/android/i18n/phonenumbers/PhoneNumberUtil; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getNationalSignificantNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getNumberType(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$PhoneNumberType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->getRegionCodeForNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Ljava/lang/String; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isNumberMatch(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$MatchType; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isPossibleNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Z +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isPossibleNumberWithReason(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Lcom/android/i18n/phonenumbers/PhoneNumberUtil$ValidationResult; +Lcom/android/i18n/phonenumbers/PhoneNumberUtil;->isValidNumber(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;)Z +Lcom/android/ims/ImsCall;->deflect(Ljava/lang/String;)V +Lcom/android/ims/ImsCall;->isMultiparty()Z +Lcom/android/ims/ImsCall;->reject(I)V +Lcom/android/ims/ImsCall;->terminate(I)V Lcom/android/ims/ImsConfigListener$Stub;-><init>()V +Lcom/android/ims/ImsEcbm;->exitEmergencyCallbackMode()V +Lcom/android/ims/ImsManager;->getConfigInterface()Lcom/android/ims/ImsConfig; +Lcom/android/ims/ImsManager;->getInstance(Landroid/content/Context;I)Lcom/android/ims/ImsManager; +Lcom/android/ims/ImsManager;->isEnhanced4gLteModeSettingEnabledByUser(Landroid/content/Context;)Z +Lcom/android/ims/ImsManager;->isNonTtyOrTtyOnVolteEnabled(Landroid/content/Context;)Z +Lcom/android/ims/ImsManager;->isVolteEnabledByPlatform(Landroid/content/Context;)Z +Lcom/android/ims/ImsUtInterface;->queryCallForward(ILjava/lang/String;Landroid/os/Message;)V Lcom/android/ims/internal/IImsCallSession$Stub;-><init>()V Lcom/android/ims/internal/IImsCallSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/ims/internal/IImsCallSession; Lcom/android/ims/internal/IImsConfig$Stub;-><init>()V @@ -1473,7 +1636,15 @@ Lcom/android/ims/internal/IImsVideoCallCallback;->receiveSessionModifyRequest(La Lcom/android/ims/internal/IImsVideoCallCallback;->receiveSessionModifyResponse(ILandroid/telecom/VideoProfile;Landroid/telecom/VideoProfile;)V Lcom/android/ims/internal/IImsVideoCallProvider$Stub;-><init>()V Lcom/android/ims/internal/IImsVideoCallProvider;->setCallback(Lcom/android/ims/internal/IImsVideoCallCallback;)V +Lcom/android/ims/internal/ImsVideoCallProviderWrapper;-><init>(Lcom/android/ims/internal/IImsVideoCallProvider;)V Lcom/android/ims/internal/uce/uceservice/IUceListener$Stub;-><init>()V +Lcom/android/internal/app/AlertActivity;-><init>()V +Lcom/android/internal/app/AlertActivity;->mAlert:Lcom/android/internal/app/AlertController; +Lcom/android/internal/app/AlertActivity;->mAlertParams:Lcom/android/internal/app/AlertController$AlertParams; +Lcom/android/internal/app/AlertActivity;->setupAlert()V +Lcom/android/internal/app/AssistUtils;-><init>(Landroid/content/Context;)V +Lcom/android/internal/app/AssistUtils;->getAssistComponentForUser(I)Landroid/content/ComponentName; +Lcom/android/internal/app/ChooserActivity;-><init>()V Lcom/android/internal/app/IAppOpsCallback$Stub;-><init>()V Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I @@ -1508,9 +1679,35 @@ Lcom/android/internal/app/IBatteryStats;->getAwakeTimeBattery()J Lcom/android/internal/app/IBatteryStats;->getStatistics()[B Lcom/android/internal/app/IBatteryStats;->isCharging()Z Lcom/android/internal/app/IMediaContainerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IMediaContainerService; +Lcom/android/internal/app/IntentForwarderActivity;->TAG:Ljava/lang/String; Lcom/android/internal/app/IVoiceInteractionManagerService$Stub$Proxy;->showSessionFromSession(Landroid/os/IBinder;Landroid/os/Bundle;I)Z Lcom/android/internal/app/IVoiceInteractionManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IVoiceInteractionManagerService; Lcom/android/internal/app/IVoiceInteractionManagerService;->getKeyphraseSoundModel(ILjava/lang/String;)Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseSoundModel; +Lcom/android/internal/app/LocaleHelper$LocaleInfoComparator;-><init>(Ljava/util/Locale;Z)V +Lcom/android/internal/app/LocaleHelper$LocaleInfoComparator;->compare(Lcom/android/internal/app/LocaleStore$LocaleInfo;Lcom/android/internal/app/LocaleStore$LocaleInfo;)I +Lcom/android/internal/app/LocaleHelper;->getDisplayCountry(Ljava/util/Locale;Ljava/util/Locale;)Ljava/lang/String; +Lcom/android/internal/app/LocaleHelper;->getDisplayName(Ljava/util/Locale;Ljava/util/Locale;Z)Ljava/lang/String; +Lcom/android/internal/app/LocaleHelper;->normalizeForSearch(Ljava/lang/String;Ljava/util/Locale;)Ljava/lang/String; +Lcom/android/internal/app/LocalePicker$LocaleInfo;->getLocale()Ljava/util/Locale; +Lcom/android/internal/app/LocalePicker;->getLocales()Landroid/os/LocaleList; +Lcom/android/internal/app/LocalePicker;->updateLocale(Ljava/util/Locale;)V +Lcom/android/internal/app/LocalePicker;->updateLocales(Landroid/os/LocaleList;)V +Lcom/android/internal/app/LocaleStore$LocaleInfo;->getFullNameInUiLanguage()Ljava/lang/String; +Lcom/android/internal/app/LocaleStore$LocaleInfo;->getFullNameNative()Ljava/lang/String; +Lcom/android/internal/app/LocaleStore$LocaleInfo;->getId()Ljava/lang/String; +Lcom/android/internal/app/LocaleStore$LocaleInfo;->getLocale()Ljava/util/Locale; +Lcom/android/internal/app/LocaleStore$LocaleInfo;->getParent()Ljava/util/Locale; +Lcom/android/internal/app/LocaleStore;->fillCache(Landroid/content/Context;)V +Lcom/android/internal/app/LocaleStore;->getLevelLocales(Landroid/content/Context;Ljava/util/Set;Lcom/android/internal/app/LocaleStore$LocaleInfo;Z)Ljava/util/Set; +Lcom/android/internal/app/LocaleStore;->getLocaleInfo(Ljava/util/Locale;)Lcom/android/internal/app/LocaleStore$LocaleInfo; +Lcom/android/internal/app/NetInitiatedActivity;->handleNIVerify(Landroid/content/Intent;)V +Lcom/android/internal/app/ResolverActivity;-><init>()V +Lcom/android/internal/app/ResolverActivity;->mAdapter:Lcom/android/internal/app/ResolverActivity$ResolveListAdapter; +Lcom/android/internal/app/ResolverActivity;->mPm:Landroid/content/pm/PackageManager; +Lcom/android/internal/app/ResolverActivity;->onCreate(Landroid/os/Bundle;Landroid/content/Intent;Ljava/lang/CharSequence;[Landroid/content/Intent;Ljava/util/List;Z)V +Lcom/android/internal/app/WindowDecorActionBar$TabImpl;->mCallback:Landroid/app/ActionBar$TabListener; +Lcom/android/internal/app/WindowDecorActionBar;->mTabScrollView:Lcom/android/internal/widget/ScrollingTabContainerView; +Lcom/android/internal/app/WindowDecorActionBar;->setShowHideAnimationEnabled(Z)V Lcom/android/internal/appwidget/IAppWidgetService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/appwidget/IAppWidgetService; Lcom/android/internal/appwidget/IAppWidgetService$Stub;->TRANSACTION_bindAppWidgetId:I Lcom/android/internal/appwidget/IAppWidgetService;->bindAppWidgetId(Ljava/lang/String;IILandroid/content/ComponentName;Landroid/os/Bundle;)Z @@ -1518,17 +1715,80 @@ Lcom/android/internal/appwidget/IAppWidgetService;->bindRemoteViewsService(Ljava Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetIds(Landroid/content/ComponentName;)[I Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetViews(Ljava/lang/String;I)Landroid/widget/RemoteViews; Lcom/android/internal/backup/IBackupTransport$Stub;-><init>()V +Lcom/android/internal/database/SortCursor;-><init>([Landroid/database/Cursor;Ljava/lang/String;)V +Lcom/android/internal/database/SortCursor;->mCursor:Landroid/database/Cursor; +Lcom/android/internal/database/SortCursor;->mCursors:[Landroid/database/Cursor; +Lcom/android/internal/http/HttpDateTime;->parse(Ljava/lang/String;)J +Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;-><init>()V +Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->requestorId:Ljava/lang/String; +Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->requestorIdEncoding:I +Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->text:Ljava/lang/String; +Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;->textEncoding:I +Lcom/android/internal/location/GpsNetInitiatedHandler;->decodeString(Ljava/lang/String;ZI)Ljava/lang/String; +Lcom/android/internal/location/GpsNetInitiatedHandler;->handleNiNotification(Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;)V +Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V Lcom/android/internal/logging/MetricsLogger;-><init>()V Lcom/android/internal/net/LegacyVpnInfo;-><init>()V Lcom/android/internal/net/VpnConfig;-><init>()V +Lcom/android/internal/os/AndroidPrintStream;-><init>(ILjava/lang/String;)V +Lcom/android/internal/os/BaseCommand;-><init>()V +Lcom/android/internal/os/BaseCommand;->mArgs:Landroid/os/ShellCommand; Lcom/android/internal/os/BatterySipper$DrainType;->values()[Lcom/android/internal/os/BatterySipper$DrainType; +Lcom/android/internal/os/BinderInternal;->getContextObject()Landroid/os/IBinder; +Lcom/android/internal/os/BinderInternal;->handleGc()V +Lcom/android/internal/os/ClassLoaderFactory;->createClassloaderNamespace(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;ZZ)Ljava/lang/String; Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService; Lcom/android/internal/os/IDropBoxManagerService;->getNextEntry(Ljava/lang/String;JLjava/lang/String;)Landroid/os/DropBoxManager$Entry; +Lcom/android/internal/os/ProcessCpuTracker$Stats;->name:Ljava/lang/String; +Lcom/android/internal/os/ProcessCpuTracker$Stats;->rel_stime:I +Lcom/android/internal/os/ProcessCpuTracker$Stats;->rel_uptime:J +Lcom/android/internal/os/ProcessCpuTracker$Stats;->rel_utime:I +Lcom/android/internal/os/ProcessCpuTracker;-><init>(Z)V +Lcom/android/internal/os/ProcessCpuTracker;->countWorkingStats()I +Lcom/android/internal/os/ProcessCpuTracker;->getWorkingStats(I)Lcom/android/internal/os/ProcessCpuTracker$Stats; +Lcom/android/internal/os/ProcessCpuTracker;->update()V +Lcom/android/internal/os/RuntimeInit;->commonInit()V +Lcom/android/internal/os/RuntimeInit;->getApplicationObject()Landroid/os/IBinder; +Lcom/android/internal/os/RuntimeInit;->initialized:Z +Lcom/android/internal/os/RuntimeInit;->main([Ljava/lang/String;)V +Lcom/android/internal/os/RuntimeInit;->mApplicationObject:Landroid/os/IBinder; +Lcom/android/internal/os/ZygoteConnection$Arguments;-><init>([Ljava/lang/String;)V +Lcom/android/internal/os/ZygoteConnection$Arguments;->effectiveCapabilities:J +Lcom/android/internal/os/ZygoteConnection$Arguments;->gid:I +Lcom/android/internal/os/ZygoteConnection$Arguments;->gids:[I +Lcom/android/internal/os/ZygoteConnection$Arguments;->permittedCapabilities:J +Lcom/android/internal/os/ZygoteConnection$Arguments;->remainingArgs:[Ljava/lang/String; +Lcom/android/internal/os/ZygoteConnection$Arguments;->rlimits:Ljava/util/ArrayList; +Lcom/android/internal/os/ZygoteConnection$Arguments;->uid:I +Lcom/android/internal/os/ZygoteConnection;->applyUidSecurityPolicy(Lcom/android/internal/os/ZygoteConnection$Arguments;Landroid/net/Credentials;)V +Lcom/android/internal/os/ZygoteConnection;->closeSocket()V +Lcom/android/internal/os/ZygoteConnection;->getFileDesciptor()Ljava/io/FileDescriptor; +Lcom/android/internal/os/ZygoteConnection;->intArray2d:[[I +Lcom/android/internal/os/ZygoteConnection;->mSocket:Landroid/net/LocalSocket; +Lcom/android/internal/os/ZygoteConnection;->mSocketOutStream:Ljava/io/DataOutputStream; +Lcom/android/internal/os/ZygoteConnection;->peer:Landroid/net/Credentials; +Lcom/android/internal/os/ZygoteConnection;->readArgumentList()[Ljava/lang/String; +Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V +Lcom/android/internal/os/ZygoteInit;->mResources:Landroid/content/res/Resources; +Lcom/android/internal/os/ZygoteSecurityException;-><init>(Ljava/lang/String;)V +Lcom/android/internal/policy/DecorView;->mLastBottomInset:I +Lcom/android/internal/policy/DecorView;->mLastLeftInset:I +Lcom/android/internal/policy/DecorView;->mLastRightInset:I +Lcom/android/internal/policy/DecorView;->mWindow:Lcom/android/internal/policy/PhoneWindow; Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService; Lcom/android/internal/policy/IKeyguardService;->doKeyguardTimeout(Landroid/os/Bundle;)V Lcom/android/internal/policy/IKeyguardService;->setKeyguardEnabled(Z)V Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback; +Lcom/android/internal/policy/PhoneFallbackEventHandler;-><init>(Landroid/content/Context;)V +Lcom/android/internal/policy/PhoneFallbackEventHandler;->mContext:Landroid/content/Context; +Lcom/android/internal/policy/PhoneFallbackEventHandler;->mView:Landroid/view/View; +Lcom/android/internal/policy/PhoneFallbackEventHandler;->onKeyDown(ILandroid/view/KeyEvent;)Z +Lcom/android/internal/policy/PhoneFallbackEventHandler;->onKeyUp(ILandroid/view/KeyEvent;)Z +Lcom/android/internal/policy/PhoneFallbackEventHandler;->startCallActivity()V +Lcom/android/internal/policy/PhoneWindow;-><init>(Landroid/content/Context;)V +Lcom/android/internal/policy/PhoneWindow;->mTitle:Ljava/lang/CharSequence; +Lcom/android/internal/preference/YesNoPreference;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V Lcom/android/internal/R$anim;->fade_in:I Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I Lcom/android/internal/R$array;->config_autoBrightnessLevels:I @@ -1996,9 +2256,961 @@ Lcom/android/internal/statusbar/IStatusBarService;->removeIcon(Ljava/lang/String Lcom/android/internal/statusbar/IStatusBarService;->setIconVisibility(Ljava/lang/String;Z)V Lcom/android/internal/telecom/ITelecomService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telecom/ITelecomService; Lcom/android/internal/telecom/ITelecomService;->getCallState()I +Lcom/android/internal/telephony/BaseCommands;->mCallStateRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mCallWaitingInfoRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mCatCallSetUpRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mCatCcAlphaRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mCatEventRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mCatProCmdRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mCatSessionEndRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mCdmaPrlChangedRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mCdmaSmsRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mCdmaSubscriptionChangedRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/BaseCommands;->mEmergencyCallbackModeRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mExitEmergencyCallbackModeRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mGsmBroadcastSmsRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mGsmSmsRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mHardwareConfigChangeRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mIccRefreshRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mIccSmsFullRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mIccStatusChangedRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mImsNetworkStateChangedRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mNITZTimeRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mOtaProvisionRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mPhoneRadioCapabilityChangedRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mPhoneType:I +Lcom/android/internal/telephony/BaseCommands;->mPreferredNetworkType:I +Lcom/android/internal/telephony/BaseCommands;->mResendIncallMuteRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mRestrictedStateRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mRilCellInfoListRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mRingbackToneRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mRingRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mSignalStrengthRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mSmsOnSimRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mSmsStatusRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mSrvccStateRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mSsnRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mSsRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mStateMonitor:Ljava/lang/Object; +Lcom/android/internal/telephony/BaseCommands;->mSubscriptionStatusRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/BaseCommands;->mUnsolOemHookRawRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mUSSDRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/BaseCommands;->mVoiceRadioTechChangedRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/Call$State;->ACTIVE:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call$State;->ALERTING:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call$State;->DIALING:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call$State;->DISCONNECTED:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call$State;->DISCONNECTING:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call$State;->HOLDING:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call$State;->IDLE:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call$State;->INCOMING:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call$State;->isAlive()Z +Lcom/android/internal/telephony/Call$State;->isRinging()Z +Lcom/android/internal/telephony/Call$State;->values()[Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call$State;->WAITING:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call;-><init>()V +Lcom/android/internal/telephony/Call;->getConnections()Ljava/util/List; +Lcom/android/internal/telephony/Call;->getEarliestConnection()Lcom/android/internal/telephony/Connection; +Lcom/android/internal/telephony/Call;->getLatestConnection()Lcom/android/internal/telephony/Connection; +Lcom/android/internal/telephony/Call;->getPhone()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/Call;->getState()Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Call;->hangup()V +Lcom/android/internal/telephony/Call;->isIdle()Z +Lcom/android/internal/telephony/Call;->isMultiparty()Z +Lcom/android/internal/telephony/Call;->mConnections:Ljava/util/ArrayList; +Lcom/android/internal/telephony/Call;->mState:Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/CallerInfoAsyncQuery$CallerInfoAsyncQueryHandler;-><init>(Lcom/android/internal/telephony/CallerInfoAsyncQuery;Landroid/content/Context;)V +Lcom/android/internal/telephony/CallerInfoAsyncQuery$CookieWrapper;-><init>()V +Lcom/android/internal/telephony/CallerInfoAsyncQuery;->release()V +Lcom/android/internal/telephony/CallForwardInfo;-><init>()V +Lcom/android/internal/telephony/CallForwardInfo;->number:Ljava/lang/String; +Lcom/android/internal/telephony/CallForwardInfo;->reason:I +Lcom/android/internal/telephony/CallForwardInfo;->serviceClass:I +Lcom/android/internal/telephony/CallForwardInfo;->status:I +Lcom/android/internal/telephony/CallForwardInfo;->timeSeconds:I +Lcom/android/internal/telephony/CallForwardInfo;->toa:I +Lcom/android/internal/telephony/CallManager;->canConference(Lcom/android/internal/telephony/Call;I)Z +Lcom/android/internal/telephony/CallManager;->canDial(Lcom/android/internal/telephony/Phone;)Z +Lcom/android/internal/telephony/CallManager;->conference(Lcom/android/internal/telephony/Call;)V +Lcom/android/internal/telephony/CallManager;->getActiveFgCall(I)Lcom/android/internal/telephony/Call; +Lcom/android/internal/telephony/CallManager;->getActiveFgCallState(I)Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/CallManager;->getBackgroundCalls()Ljava/util/List; +Lcom/android/internal/telephony/CallManager;->getBgCallConnections()Ljava/util/List; +Lcom/android/internal/telephony/CallManager;->getBgPhone()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/CallManager;->getContext()Landroid/content/Context; +Lcom/android/internal/telephony/CallManager;->getDefaultPhone()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/CallManager;->getFgCallConnections()Ljava/util/List; +Lcom/android/internal/telephony/CallManager;->getFgPhone()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/CallManager;->getFgPhone(I)Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/CallManager;->getFirstActiveBgCall()Lcom/android/internal/telephony/Call; +Lcom/android/internal/telephony/CallManager;->getFirstActiveBgCall(I)Lcom/android/internal/telephony/Call; +Lcom/android/internal/telephony/CallManager;->getFirstActiveRingingCall()Lcom/android/internal/telephony/Call; +Lcom/android/internal/telephony/CallManager;->getFirstActiveRingingCall(I)Lcom/android/internal/telephony/Call; +Lcom/android/internal/telephony/CallManager;->getInstance()Lcom/android/internal/telephony/CallManager; +Lcom/android/internal/telephony/CallManager;->getPhoneInCall()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/CallManager;->getRingingCalls()Ljava/util/List; +Lcom/android/internal/telephony/CallManager;->getRingingPhone()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/CallManager;->getState()Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/CallManager;->getState(I)Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/CallManager;->hasActiveBgCall()Z +Lcom/android/internal/telephony/CallManager;->hasActiveBgCall(I)Z +Lcom/android/internal/telephony/CallManager;->hasActiveFgCall()Z +Lcom/android/internal/telephony/CallManager;->hasActiveFgCall(I)Z +Lcom/android/internal/telephony/CallManager;->hasActiveRingingCall(I)Z +Lcom/android/internal/telephony/CallManager;->hasMoreThanOneRingingCall()Z +Lcom/android/internal/telephony/CallManager;->hasMoreThanOneRingingCall(I)Z +Lcom/android/internal/telephony/CallManager;->mBackgroundCalls:Ljava/util/ArrayList; +Lcom/android/internal/telephony/CallManager;->mEmptyConnections:Ljava/util/ArrayList; +Lcom/android/internal/telephony/CallManager;->mForegroundCalls:Ljava/util/ArrayList; +Lcom/android/internal/telephony/CallManager;->mPhones:Ljava/util/ArrayList; +Lcom/android/internal/telephony/CallManager;->mRingingCalls:Ljava/util/ArrayList; +Lcom/android/internal/telephony/CallManager;->registerForDisconnect(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CallManager;->registerForNewRingingConnection(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CallManager;->registerForPreciseCallStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CallManager;->registerPhone(Lcom/android/internal/telephony/Phone;)Z +Lcom/android/internal/telephony/CallManager;->unregisterForDisconnect(Landroid/os/Handler;)V +Lcom/android/internal/telephony/CallManager;->unregisterForNewRingingConnection(Landroid/os/Handler;)V +Lcom/android/internal/telephony/CallManager;->unregisterForPreciseCallStateChanged(Landroid/os/Handler;)V +Lcom/android/internal/telephony/CallManager;->unregisterPhone(Lcom/android/internal/telephony/Phone;)V +Lcom/android/internal/telephony/CallStateException;-><init>(Ljava/lang/String;)V +Lcom/android/internal/telephony/CallTracker;-><init>()V +Lcom/android/internal/telephony/CallTracker;->getState()Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/CallTracker;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/CallTracker;->mCi:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/CallTracker;->mNeedsPoll:Z +Lcom/android/internal/telephony/CallTracker;->mNumberConverted:Z +Lcom/android/internal/telephony/CallTracker;->mPendingOperations:I +Lcom/android/internal/telephony/CallTracker;->registerForVoiceCallEnded(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CarrierServiceBindHelper;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/CarrierServiceBindHelper;->mHandler:Landroid/os/Handler; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->CLOSE_CHANNEL:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->DISPLAY_TEXT:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->fromInt(I)Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_CHANNEL_STATUS:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_INKEY:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_INPUT:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->LANGUAGE_NOTIFICATION:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->LAUNCH_BROWSER:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->OPEN_CHANNEL:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->PLAY_TONE:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->PROVIDE_LOCAL_INFORMATION:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->RECEIVE_DATA:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->REFRESH:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SELECT_ITEM:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_DATA:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_DTMF:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_SMS:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_SS:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_USSD:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_CALL:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_EVENT_LIST:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_IDLE_MODE_TEXT:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_MENU:Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/AppInterface$CommandType;->values()[Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;->callMsg:Lcom/android/internal/telephony/cat/TextMessage; +Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;->confirmMsg:Lcom/android/internal/telephony/cat/TextMessage; +Lcom/android/internal/telephony/cat/CatCmdMessage$SetupEventListSettings;->eventList:[I +Lcom/android/internal/telephony/cat/CatCmdMessage;->getCallSettings()Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings; +Lcom/android/internal/telephony/cat/CatCmdMessage;->getCmdType()Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/CatCmdMessage;->geTextMessage()Lcom/android/internal/telephony/cat/TextMessage; +Lcom/android/internal/telephony/cat/CatCmdMessage;->getSetEventList()Lcom/android/internal/telephony/cat/CatCmdMessage$SetupEventListSettings; +Lcom/android/internal/telephony/cat/CatCmdMessage;->hasIconLoadFailed()Z +Lcom/android/internal/telephony/cat/CatCmdMessage;->mCallSettings:Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings; +Lcom/android/internal/telephony/cat/CatCmdMessage;->mCmdDet:Lcom/android/internal/telephony/cat/CommandDetails; +Lcom/android/internal/telephony/cat/CatCmdMessage;->mInput:Lcom/android/internal/telephony/cat/Input; +Lcom/android/internal/telephony/cat/CatCmdMessage;->mMenu:Lcom/android/internal/telephony/cat/Menu; +Lcom/android/internal/telephony/cat/CatCmdMessage;->mTextMsg:Lcom/android/internal/telephony/cat/TextMessage; +Lcom/android/internal/telephony/cat/CatLog;->d(Ljava/lang/Object;Ljava/lang/String;)V +Lcom/android/internal/telephony/cat/CatLog;->d(Ljava/lang/String;Ljava/lang/String;)V +Lcom/android/internal/telephony/cat/CatLog;->e(Ljava/lang/Object;Ljava/lang/String;)V +Lcom/android/internal/telephony/cat/CatResponseMessage;->setEventDownload(I[B)V +Lcom/android/internal/telephony/cat/CatService;->dispose()V +Lcom/android/internal/telephony/cat/CatService;->isStkAppInstalled()Z +Lcom/android/internal/telephony/cat/CatService;->mCmdIf:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/cat/CatService;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/cat/CatService;->mCurrntCmd:Lcom/android/internal/telephony/cat/CatCmdMessage; +Lcom/android/internal/telephony/cat/CatService;->mHandlerThread:Landroid/os/HandlerThread; +Lcom/android/internal/telephony/cat/CatService;->mMenuCmd:Lcom/android/internal/telephony/cat/CatCmdMessage; +Lcom/android/internal/telephony/cat/CatService;->mMsgDecoder:Lcom/android/internal/telephony/cat/RilMessageDecoder; +Lcom/android/internal/telephony/cat/CatService;->mSlotId:I +Lcom/android/internal/telephony/cat/CatService;->mStkAppInstalled:Z +Lcom/android/internal/telephony/cat/CatService;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController; +Lcom/android/internal/telephony/cat/CatService;->sendTerminalResponse(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/ResultCode;ZILcom/android/internal/telephony/cat/ResponseData;)V +Lcom/android/internal/telephony/cat/CatService;->sInstance:[Lcom/android/internal/telephony/cat/CatService; +Lcom/android/internal/telephony/cat/CatService;->sInstanceLock:Ljava/lang/Object; +Lcom/android/internal/telephony/cat/CommandDetails;->commandNumber:I +Lcom/android/internal/telephony/cat/CommandDetails;->commandQualifier:I +Lcom/android/internal/telephony/cat/CommandDetails;->compRequired:Z +Lcom/android/internal/telephony/cat/CommandDetails;->typeOfCommand:I +Lcom/android/internal/telephony/cat/CommandParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;)V +Lcom/android/internal/telephony/cat/CommandParams;->getCommandType()Lcom/android/internal/telephony/cat/AppInterface$CommandType; +Lcom/android/internal/telephony/cat/CommandParams;->mCmdDet:Lcom/android/internal/telephony/cat/CommandDetails; +Lcom/android/internal/telephony/cat/CommandParamsFactory;->dispose()V +Lcom/android/internal/telephony/cat/CommandParamsFactory;->mIconLoader:Lcom/android/internal/telephony/cat/IconLoader; +Lcom/android/internal/telephony/cat/CommandParamsFactory;->searchForNextTag(Lcom/android/internal/telephony/cat/ComprehensionTlvTag;Ljava/util/Iterator;)Lcom/android/internal/telephony/cat/ComprehensionTlv; +Lcom/android/internal/telephony/cat/CommandParamsFactory;->searchForTag(Lcom/android/internal/telephony/cat/ComprehensionTlvTag;Ljava/util/List;)Lcom/android/internal/telephony/cat/ComprehensionTlv; +Lcom/android/internal/telephony/cat/ComprehensionTlv;->getLength()I +Lcom/android/internal/telephony/cat/ComprehensionTlv;->getRawValue()[B +Lcom/android/internal/telephony/cat/ComprehensionTlv;->getTag()I +Lcom/android/internal/telephony/cat/ComprehensionTlv;->getValueIndex()I +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ADDRESS:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ALPHA_ID:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->COMMAND_DETAILS:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->DEVICE_IDENTITIES:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ICON_ID:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->RESULT:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->SMS_TPDU:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->TEXT_ATTRIBUTE:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->TEXT_STRING:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->USSD_STRING:Lcom/android/internal/telephony/cat/ComprehensionTlvTag; +Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->value()I +Lcom/android/internal/telephony/cat/DeviceIdentities;->destinationId:I +Lcom/android/internal/telephony/cat/DisplayTextParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/TextMessage;)V +Lcom/android/internal/telephony/cat/DisplayTextParams;->mTextMsg:Lcom/android/internal/telephony/cat/TextMessage; +Lcom/android/internal/telephony/cat/Duration$TimeUnit;->value()I +Lcom/android/internal/telephony/cat/Duration;->timeInterval:I +Lcom/android/internal/telephony/cat/Duration;->timeUnit:Lcom/android/internal/telephony/cat/Duration$TimeUnit; +Lcom/android/internal/telephony/cat/GetInputParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/Input;)V +Lcom/android/internal/telephony/cat/IconId;->recordNumber:I +Lcom/android/internal/telephony/cat/IconLoader;->loadIcon(ILandroid/os/Message;)V +Lcom/android/internal/telephony/cat/Menu;->titleAttrs:Ljava/util/List; +Lcom/android/internal/telephony/cat/PlayToneParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/TextMessage;Lcom/android/internal/telephony/cat/Tone;Lcom/android/internal/telephony/cat/Duration;Z)V +Lcom/android/internal/telephony/cat/ResponseData;-><init>()V +Lcom/android/internal/telephony/cat/ResponseData;->format(Ljava/io/ByteArrayOutputStream;)V +Lcom/android/internal/telephony/cat/ResultCode;->BACKWARD_MOVE_BY_USER:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->BEYOND_TERMINAL_CAPABILITY:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->BIP_ERROR:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->CMD_DATA_NOT_UNDERSTOOD:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->HELP_INFO_REQUIRED:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->LAUNCH_BROWSER_ERROR:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->NETWORK_CRNTLY_UNABLE_TO_PROCESS:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->NO_RESPONSE_FROM_USER:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->OK:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_ICON_NOT_DISPLAYED:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_LIMITED_SERVICE:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_MODIFIED_BY_NAA:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_NAA_NOT_ACTIVE:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_TONE_NOT_PLAYED:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_ADDITIONAL_EFS_READ:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_MISSING_INFO:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_MODIFICATION:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_PARTIAL_COMPREHENSION:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->REQUIRED_VALUES_MISSING:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->TERMINAL_CRNTLY_UNABLE_TO_PROCESS:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->UICC_SESSION_TERM_BY_USER:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->USER_NOT_ACCEPT:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->USIM_CALL_CONTROL_PERMANENT:Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultCode;->value()I +Lcom/android/internal/telephony/cat/ResultCode;->values()[Lcom/android/internal/telephony/cat/ResultCode; +Lcom/android/internal/telephony/cat/ResultException;-><init>(Lcom/android/internal/telephony/cat/ResultCode;)V +Lcom/android/internal/telephony/cat/RilMessage;-><init>(ILjava/lang/String;)V +Lcom/android/internal/telephony/cat/RilMessage;->mData:Ljava/lang/Object; +Lcom/android/internal/telephony/cat/RilMessage;->mId:I +Lcom/android/internal/telephony/cat/RilMessageDecoder;->getInstance(Landroid/os/Handler;Lcom/android/internal/telephony/uicc/IccFileHandler;I)Lcom/android/internal/telephony/cat/RilMessageDecoder; +Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCmdParamsFactory:Lcom/android/internal/telephony/cat/CommandParamsFactory; +Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCurrentRilMessage:Lcom/android/internal/telephony/cat/RilMessage; +Lcom/android/internal/telephony/cat/RilMessageDecoder;->mInstance:[Lcom/android/internal/telephony/cat/RilMessageDecoder; +Lcom/android/internal/telephony/cat/RilMessageDecoder;->mStateStart:Lcom/android/internal/telephony/cat/RilMessageDecoder$StateStart; +Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendCmdForExecution(Lcom/android/internal/telephony/cat/RilMessage;)V +Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendStartDecodingMessageParams(Lcom/android/internal/telephony/cat/RilMessage;)V +Lcom/android/internal/telephony/cat/SelectItemParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/Menu;Z)V +Lcom/android/internal/telephony/cat/TextMessage;-><init>()V +Lcom/android/internal/telephony/cat/TextMessage;->iconSelfExplanatory:Z +Lcom/android/internal/telephony/cat/TextMessage;->text:Ljava/lang/String; +Lcom/android/internal/telephony/cat/ValueObject;-><init>()V +Lcom/android/internal/telephony/cat/ValueParser;->retrieveAlphaId(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/lang/String; +Lcom/android/internal/telephony/cat/ValueParser;->retrieveDeviceIdentities(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Lcom/android/internal/telephony/cat/DeviceIdentities; +Lcom/android/internal/telephony/cat/ValueParser;->retrieveTextAttribute(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/util/List; +Lcom/android/internal/telephony/cat/ValueParser;->retrieveTextString(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/lang/String; +Lcom/android/internal/telephony/cdma/CdmaCallWaitingNotification;->number:Ljava/lang/String; +Lcom/android/internal/telephony/cdma/CdmaMmiCode;->makeEmptyNull(Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/telephony/cdma/CdmaMmiCode;->mSc:Ljava/lang/String; +Lcom/android/internal/telephony/cdma/CdmaSMSDispatcher;->getFormat()Ljava/lang/String; +Lcom/android/internal/telephony/cdma/CdmaSMSDispatcher;->handleCdmaStatusReport(Lcom/android/internal/telephony/cdma/SmsMessage;)V +Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;->getCdmaSubscriptionSource()I +Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;->getInstance(Landroid/content/Context;Lcom/android/internal/telephony/CommandsInterface;Landroid/os/Handler;ILjava/lang/Object;)Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager; +Lcom/android/internal/telephony/cdma/EriManager$EriDisplayInformation;->mEriIconText:Ljava/lang/String; +Lcom/android/internal/telephony/cdma/EriManager;->getEriDisplayInformation(II)Lcom/android/internal/telephony/cdma/EriManager$EriDisplayInformation; +Lcom/android/internal/telephony/cdma/sms/BearerData$CodingException;-><init>(Ljava/lang/String;)V +Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp;-><init>()V +Lcom/android/internal/telephony/cdma/sms/BearerData;-><init>()V +Lcom/android/internal/telephony/cdma/sms/BearerData;->countAsciiSeptets(Ljava/lang/CharSequence;Z)I +Lcom/android/internal/telephony/cdma/sms/BearerData;->decodeUserDataPayload(Lcom/android/internal/telephony/cdma/sms/UserData;Z)V +Lcom/android/internal/telephony/cdma/sms/BearerData;->displayMode:I +Lcom/android/internal/telephony/cdma/sms/BearerData;->encode(Lcom/android/internal/telephony/cdma/sms/BearerData;)[B +Lcom/android/internal/telephony/cdma/sms/BearerData;->encode7bitAscii(Ljava/lang/String;Z)[B +Lcom/android/internal/telephony/cdma/sms/BearerData;->getBitsForNumFields(II)I +Lcom/android/internal/telephony/cdma/sms/BearerData;->hasUserDataHeader:Z +Lcom/android/internal/telephony/cdma/sms/BearerData;->messageId:I +Lcom/android/internal/telephony/cdma/sms/BearerData;->msgCenterTimeStamp:Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp; +Lcom/android/internal/telephony/cdma/sms/BearerData;->priority:I +Lcom/android/internal/telephony/cdma/sms/BearerData;->priorityIndicatorSet:Z +Lcom/android/internal/telephony/cdma/sms/BearerData;->userData:Lcom/android/internal/telephony/cdma/sms/UserData; +Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;-><init>()V +Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->digitMode:I +Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberMode:I +Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberOfDigits:I +Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->numberPlan:I +Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;->parse(Ljava/lang/String;)Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress; +Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;-><init>()V +Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->bearerData:[B +Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->serviceCategory:I +Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;->teleService:I +Lcom/android/internal/telephony/cdma/sms/UserData;-><init>()V +Lcom/android/internal/telephony/cdma/sms/UserData;->charToAscii:Landroid/util/SparseIntArray; +Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncoding:I +Lcom/android/internal/telephony/cdma/sms/UserData;->msgEncodingSet:Z +Lcom/android/internal/telephony/cdma/sms/UserData;->numFields:I +Lcom/android/internal/telephony/cdma/sms/UserData;->payload:[B +Lcom/android/internal/telephony/cdma/sms/UserData;->payloadStr:Ljava/lang/String; +Lcom/android/internal/telephony/cdma/sms/UserData;->userDataHeader:Lcom/android/internal/telephony/SmsHeader; +Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;-><init>()V +Lcom/android/internal/telephony/cdma/SmsMessage;-><init>()V +Lcom/android/internal/telephony/cdma/SmsMessage;->calculateLength(Ljava/lang/CharSequence;ZZ)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails; +Lcom/android/internal/telephony/cdma/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/cdma/SmsMessage; +Lcom/android/internal/telephony/cdma/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/cdma/SmsMessage; +Lcom/android/internal/telephony/cdma/SmsMessage;->getIncomingSmsFingerprint()[B +Lcom/android/internal/telephony/cdma/SmsMessage;->getMessageType()I +Lcom/android/internal/telephony/cdma/SmsMessage;->getNextMessageId()I +Lcom/android/internal/telephony/cdma/SmsMessage;->getNumOfVoicemails()I +Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;Z)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Lcom/android/internal/telephony/cdma/sms/UserData;ZI)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;I[BZ)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/cdma/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLcom/android/internal/telephony/SmsHeader;I)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/cdma/SmsMessage;->getTeleService()I +Lcom/android/internal/telephony/cdma/SmsMessage;->isStatusReportMessage()Z +Lcom/android/internal/telephony/cdma/SmsMessage;->mBearerData:Lcom/android/internal/telephony/cdma/sms/BearerData; +Lcom/android/internal/telephony/cdma/SmsMessage;->mEnvelope:Lcom/android/internal/telephony/cdma/sms/SmsEnvelope; +Lcom/android/internal/telephony/cdma/SmsMessage;->parseSms()V +Lcom/android/internal/telephony/cdma/SmsMessage;->privateGetSubmitPdu(Ljava/lang/String;ZLcom/android/internal/telephony/cdma/sms/UserData;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/CommandException$Error;->GENERIC_FAILURE:Lcom/android/internal/telephony/CommandException$Error; +Lcom/android/internal/telephony/CommandException$Error;->PASSWORD_INCORRECT:Lcom/android/internal/telephony/CommandException$Error; +Lcom/android/internal/telephony/CommandException$Error;->RADIO_NOT_AVAILABLE:Lcom/android/internal/telephony/CommandException$Error; +Lcom/android/internal/telephony/CommandException$Error;->REQUEST_NOT_SUPPORTED:Lcom/android/internal/telephony/CommandException$Error; +Lcom/android/internal/telephony/CommandException$Error;->SIM_PUK2:Lcom/android/internal/telephony/CommandException$Error; +Lcom/android/internal/telephony/CommandException$Error;->SMS_FAIL_RETRY:Lcom/android/internal/telephony/CommandException$Error; +Lcom/android/internal/telephony/CommandException;-><init>(Lcom/android/internal/telephony/CommandException$Error;)V +Lcom/android/internal/telephony/CommandException;->fromRilErrno(I)Lcom/android/internal/telephony/CommandException; +Lcom/android/internal/telephony/CommandException;->getCommandError()Lcom/android/internal/telephony/CommandException$Error; +Lcom/android/internal/telephony/CommandException;->mError:Lcom/android/internal/telephony/CommandException$Error; +Lcom/android/internal/telephony/CommandsInterface;->acceptCall(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->acknowledgeLastIncomingCdmaSms(ZILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->acknowledgeLastIncomingGsmSms(ZILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->changeBarringPassword(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnRuim(ILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnSim(ILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->dial(Ljava/lang/String;ILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->dial(Ljava/lang/String;ILcom/android/internal/telephony/UUSInfo;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->exitEmergencyCallbackMode(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getBasebandVersion(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getCdmaBroadcastConfig(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getCDMASubscription(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getDataCallList(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getIccCardStatus(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getIMEISV(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getIMSI(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getLastDataCallFailCause(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getLastPdpFailCause(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getNetworkSelectionMode(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getOperator(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getPDPContextList(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getPreferredNetworkType(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getSignalStrength(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getSmscAddress(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->getVoiceRegistrationState(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->handleCallSetupRequestFromSim(ZLandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->iccIO(IILjava/lang/String;IIILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->iccIOForApp(IILjava/lang/String;IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->invokeOemRilRequestRaw([BLandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->queryCallForwardStatus(IILjava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->queryCallWaiting(ILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->queryFacilityLock(Ljava/lang/String;Ljava/lang/String;ILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->queryTTYMode(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForAvailable(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForCdmaOtaProvision(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForCellInfoList(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForIccRefresh(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForImsNetworkStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForNotAvailable(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForOffOrNotAvailable(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForOn(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForRadioStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->registerForRilConnected(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->reportSmsMemoryStatus(ZLandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->reportStkServiceIsRunning(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->requestIccSimAuthentication(ILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->requestShutdown(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->sendDtmf(CLandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->sendEnvelope(Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->sendTerminalResponse(Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setCallForward(IIILjava/lang/String;ILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setCallWaiting(ZILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setCdmaBroadcastActivation(ZLandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setDataAllowed(ZLandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setEmergencyCallbackMode(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setFacilityLock(Ljava/lang/String;ZLjava/lang/String;ILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setNetworkSelectionModeAutomatic(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setNetworkSelectionModeManual(Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnCallRing(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnCatCallSetUp(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnCatCcAlphaNotify(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnCatEvent(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnCatProactiveCmd(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnCatSessionEnd(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnIccRefresh(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnIccSmsFull(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnNewGsmBroadcastSms(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnNITZTime(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnSignalStrengthUpdate(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnSmsOnSim(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnSmsStatus(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setOnSuppServiceNotification(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/CommandsInterface;->setPhoneType(I)V +Lcom/android/internal/telephony/CommandsInterface;->setPreferredNetworkType(ILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setRadioPower(ZLandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setSmscAddress(Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setTTYMode(ILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->setUiccSubscription(IIIILandroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->supplyIccPin(Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->switchWaitingOrHoldingAndActive(Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->unregisterForAvailable(Landroid/os/Handler;)V +Lcom/android/internal/telephony/CommandsInterface;->unregisterForCdmaOtaProvision(Landroid/os/Handler;)V +Lcom/android/internal/telephony/CommandsInterface;->unregisterForOffOrNotAvailable(Landroid/os/Handler;)V +Lcom/android/internal/telephony/CommandsInterface;->unregisterForOn(Landroid/os/Handler;)V +Lcom/android/internal/telephony/CommandsInterface;->unregisterForRilConnected(Landroid/os/Handler;)V +Lcom/android/internal/telephony/CommandsInterface;->unregisterForVoiceRadioTechChanged(Landroid/os/Handler;)V +Lcom/android/internal/telephony/CommandsInterface;->writeSmsToRuim(ILjava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/CommandsInterface;->writeSmsToSim(ILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/Connection$PostDialState;->CANCELLED:Lcom/android/internal/telephony/Connection$PostDialState; +Lcom/android/internal/telephony/Connection$PostDialState;->COMPLETE:Lcom/android/internal/telephony/Connection$PostDialState; +Lcom/android/internal/telephony/Connection$PostDialState;->NOT_STARTED:Lcom/android/internal/telephony/Connection$PostDialState; +Lcom/android/internal/telephony/Connection$PostDialState;->STARTED:Lcom/android/internal/telephony/Connection$PostDialState; +Lcom/android/internal/telephony/Connection$PostDialState;->WAIT:Lcom/android/internal/telephony/Connection$PostDialState; +Lcom/android/internal/telephony/Connection$PostDialState;->WILD:Lcom/android/internal/telephony/Connection$PostDialState; +Lcom/android/internal/telephony/Connection;-><init>(I)V +Lcom/android/internal/telephony/Connection;->getAddress()Ljava/lang/String; +Lcom/android/internal/telephony/Connection;->getCall()Lcom/android/internal/telephony/Call; +Lcom/android/internal/telephony/Connection;->getConnectTime()J +Lcom/android/internal/telephony/Connection;->getCreateTime()J +Lcom/android/internal/telephony/Connection;->getDisconnectCause()I +Lcom/android/internal/telephony/Connection;->getDisconnectTime()J +Lcom/android/internal/telephony/Connection;->getDurationMillis()J +Lcom/android/internal/telephony/Connection;->getState()Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/Connection;->getUserData()Ljava/lang/Object; +Lcom/android/internal/telephony/Connection;->hangup()V +Lcom/android/internal/telephony/Connection;->isAlive()Z +Lcom/android/internal/telephony/Connection;->isIncoming()Z +Lcom/android/internal/telephony/Connection;->LOG_TAG:Ljava/lang/String; +Lcom/android/internal/telephony/Connection;->mAddress:Ljava/lang/String; +Lcom/android/internal/telephony/Connection;->mCnapName:Ljava/lang/String; +Lcom/android/internal/telephony/Connection;->mCnapNamePresentation:I +Lcom/android/internal/telephony/Connection;->mDialString:Ljava/lang/String; +Lcom/android/internal/telephony/Connection;->mDuration:J +Lcom/android/internal/telephony/Connection;->mIsIncoming:Z +Lcom/android/internal/telephony/Connection;->mNumberPresentation:I +Lcom/android/internal/telephony/Connection;->setVideoState(I)V +Lcom/android/internal/telephony/dataconnection/ApnContext;->getApnType()Ljava/lang/String; +Lcom/android/internal/telephony/dataconnection/ApnContext;->getReason()Ljava/lang/String; +Lcom/android/internal/telephony/dataconnection/ApnContext;->getState()Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/dataconnection/ApnContext;->isConnectable()Z +Lcom/android/internal/telephony/dataconnection/ApnContext;->isDisconnected()Z +Lcom/android/internal/telephony/dataconnection/ApnContext;->isEnabled()Z +Lcom/android/internal/telephony/dataconnection/ApnContext;->isReady()Z +Lcom/android/internal/telephony/dataconnection/ApnContext;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/ApnContext;->mApnType:Ljava/lang/String; +Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCount:I +Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCountLock:Ljava/lang/Object; +Lcom/android/internal/telephony/dataconnection/ApnContext;->setState(Lcom/android/internal/telephony/DctConstants$State;)V +Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;->mApnContext:Lcom/android/internal/telephony/dataconnection/ApnContext; +Lcom/android/internal/telephony/dataconnection/DataConnection;->clearSettings()V +Lcom/android/internal/telephony/dataconnection/DataConnection;->dumpToLog()V +Lcom/android/internal/telephony/dataconnection/DataConnection;->initConnection(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)Z +Lcom/android/internal/telephony/dataconnection/DataConnection;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DataConnection;->mActivatingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActivatingState; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mActiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mApnContexts:Ljava/util/HashMap; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mConnectionParams:Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mDataRegState:I +Lcom/android/internal/telephony/dataconnection/DataConnection;->mDcFailCause:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingErrorCreatingConnection:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectionErrorCreatingConnection; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectingState; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectParams:Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mId:I +Lcom/android/internal/telephony/dataconnection/DataConnection;->mInactiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcInactiveState; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mLinkProperties:Landroid/net/LinkProperties; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mNetworkInfo:Landroid/net/NetworkInfo; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mPhone:Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/dataconnection/DataConnection;->mRilRat:I +Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DcFailCause;)V +Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfConnected(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfDisconnectDcRetrying(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyConnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;Lcom/android/internal/telephony/dataconnection/DcFailCause;Z)V +Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;Z)V +Lcom/android/internal/telephony/dataconnection/DataConnection;->onConnect(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)V +Lcom/android/internal/telephony/dataconnection/DataConnection;->tearDownData(Ljava/lang/Object;)V +Lcom/android/internal/telephony/dataconnection/DataConnection;->updateTcpBufferSizes(I)V +Lcom/android/internal/telephony/dataconnection/DcController;->lr(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DcController;->mDcListActiveByCid:Ljava/util/HashMap; +Lcom/android/internal/telephony/dataconnection/DcController;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker; +Lcom/android/internal/telephony/dataconnection/DcController;->mDcTesterDeactivateAll:Lcom/android/internal/telephony/dataconnection/DcTesterDeactivateAll; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_GGSN:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_UNSPECIFIED:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->APN_TYPE_CONFLICT:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->INSUFFICIENT_RESOURCES:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->MISSING_UNKNOWN_APN:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->NSAPI_IN_USE:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV4_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV6_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_SINGLE_BEARER_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->OPERATOR_BARRED:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->PROTOCOL_ERRORS:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUBSCRIBED:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUPPORTED:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_OUT_OF_ORDER:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->UNKNOWN_PDP_ADDRESS_TYPE:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcFailCause;->USER_AUTHENTICATION:Lcom/android/internal/telephony/dataconnection/DcFailCause; +Lcom/android/internal/telephony/dataconnection/DcTracker$RecoveryAction;->isAggressiveRecovery(I)Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->cancelReconnectAlarm(Lcom/android/internal/telephony/dataconnection/ApnContext;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(ZLjava/lang/String;)Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpConnection(ZLcom/android/internal/telephony/dataconnection/ApnContext;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->createAllApnList()V +Lcom/android/internal/telephony/dataconnection/DcTracker;->getActiveApnTypes()[Ljava/lang/String; +Lcom/android/internal/telephony/dataconnection/DcTracker;->getOverallState()Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/dataconnection/DcTracker;->getUiccRecords(I)Lcom/android/internal/telephony/uicc/IccRecords; +Lcom/android/internal/telephony/dataconnection/DcTracker;->isConnected()Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->isDisconnected()Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->isOnlySingleDcAllowed(I)Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->mAllApnSettings:Ljava/util/ArrayList; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mApnContexts:Ljava/util/concurrent/ConcurrentHashMap; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mAttached:Ljava/util/concurrent/atomic/AtomicBoolean; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mAutoAttachOnCreation:Ljava/util/concurrent/atomic/AtomicBoolean; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mDataConnectionTracker:Landroid/os/Handler; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mDisconnectPendingCount:I +Lcom/android/internal/telephony/dataconnection/DcTracker;->mIccRecords:Ljava/util/concurrent/atomic/AtomicReference; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsPsRestricted:Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsScreenOn:Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollEnabled:Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollPeriod:I +Lcom/android/internal/telephony/dataconnection/DcTracker;->mPhone:Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mPrioritySortedApnContexts:Ljava/util/PriorityQueue; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mProvisioningSpinner:Landroid/app/ProgressDialog; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mResolver:Landroid/content/ContentResolver; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mState:Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/dataconnection/DcTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager; +Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyDataConnection(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyOffApnsOfAvailability(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentDataStallAlarm(Landroid/content/Intent;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentProvisioningApnAlarm(Landroid/content/Intent;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->onCleanUpAllConnections(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->onRecordsLoadedOrSubIdChanged()V +Lcom/android/internal/telephony/dataconnection/DcTracker;->onSetUserDataEnabled(Z)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Lcom/android/internal/telephony/dataconnection/ApnContext;)Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Ljava/lang/String;)Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->registerForAllDataDisconnected(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->registerSettingsObserver()V +Lcom/android/internal/telephony/dataconnection/DcTracker;->resetPollStats()V +Lcom/android/internal/telephony/dataconnection/DcTracker;->restartDataStallAlarm()V +Lcom/android/internal/telephony/dataconnection/DcTracker;->setInitialAttachApn()V +Lcom/android/internal/telephony/dataconnection/DcTracker;->setInternalDataEnabled(ZLandroid/os/Message;)Z +Lcom/android/internal/telephony/dataconnection/DcTracker;->setPreferredApn(I)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->setRadio(Z)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->setupDataOnConnectableApns(Ljava/lang/String;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->startDataStallAlarm(Z)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->startNetStatPoll()V +Lcom/android/internal/telephony/dataconnection/DcTracker;->stopDataStallAlarm()V +Lcom/android/internal/telephony/dataconnection/DcTracker;->stopNetStatPoll()V +Lcom/android/internal/telephony/dataconnection/DcTracker;->unregisterForAllDataDisconnected(Landroid/os/Handler;)V +Lcom/android/internal/telephony/dataconnection/DcTracker;->updateRecords()V +Lcom/android/internal/telephony/DctConstants$Activity;->DATAIN:Lcom/android/internal/telephony/DctConstants$Activity; +Lcom/android/internal/telephony/DctConstants$Activity;->DATAINANDOUT:Lcom/android/internal/telephony/DctConstants$Activity; +Lcom/android/internal/telephony/DctConstants$Activity;->DATAOUT:Lcom/android/internal/telephony/DctConstants$Activity; +Lcom/android/internal/telephony/DctConstants$Activity;->DORMANT:Lcom/android/internal/telephony/DctConstants$Activity; +Lcom/android/internal/telephony/DctConstants$Activity;->values()[Lcom/android/internal/telephony/DctConstants$Activity; +Lcom/android/internal/telephony/DctConstants$State;->CONNECTED:Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/DctConstants$State;->CONNECTING:Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/DctConstants$State;->DISCONNECTING:Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/DctConstants$State;->FAILED:Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/DctConstants$State;->IDLE:Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/DctConstants$State;->RETRYING:Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/DctConstants$State;->SCANNING:Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/DctConstants$State;->values()[Lcom/android/internal/telephony/DctConstants$State; +Lcom/android/internal/telephony/DefaultPhoneNotifier;->mRegistry:Lcom/android/internal/telephony/ITelephonyRegistry; +Lcom/android/internal/telephony/DriverCall$State;->ACTIVE:Lcom/android/internal/telephony/DriverCall$State; +Lcom/android/internal/telephony/DriverCall$State;->ALERTING:Lcom/android/internal/telephony/DriverCall$State; +Lcom/android/internal/telephony/DriverCall$State;->DIALING:Lcom/android/internal/telephony/DriverCall$State; +Lcom/android/internal/telephony/DriverCall$State;->HOLDING:Lcom/android/internal/telephony/DriverCall$State; +Lcom/android/internal/telephony/DriverCall$State;->INCOMING:Lcom/android/internal/telephony/DriverCall$State; +Lcom/android/internal/telephony/DriverCall$State;->values()[Lcom/android/internal/telephony/DriverCall$State; +Lcom/android/internal/telephony/DriverCall$State;->WAITING:Lcom/android/internal/telephony/DriverCall$State; +Lcom/android/internal/telephony/DriverCall;-><init>()V +Lcom/android/internal/telephony/DriverCall;->index:I +Lcom/android/internal/telephony/DriverCall;->isMT:Z +Lcom/android/internal/telephony/DriverCall;->isVoice:Z +Lcom/android/internal/telephony/DriverCall;->name:Ljava/lang/String; +Lcom/android/internal/telephony/DriverCall;->number:Ljava/lang/String; +Lcom/android/internal/telephony/DriverCall;->numberPresentation:I +Lcom/android/internal/telephony/DriverCall;->state:Lcom/android/internal/telephony/DriverCall$State; +Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;-><init>(Lcom/android/internal/telephony/gsm/SmsCbHeader;Landroid/telephony/SmsCbLocation;)V +Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;->matchesLocation(Ljava/lang/String;II)Z +Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler;->mSmsCbPageMap:Ljava/util/HashMap; +Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;->acknowledgeLastIncomingSms(ZILandroid/os/Message;)V +Lcom/android/internal/telephony/gsm/GsmMmiCode;-><init>(Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)V +Lcom/android/internal/telephony/gsm/GsmMmiCode;->getCLIRMode()I +Lcom/android/internal/telephony/gsm/GsmMmiCode;->getScString()Ljava/lang/CharSequence; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->isActivate()Z +Lcom/android/internal/telephony/gsm/GsmMmiCode;->isDeactivate()Z +Lcom/android/internal/telephony/gsm/GsmMmiCode;->isErasure()Z +Lcom/android/internal/telephony/gsm/GsmMmiCode;->isInterrogate()Z +Lcom/android/internal/telephony/gsm/GsmMmiCode;->isRegister()Z +Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallBarring(Ljava/lang/String;)Z +Lcom/android/internal/telephony/gsm/GsmMmiCode;->isServiceCodeCallForwarding(Ljava/lang/String;)Z +Lcom/android/internal/telephony/gsm/GsmMmiCode;->isTemporaryModeCLIR()Z +Lcom/android/internal/telephony/gsm/GsmMmiCode;->makeEmptyNull(Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->mDialingNumber:Ljava/lang/String; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSc:Ljava/lang/String; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSia:Ljava/lang/String; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSib:Ljava/lang/String; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->mSic:Ljava/lang/String; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->newFromDialString(Ljava/lang/String;Lcom/android/internal/telephony/GsmCdmaPhone;Lcom/android/internal/telephony/uicc/UiccCardApplication;)Lcom/android/internal/telephony/gsm/GsmMmiCode; +Lcom/android/internal/telephony/gsm/GsmMmiCode;->processCode()V +Lcom/android/internal/telephony/gsm/GsmMmiCode;->siToServiceClass(Ljava/lang/String;)I +Lcom/android/internal/telephony/gsm/GsmMmiCode;->sPatternSuppService:Ljava/util/regex/Pattern; +Lcom/android/internal/telephony/gsm/GsmSmsAddress;-><init>([BII)V +Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageClear()Z +Lcom/android/internal/telephony/gsm/GsmSmsAddress;->isCphsVoiceMessageSet()Z +Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->getFormat()Ljava/lang/String; +Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->mGsmInboundSmsHandler:Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler; +Lcom/android/internal/telephony/gsm/GsmSMSDispatcher;->sendSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V +Lcom/android/internal/telephony/gsm/SimTlv;-><init>([BII)V +Lcom/android/internal/telephony/gsm/SimTlv;->getData()[B +Lcom/android/internal/telephony/gsm/SimTlv;->getTag()I +Lcom/android/internal/telephony/gsm/SimTlv;->isValidObject()Z +Lcom/android/internal/telephony/gsm/SimTlv;->mHasValidTlvObject:Z +Lcom/android/internal/telephony/gsm/SimTlv;->nextObject()Z +Lcom/android/internal/telephony/gsm/SmsCbHeader;-><init>([B)V +Lcom/android/internal/telephony/gsm/SmsCbHeader;->getGeographicalScope()I +Lcom/android/internal/telephony/gsm/SmsCbHeader;->getNumberOfPages()I +Lcom/android/internal/telephony/gsm/SmsCbHeader;->getPageIndex()I +Lcom/android/internal/telephony/gsm/SmsCbHeader;->getSerialNumber()I +Lcom/android/internal/telephony/gsm/SmsCbHeader;->getServiceCategory()I +Lcom/android/internal/telephony/gsm/SmsCbHeader;->mMessageIdentifier:I +Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;-><init>([B)V +Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getByte()I +Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserData()[B +Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->getUserDataUCS2(I)Ljava/lang/String; +Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mCur:I +Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mPdu:[B +Lcom/android/internal/telephony/gsm/SmsMessage$PduParser;->mUserDataSeptetPadding:I +Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;-><init>()V +Lcom/android/internal/telephony/gsm/SmsMessage;-><init>()V +Lcom/android/internal/telephony/gsm/SmsMessage;->calculateLength(Ljava/lang/CharSequence;Z)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails; +Lcom/android/internal/telephony/gsm/SmsMessage;->createFromEfRecord(I[B)Lcom/android/internal/telephony/gsm/SmsMessage; +Lcom/android/internal/telephony/gsm/SmsMessage;->createFromPdu([B)Lcom/android/internal/telephony/gsm/SmsMessage; +Lcom/android/internal/telephony/gsm/SmsMessage;->encodeUCS2(Ljava/lang/String;[B)[B +Lcom/android/internal/telephony/gsm/SmsMessage;->getStatus()I +Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZI)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[B)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPdu(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z[BIIII)Lcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu; +Lcom/android/internal/telephony/gsm/SmsMessage;->getSubmitPduHead(Ljava/lang/String;Ljava/lang/String;BZLcom/android/internal/telephony/gsm/SmsMessage$SubmitPdu;)Ljava/io/ByteArrayOutputStream; +Lcom/android/internal/telephony/gsm/SmsMessage;->isMWIClearMessage()Z +Lcom/android/internal/telephony/gsm/SmsMessage;->isMwiDontStore()Z +Lcom/android/internal/telephony/gsm/SmsMessage;->isMWISetMessage()Z +Lcom/android/internal/telephony/gsm/SmsMessage;->isStatusReportMessage()Z +Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->loadEfFilesFromUsim()Ljava/util/ArrayList; +Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler; +Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mLock:Ljava/lang/Object; +Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mPhoneBookRecords:Ljava/util/ArrayList; +Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->reset()V Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;-><init>()V +Lcom/android/internal/telephony/GsmCdmaCall;->attachFake(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V +Lcom/android/internal/telephony/GsmCdmaCallTracker;->clearDisconnected()V +Lcom/android/internal/telephony/GsmCdmaCallTracker;->dialThreeWay(Ljava/lang/String;)Lcom/android/internal/telephony/Connection; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->disableDataCallInEmergencyCall(Ljava/lang/String;)V +Lcom/android/internal/telephony/GsmCdmaCallTracker;->fakeHoldForegroundBeforeDial()V +Lcom/android/internal/telephony/GsmCdmaCallTracker;->getPhone()Lcom/android/internal/telephony/GsmCdmaPhone; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->handleEcmTimer(I)V +Lcom/android/internal/telephony/GsmCdmaCallTracker;->isPhoneTypeGsm()Z +Lcom/android/internal/telephony/GsmCdmaCallTracker;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/GsmCdmaCallTracker;->mBackgroundCall:Lcom/android/internal/telephony/GsmCdmaCall; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->mForegroundCall:Lcom/android/internal/telephony/GsmCdmaCall; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->mPendingMO:Lcom/android/internal/telephony/GsmCdmaConnection; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->mRingingCall:Lcom/android/internal/telephony/GsmCdmaCall; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->mState:Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->obtainCompleteMessage()Landroid/os/Message; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->obtainCompleteMessage(I)Landroid/os/Message; +Lcom/android/internal/telephony/GsmCdmaCallTracker;->setMute(Z)V +Lcom/android/internal/telephony/GsmCdmaCallTracker;->switchWaitingOrHoldingAndActive()V +Lcom/android/internal/telephony/GsmCdmaCallTracker;->updatePhoneState()V +Lcom/android/internal/telephony/GsmCdmaConnection$MyHandler;-><init>(Lcom/android/internal/telephony/GsmCdmaConnection;Landroid/os/Looper;)V +Lcom/android/internal/telephony/GsmCdmaConnection;->acquireWakeLock()V +Lcom/android/internal/telephony/GsmCdmaConnection;->createWakeLock(Landroid/content/Context;)V +Lcom/android/internal/telephony/GsmCdmaConnection;->disconnectCauseFromCode(I)I +Lcom/android/internal/telephony/GsmCdmaConnection;->fetchDtmfToneDelay(Lcom/android/internal/telephony/GsmCdmaPhone;)V +Lcom/android/internal/telephony/GsmCdmaConnection;->findNextPCharOrNonPOrNonWCharIndex(Ljava/lang/String;I)I +Lcom/android/internal/telephony/GsmCdmaConnection;->findPOrWCharToAppend(Ljava/lang/String;II)C +Lcom/android/internal/telephony/GsmCdmaConnection;->formatDialString(Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/telephony/GsmCdmaConnection;->getState()Lcom/android/internal/telephony/Call$State; +Lcom/android/internal/telephony/GsmCdmaConnection;->isPause(C)Z +Lcom/android/internal/telephony/GsmCdmaConnection;->isPhoneTypeGsm()Z +Lcom/android/internal/telephony/GsmCdmaConnection;->isWait(C)Z +Lcom/android/internal/telephony/GsmCdmaConnection;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/GsmCdmaConnection;->maskDialString(Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/telephony/GsmCdmaConnection;->mIndex:I +Lcom/android/internal/telephony/GsmCdmaConnection;->mOwner:Lcom/android/internal/telephony/GsmCdmaCallTracker; +Lcom/android/internal/telephony/GsmCdmaConnection;->onConnectedInOrOut()V +Lcom/android/internal/telephony/GsmCdmaConnection;->updateParent(Lcom/android/internal/telephony/GsmCdmaCall;Lcom/android/internal/telephony/GsmCdmaCall;)V +Lcom/android/internal/telephony/GsmCdmaPhone$Cfu;-><init>(Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/GsmCdmaPhone;->exitEmergencyCallbackMode()V +Lcom/android/internal/telephony/GsmCdmaPhone;->getCallTracker()Lcom/android/internal/telephony/CallTracker; +Lcom/android/internal/telephony/GsmCdmaPhone;->getCdmaEriText()Ljava/lang/String; +Lcom/android/internal/telephony/GsmCdmaPhone;->getEsn()Ljava/lang/String; +Lcom/android/internal/telephony/GsmCdmaPhone;->getLine1Number()Ljava/lang/String; +Lcom/android/internal/telephony/GsmCdmaPhone;->getPhoneType()I +Lcom/android/internal/telephony/GsmCdmaPhone;->getServiceState()Landroid/telephony/ServiceState; +Lcom/android/internal/telephony/GsmCdmaPhone;->getState()Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/GsmCdmaPhone;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/telephony/GsmCdmaPhone;->handleInCallMmiCommands(Ljava/lang/String;)Z +Lcom/android/internal/telephony/GsmCdmaPhone;->isCfEnable(I)Z +Lcom/android/internal/telephony/GsmCdmaPhone;->isEriFileLoaded()Z +Lcom/android/internal/telephony/GsmCdmaPhone;->isInCall()Z +Lcom/android/internal/telephony/GsmCdmaPhone;->isManualSelProhibitedInGlobalMode()Z +Lcom/android/internal/telephony/GsmCdmaPhone;->isPhoneTypeGsm()Z +Lcom/android/internal/telephony/GsmCdmaPhone;->isValidCommandInterfaceCFAction(I)Z +Lcom/android/internal/telephony/GsmCdmaPhone;->isValidCommandInterfaceCFReason(I)Z +Lcom/android/internal/telephony/GsmCdmaPhone;->logd(Ljava/lang/String;)V +Lcom/android/internal/telephony/GsmCdmaPhone;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/GsmCdmaPhone;->mCT:Lcom/android/internal/telephony/GsmCdmaCallTracker; +Lcom/android/internal/telephony/GsmCdmaPhone;->mEcmExitRespRegistrant:Landroid/os/Registrant; +Lcom/android/internal/telephony/GsmCdmaPhone;->mEriManager:Lcom/android/internal/telephony/cdma/EriManager; +Lcom/android/internal/telephony/GsmCdmaPhone;->mIccSmsInterfaceManager:Lcom/android/internal/telephony/IccSmsInterfaceManager; +Lcom/android/internal/telephony/GsmCdmaPhone;->mIsimUiccRecords:Lcom/android/internal/telephony/uicc/IsimUiccRecords; +Lcom/android/internal/telephony/GsmCdmaPhone;->mPendingMMIs:Ljava/util/ArrayList; +Lcom/android/internal/telephony/GsmCdmaPhone;->mSST:Lcom/android/internal/telephony/ServiceStateTracker; +Lcom/android/internal/telephony/GsmCdmaPhone;->notifyPreciseCallStateChanged()V +Lcom/android/internal/telephony/GsmCdmaPhone;->notifyServiceStateChanged(Landroid/telephony/ServiceState;)V +Lcom/android/internal/telephony/GsmCdmaPhone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/GsmCdmaPhone;->syncClirSetting()V Lcom/android/internal/telephony/ICarrierConfigLoader;->getConfigForSubId(ILjava/lang/String;)Landroid/os/PersistableBundle; +Lcom/android/internal/telephony/IccCard;->getState()Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCard;->registerForNetworkLocked(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/IccCard;->supplyNetworkDepersonalization(Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/IccCard;->supplyPin(Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/IccCard;->supplyPuk(Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/IccCardConstants$State;->ABSENT:Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCardConstants$State;->CARD_IO_ERROR:Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCardConstants$State;->NETWORK_LOCKED:Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCardConstants$State;->NOT_READY:Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCardConstants$State;->PERM_DISABLED:Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCardConstants$State;->PIN_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCardConstants$State;->PUK_REQUIRED:Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCardConstants$State;->READY:Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCardConstants$State;->UNKNOWN:Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccCardConstants$State;->values()[Lcom/android/internal/telephony/IccCardConstants$State; +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->checkThread()V +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->DBG:Z +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->logd(Ljava/lang/String;)V +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mAdnCache:Lcom/android/internal/telephony/uicc/AdnRecordCache; +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mBaseHandler:Landroid/os/Handler; +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mCurrentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication; +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mIs3gCard:Z +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mLock:Ljava/lang/Object; +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mPhone:Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mRecords:Ljava/util/List; +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mRecordSize:[I +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mSuccess:Z +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->updateEfForIccType(I)I +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->waitForResult(Ljava/util/concurrent/atomic/AtomicBoolean;)V +Lcom/android/internal/telephony/IccProvider;-><init>()V +Lcom/android/internal/telephony/IccProvider;->ADDRESS_BOOK_COLUMN_NAMES:[Ljava/lang/String; +Lcom/android/internal/telephony/IccProvider;->DBG:Z +Lcom/android/internal/telephony/IccProvider;->loadRecord(Lcom/android/internal/telephony/uicc/AdnRecord;Landroid/database/MatrixCursor;I)V +Lcom/android/internal/telephony/IccProvider;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/IccSmsInterfaceManager;->copyMessageToIccEf(Ljava/lang/String;I[B[B)Z +Lcom/android/internal/telephony/IccSmsInterfaceManager;->disableCdmaBroadcastRange(II)Z +Lcom/android/internal/telephony/IccSmsInterfaceManager;->disableGsmBroadcastRange(II)Z +Lcom/android/internal/telephony/IccSmsInterfaceManager;->enableCdmaBroadcastRange(II)Z +Lcom/android/internal/telephony/IccSmsInterfaceManager;->enableGsmBroadcastRange(II)Z +Lcom/android/internal/telephony/IccSmsInterfaceManager;->enforceReceiveAndSend(Ljava/lang/String;)V +Lcom/android/internal/telephony/IccSmsInterfaceManager;->filterDestAddress(Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->getAllMessagesFromIccEf(Ljava/lang/String;)Ljava/util/List; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->getImsSmsFormat()Ljava/lang/String; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->getPremiumSmsPermission(Ljava/lang/String;)I +Lcom/android/internal/telephony/IccSmsInterfaceManager;->injectSmsPdu([BLjava/lang/String;Landroid/app/PendingIntent;)V +Lcom/android/internal/telephony/IccSmsInterfaceManager;->isImsSmsSupported()Z +Lcom/android/internal/telephony/IccSmsInterfaceManager;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/IccSmsInterfaceManager;->mAppOps:Landroid/app/AppOpsManager; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->mCellBroadcastRangeManager:Lcom/android/internal/telephony/IccSmsInterfaceManager$CellBroadcastRangeManager; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->mHandler:Landroid/os/Handler; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->mLock:Ljava/lang/Object; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->mPhone:Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->mSms:Ljava/util/List; +Lcom/android/internal/telephony/IccSmsInterfaceManager;->mSuccess:Z +Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendData(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V +Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendStoredMultipartText(Ljava/lang/String;Landroid/net/Uri;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V +Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendStoredText(Ljava/lang/String;Landroid/net/Uri;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)V +Lcom/android/internal/telephony/IccSmsInterfaceManager;->setCdmaBroadcastConfig([Lcom/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo;)Z +Lcom/android/internal/telephony/IccSmsInterfaceManager;->setCellBroadcastConfig([Lcom/android/internal/telephony/gsm/SmsBroadcastConfigInfo;)Z +Lcom/android/internal/telephony/IccSmsInterfaceManager;->setPremiumSmsPermission(Ljava/lang/String;I)V +Lcom/android/internal/telephony/IccSmsInterfaceManager;->updateMessageOnIccEf(Ljava/lang/String;II[B)Z +Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;->mRemote:Landroid/os/IBinder; +Lcom/android/internal/telephony/IIccPhoneBook$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IIccPhoneBook; +Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEf(I)Ljava/util/List; +Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEfForSubscriber(II)Ljava/util/List; +Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSize(I)[I +Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSizeForSubscriber(II)[I +Lcom/android/internal/telephony/IIccPhoneBook;->updateAdnRecordsInEfBySearch(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z Lcom/android/internal/telephony/IMms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IMms; +Lcom/android/internal/telephony/imsphone/ImsExternalCall;-><init>(Lcom/android/internal/telephony/Phone;Lcom/android/internal/telephony/imsphone/ImsExternalConnection;)V +Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalCallStateListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V +Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalConnectionListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V +Lcom/android/internal/telephony/imsphone/ImsExternalConnection;->rebuildCapabilities()V +Lcom/android/internal/telephony/imsphone/ImsExternalConnection;->setActive()V +Lcom/android/internal/telephony/imsphone/ImsPhone$Cf;-><init>(Ljava/lang/String;ZLandroid/os/Message;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->getActionFromCFAction(I)I +Lcom/android/internal/telephony/imsphone/ImsPhone;->getBackgroundCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall; +Lcom/android/internal/telephony/imsphone/ImsPhone;->getCallForwardingOption(ILandroid/os/Message;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->getCallWaiting(Landroid/os/Message;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->getConditionFromCFReason(I)I +Lcom/android/internal/telephony/imsphone/ImsPhone;->getForegroundCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall; +Lcom/android/internal/telephony/imsphone/ImsPhone;->getRingingCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall; +Lcom/android/internal/telephony/imsphone/ImsPhone;->getServiceState()Landroid/telephony/ServiceState; +Lcom/android/internal/telephony/imsphone/ImsPhone;->getState()Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/imsphone/ImsPhone;->handleEnterEmergencyCallbackMode()V +Lcom/android/internal/telephony/imsphone/ImsPhone;->handleExitEmergencyCallbackMode()V +Lcom/android/internal/telephony/imsphone/ImsPhone;->handleInCallMmiCommands(Ljava/lang/String;)Z +Lcom/android/internal/telephony/imsphone/ImsPhone;->isCfEnable(I)Z +Lcom/android/internal/telephony/imsphone/ImsPhone;->isUtEnabled()Z +Lcom/android/internal/telephony/imsphone/ImsPhone;->isValidCommandInterfaceCFAction(I)Z +Lcom/android/internal/telephony/imsphone/ImsPhone;->isValidCommandInterfaceCFReason(I)Z +Lcom/android/internal/telephony/imsphone/ImsPhone;->isVolteEnabled()Z +Lcom/android/internal/telephony/imsphone/ImsPhone;->mCT:Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker; +Lcom/android/internal/telephony/imsphone/ImsPhone;->mPendingMMIs:Ljava/util/ArrayList; +Lcom/android/internal/telephony/imsphone/ImsPhone;->mSS:Landroid/telephony/ServiceState; +Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyCallForwardingIndicator()V +Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyPreciseCallStateChanged()V +Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyUnknownConnection(Lcom/android/internal/telephony/Connection;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->onMMIDone(Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->sendErrorResponse(Landroid/os/Message;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->sendErrorResponse(Landroid/os/Message;Ljava/lang/Throwable;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->setCallForwardingOption(IILjava/lang/String;IILandroid/os/Message;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->setCallWaiting(ZLandroid/os/Message;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->setImsRegistered(Z)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/imsphone/ImsPhone;->setServiceState(I)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->attach(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->attachFake(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getConnections()Ljava/util/List; +Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getImsCall()Lcom/android/ims/ImsCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->hangup()V +Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->merge(Lcom/android/internal/telephony/imsphone/ImsPhoneCall;Lcom/android/internal/telephony/Call$State;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->onHangupLocal()V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->addConnection(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->clearDisconnected()V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->dial(Ljava/lang/String;ILandroid/os/Bundle;)Lcom/android/internal/telephony/Connection; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->dialPendingMO()V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->findConnection(Lcom/android/ims/ImsCall;)Lcom/android/internal/telephony/imsphone/ImsPhoneConnection; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getEcbmInterface()Lcom/android/ims/ImsEcbm; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getUtInterface()Lcom/android/ims/ImsUtInterface; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->handleEcmTimer(I)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mAllowEmergencyVideoCalls:Z +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mBackgroundCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mCallExpectedToResume:Lcom/android/ims/ImsCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mConnections:Ljava/util/ArrayList; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mForegroundCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mHandoverCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsCallListener:Lcom/android/ims/ImsCall$Listener; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsManager:Lcom/android/ims/ImsManager; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mOnHoldToneId:I +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mOnHoldToneStarted:Z +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPendingMO:Lcom/android/internal/telephony/imsphone/ImsPhoneConnection; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPendingUssd:Landroid/os/Message; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPhone:Lcom/android/internal/telephony/imsphone/ImsPhone; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mRingingCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mSwitchingFgAndBgCalls:Z +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mSyncHold:Ljava/lang/Object; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mUssdSession:Lcom/android/ims/ImsCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;I)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;IZ)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->removeConnection(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->setVideoCallProvider(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Lcom/android/ims/ImsCall;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->switchAfterConferenceSuccess()V +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->updatePhoneState()V +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection$MyHandler;-><init>(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Landroid/os/Looper;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->acquireWakeLock()V +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->createWakeLock(Landroid/content/Context;)V +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->getCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->getOwner()Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker; +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->isMultiparty()Z +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mDisconnected:Z +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mImsCall:Lcom/android/ims/ImsCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mOwner:Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker; +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mParent:Lcom/android/internal/telephony/imsphone/ImsPhoneCall; +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->onDisconnect()Z +Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->update(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;)Z +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getCLIRMode()I +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getDialingNumber()Ljava/lang/String; +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getErrorMessage(Landroid/os/AsyncResult;)Ljava/lang/CharSequence; +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getScString()Ljava/lang/CharSequence; +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isActivate()Z +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isDeactivate()Z +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isEmptyOrNull(Ljava/lang/CharSequence;)Z +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isErasure()Z +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isRegister()Z +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isSupportedOverImsPhone()Z +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isTemporaryModeCLIR()Z +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->mPhone:Lcom/android/internal/telephony/imsphone/ImsPhone; +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->newFromDialString(Ljava/lang/String;Lcom/android/internal/telephony/imsphone/ImsPhone;)Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode; +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->processCode()V +Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->serviceClassToCFString(I)Ljava/lang/CharSequence; +Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;-><init>(Lcom/android/internal/telephony/InboundSmsHandler;Lcom/android/internal/telephony/InboundSmsTracker;)V +Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;->mDeleteWhere:Ljava/lang/String; +Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;->mDeleteWhereArgs:[Ljava/lang/String; +Lcom/android/internal/telephony/InboundSmsHandler;->acknowledgeLastIncomingSms(ZILandroid/os/Message;)V +Lcom/android/internal/telephony/InboundSmsHandler;->deleteFromRawTable(Ljava/lang/String;[Ljava/lang/String;I)V +Lcom/android/internal/telephony/InboundSmsHandler;->dispatchIntent(Landroid/content/Intent;Ljava/lang/String;ILandroid/os/Bundle;Landroid/content/BroadcastReceiver;Landroid/os/UserHandle;)V +Lcom/android/internal/telephony/InboundSmsHandler;->dispatchNormalMessage(Lcom/android/internal/telephony/SmsMessageBase;)I +Lcom/android/internal/telephony/InboundSmsHandler;->getPhone()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/InboundSmsHandler;->handleInjectSms(Landroid/os/AsyncResult;)V +Lcom/android/internal/telephony/InboundSmsHandler;->handleNewSms(Landroid/os/AsyncResult;)V +Lcom/android/internal/telephony/InboundSmsHandler;->handleSmsWhitelisting(Landroid/content/ComponentName;)Landroid/os/Bundle; +Lcom/android/internal/telephony/InboundSmsHandler;->isSkipNotifyFlagSet(I)Z +Lcom/android/internal/telephony/InboundSmsHandler;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/InboundSmsHandler;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/InboundSmsHandler;->mCellBroadcastHandler:Lcom/android/internal/telephony/CellBroadcastHandler; +Lcom/android/internal/telephony/InboundSmsHandler;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/InboundSmsHandler;->mDeliveringState:Lcom/android/internal/telephony/InboundSmsHandler$DeliveringState; +Lcom/android/internal/telephony/InboundSmsHandler;->mDeviceIdleController:Landroid/os/IDeviceIdleController; +Lcom/android/internal/telephony/InboundSmsHandler;->mIdleState:Lcom/android/internal/telephony/InboundSmsHandler$IdleState; +Lcom/android/internal/telephony/InboundSmsHandler;->mPhone:Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/InboundSmsHandler;->mResolver:Landroid/content/ContentResolver; +Lcom/android/internal/telephony/InboundSmsHandler;->mUserManager:Landroid/os/UserManager; +Lcom/android/internal/telephony/InboundSmsHandler;->mWaitingState:Lcom/android/internal/telephony/InboundSmsHandler$WaitingState; +Lcom/android/internal/telephony/InboundSmsHandler;->mWakeLock:Landroid/os/PowerManager$WakeLock; +Lcom/android/internal/telephony/InboundSmsHandler;->mWapPush:Lcom/android/internal/telephony/WapPushOverSms; +Lcom/android/internal/telephony/InboundSmsHandler;->processMessagePart(Lcom/android/internal/telephony/InboundSmsTracker;)Z +Lcom/android/internal/telephony/InboundSmsHandler;->showNewMessageNotification()V +Lcom/android/internal/telephony/InboundSmsHandler;->writeInboxMessage(Landroid/content/Intent;)Landroid/net/Uri; +Lcom/android/internal/telephony/InboundSmsTracker;->getFormat()Ljava/lang/String; +Lcom/android/internal/telephony/InboundSmsTracker;->getIndexOffset()I +Lcom/android/internal/telephony/IntRangeManager;->mRanges:Ljava/util/ArrayList; Lcom/android/internal/telephony/IPhoneStateListener$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneStateListener; Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String; @@ -2060,16 +3272,808 @@ Lcom/android/internal/telephony/IWapPushManager$Stub;->asInterface(Landroid/os/I Lcom/android/internal/telephony/IWapPushManager;->addPackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z Lcom/android/internal/telephony/IWapPushManager;->deletePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z Lcom/android/internal/telephony/IWapPushManager;->updatePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z +Lcom/android/internal/telephony/MccTable$MccEntry;->mIso:Ljava/lang/String; +Lcom/android/internal/telephony/MccTable;->countryCodeForMcc(I)Ljava/lang/String; +Lcom/android/internal/telephony/MccTable;->defaultLanguageForMcc(I)Ljava/lang/String; +Lcom/android/internal/telephony/MccTable;->defaultTimeZoneForMcc(I)Ljava/lang/String; +Lcom/android/internal/telephony/MccTable;->entryForMcc(I)Lcom/android/internal/telephony/MccTable$MccEntry; +Lcom/android/internal/telephony/MccTable;->getLocaleForLanguageCountry(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale; +Lcom/android/internal/telephony/MccTable;->smallestDigitsMccForMnc(I)I +Lcom/android/internal/telephony/MmiCode$State;->CANCELLED:Lcom/android/internal/telephony/MmiCode$State; +Lcom/android/internal/telephony/MmiCode$State;->COMPLETE:Lcom/android/internal/telephony/MmiCode$State; +Lcom/android/internal/telephony/MmiCode$State;->FAILED:Lcom/android/internal/telephony/MmiCode$State; +Lcom/android/internal/telephony/MmiCode$State;->PENDING:Lcom/android/internal/telephony/MmiCode$State; +Lcom/android/internal/telephony/MmiCode;->getPhone()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/Phone;->dispose()V +Lcom/android/internal/telephony/Phone;->exitEmergencyCallbackMode()V +Lcom/android/internal/telephony/Phone;->getActiveApnTypes()[Ljava/lang/String; +Lcom/android/internal/telephony/Phone;->getCallTracker()Lcom/android/internal/telephony/CallTracker; +Lcom/android/internal/telephony/Phone;->getCellLocation()Landroid/telephony/CellLocation; +Lcom/android/internal/telephony/Phone;->getContext()Landroid/content/Context; +Lcom/android/internal/telephony/Phone;->getDataConnectionState()Lcom/android/internal/telephony/PhoneConstants$DataState; +Lcom/android/internal/telephony/Phone;->getIccCard()Lcom/android/internal/telephony/IccCard; +Lcom/android/internal/telephony/Phone;->getIccFileHandler()Lcom/android/internal/telephony/uicc/IccFileHandler; +Lcom/android/internal/telephony/Phone;->getIccSerialNumber()Ljava/lang/String; +Lcom/android/internal/telephony/Phone;->getIccSmsInterfaceManager()Lcom/android/internal/telephony/IccSmsInterfaceManager; +Lcom/android/internal/telephony/Phone;->getImsPhone()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/Phone;->getIsimRecords()Lcom/android/internal/telephony/uicc/IsimRecords; +Lcom/android/internal/telephony/Phone;->getMsisdn()Ljava/lang/String; +Lcom/android/internal/telephony/Phone;->getNai()Ljava/lang/String; +Lcom/android/internal/telephony/Phone;->getPhoneId()I +Lcom/android/internal/telephony/Phone;->getPhoneName()Ljava/lang/String; +Lcom/android/internal/telephony/Phone;->getPhoneType()I +Lcom/android/internal/telephony/Phone;->getServiceStateTracker()Lcom/android/internal/telephony/ServiceStateTracker; +Lcom/android/internal/telephony/Phone;->getSmscAddress(Landroid/os/Message;)V +Lcom/android/internal/telephony/Phone;->getState()Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/Phone;->getSubId()I +Lcom/android/internal/telephony/Phone;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/telephony/Phone;->getUiccCard()Lcom/android/internal/telephony/uicc/UiccCard; +Lcom/android/internal/telephony/Phone;->getVideoState(Lcom/android/internal/telephony/Call;)I +Lcom/android/internal/telephony/Phone;->invokeOemRilRequestRaw([BLandroid/os/Message;)V +Lcom/android/internal/telephony/Phone;->invokeOemRilRequestStrings([Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/Phone;->isCspPlmnEnabled()Z +Lcom/android/internal/telephony/Phone;->isUtEnabled()Z +Lcom/android/internal/telephony/Phone;->isVideoEnabled()Z +Lcom/android/internal/telephony/Phone;->isVolteEnabled()Z +Lcom/android/internal/telephony/Phone;->isWifiCallingEnabled()Z +Lcom/android/internal/telephony/Phone;->mCi:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/Phone;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/Phone;->mDcTracker:Lcom/android/internal/telephony/dataconnection/DcTracker; +Lcom/android/internal/telephony/Phone;->mIccRecords:Ljava/util/concurrent/atomic/AtomicReference; +Lcom/android/internal/telephony/Phone;->mImsPhone:Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/Phone;->mMmiRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/Phone;->mNotifier:Lcom/android/internal/telephony/PhoneNotifier; +Lcom/android/internal/telephony/Phone;->mPhoneId:I +Lcom/android/internal/telephony/Phone;->mSmsStorageMonitor:Lcom/android/internal/telephony/SmsStorageMonitor; +Lcom/android/internal/telephony/Phone;->mUiccApplication:Ljava/util/concurrent/atomic/AtomicReference; +Lcom/android/internal/telephony/Phone;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController; +Lcom/android/internal/telephony/Phone;->needsOtaServiceProvisioning()Z +Lcom/android/internal/telephony/Phone;->notifyOtaspChanged(I)V +Lcom/android/internal/telephony/Phone;->registerForDisconnect(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForEcmTimerReset(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForIncomingRing(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForMmiComplete(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForMmiInitiate(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForNewRingingConnection(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForPreciseCallStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForRingbackTone(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForServiceStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForSimRecordsLoaded(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->registerForUnknownConnection(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->selectNetworkManually(Lcom/android/internal/telephony/OperatorInfo;ZLandroid/os/Message;)V +Lcom/android/internal/telephony/Phone;->setNetworkSelectionModeAutomatic(Landroid/os/Message;)V +Lcom/android/internal/telephony/Phone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->setOnPostDialCharacter(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/Phone;->setPreferredNetworkType(ILandroid/os/Message;)V +Lcom/android/internal/telephony/Phone;->setSmscAddress(Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/Phone;->unregisterForDisconnect(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForEcmTimerReset(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForIncomingRing(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForMmiComplete(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForMmiInitiate(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForNewRingingConnection(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForPreciseCallStateChanged(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForRingbackTone(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForServiceStateChanged(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForSimRecordsLoaded(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unregisterForUnknownConnection(Landroid/os/Handler;)V +Lcom/android/internal/telephony/Phone;->unsetOnEcbModeExitResponse(Landroid/os/Handler;)V +Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState; +Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTING:Lcom/android/internal/telephony/PhoneConstants$DataState; +Lcom/android/internal/telephony/PhoneConstants$DataState;->DISCONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState; +Lcom/android/internal/telephony/PhoneConstants$DataState;->SUSPENDED:Lcom/android/internal/telephony/PhoneConstants$DataState; +Lcom/android/internal/telephony/PhoneConstants$DataState;->values()[Lcom/android/internal/telephony/PhoneConstants$DataState; +Lcom/android/internal/telephony/PhoneConstants$State;->IDLE:Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/PhoneConstants$State;->OFFHOOK:Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/PhoneConstants$State;->RINGING:Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/PhoneConstants$State;->values()[Lcom/android/internal/telephony/PhoneConstants$State; +Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_ALLOWED:I +Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_PAYPHONE:I +Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_RESTRICTED:I +Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_UNKNOWN:I +Lcom/android/internal/telephony/PhoneFactory;->calculatePreferredNetworkType(Landroid/content/Context;I)I +Lcom/android/internal/telephony/PhoneFactory;->getDefaultPhone()Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/PhoneFactory;->getDefaultSubscription()I +Lcom/android/internal/telephony/PhoneFactory;->getPhone(I)Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/PhoneFactory;->getPhones()[Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/PhoneFactory;->makeDefaultPhone(Landroid/content/Context;)V +Lcom/android/internal/telephony/PhoneFactory;->sCommandsInterface:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/PhoneFactory;->sContext:Landroid/content/Context; +Lcom/android/internal/telephony/PhoneFactory;->sMadeDefaults:Z +Lcom/android/internal/telephony/PhoneFactory;->sPhoneNotifier:Lcom/android/internal/telephony/PhoneNotifier; +Lcom/android/internal/telephony/PhoneInternalInterface$DataActivityState;->NONE:Lcom/android/internal/telephony/PhoneInternalInterface$DataActivityState; +Lcom/android/internal/telephony/PhoneInternalInterface;->PREFERRED_NT_MODE:I +Lcom/android/internal/telephony/PhoneNotifier;->notifyMessageWaitingChanged(Lcom/android/internal/telephony/Phone;)V +Lcom/android/internal/telephony/PhoneNotifier;->notifySignalStrength(Lcom/android/internal/telephony/Phone;)V +Lcom/android/internal/telephony/PhoneStateIntentReceiver;-><init>(Landroid/content/Context;Landroid/os/Handler;)V +Lcom/android/internal/telephony/PhoneStateIntentReceiver;->getSignalStrengthDbm()I +Lcom/android/internal/telephony/PhoneStateIntentReceiver;->mSignalStrength:Landroid/telephony/SignalStrength; +Lcom/android/internal/telephony/PhoneStateIntentReceiver;->mWants:I +Lcom/android/internal/telephony/PhoneStateIntentReceiver;->notifyServiceState(I)V +Lcom/android/internal/telephony/PhoneStateIntentReceiver;->notifySignalStrength(I)V +Lcom/android/internal/telephony/PhoneStateIntentReceiver;->registerIntent()V +Lcom/android/internal/telephony/PhoneStateIntentReceiver;->unregisterIntent()V +Lcom/android/internal/telephony/PhoneSubInfoController;->getDefaultSubscription()I +Lcom/android/internal/telephony/PhoneSubInfoController;->getPhone(I)Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/PhoneSubInfoController;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/PhoneSubInfoController;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/PhoneSubInfoController;->mPhone:[Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/PhoneSwitcher;->activate(I)V +Lcom/android/internal/telephony/PhoneSwitcher;->deactivate(I)V +Lcom/android/internal/telephony/PhoneSwitcher;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/PhoneSwitcher;->mMaxActivePhones:I +Lcom/android/internal/telephony/PhoneSwitcher;->mNumPhones:I +Lcom/android/internal/telephony/PhoneSwitcher;->mPhones:[Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/ProxyController;->completeRadioCapabilityTransaction()V +Lcom/android/internal/telephony/ProxyController;->getInstance()Lcom/android/internal/telephony/ProxyController; +Lcom/android/internal/telephony/ProxyController;->logd(Ljava/lang/String;)V +Lcom/android/internal/telephony/ProxyController;->mOldRadioAccessFamily:[I +Lcom/android/internal/telephony/ProxyController;->mRadioCapabilitySessionId:I +Lcom/android/internal/telephony/ProxyController;->mSetRadioAccessFamilyStatus:[I +Lcom/android/internal/telephony/ProxyController;->mUniqueIdGenerator:Ljava/util/concurrent/atomic/AtomicInteger; +Lcom/android/internal/telephony/ProxyController;->registerForAllDataDisconnected(ILandroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/ProxyController;->sendRadioCapabilityRequest(IIIILjava/lang/String;II)V +Lcom/android/internal/telephony/ProxyController;->sProxyController:Lcom/android/internal/telephony/ProxyController; +Lcom/android/internal/telephony/RadioCapability;->getRadioAccessFamily()I +Lcom/android/internal/telephony/RetryManager;->configure(Ljava/lang/String;)Z +Lcom/android/internal/telephony/RetryManager;->getRetryTimer()I +Lcom/android/internal/telephony/RetryManager;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/RetryManager;->mApnType:Ljava/lang/String; +Lcom/android/internal/telephony/RetryManager;->mFailFastInterApnDelay:J +Lcom/android/internal/telephony/RetryManager;->mInterApnDelay:J +Lcom/android/internal/telephony/RetryManager;->mPhone:Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/RIL;-><init>(Landroid/content/Context;II)V +Lcom/android/internal/telephony/RIL;-><init>(Landroid/content/Context;IILjava/lang/Integer;)V +Lcom/android/internal/telephony/RIL;->acquireWakeLock(Lcom/android/internal/telephony/RILRequest;I)V +Lcom/android/internal/telephony/RIL;->clearRequestList(IZ)V +Lcom/android/internal/telephony/RIL;->clearWakeLock(I)Z +Lcom/android/internal/telephony/RIL;->decrementWakeLock(Lcom/android/internal/telephony/RILRequest;)V +Lcom/android/internal/telephony/RIL;->findAndRemoveRequestFromList(I)Lcom/android/internal/telephony/RILRequest; +Lcom/android/internal/telephony/RIL;->getResponseForTimedOutRILRequest(Lcom/android/internal/telephony/RILRequest;)Ljava/lang/Object; +Lcom/android/internal/telephony/RIL;->hangupForegroundResumeBackground(Landroid/os/Message;)V +Lcom/android/internal/telephony/RIL;->hangupWaitingOrBackground(Landroid/os/Message;)V +Lcom/android/internal/telephony/RIL;->invokeOemRilRequestRaw([BLandroid/os/Message;)V +Lcom/android/internal/telephony/RIL;->makeStaticRadioCapability()Lcom/android/internal/telephony/RadioCapability; +Lcom/android/internal/telephony/RIL;->mRequestList:Landroid/util/SparseArray; +Lcom/android/internal/telephony/RIL;->mTestingEmergencyCall:Ljava/util/concurrent/atomic/AtomicBoolean; +Lcom/android/internal/telephony/RIL;->mWakeLock:Landroid/os/PowerManager$WakeLock; +Lcom/android/internal/telephony/RIL;->notifyRegistrantsCdmaInfoRec(Lcom/android/internal/telephony/cdma/CdmaInformationRecords;)V +Lcom/android/internal/telephony/RIL;->notifyRegistrantsRilConnectionChanged(I)V +Lcom/android/internal/telephony/RIL;->requestToString(I)Ljava/lang/String; +Lcom/android/internal/telephony/RIL;->responseToString(I)Ljava/lang/String; +Lcom/android/internal/telephony/RIL;->retToString(ILjava/lang/Object;)Ljava/lang/String; +Lcom/android/internal/telephony/RIL;->riljLog(Ljava/lang/String;)V +Lcom/android/internal/telephony/RIL;->setRadioPower(ZLandroid/os/Message;)V +Lcom/android/internal/telephony/RIL;->unsljLog(I)V +Lcom/android/internal/telephony/RIL;->unsljLogMore(ILjava/lang/String;)V +Lcom/android/internal/telephony/RIL;->unsljLogRet(ILjava/lang/Object;)V +Lcom/android/internal/telephony/RIL;->unsljLogvRet(ILjava/lang/Object;)V +Lcom/android/internal/telephony/RILConstants;->PREFERRED_NETWORK_MODE:I +Lcom/android/internal/telephony/RILRequest;->mRequest:I +Lcom/android/internal/telephony/RILRequest;->mResult:Landroid/os/Message; +Lcom/android/internal/telephony/RILRequest;->mSerial:I +Lcom/android/internal/telephony/RILRequest;->obtain(ILandroid/os/Message;)Lcom/android/internal/telephony/RILRequest; +Lcom/android/internal/telephony/RILRequest;->onError(ILjava/lang/Object;)V +Lcom/android/internal/telephony/RILRequest;->release()V +Lcom/android/internal/telephony/RILRequest;->serialString()Ljava/lang/String; +Lcom/android/internal/telephony/ServiceStateTracker;->fixUnknownMcc(Ljava/lang/String;I)Ljava/lang/String; +Lcom/android/internal/telephony/ServiceStateTracker;->getCurrentDataConnectionState()I +Lcom/android/internal/telephony/ServiceStateTracker;->getDesiredPowerState()Z +Lcom/android/internal/telephony/ServiceStateTracker;->getPhoneId()I +Lcom/android/internal/telephony/ServiceStateTracker;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Lcom/android/internal/telephony/ServiceStateTracker;->isConcurrentVoiceAndDataAllowed()Z +Lcom/android/internal/telephony/ServiceStateTracker;->isGprsConsistent(II)Z +Lcom/android/internal/telephony/ServiceStateTracker;->isImsRegistered()Z +Lcom/android/internal/telephony/ServiceStateTracker;->isInHomeSidNid(II)Z +Lcom/android/internal/telephony/ServiceStateTracker;->isInvalidOperatorNumeric(Ljava/lang/String;)Z +Lcom/android/internal/telephony/ServiceStateTracker;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/ServiceStateTracker;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/ServiceStateTracker;->mAttachedRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/ServiceStateTracker;->mCi:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/ServiceStateTracker;->mCr:Landroid/content/ContentResolver; +Lcom/android/internal/telephony/ServiceStateTracker;->mCurDataSpn:Ljava/lang/String; +Lcom/android/internal/telephony/ServiceStateTracker;->mCurPlmn:Ljava/lang/String; +Lcom/android/internal/telephony/ServiceStateTracker;->mCurShowPlmn:Z +Lcom/android/internal/telephony/ServiceStateTracker;->mCurShowSpn:Z +Lcom/android/internal/telephony/ServiceStateTracker;->mCurSpn:Ljava/lang/String; +Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOffRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOnRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/ServiceStateTracker;->mDefaultRoamingIndicator:I +Lcom/android/internal/telephony/ServiceStateTracker;->mDesiredPowerState:Z +Lcom/android/internal/telephony/ServiceStateTracker;->mDetachedRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/ServiceStateTracker;->mDeviceShuttingDown:Z +Lcom/android/internal/telephony/ServiceStateTracker;->mEmergencyOnly:Z +Lcom/android/internal/telephony/ServiceStateTracker;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords; +Lcom/android/internal/telephony/ServiceStateTracker;->mIntentReceiver:Landroid/content/BroadcastReceiver; +Lcom/android/internal/telephony/ServiceStateTracker;->mIsSubscriptionFromRuim:Z +Lcom/android/internal/telephony/ServiceStateTracker;->mMaxDataCalls:I +Lcom/android/internal/telephony/ServiceStateTracker;->mNetworkAttachedRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/ServiceStateTracker;->mNewMaxDataCalls:I +Lcom/android/internal/telephony/ServiceStateTracker;->mNewReasonDataDenied:I +Lcom/android/internal/telephony/ServiceStateTracker;->mNewSS:Landroid/telephony/ServiceState; +Lcom/android/internal/telephony/ServiceStateTracker;->mOnSubscriptionsChangedListener:Lcom/android/internal/telephony/ServiceStateTracker$SstSubscriptionsChangedListener; +Lcom/android/internal/telephony/ServiceStateTracker;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone; +Lcom/android/internal/telephony/ServiceStateTracker;->mPreferredNetworkType:I +Lcom/android/internal/telephony/ServiceStateTracker;->mReasonDataDenied:I +Lcom/android/internal/telephony/ServiceStateTracker;->mReportedGprsNoReg:Z +Lcom/android/internal/telephony/ServiceStateTracker;->mRoamingIndicator:I +Lcom/android/internal/telephony/ServiceStateTracker;->mSignalStrength:Landroid/telephony/SignalStrength; +Lcom/android/internal/telephony/ServiceStateTracker;->mSpnUpdatePending:Z +Lcom/android/internal/telephony/ServiceStateTracker;->mSS:Landroid/telephony/ServiceState; +Lcom/android/internal/telephony/ServiceStateTracker;->mStartedGprsRegCheck:Z +Lcom/android/internal/telephony/ServiceStateTracker;->mSubId:I +Lcom/android/internal/telephony/ServiceStateTracker;->mSubscriptionController:Lcom/android/internal/telephony/SubscriptionController; +Lcom/android/internal/telephony/ServiceStateTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager; +Lcom/android/internal/telephony/ServiceStateTracker;->mUiccApplcation:Lcom/android/internal/telephony/uicc/UiccCardApplication; +Lcom/android/internal/telephony/ServiceStateTracker;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController; +Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOffRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOnRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/ServiceStateTracker;->notifyDataRegStateRilRadioTechnologyChanged()V +Lcom/android/internal/telephony/ServiceStateTracker;->notifySignalStrength()Z +Lcom/android/internal/telephony/ServiceStateTracker;->pollState()V +Lcom/android/internal/telephony/ServiceStateTracker;->powerOffRadioSafely(Lcom/android/internal/telephony/dataconnection/DcTracker;)V +Lcom/android/internal/telephony/ServiceStateTracker;->reRegisterNetwork(Landroid/os/Message;)V +Lcom/android/internal/telephony/ServiceStateTracker;->resetServiceStateInIwlanMode()V +Lcom/android/internal/telephony/ServiceStateTracker;->setOperatorIdd(Ljava/lang/String;)V +Lcom/android/internal/telephony/ServiceStateTracker;->setRoamingType(Landroid/telephony/ServiceState;)V +Lcom/android/internal/telephony/ServiceStateTracker;->setSignalStrengthDefaultValues()V +Lcom/android/internal/telephony/ServiceStateTracker;->updateOtaspState()V +Lcom/android/internal/telephony/ServiceStateTracker;->updatePhoneObject()V +Lcom/android/internal/telephony/ServiceStateTracker;->updateRoamingState()V +Lcom/android/internal/telephony/ServiceStateTracker;->updateSpnDisplay()V +Lcom/android/internal/telephony/ServiceStateTracker;->useDataRegStateForDataOnlyDevices()V +Lcom/android/internal/telephony/sip/SipPhone$SipCall;->hold()V +Lcom/android/internal/telephony/sip/SipPhone$SipCall;->switchWith(Lcom/android/internal/telephony/sip/SipPhone$SipCall;)V +Lcom/android/internal/telephony/sip/SipPhone$SipCall;->unhold()V +Lcom/android/internal/telephony/sip/SipPhone;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/sip/SipPhone;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/sip/SipPhone;->mBackgroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall; +Lcom/android/internal/telephony/sip/SipPhone;->mForegroundCall:Lcom/android/internal/telephony/sip/SipPhone$SipCall; +Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->DBG:Z +Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCDMA:Landroid/util/SparseIntArray; +Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableCommon:Landroid/util/SparseIntArray; +Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->mTranslationTableGSM:Landroid/util/SparseIntArray; +Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->translate(Ljava/lang/CharSequence;)Ljava/lang/String; +Lcom/android/internal/telephony/Sms7BitEncodingTranslator;->useCdmaFormatForMoSms()Z +Lcom/android/internal/telephony/SmsApplication$SmsApplicationData;->mApplicationName:Ljava/lang/String; +Lcom/android/internal/telephony/SmsApplication;->configurePreferredActivity(Landroid/content/pm/PackageManager;Landroid/content/ComponentName;I)V +Lcom/android/internal/telephony/SmsApplication;->getApplicationCollection(Landroid/content/Context;)Ljava/util/Collection; +Lcom/android/internal/telephony/SmsApplication;->getDefaultMmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName; +Lcom/android/internal/telephony/SmsApplication;->getDefaultRespondViaMessageApplication(Landroid/content/Context;Z)Landroid/content/ComponentName; +Lcom/android/internal/telephony/SmsApplication;->getDefaultSmsApplication(Landroid/content/Context;Z)Landroid/content/ComponentName; +Lcom/android/internal/telephony/SmsApplication;->getSmsApplicationData(Ljava/lang/String;Landroid/content/Context;)Lcom/android/internal/telephony/SmsApplication$SmsApplicationData; +Lcom/android/internal/telephony/SmsApplication;->isDefaultSmsApplication(Landroid/content/Context;Ljava/lang/String;)Z +Lcom/android/internal/telephony/SmsApplication;->setDefaultApplication(Ljava/lang/String;Landroid/content/Context;)V +Lcom/android/internal/telephony/SmsApplication;->shouldWriteMessageForPackage(Ljava/lang/String;Landroid/content/Context;)Z +Lcom/android/internal/telephony/SmsBroadcastUndelivered;-><init>(Landroid/content/Context;Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler;)V +Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mNegativeButton:Landroid/widget/Button; +Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mPositiveButton:Landroid/widget/Button; +Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mRememberUndoInstruction:Landroid/widget/TextView; +Lcom/android/internal/telephony/SMSDispatcher$DataSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V +Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Ljava/util/ArrayList;[Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V +Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;->sendSmsByCarrierApp(Ljava/lang/String;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;)V +Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;)V +Lcom/android/internal/telephony/SMSDispatcher$SmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsSender;)V +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->isMultipart()Z +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mAppInfo:Landroid/content/pm/PackageInfo; +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mData:Ljava/util/HashMap; +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mDeliveryIntent:Landroid/app/PendingIntent; +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mDestAddress:Ljava/lang/String; +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mMessageRef:I +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mMessageUri:Landroid/net/Uri; +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mPersistMessage:Z +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mSentIntent:Landroid/app/PendingIntent; +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mTimestamp:J +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->onFailed(Landroid/content/Context;II)V +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->onSent(Landroid/content/Context;)V +Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->updateSentMessageStatus(Landroid/content/Context;I)V +Lcom/android/internal/telephony/SMSDispatcher$TextSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V +Lcom/android/internal/telephony/SMSDispatcher;->calculateLength(Ljava/lang/CharSequence;Z)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails; +Lcom/android/internal/telephony/SMSDispatcher;->checkCallerIsPhoneOrCarrierApp()V +Lcom/android/internal/telephony/SMSDispatcher;->deliveryPendingList:Ljava/util/ArrayList; +Lcom/android/internal/telephony/SMSDispatcher;->dispose()V +Lcom/android/internal/telephony/SMSDispatcher;->getCarrierAppPackageName()Ljava/lang/String; +Lcom/android/internal/telephony/SMSDispatcher;->getMultipartMessageText(Ljava/util/ArrayList;)Ljava/lang/String; +Lcom/android/internal/telephony/SMSDispatcher;->getNextConcatenatedRef()I +Lcom/android/internal/telephony/SMSDispatcher;->getSubId()I +Lcom/android/internal/telephony/SMSDispatcher;->handleConfirmShortCode(ZLcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V +Lcom/android/internal/telephony/SMSDispatcher;->mCi:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/SMSDispatcher;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/SMSDispatcher;->mPhone:Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/SMSDispatcher;->mResolver:Landroid/content/ContentResolver; +Lcom/android/internal/telephony/SMSDispatcher;->mTelephonyManager:Landroid/telephony/TelephonyManager; +Lcom/android/internal/telephony/SMSDispatcher;->processSendSmsResponse(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;II)V +Lcom/android/internal/telephony/SMSDispatcher;->sendData(Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V +Lcom/android/internal/telephony/SMSDispatcher;->sendMultipartSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V +Lcom/android/internal/telephony/SMSDispatcher;->sendSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V +Lcom/android/internal/telephony/SMSDispatcher;->sendSubmitPdu(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V Lcom/android/internal/telephony/SmsHeader$ConcatRef;-><init>()V Lcom/android/internal/telephony/SmsHeader$PortAddrs;-><init>()V Lcom/android/internal/telephony/SmsMessageBase;-><init>()V +Lcom/android/internal/telephony/SmsResponse;-><init>(ILjava/lang/String;I)V +Lcom/android/internal/telephony/SmsResponse;->mAckPdu:Ljava/lang/String; +Lcom/android/internal/telephony/SmsResponse;->mErrorCode:I +Lcom/android/internal/telephony/SmsResponse;->mMessageRef:I +Lcom/android/internal/telephony/SmsStorageMonitor;->mCi:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/SmsUsageMonitor;-><init>(Landroid/content/Context;)V +Lcom/android/internal/telephony/SmsUsageMonitor;->check(Ljava/lang/String;I)Z +Lcom/android/internal/telephony/SubscriptionController;->broadcastDefaultDataSubIdChanged(I)V +Lcom/android/internal/telephony/SubscriptionController;->colorArr:[I +Lcom/android/internal/telephony/SubscriptionController;->enforceModifyPhoneState(Ljava/lang/String;)V +Lcom/android/internal/telephony/SubscriptionController;->getActiveSubInfoCount(Ljava/lang/String;)I +Lcom/android/internal/telephony/SubscriptionController;->getActiveSubscriptionInfo(ILjava/lang/String;)Landroid/telephony/SubscriptionInfo; +Lcom/android/internal/telephony/SubscriptionController;->getActiveSubscriptionInfoList(Ljava/lang/String;)Ljava/util/List; +Lcom/android/internal/telephony/SubscriptionController;->getDefaultDataSubId()I +Lcom/android/internal/telephony/SubscriptionController;->getDefaultSmsSubId()I +Lcom/android/internal/telephony/SubscriptionController;->getDefaultSubId()I +Lcom/android/internal/telephony/SubscriptionController;->getDefaultVoiceSubId()I +Lcom/android/internal/telephony/SubscriptionController;->getDummySubIds(I)[I +Lcom/android/internal/telephony/SubscriptionController;->getInstance()Lcom/android/internal/telephony/SubscriptionController; +Lcom/android/internal/telephony/SubscriptionController;->getPhoneId(I)I +Lcom/android/internal/telephony/SubscriptionController;->getSubId(I)[I +Lcom/android/internal/telephony/SubscriptionController;->getSubIdUsingPhoneId(I)I +Lcom/android/internal/telephony/SubscriptionController;->getSubInfo(Ljava/lang/String;Ljava/lang/Object;)Ljava/util/List; +Lcom/android/internal/telephony/SubscriptionController;->getSubInfoRecord(Landroid/database/Cursor;)Landroid/telephony/SubscriptionInfo; +Lcom/android/internal/telephony/SubscriptionController;->isActiveSubId(I)Z +Lcom/android/internal/telephony/SubscriptionController;->isSubInfoReady()Z +Lcom/android/internal/telephony/SubscriptionController;->logd(Ljava/lang/String;)V +Lcom/android/internal/telephony/SubscriptionController;->logdl(Ljava/lang/String;)V +Lcom/android/internal/telephony/SubscriptionController;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/SubscriptionController;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/SubscriptionController;->mDefaultPhoneId:I +Lcom/android/internal/telephony/SubscriptionController;->mLock:Ljava/lang/Object; +Lcom/android/internal/telephony/SubscriptionController;->notifySubscriptionInfoChanged()V +Lcom/android/internal/telephony/SubscriptionController;->setDefaultDataSubId(I)V +Lcom/android/internal/telephony/SubscriptionController;->setDefaultFallbackSubId(I)V +Lcom/android/internal/telephony/SubscriptionController;->setDefaultSmsSubId(I)V +Lcom/android/internal/telephony/SubscriptionController;->setDefaultVoiceSubId(I)V +Lcom/android/internal/telephony/SubscriptionController;->setPlmnSpn(IZLjava/lang/String;ZLjava/lang/String;)Z +Lcom/android/internal/telephony/SubscriptionController;->updateAllDataConnectionTrackers()V +Lcom/android/internal/telephony/SubscriptionController;->validateSubId(I)V +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->broadcastSimStateChanged(ILjava/lang/String;Ljava/lang/String;)V +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->isAllIccIdQueryDone()Z +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->logd(Ljava/lang/String;)V +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String; +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mInsertSimState:[I +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager; +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I +Lcom/android/internal/telephony/SubscriptionInfoUpdater;->updateSubscriptionInfoByIccId()V +Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z +Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String; +Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V +Lcom/android/internal/telephony/test/SimulatedCommands;->acceptCall(Landroid/os/Message;)V +Lcom/android/internal/telephony/test/SimulatedCommands;->dial(Ljava/lang/String;ILandroid/os/Message;)V +Lcom/android/internal/telephony/test/SimulatedCommands;->dial(Ljava/lang/String;ILcom/android/internal/telephony/UUSInfo;Landroid/os/Message;)V +Lcom/android/internal/telephony/test/SimulatedCommands;->mDcSuccess:Z +Lcom/android/internal/telephony/test/SimulatedCommands;->resultFail(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)V +Lcom/android/internal/telephony/test/SimulatedCommands;->resultSuccess(Landroid/os/Message;Ljava/lang/Object;)V +Lcom/android/internal/telephony/test/SimulatedCommands;->simulatedCallState:Lcom/android/internal/telephony/test/SimulatedGsmCallState; +Lcom/android/internal/telephony/test/SimulatedCommands;->unimplemented(Landroid/os/Message;)V +Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->getInstance()Lcom/android/internal/telephony/test/SimulatedCommandsVerifier; +Lcom/android/internal/telephony/test/SimulatedCommandsVerifier;->setCallForward(IIILjava/lang/String;ILandroid/os/Message;)V +Lcom/android/internal/telephony/test/SimulatedGsmCallState;->conference()Z +Lcom/android/internal/telephony/test/SimulatedGsmCallState;->onChld(CC)Z +Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseActiveAcceptHeldOrWaiting()Z +Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseHeldOrUDUB()Z +Lcom/android/internal/telephony/test/SimulatedGsmCallState;->separateCall(I)Z +Lcom/android/internal/telephony/test/SimulatedGsmCallState;->switchActiveAndHeldOrWaiting()Z +Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(IILjava/lang/String;Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(II[B)V +Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/AdnRecord;-><init>([B)V +Lcom/android/internal/telephony/uicc/AdnRecord;->buildAdnString(I)[B +Lcom/android/internal/telephony/uicc/AdnRecord;->CREATOR:Landroid/os/Parcelable$Creator; +Lcom/android/internal/telephony/uicc/AdnRecord;->getEmails()[Ljava/lang/String; +Lcom/android/internal/telephony/uicc/AdnRecord;->getNumber()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/AdnRecord;->isEmpty()Z +Lcom/android/internal/telephony/uicc/AdnRecord;->mAlphaTag:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/AdnRecord;->mEfid:I +Lcom/android/internal/telephony/uicc/AdnRecord;->mEmails:[Ljava/lang/String; +Lcom/android/internal/telephony/uicc/AdnRecord;->mExtRecord:I +Lcom/android/internal/telephony/uicc/AdnRecord;->mNumber:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/AdnRecord;->mRecordNumber:I +Lcom/android/internal/telephony/uicc/AdnRecord;->setEmails([Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/AdnRecordCache;->extensionEfForEf(I)I +Lcom/android/internal/telephony/uicc/AdnRecordCache;->getRecordsIfLoaded(I)Ljava/util/ArrayList; +Lcom/android/internal/telephony/uicc/AdnRecordCache;->mAdnLikeWaiters:Landroid/util/SparseArray; +Lcom/android/internal/telephony/uicc/AdnRecordCache;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler; +Lcom/android/internal/telephony/uicc/AdnRecordCache;->mUserWriteResponse:Landroid/util/SparseArray; +Lcom/android/internal/telephony/uicc/AdnRecordCache;->mUsimPhoneBookManager:Lcom/android/internal/telephony/gsm/UsimPhoneBookManager; +Lcom/android/internal/telephony/uicc/AdnRecordCache;->reset()V +Lcom/android/internal/telephony/uicc/AdnRecordCache;->sendErrorResponse(Landroid/os/Message;Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/AdnRecordCache;->updateAdnByIndex(ILcom/android/internal/telephony/uicc/AdnRecord;ILjava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/uicc/AdnRecordLoader;-><init>(Lcom/android/internal/telephony/uicc/IccFileHandler;)V +Lcom/android/internal/telephony/uicc/AdnRecordLoader;->getEFPath(I)Ljava/lang/String; +Lcom/android/internal/telephony/uicc/AdnRecordLoader;->loadFromEF(IIILandroid/os/Message;)V +Lcom/android/internal/telephony/uicc/AdnRecordLoader;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler; +Lcom/android/internal/telephony/uicc/AdnRecordLoader;->updateEF(Lcom/android/internal/telephony/uicc/AdnRecord;IIILjava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_DETECTED:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_PIN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_READY:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_SUBSCRIPTION_PERSO:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_CSIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_ISIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_RUIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_SIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_USIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK_SUBSET:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_SERVICE_PROVIDER:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;-><init>()V +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;->AppTypeFromRILInt(I)Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;->app_type:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_ABSENT:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState; +Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_ERROR:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState; +Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_PRESENT:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState; +Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->isCardPresent()Z +Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_DISABLED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState; +Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_ENABLED_BLOCKED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState; +Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_ENABLED_PERM_BLOCKED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState; +Lcom/android/internal/telephony/uicc/IccCardStatus;->mApplications:[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus; +Lcom/android/internal/telephony/uicc/IccCardStatus;->mCardState:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState; +Lcom/android/internal/telephony/uicc/IccCardStatus;->mCdmaSubscriptionAppIndex:I +Lcom/android/internal/telephony/uicc/IccCardStatus;->mGsmUmtsSubscriptionAppIndex:I +Lcom/android/internal/telephony/uicc/IccCardStatus;->mImsSubscriptionAppIndex:I +Lcom/android/internal/telephony/uicc/IccCardStatus;->mUniversalPinState:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState; +Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;-><init>(IILandroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;->mRecordSize:I +Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;->results:Ljava/util/ArrayList; +Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFLinearRecordSize(ILandroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFLinearRecordSize(ILjava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFPath(I)Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixed(IILandroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixed(ILjava/lang/String;ILandroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixedAll(ILandroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixedAll(ILjava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFTransparent(ILandroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler;->mAid:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccFileHandler;->mCi:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/uicc/IccFileHandler;->mParentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication; +Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFLinearFixed(II[BLjava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFLinearFixed(ILjava/lang/String;I[BLjava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFTransparent(I[BLandroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccIoResult;-><init>(IILjava/lang/String;)V +Lcom/android/internal/telephony/uicc/IccIoResult;-><init>(II[B)V +Lcom/android/internal/telephony/uicc/IccIoResult;->payload:[B +Lcom/android/internal/telephony/uicc/IccIoResult;->success()Z +Lcom/android/internal/telephony/uicc/IccIoResult;->sw1:I +Lcom/android/internal/telephony/uicc/IccIoResult;->sw2:I +Lcom/android/internal/telephony/uicc/IccRecords;->auth_rsp:Lcom/android/internal/telephony/uicc/IccIoResult; +Lcom/android/internal/telephony/uicc/IccRecords;->getGid1()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->getIccId()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->getIccSimChallengeResponse(ILjava/lang/String;)Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->getIMSI()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->getMsisdnNumber()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->getOperatorNumeric()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->getRecordsLoaded()Z +Lcom/android/internal/telephony/uicc/IccRecords;->getServiceProviderName()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->getUsimServiceTable()Lcom/android/internal/telephony/uicc/UsimServiceTable; +Lcom/android/internal/telephony/uicc/IccRecords;->handleRefresh(Lcom/android/internal/telephony/uicc/IccRefreshResponse;)V +Lcom/android/internal/telephony/uicc/IccRecords;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/IccRecords;->mAdnCache:Lcom/android/internal/telephony/uicc/AdnRecordCache; +Lcom/android/internal/telephony/uicc/IccRecords;->mCi:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/uicc/IccRecords;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/uicc/IccRecords;->mDestroyed:Ljava/util/concurrent/atomic/AtomicBoolean; +Lcom/android/internal/telephony/uicc/IccRecords;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler; +Lcom/android/internal/telephony/uicc/IccRecords;->mGid1:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->mIccId:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->mImsi:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->mIsVoiceMailFixed:Z +Lcom/android/internal/telephony/uicc/IccRecords;->mLock:Ljava/lang/Object; +Lcom/android/internal/telephony/uicc/IccRecords;->mMncLength:I +Lcom/android/internal/telephony/uicc/IccRecords;->mParentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication; +Lcom/android/internal/telephony/uicc/IccRecords;->mRecordsEventsRegistrants:Landroid/os/RegistrantList; +Lcom/android/internal/telephony/uicc/IccRecords;->mRecordsToLoad:I +Lcom/android/internal/telephony/uicc/IccRecords;->mSpn:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->mTelephonyManager:Landroid/telephony/TelephonyManager; +Lcom/android/internal/telephony/uicc/IccRecords;->mVoiceMailNum:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRecords;->registerForNetworkSelectionModeAutomatic(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/uicc/IccRecords;->registerForNewSms(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/uicc/IccRecords;->registerForRecordsEvents(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/uicc/IccRecords;->registerForRecordsLoaded(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/uicc/IccRecords;->setMsisdnNumber(Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V +Lcom/android/internal/telephony/uicc/IccRecords;->setVoiceCallForwardingFlag(IZLjava/lang/String;)V +Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForNetworkSelectionModeAutomatic(Landroid/os/Handler;)V +Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForNewSms(Landroid/os/Handler;)V +Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForRecordsEvents(Landroid/os/Handler;)V +Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForRecordsLoaded(Landroid/os/Handler;)V +Lcom/android/internal/telephony/uicc/IccRefreshResponse;-><init>()V +Lcom/android/internal/telephony/uicc/IccRefreshResponse;->aid:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccRefreshResponse;->efId:I +Lcom/android/internal/telephony/uicc/IccRefreshResponse;->refreshResult:I +Lcom/android/internal/telephony/uicc/IccServiceTable;->getTag()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccServiceTable;->mServiceTable:[B +Lcom/android/internal/telephony/uicc/IccUtils;->adnStringFieldToString([BII)Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccUtils;->bcdToString([BII)Ljava/lang/String; Lcom/android/internal/telephony/uicc/IccUtils;->bytesToHexString([B)Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdByteToInt(B)I +Lcom/android/internal/telephony/uicc/IccUtils;->cdmaBcdToString([BII)Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccUtils;->gsmBcdByteToInt(B)I +Lcom/android/internal/telephony/uicc/IccUtils;->hexCharToInt(C)I +Lcom/android/internal/telephony/uicc/IccUtils;->hexStringToBytes(Ljava/lang/String;)[B +Lcom/android/internal/telephony/uicc/IccUtils;->networkNameToString([BII)Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IccUtils;->parseToBnW([BI)Landroid/graphics/Bitmap; +Lcom/android/internal/telephony/uicc/IccUtils;->parseToRGB([BIZ)Landroid/graphics/Bitmap; +Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimDomain()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimImpi()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimImpu()[Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->auth_rsp:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->fetchIsimRecords()V +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->isimTlvToString([B)Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimDomain:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimImpi:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimImpu:[Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimIst:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimPcscf:[Ljava/lang/String; +Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mLock:Ljava/lang/Object; +Lcom/android/internal/telephony/uicc/RuimRecords;->adjstMinDigits(I)I +Lcom/android/internal/telephony/uicc/RuimRecords;->fetchRuimRecords()V +Lcom/android/internal/telephony/uicc/RuimRecords;->getAssetLanguages(Landroid/content/Context;)[Ljava/lang/String; +Lcom/android/internal/telephony/uicc/RuimRecords;->getCsimSpnDisplayCondition()Z +Lcom/android/internal/telephony/uicc/RuimRecords;->getMdn()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/RuimRecords;->getMdnNumber()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/RuimRecords;->getRUIMOperatorNumeric()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/RuimRecords;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/RuimRecords;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/RuimRecords;->mEFli:[B +Lcom/android/internal/telephony/uicc/RuimRecords;->mEFpl:[B +Lcom/android/internal/telephony/uicc/RuimRecords;->mMin:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/RuimRecords;->mNai:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/RuimRecords;->onGetCSimEprlDone(Landroid/os/AsyncResult;)V +Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->INIT:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState; +Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_3GPP:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState; +Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_CPHS:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState; +Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_SHORT_CPHS:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState; +Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->values()[Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState; +Lcom/android/internal/telephony/uicc/SIMRecords;->fetchSimRecords()V +Lcom/android/internal/telephony/uicc/SIMRecords;->getExtFromEf(I)I +Lcom/android/internal/telephony/uicc/SIMRecords;->getMsisdnNumber()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/SIMRecords;->getOperatorNumeric()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/SIMRecords;->getSpnFsm(ZLandroid/os/AsyncResult;)V +Lcom/android/internal/telephony/uicc/SIMRecords;->getVoiceMailNumber()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/SIMRecords;->isCphsMailboxEnabled()Z +Lcom/android/internal/telephony/uicc/SIMRecords;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/SIMRecords;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/SIMRecords;->logv(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCff:[B +Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCfis:[B +Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCPHS_MWI:[B +Lcom/android/internal/telephony/uicc/SIMRecords;->mEfLi:[B +Lcom/android/internal/telephony/uicc/SIMRecords;->mEfMWIS:[B +Lcom/android/internal/telephony/uicc/SIMRecords;->mEfPl:[B +Lcom/android/internal/telephony/uicc/SIMRecords;->mSpnDisplayCondition:I +Lcom/android/internal/telephony/uicc/SIMRecords;->mUsimServiceTable:Lcom/android/internal/telephony/uicc/UsimServiceTable; +Lcom/android/internal/telephony/uicc/SIMRecords;->mVmConfig:Lcom/android/internal/telephony/uicc/VoiceMailConstants; +Lcom/android/internal/telephony/uicc/SIMRecords;->setVoiceCallForwardingFlag(IZLjava/lang/String;)V +Lcom/android/internal/telephony/uicc/UiccCard;->getApplication(I)Lcom/android/internal/telephony/uicc/UiccCardApplication; +Lcom/android/internal/telephony/uicc/UiccCard;->getApplicationByType(I)Lcom/android/internal/telephony/uicc/UiccCardApplication; +Lcom/android/internal/telephony/uicc/UiccCard;->getApplicationIndex(I)Lcom/android/internal/telephony/uicc/UiccCardApplication; +Lcom/android/internal/telephony/uicc/UiccCard;->getCardState()Lcom/android/internal/telephony/uicc/IccCardStatus$CardState; +Lcom/android/internal/telephony/uicc/UiccCard;->getCarrierPackageNamesForIntent(Landroid/content/pm/PackageManager;Landroid/content/Intent;)Ljava/util/List; +Lcom/android/internal/telephony/uicc/UiccCard;->getIccId()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/UiccCard;->getNumApplications()I +Lcom/android/internal/telephony/uicc/UiccCard;->getOperatorBrandOverride()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/UiccCard;->isApplicationOnIcc(Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;)Z +Lcom/android/internal/telephony/uicc/UiccCard;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/UiccCard;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/UiccCard;->mCardState:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState; +Lcom/android/internal/telephony/uicc/UiccCard;->mCi:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/uicc/UiccCard;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/uicc/UiccCard;->mLock:Ljava/lang/Object; +Lcom/android/internal/telephony/uicc/UiccCard;->mPhoneId:I +Lcom/android/internal/telephony/uicc/UiccCardApplication;->dispose()V +Lcom/android/internal/telephony/uicc/UiccCardApplication;->getAid()Ljava/lang/String; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->getAuthContext()I +Lcom/android/internal/telephony/uicc/UiccCardApplication;->getIccFileHandler()Lcom/android/internal/telephony/uicc/IccFileHandler; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->getIccRecords()Lcom/android/internal/telephony/uicc/IccRecords; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPersoSubState()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPhoneId()I +Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPin1State()Lcom/android/internal/telephony/uicc/IccCardStatus$PinState; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->getState()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->getType()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/UiccCardApplication;->loge(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAid:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAppState:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAppType:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->mCi:Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->mDestroyed:Z +Lcom/android/internal/telephony/uicc/UiccCardApplication;->mLock:Ljava/lang/Object; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->mPersoSubState:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->mPin1State:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState; +Lcom/android/internal/telephony/uicc/UiccCardApplication;->registerForReady(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/uicc/UiccCardApplication;->unregisterForReady(Landroid/os/Handler;)V +Lcom/android/internal/telephony/uicc/UiccCardApplication;->update(Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;Landroid/content/Context;Lcom/android/internal/telephony/CommandsInterface;)V +Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules$TLV;->length:Ljava/lang/Integer; +Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules$TLV;->value:Ljava/lang/String; +Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules;->mLoadedCallback:Landroid/os/Message; +Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules;->mState:Ljava/util/concurrent/atomic/AtomicInteger; +Lcom/android/internal/telephony/uicc/UiccController;->getIccFileHandler(II)Lcom/android/internal/telephony/uicc/IccFileHandler; +Lcom/android/internal/telephony/uicc/UiccController;->getIccRecords(II)Lcom/android/internal/telephony/uicc/IccRecords; +Lcom/android/internal/telephony/uicc/UiccController;->getInstance()Lcom/android/internal/telephony/uicc/UiccController; +Lcom/android/internal/telephony/uicc/UiccController;->getUiccCard(I)Lcom/android/internal/telephony/uicc/UiccCard; +Lcom/android/internal/telephony/uicc/UiccController;->getUiccCardApplication(II)Lcom/android/internal/telephony/uicc/UiccCardApplication; +Lcom/android/internal/telephony/uicc/UiccController;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/uicc/UiccController;->mCis:[Lcom/android/internal/telephony/CommandsInterface; +Lcom/android/internal/telephony/uicc/UiccController;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/uicc/UiccController;->mInstance:Lcom/android/internal/telephony/uicc/UiccController; +Lcom/android/internal/telephony/uicc/UiccController;->mLock:Ljava/lang/Object; +Lcom/android/internal/telephony/uicc/UiccController;->registerForIccChanged(Landroid/os/Handler;ILjava/lang/Object;)V +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->ALLOWED_CSG_LISTS_AND_INDICATIONS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->CFI_STATUS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->CSG_DISPLAY_CONTROL:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->FDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MBDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MSISDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MWI_STATUS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->OPERATOR_CSG_LISTS_AND_INDICATIONS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->OPERATOR_PLMN_LIST:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->PLMN_NETWORK_NAME:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_OVER_IP:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_SERVICE_PARAMS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_STORAGE:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SPN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService; +Lcom/android/internal/telephony/uicc/UsimServiceTable;->isAvailable(Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;)Z +Lcom/android/internal/telephony/uicc/VoiceMailConstants;-><init>()V +Lcom/android/internal/telephony/UiccPhoneBookController;-><init>([Lcom/android/internal/telephony/Phone;)V +Lcom/android/internal/telephony/UiccPhoneBookController;->getDefaultSubscription()I +Lcom/android/internal/telephony/UiccPhoneBookController;->getIccPhoneBookInterfaceManager(I)Lcom/android/internal/telephony/IccPhoneBookInterfaceManager; +Lcom/android/internal/telephony/UiccPhoneBookController;->mPhone:[Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/UiccSmsController;->copyMessageToIccEfForSubscriber(ILjava/lang/String;I[B[B)Z +Lcom/android/internal/telephony/UiccSmsController;->disableCellBroadcastForSubscriber(III)Z +Lcom/android/internal/telephony/UiccSmsController;->disableCellBroadcastRangeForSubscriber(IIII)Z +Lcom/android/internal/telephony/UiccSmsController;->enableCellBroadcastForSubscriber(III)Z +Lcom/android/internal/telephony/UiccSmsController;->enableCellBroadcastRangeForSubscriber(IIII)Z +Lcom/android/internal/telephony/UiccSmsController;->getAllMessagesFromIccEfForSubscriber(ILjava/lang/String;)Ljava/util/List; +Lcom/android/internal/telephony/UiccSmsController;->getIccSmsInterfaceManager(I)Lcom/android/internal/telephony/IccSmsInterfaceManager; +Lcom/android/internal/telephony/UiccSmsController;->getImsSmsFormatForSubscriber(I)Ljava/lang/String; +Lcom/android/internal/telephony/UiccSmsController;->getPreferredSmsSubscription()I +Lcom/android/internal/telephony/UiccSmsController;->isImsSmsSupportedForSubscriber(I)Z +Lcom/android/internal/telephony/UiccSmsController;->sendDataForSubscriber(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V +Lcom/android/internal/telephony/UiccSmsController;->sendErrorInPendingIntent(Landroid/app/PendingIntent;I)V +Lcom/android/internal/telephony/UiccSmsController;->sendErrorInPendingIntents(Ljava/util/List;I)V +Lcom/android/internal/telephony/UiccSmsController;->updateMessageOnIccEfForSubscriber(ILjava/lang/String;II[B)Z +Lcom/android/internal/telephony/UUSInfo;->getDcs()I +Lcom/android/internal/telephony/UUSInfo;->getType()I +Lcom/android/internal/telephony/UUSInfo;->getUserData()[B +Lcom/android/internal/telephony/WakeLockStateMachine;->log(Ljava/lang/String;)V +Lcom/android/internal/telephony/WakeLockStateMachine;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/WakeLockStateMachine;->mIdleState:Lcom/android/internal/telephony/WakeLockStateMachine$IdleState; +Lcom/android/internal/telephony/WakeLockStateMachine;->mPhone:Lcom/android/internal/telephony/Phone; +Lcom/android/internal/telephony/WapPushOverSms;->dispatchWapPdu([BLandroid/content/BroadcastReceiver;Lcom/android/internal/telephony/InboundSmsHandler;)I +Lcom/android/internal/telephony/WapPushOverSms;->getDeliveryOrReadReportThreadId(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)J +Lcom/android/internal/telephony/WapPushOverSms;->isDuplicateNotification(Landroid/content/Context;Lcom/google/android/mms/pdu/NotificationInd;)Z +Lcom/android/internal/telephony/WapPushOverSms;->isWapPushForMms([BLcom/android/internal/telephony/InboundSmsHandler;)Z +Lcom/android/internal/telephony/WapPushOverSms;->mContext:Landroid/content/Context; +Lcom/android/internal/telephony/WapPushOverSms;->mDeviceIdleController:Landroid/os/IDeviceIdleController; +Lcom/android/internal/telephony/WapPushOverSms;->mWapPushManager:Lcom/android/internal/telephony/IWapPushManager; +Lcom/android/internal/telephony/WspTypeDecoder;-><init>([B)V +Lcom/android/internal/telephony/WspTypeDecoder;->decodeContentType(I)Z +Lcom/android/internal/telephony/WspTypeDecoder;->decodeIntegerValue(I)Z +Lcom/android/internal/telephony/WspTypeDecoder;->decodeShortInteger(I)Z +Lcom/android/internal/telephony/WspTypeDecoder;->decodeTextString(I)Z +Lcom/android/internal/telephony/WspTypeDecoder;->decodeUintvarInteger(I)Z +Lcom/android/internal/telephony/WspTypeDecoder;->decodeValueLength(I)Z +Lcom/android/internal/telephony/WspTypeDecoder;->decodeXWapApplicationId(I)Z +Lcom/android/internal/telephony/WspTypeDecoder;->getContentParameters()Ljava/util/HashMap; +Lcom/android/internal/telephony/WspTypeDecoder;->getDecodedDataLength()I +Lcom/android/internal/telephony/WspTypeDecoder;->getValue32()J +Lcom/android/internal/telephony/WspTypeDecoder;->getValueString()Ljava/lang/String; +Lcom/android/internal/telephony/WspTypeDecoder;->mWspData:[B +Lcom/android/internal/telephony/WspTypeDecoder;->seekXWapApplicationId(II)Z Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V +Lcom/android/internal/util/ArrayUtils;->appendElement(Ljava/lang/Class;[Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object; +Lcom/android/internal/util/ArrayUtils;->appendInt([II)[I +Lcom/android/internal/util/ArrayUtils;->contains([II)Z +Lcom/android/internal/util/ArrayUtils;->contains([Ljava/lang/Object;Ljava/lang/Object;)Z +Lcom/android/internal/util/ArrayUtils;->emptyArray(Ljava/lang/Class;)[Ljava/lang/Object; +Lcom/android/internal/util/ArrayUtils;->indexOf([Ljava/lang/Object;Ljava/lang/Object;)I +Lcom/android/internal/util/ArrayUtils;->isEmpty([Ljava/lang/Object;)Z +Lcom/android/internal/util/ArrayUtils;->newUnpaddedArray(Ljava/lang/Class;I)[Ljava/lang/Object; +Lcom/android/internal/util/ArrayUtils;->newUnpaddedIntArray(I)[I +Lcom/android/internal/util/ArrayUtils;->removeElement(Ljava/lang/Class;[Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object; +Lcom/android/internal/util/BitwiseInputStream;-><init>([B)V +Lcom/android/internal/util/BitwiseInputStream;->available()I +Lcom/android/internal/util/BitwiseInputStream;->read(I)I +Lcom/android/internal/util/BitwiseInputStream;->readByteArray(I)[B +Lcom/android/internal/util/BitwiseInputStream;->skip(I)V +Lcom/android/internal/util/BitwiseOutputStream;-><init>(I)V +Lcom/android/internal/util/BitwiseOutputStream;->toByteArray()[B +Lcom/android/internal/util/BitwiseOutputStream;->write(II)V +Lcom/android/internal/util/BitwiseOutputStream;->writeByteArray(I[B)V +Lcom/android/internal/util/CharSequences;->compareToIgnoreCase(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)I +Lcom/android/internal/util/CharSequences;->equals(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Z +Lcom/android/internal/util/FastMath;->round(F)I +Lcom/android/internal/util/FastXmlSerializer;-><init>()V +Lcom/android/internal/util/GrowingArrayUtils;->append([III)[I +Lcom/android/internal/util/GrowingArrayUtils;->append([Ljava/lang/Object;ILjava/lang/Object;)[Ljava/lang/Object; +Lcom/android/internal/util/HexDump;->hexStringToByteArray(Ljava/lang/String;)[B +Lcom/android/internal/util/HexDump;->toHexString(I)Ljava/lang/String; +Lcom/android/internal/util/HexDump;->toHexString([B)Ljava/lang/String; +Lcom/android/internal/util/HexDump;->toHexString([BII)Ljava/lang/String; Lcom/android/internal/util/HexDump;->toHexString([BZ)Ljava/lang/String; +Lcom/android/internal/util/IState;->getName()Ljava/lang/String; +Lcom/android/internal/util/MemInfoReader;-><init>()V +Lcom/android/internal/util/MemInfoReader;->getCachedSize()J +Lcom/android/internal/util/MemInfoReader;->getFreeSize()J +Lcom/android/internal/util/MemInfoReader;->getRawInfo()[J +Lcom/android/internal/util/MemInfoReader;->getTotalSize()J +Lcom/android/internal/util/MemInfoReader;->readMemInfo()V +Lcom/android/internal/util/Preconditions;->checkArgument(Z)V +Lcom/android/internal/util/Preconditions;->checkArgument(ZLjava/lang/Object;)V +Lcom/android/internal/util/Preconditions;->checkArgumentInRange(IIILjava/lang/String;)I +Lcom/android/internal/util/Preconditions;->checkNotNull(Ljava/lang/Object;)Ljava/lang/Object; +Lcom/android/internal/util/Preconditions;->checkNotNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +Lcom/android/internal/util/Preconditions;->checkState(Z)V +Lcom/android/internal/util/Preconditions;->checkState(ZLjava/lang/String;)V +Lcom/android/internal/util/State;-><init>()V +Lcom/android/internal/util/State;->enter()V +Lcom/android/internal/util/State;->exit()V +Lcom/android/internal/util/State;->getName()Ljava/lang/String; +Lcom/android/internal/util/State;->processMessage(Landroid/os/Message;)Z +Lcom/android/internal/util/StateMachine;-><init>(Ljava/lang/String;)V +Lcom/android/internal/util/StateMachine;-><init>(Ljava/lang/String;Landroid/os/Handler;)V +Lcom/android/internal/util/StateMachine;-><init>(Ljava/lang/String;Landroid/os/Looper;)V +Lcom/android/internal/util/StateMachine;->dump(Ljava/io/FileDescriptor;Ljava/io/PrintWriter;[Ljava/lang/String;)V +Lcom/android/internal/util/StateMachine;->obtainMessage(III)Landroid/os/Message; +Lcom/android/internal/util/StateMachine;->obtainMessage(IIILjava/lang/Object;)Landroid/os/Message; +Lcom/android/internal/util/StateMachine;->sendMessage(I)V +Lcom/android/internal/util/StateMachine;->sendMessage(II)V +Lcom/android/internal/util/StateMachine;->sendMessage(IIILjava/lang/Object;)V +Lcom/android/internal/util/StateMachine;->sendMessage(ILjava/lang/Object;)V +Lcom/android/internal/util/StateMachine;->sendMessage(Landroid/os/Message;)V +Lcom/android/internal/view/ActionBarPolicy;-><init>(Landroid/content/Context;)V +Lcom/android/internal/view/ActionBarPolicy;->get(Landroid/content/Context;)Lcom/android/internal/view/ActionBarPolicy; +Lcom/android/internal/view/ActionBarPolicy;->getEmbeddedMenuWidthLimit()I +Lcom/android/internal/view/ActionBarPolicy;->getMaxActionButtons()I +Lcom/android/internal/view/ActionBarPolicy;->getStackedTabMaxWidth()I +Lcom/android/internal/view/ActionBarPolicy;->getTabContainerHeight()I +Lcom/android/internal/view/ActionBarPolicy;->hasEmbeddedTabs()Z +Lcom/android/internal/view/ActionBarPolicy;->mContext:Landroid/content/Context; +Lcom/android/internal/view/ActionBarPolicy;->showsOverflowMenuButton()Z Lcom/android/internal/view/BaseIWindow;-><init>()V Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager; Lcom/android/internal/view/IInputMethodSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodSession; +Lcom/android/internal/view/InputConnectionWrapper$InputContextCallback;->dispose()V +Lcom/android/internal/view/InputConnectionWrapper$InputContextCallback;->getInstance()Lcom/android/internal/view/InputConnectionWrapper$InputContextCallback; +Lcom/android/internal/view/menu/ActionMenu;-><init>(Landroid/content/Context;)V +Lcom/android/internal/view/menu/ActionMenuItem;-><init>(Landroid/content/Context;IIIILjava/lang/CharSequence;)V +Lcom/android/internal/view/menu/ContextMenuBuilder;-><init>(Landroid/content/Context;)V +Lcom/android/internal/view/menu/IconMenuItemView;->getTextAppropriateLayoutParams()Lcom/android/internal/view/menu/IconMenuView$LayoutParams; +Lcom/android/internal/view/menu/IconMenuItemView;->setIconMenuView(Lcom/android/internal/view/menu/IconMenuView;)V +Lcom/android/internal/view/menu/IconMenuItemView;->setItemInvoker(Lcom/android/internal/view/menu/MenuBuilder$ItemInvoker;)V +Lcom/android/internal/view/menu/IconMenuView$SavedState;-><init>(Landroid/os/Parcel;)V +Lcom/android/internal/view/menu/IconMenuView;->createMoreItemView()Lcom/android/internal/view/menu/IconMenuItemView; +Lcom/android/internal/view/menu/IconMenuView;->getNumActualItemsShown()I +Lcom/android/internal/view/menu/IconMenuView;->mItemBackground:Landroid/graphics/drawable/Drawable; +Lcom/android/internal/view/menu/IconMenuView;->mMaxItems:I +Lcom/android/internal/view/menu/IconMenuView;->mMenu:Lcom/android/internal/view/menu/MenuBuilder; +Lcom/android/internal/view/menu/MenuDialogHelper;-><init>(Lcom/android/internal/view/menu/MenuBuilder;)V +Lcom/android/internal/view/menu/MenuDialogHelper;->dismiss()V +Lcom/android/internal/view/menu/MenuDialogHelper;->show(Landroid/os/IBinder;)V +Lcom/android/internal/view/WindowManagerPolicyThread;->getLooper()Landroid/os/Looper; +Lcom/android/internal/widget/AbsActionBarView;->dismissPopupMenus()V +Lcom/android/internal/widget/ActionBarContextView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V +Lcom/android/internal/widget/ActionBarOverlayLayout;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V +Lcom/android/internal/widget/ActionBarOverlayLayout;->setWindowCallback(Landroid/view/Window$Callback;)V +Lcom/android/internal/widget/EditableInputConnection;-><init>(Landroid/widget/TextView;)V Lcom/android/internal/widget/ILockSettings$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/widget/ILockSettings; Lcom/android/internal/widget/ILockSettings;->getBoolean(Ljava/lang/String;ZI)Z Lcom/android/internal/widget/ILockSettings;->getLong(Ljava/lang/String;JI)J @@ -2088,17 +4092,109 @@ Lcom/android/internal/widget/IRemoteViewsFactory;->getViewTypeCount()I Lcom/android/internal/widget/IRemoteViewsFactory;->hasStableIds()Z Lcom/android/internal/widget/IRemoteViewsFactory;->isCreated()Z Lcom/android/internal/widget/IRemoteViewsFactory;->onDataSetChanged()V +Lcom/android/internal/widget/LinearLayoutWithDefaultTouchRecepient;-><init>(Landroid/content/Context;)V +Lcom/android/internal/widget/LinearLayoutWithDefaultTouchRecepient;->setDefaultTouchRecepient(Landroid/view/View;)V +Lcom/android/internal/widget/LockPatternChecker;->checkPassword(Lcom/android/internal/widget/LockPatternUtils;Ljava/lang/String;ILcom/android/internal/widget/LockPatternChecker$OnCheckCallback;)Landroid/os/AsyncTask; +Lcom/android/internal/widget/LockPatternUtils$RequestThrottledException;-><init>(I)V +Lcom/android/internal/widget/LockPatternUtils$RequestThrottledException;->getTimeoutMs()I +Lcom/android/internal/widget/LockPatternUtils;-><init>(Landroid/content/Context;)V +Lcom/android/internal/widget/LockPatternUtils;->checkPassword(Ljava/lang/String;I)Z +Lcom/android/internal/widget/LockPatternUtils;->getActivePasswordQuality(I)I +Lcom/android/internal/widget/LockPatternUtils;->getDevicePolicyManager()Landroid/app/admin/DevicePolicyManager; +Lcom/android/internal/widget/LockPatternUtils;->getKeyguardStoredPasswordQuality(I)I +Lcom/android/internal/widget/LockPatternUtils;->getLockSettings()Lcom/android/internal/widget/ILockSettings; +Lcom/android/internal/widget/LockPatternUtils;->getOwnerInfo(I)Ljava/lang/String; +Lcom/android/internal/widget/LockPatternUtils;->getPowerButtonInstantlyLocks(I)Z +Lcom/android/internal/widget/LockPatternUtils;->getString(Ljava/lang/String;I)Ljava/lang/String; +Lcom/android/internal/widget/LockPatternUtils;->isDeviceEncryptionEnabled()Z +Lcom/android/internal/widget/LockPatternUtils;->isLockPasswordEnabled(I)Z +Lcom/android/internal/widget/LockPatternUtils;->isLockPatternEnabled(I)Z +Lcom/android/internal/widget/LockPatternUtils;->isLockScreenDisabled(I)Z +Lcom/android/internal/widget/LockPatternUtils;->isSecure(I)Z +Lcom/android/internal/widget/LockPatternUtils;->isTactileFeedbackEnabled()Z +Lcom/android/internal/widget/LockPatternUtils;->isVisiblePatternEnabled(I)Z +Lcom/android/internal/widget/LockPatternUtils;->mContentResolver:Landroid/content/ContentResolver; +Lcom/android/internal/widget/LockPatternUtils;->mContext:Landroid/content/Context; +Lcom/android/internal/widget/LockPatternUtils;->patternToHash(Ljava/util/List;)[B +Lcom/android/internal/widget/LockPatternUtils;->patternToString(Ljava/util/List;)Ljava/lang/String; +Lcom/android/internal/widget/LockPatternUtils;->reportFailedPasswordAttempt(I)V +Lcom/android/internal/widget/LockPatternUtils;->reportSuccessfulPasswordAttempt(I)V +Lcom/android/internal/widget/LockPatternUtils;->saveLockPassword(Ljava/lang/String;Ljava/lang/String;II)V +Lcom/android/internal/widget/LockPatternUtils;->setLockoutAttemptDeadline(II)J +Lcom/android/internal/widget/LockPatternUtils;->setLong(Ljava/lang/String;JI)V +Lcom/android/internal/widget/LockPatternUtils;->setOwnerInfo(Ljava/lang/String;I)V +Lcom/android/internal/widget/LockPatternUtils;->setOwnerInfoEnabled(ZI)V +Lcom/android/internal/widget/LockPatternUtils;->setString(Ljava/lang/String;Ljava/lang/String;I)V +Lcom/android/internal/widget/LockPatternView$Cell;->column:I +Lcom/android/internal/widget/LockPatternView$Cell;->row:I +Lcom/android/internal/widget/LockPatternView$DisplayMode;->Animate:Lcom/android/internal/widget/LockPatternView$DisplayMode; +Lcom/android/internal/widget/LockPatternView$DisplayMode;->Correct:Lcom/android/internal/widget/LockPatternView$DisplayMode; +Lcom/android/internal/widget/LockPatternView$DisplayMode;->Wrong:Lcom/android/internal/widget/LockPatternView$DisplayMode; +Lcom/android/internal/widget/LockPatternView$SavedState;-><init>(Landroid/os/Parcel;)V +Lcom/android/internal/widget/LockPatternView$SavedState;-><init>(Landroid/os/Parcelable;Ljava/lang/String;IZZZ)V +Lcom/android/internal/widget/LockPatternView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V +Lcom/android/internal/widget/LockPatternView;->clearPattern()V +Lcom/android/internal/widget/LockPatternView;->disableInput()V +Lcom/android/internal/widget/LockPatternView;->enableInput()V +Lcom/android/internal/widget/LockPatternView;->getCellStates()[[Lcom/android/internal/widget/LockPatternView$CellState; +Lcom/android/internal/widget/LockPatternView;->mInStealthMode:Z +Lcom/android/internal/widget/LockPatternView;->mPaint:Landroid/graphics/Paint; +Lcom/android/internal/widget/LockPatternView;->mPathPaint:Landroid/graphics/Paint; +Lcom/android/internal/widget/LockPatternView;->mPattern:Ljava/util/ArrayList; +Lcom/android/internal/widget/LockPatternView;->mPatternDisplayMode:Lcom/android/internal/widget/LockPatternView$DisplayMode; +Lcom/android/internal/widget/LockPatternView;->mPatternInProgress:Z +Lcom/android/internal/widget/LockPatternView;->mSquareHeight:F +Lcom/android/internal/widget/LockPatternView;->mSquareWidth:F +Lcom/android/internal/widget/LockPatternView;->notifyPatternDetected()V +Lcom/android/internal/widget/LockPatternView;->setDisplayMode(Lcom/android/internal/widget/LockPatternView$DisplayMode;)V +Lcom/android/internal/widget/LockPatternView;->setInStealthMode(Z)V +Lcom/android/internal/widget/LockPatternView;->setOnPatternListener(Lcom/android/internal/widget/LockPatternView$OnPatternListener;)V +Lcom/android/internal/widget/LockPatternView;->setTactileFeedbackEnabled(Z)V +Lcom/android/internal/widget/PointerLocationView$PointerState;-><init>()V +Lcom/android/internal/widget/PointerLocationView$PointerState;->mCurDown:Z +Lcom/android/internal/widget/PointerLocationView;->mCurDown:Z +Lcom/android/internal/widget/PointerLocationView;->mCurNumPointers:I +Lcom/android/internal/widget/PointerLocationView;->mMaxNumPointers:I +Lcom/android/internal/widget/PointerLocationView;->mPointers:Ljava/util/ArrayList; +Lcom/android/internal/widget/PointerLocationView;->mPrintCoords:Z +Lcom/android/internal/widget/PreferenceImageView;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V +Lcom/android/internal/widget/RecyclerView$RecycledViewPool$ScrapData;->mScrapHeap:Ljava/util/ArrayList; Lcom/android/internal/widget/ScrollBarUtils;->getThumbLength(IIII)I +Lcom/android/internal/widget/SlidingTab$Slider;->tab:Landroid/widget/ImageView; +Lcom/android/internal/widget/SlidingTab$Slider;->text:Landroid/widget/TextView; +Lcom/android/internal/widget/SlidingTab;->mAnimationDoneListener:Landroid/view/animation/Animation$AnimationListener; +Lcom/android/internal/widget/SlidingTab;->mLeftSlider:Lcom/android/internal/widget/SlidingTab$Slider; +Lcom/android/internal/widget/SlidingTab;->mRightSlider:Lcom/android/internal/widget/SlidingTab$Slider; +Lcom/android/internal/widget/SlidingTab;->onAnimationDone()V +Lcom/android/internal/widget/SlidingTab;->resetView()V +Lcom/android/internal/widget/SlidingTab;->setHoldAfterTrigger(ZZ)V +Lcom/android/internal/widget/SlidingTab;->setLeftHintText(I)V +Lcom/android/internal/widget/SlidingTab;->setLeftTabResources(IIII)V +Lcom/android/internal/widget/SlidingTab;->setOnTriggerListener(Lcom/android/internal/widget/SlidingTab$OnTriggerListener;)V +Lcom/android/internal/widget/SlidingTab;->setRightHintText(I)V +Lcom/android/internal/widget/SlidingTab;->setRightTabResources(IIII)V +Lcom/android/internal/widget/TextViewInputDisabler;-><init>(Landroid/widget/TextView;)V +Lcom/android/internal/widget/TextViewInputDisabler;->setInputEnabled(Z)V +Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageScrolled(IFI)V +Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageScrollStateChanged(I)V +Lcom/android/internal/widget/ViewPager$OnPageChangeListener;->onPageSelected(I)V +Lcom/android/internal/widget/ViewPager;->getCurrentItem()I Lcom/android/okhttp/Connection;->getSocket()Ljava/net/Socket; Lcom/android/okhttp/ConnectionPool;->connections:Ljava/util/Deque; Lcom/android/okhttp/ConnectionPool;->keepAliveDurationNs:J Lcom/android/okhttp/ConnectionPool;->maxIdleConnections:I Lcom/android/okhttp/ConnectionPool;->systemDefault:Lcom/android/okhttp/ConnectionPool; +Lcom/android/okhttp/HttpHandler;-><init>()V +Lcom/android/okhttp/HttpsHandler;-><init>()V Lcom/android/okhttp/HttpUrl$Builder;->build()Lcom/android/okhttp/HttpUrl; Lcom/android/okhttp/HttpUrl;->encodedPath()Ljava/lang/String; Lcom/android/okhttp/HttpUrl;->newBuilder()Lcom/android/okhttp/HttpUrl$Builder; Lcom/android/okhttp/HttpUrl;->parse(Ljava/lang/String;)Lcom/android/okhttp/HttpUrl; Lcom/android/okhttp/HttpUrl;->query()Ljava/lang/String; +Lcom/android/okhttp/internal/http/HeaderParser;->skipUntil(Ljava/lang/String;ILjava/lang/String;)I +Lcom/android/okhttp/internal/http/HeaderParser;->skipWhitespace(Ljava/lang/String;I)I +Lcom/android/okhttp/internal/http/HttpDate;->format(Ljava/util/Date;)Ljava/lang/String; +Lcom/android/okhttp/internal/http/HttpDate;->parse(Ljava/lang/String;)Ljava/util/Date; Lcom/android/okhttp/internal/http/HttpEngine;->getConnection()Lcom/android/okhttp/Connection; Lcom/android/okhttp/internal/http/HttpEngine;->hasResponse()Z Lcom/android/okhttp/internal/http/HttpEngine;->httpStream:Lcom/android/okhttp/internal/http/HttpStream; @@ -2111,6 +4207,29 @@ Lcom/android/okhttp/internal/http/HttpEngine;->sentRequestMillis:J Lcom/android/okhttp/internal/http/HttpEngine;->userResponse:Lcom/android/okhttp/Response; Lcom/android/okhttp/internal/http/HttpEngine;->writingRequestHeaders()V Lcom/android/okhttp/internal/http/RouteSelector;->hasNext()Z +Lcom/android/okhttp/internal/huc/HttpsURLConnectionImpl;->delegate:Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl; +Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;->client:Lcom/android/okhttp/OkHttpClient; +Lcom/android/okhttp/internal/huc/HttpURLConnectionImpl;->httpEngine:Lcom/android/okhttp/internal/http/HttpEngine; +Lcom/android/okhttp/internal/Internal;-><init>()V +Lcom/android/okhttp/internal/Internal;->addLenient(Lcom/android/okhttp/Headers$Builder;Ljava/lang/String;)V +Lcom/android/okhttp/internal/Internal;->addLenient(Lcom/android/okhttp/Headers$Builder;Ljava/lang/String;Ljava/lang/String;)V +Lcom/android/okhttp/internal/Internal;->apply(Lcom/android/okhttp/ConnectionSpec;Ljavax/net/ssl/SSLSocket;Z)V +Lcom/android/okhttp/internal/Internal;->callEngineGetStreamAllocation(Lcom/android/okhttp/Call;)Lcom/android/okhttp/internal/http/StreamAllocation; +Lcom/android/okhttp/internal/Internal;->callEnqueue(Lcom/android/okhttp/Call;Lcom/android/okhttp/Callback;Z)V +Lcom/android/okhttp/internal/Internal;->connectionBecameIdle(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/internal/io/RealConnection;)Z +Lcom/android/okhttp/internal/Internal;->get(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/Address;Lcom/android/okhttp/internal/http/StreamAllocation;)Lcom/android/okhttp/internal/io/RealConnection; +Lcom/android/okhttp/internal/Internal;->getHttpUrlChecked(Ljava/lang/String;)Lcom/android/okhttp/HttpUrl; +Lcom/android/okhttp/internal/Internal;->instance:Lcom/android/okhttp/internal/Internal; +Lcom/android/okhttp/internal/Internal;->internalCache(Lcom/android/okhttp/OkHttpClient;)Lcom/android/okhttp/internal/InternalCache; +Lcom/android/okhttp/internal/Internal;->put(Lcom/android/okhttp/ConnectionPool;Lcom/android/okhttp/internal/io/RealConnection;)V +Lcom/android/okhttp/internal/Internal;->routeDatabase(Lcom/android/okhttp/ConnectionPool;)Lcom/android/okhttp/internal/RouteDatabase; +Lcom/android/okhttp/internal/Internal;->setCache(Lcom/android/okhttp/OkHttpClient;Lcom/android/okhttp/internal/InternalCache;)V +Lcom/android/okhttp/internal/Platform;->get()Lcom/android/okhttp/internal/Platform; +Lcom/android/okhttp/internal/Platform;->logW(Ljava/lang/String;)V +Lcom/android/okhttp/internal/Util;->closeAll(Ljava/io/Closeable;Ljava/io/Closeable;)V +Lcom/android/okhttp/internal/Util;->closeQuietly(Ljava/io/Closeable;)V +Lcom/android/okhttp/internal/Util;->EMPTY_BYTE_ARRAY:[B +Lcom/android/okhttp/internal/Util;->UTF_8:Ljava/nio/charset/Charset; Lcom/android/okhttp/OkHttpClient;-><init>()V Lcom/android/okhttp/OkHttpClient;->connectionPool:Lcom/android/okhttp/ConnectionPool; Lcom/android/okhttp/OkHttpClient;->DEFAULT_PROTOCOLS:Ljava/util/List; @@ -2131,6 +4250,59 @@ Lcom/android/okhttp/Response;->headers:Lcom/android/okhttp/Headers; Lcom/android/okhttp/Response;->message:Ljava/lang/String; Lcom/android/okhttp/Response;->networkResponse:Lcom/android/okhttp/Response; Lcom/android/okhttp/Response;->protocol:Lcom/android/okhttp/Protocol; +Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;-><init>()V +Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;->add(Lcom/android/org/bouncycastle/asn1/ASN1Encodable;)V +Lcom/android/org/bouncycastle/asn1/ASN1InputStream;-><init>(Ljava/io/InputStream;)V +Lcom/android/org/bouncycastle/asn1/ASN1InputStream;-><init>([B)V +Lcom/android/org/bouncycastle/asn1/ASN1InputStream;->readObject()Lcom/android/org/bouncycastle/asn1/ASN1Primitive; +Lcom/android/org/bouncycastle/asn1/ASN1Integer;-><init>(Ljava/math/BigInteger;)V +Lcom/android/org/bouncycastle/asn1/DERBitString;-><init>([B)V +Lcom/android/org/bouncycastle/asn1/DEREncodableVector;-><init>()V +Lcom/android/org/bouncycastle/asn1/DERInteger;-><init>(J)V +Lcom/android/org/bouncycastle/asn1/DERInteger;-><init>(Ljava/math/BigInteger;)V +Lcom/android/org/bouncycastle/asn1/DERNull;->INSTANCE:Lcom/android/org/bouncycastle/asn1/DERNull; +Lcom/android/org/bouncycastle/asn1/DERObjectIdentifier;-><init>(Ljava/lang/String;)V +Lcom/android/org/bouncycastle/asn1/DEROctetString;-><init>([B)V +Lcom/android/org/bouncycastle/asn1/DEROutputStream;-><init>(Ljava/io/OutputStream;)V +Lcom/android/org/bouncycastle/asn1/DERSequence;-><init>()V +Lcom/android/org/bouncycastle/asn1/DERSequence;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;)V +Lcom/android/org/bouncycastle/asn1/DERSet;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1EncodableVector;)V +Lcom/android/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers;->sha256WithRSAEncryption:Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier; +Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;)V +Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier;Lcom/android/org/bouncycastle/asn1/ASN1Encodable;)V +Lcom/android/org/bouncycastle/asn1/x509/Certificate;->getInstance(Ljava/lang/Object;)Lcom/android/org/bouncycastle/asn1/x509/Certificate; +Lcom/android/org/bouncycastle/asn1/x509/DigestInfo;-><init>(Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;[B)V +Lcom/android/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo;->getInstance(Ljava/lang/Object;)Lcom/android/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo; +Lcom/android/org/bouncycastle/asn1/x509/Time;-><init>(Ljava/util/Date;)V +Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;-><init>()V +Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->generateTBSCertificate()Lcom/android/org/bouncycastle/asn1/x509/TBSCertificate; +Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setEndDate(Lcom/android/org/bouncycastle/asn1/x509/Time;)V +Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setIssuer(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V +Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSerialNumber(Lcom/android/org/bouncycastle/asn1/ASN1Integer;)V +Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSignature(Lcom/android/org/bouncycastle/asn1/x509/AlgorithmIdentifier;)V +Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setStartDate(Lcom/android/org/bouncycastle/asn1/x509/Time;)V +Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSubject(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V +Lcom/android/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator;->setSubjectPublicKeyInfo(Lcom/android/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo;)V +Lcom/android/org/bouncycastle/asn1/x509/X509Name;-><init>(Lcom/android/org/bouncycastle/asn1/ASN1Sequence;)V +Lcom/android/org/bouncycastle/asn1/x509/X509Name;-><init>(Ljava/lang/String;)V +Lcom/android/org/bouncycastle/asn1/x509/X509Name;->CN:Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier; +Lcom/android/org/bouncycastle/asn1/x509/X509Name;->getOIDs()Ljava/util/Vector; +Lcom/android/org/bouncycastle/asn1/x509/X509Name;->getValues()Ljava/util/Vector; +Lcom/android/org/bouncycastle/asn1/x9/X9ObjectIdentifiers;->ecdsa_with_SHA256:Lcom/android/org/bouncycastle/asn1/ASN1ObjectIdentifier; +Lcom/android/org/bouncycastle/jce/provider/BouncyCastleProvider;-><init>()V +Lcom/android/org/bouncycastle/jce/provider/X509CertificateObject;-><init>(Lcom/android/org/bouncycastle/asn1/x509/Certificate;)V +Lcom/android/org/bouncycastle/jce/X509Principal;-><init>([B)V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;-><init>()V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->generate(Ljava/security/PrivateKey;)Ljava/security/cert/X509Certificate; +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setIssuerDN(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setIssuerDN(Ljavax/security/auth/x500/X500Principal;)V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setNotAfter(Ljava/util/Date;)V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setNotBefore(Ljava/util/Date;)V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setPublicKey(Ljava/security/PublicKey;)V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSerialNumber(Ljava/math/BigInteger;)V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSignatureAlgorithm(Ljava/lang/String;)V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSubjectDN(Lcom/android/org/bouncycastle/asn1/x509/X509Name;)V +Lcom/android/org/bouncycastle/x509/X509V3CertificateGenerator;->setSubjectDN(Ljavax/security/auth/x500/X500Principal;)V Lcom/android/org/conscrypt/AbstractConscryptSocket;->getAlpnSelectedProtocol()[B Lcom/android/org/conscrypt/AbstractConscryptSocket;->getApplicationProtocol()Ljava/lang/String; Lcom/android/org/conscrypt/AbstractConscryptSocket;->getApplicationProtocols()[Ljava/lang/String; @@ -2150,14 +4322,73 @@ Lcom/android/org/conscrypt/AbstractConscryptSocket;->setHostname(Ljava/lang/Stri Lcom/android/org/conscrypt/AbstractConscryptSocket;->setNpnProtocols([B)V Lcom/android/org/conscrypt/AbstractConscryptSocket;->setSoWriteTimeout(I)V Lcom/android/org/conscrypt/AbstractConscryptSocket;->setUseSessionTickets(Z)V +Lcom/android/org/conscrypt/ClientSessionContext;->getSession(Ljava/lang/String;I)Lcom/android/org/conscrypt/NativeSslSession; +Lcom/android/org/conscrypt/ClientSessionContext;->setPersistentCache(Lcom/android/org/conscrypt/SSLClientSessionCache;)V Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setHostname(Ljava/lang/String;)V Lcom/android/org/conscrypt/ConscryptFileDescriptorSocket;->setUseSessionTickets(Z)V +Lcom/android/org/conscrypt/FileClientSessionCache$Impl;->getSessionData(Ljava/lang/String;I)[B +Lcom/android/org/conscrypt/FileClientSessionCache;->usingDirectory(Ljava/io/File;)Lcom/android/org/conscrypt/SSLClientSessionCache; +Lcom/android/org/conscrypt/NativeCrypto;->ASN1_seq_pack_X509([J)[B +Lcom/android/org/conscrypt/NativeCrypto;->ASN1_seq_unpack_X509_bio(J)[J +Lcom/android/org/conscrypt/NativeCrypto;->ASN1_TIME_to_Calendar(JLjava/util/Calendar;)V +Lcom/android/org/conscrypt/NativeCrypto;->BIO_free_all(J)V +Lcom/android/org/conscrypt/NativeCrypto;->create_BIO_InputStream(Lcom/android/org/conscrypt/OpenSSLBIOInputStream;Z)J +Lcom/android/org/conscrypt/NativeCrypto;->create_BIO_OutputStream(Ljava/io/OutputStream;)J +Lcom/android/org/conscrypt/NativeCrypto;->d2i_PKCS7_bio(JI)[J +Lcom/android/org/conscrypt/NativeCrypto;->d2i_SSL_SESSION([B)J +Lcom/android/org/conscrypt/NativeCrypto;->d2i_X509([B)J +Lcom/android/org/conscrypt/NativeCrypto;->d2i_X509_bio(J)J +Lcom/android/org/conscrypt/NativeCrypto;->d2i_X509_CRL_bio(J)J +Lcom/android/org/conscrypt/NativeCrypto;->EC_GROUP_clear_free(J)V +Lcom/android/org/conscrypt/NativeCrypto;->EC_GROUP_new_by_curve_name(Ljava/lang/String;)J +Lcom/android/org/conscrypt/NativeCrypto;->EC_POINT_clear_free(J)V +Lcom/android/org/conscrypt/NativeCrypto;->EVP_CIPHER_CTX_new()J +Lcom/android/org/conscrypt/NativeCrypto;->EVP_CIPHER_iv_length(J)I +Lcom/android/org/conscrypt/NativeCrypto;->EVP_get_cipherbyname(Ljava/lang/String;)J +Lcom/android/org/conscrypt/NativeCrypto;->EVP_get_digestbyname(Ljava/lang/String;)J +Lcom/android/org/conscrypt/NativeCrypto;->EVP_MD_CTX_create()J +Lcom/android/org/conscrypt/NativeCrypto;->EVP_MD_CTX_destroy(J)V +Lcom/android/org/conscrypt/NativeCrypto;->EVP_MD_size(J)I +Lcom/android/org/conscrypt/NativeCrypto;->EVP_PKEY_free(J)V +Lcom/android/org/conscrypt/NativeCrypto;->EVP_PKEY_new_RSA([B[B[B[B[B[B[B[B)J +Lcom/android/org/conscrypt/NativeCrypto;->get_X509_REVOKED_ext_oids(JI)[Ljava/lang/String; +Lcom/android/org/conscrypt/NativeCrypto;->get_X509_REVOKED_revocationDate(J)J +Lcom/android/org/conscrypt/NativeCrypto;->i2d_PKCS7([J)[B +Lcom/android/org/conscrypt/NativeCrypto;->i2d_SSL_SESSION(J)[B +Lcom/android/org/conscrypt/NativeCrypto;->i2d_X509_REVOKED(J)[B +Lcom/android/org/conscrypt/NativeCrypto;->PEM_read_bio_PKCS7(JI)[J +Lcom/android/org/conscrypt/NativeCrypto;->PEM_read_bio_X509(J)J +Lcom/android/org/conscrypt/NativeCrypto;->PEM_read_bio_X509_CRL(J)J +Lcom/android/org/conscrypt/NativeCrypto;->RAND_bytes([B)V +Lcom/android/org/conscrypt/NativeCrypto;->RSA_generate_key_ex(I[B)J +Lcom/android/org/conscrypt/NativeCrypto;->SSL_CTX_new()J +Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_cipher(J)Ljava/lang/String; +Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_free(J)V +Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_get_time(J)J +Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_get_version(J)Ljava/lang/String; +Lcom/android/org/conscrypt/NativeCrypto;->SSL_SESSION_session_id(J)[B +Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_dup(J)J +Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_get_ext(JLjava/lang/String;)J +Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_get_ext_oid(JLjava/lang/String;)[B +Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_get_serialNumber(J)[B +Lcom/android/org/conscrypt/NativeCrypto;->X509_REVOKED_print(JJ)V +Lcom/android/org/conscrypt/NativeCrypto;->X509_supported_extension(J)I +Lcom/android/org/conscrypt/OpenSSLBIOInputStream;-><init>(Ljava/io/InputStream;Z)V +Lcom/android/org/conscrypt/OpenSSLBIOInputStream;->getBioContext()J +Lcom/android/org/conscrypt/OpenSSLBIOInputStream;->release()V +Lcom/android/org/conscrypt/OpenSSLContextImpl$TLSv12;-><init>()V +Lcom/android/org/conscrypt/OpenSSLContextImpl;-><init>()V +Lcom/android/org/conscrypt/OpenSSLContextImpl;->engineGetClientSessionContext()Lcom/android/org/conscrypt/ClientSessionContext; +Lcom/android/org/conscrypt/OpenSSLContextImpl;->getPreferred()Lcom/android/org/conscrypt/OpenSSLContextImpl; Lcom/android/org/conscrypt/OpenSSLKey;-><init>(J)V Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey; Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY; Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey()Ljava/security/PublicKey; +Lcom/android/org/conscrypt/OpenSSLKeyHolder;->getOpenSSLKey()Lcom/android/org/conscrypt/OpenSSLKey; Lcom/android/org/conscrypt/OpenSSLProvider;-><init>()V Lcom/android/org/conscrypt/OpenSSLRandom;-><init>()V +Lcom/android/org/conscrypt/OpenSSLSocketFactoryImpl;-><init>()V +Lcom/android/org/conscrypt/OpenSSLSocketFactoryImpl;->sslParameters:Lcom/android/org/conscrypt/SSLParametersImpl; Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String; @@ -2175,32 +4406,83 @@ Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setSoWriteTimeout(I)V Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromX509PemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509Certificate; Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mContext:J +Lcom/android/org/conscrypt/SSLParametersImpl;->getDefault()Lcom/android/org/conscrypt/SSLParametersImpl; +Lcom/android/org/conscrypt/SSLParametersImpl;->getDefaultX509TrustManager()Ljavax/net/ssl/X509TrustManager; +Lcom/android/org/conscrypt/SSLParametersImpl;->getX509TrustManager()Ljavax/net/ssl/X509TrustManager; +Lcom/android/org/conscrypt/SSLParametersImpl;->setEnabledProtocols([Ljava/lang/String;)V +Lcom/android/org/conscrypt/SSLParametersImpl;->x509TrustManager:Ljavax/net/ssl/X509TrustManager; Lcom/android/org/conscrypt/TrustedCertificateStore;-><init>()V Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateChain(Ljava/security/cert/X509Certificate;)Ljava/util/List; Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List; +Lcom/android/org/conscrypt/X509PublicKey;-><init>(Ljava/lang/String;[B)V +Lcom/android/server/net/BaseNetworkObserver;-><init>()V +Lcom/android/server/net/NetlinkTracker;-><init>(Ljava/lang/String;Lcom/android/server/net/NetlinkTracker$Callback;)V +Lcom/android/server/net/NetlinkTracker;->clearLinkProperties()V +Lcom/android/server/net/NetlinkTracker;->getLinkProperties()Landroid/net/LinkProperties; +Lcom/android/server/ResettableTimeout$T;-><init>(Lcom/android/server/ResettableTimeout;)V +Lcom/android/server/ResettableTimeout;->mLock:Landroid/os/ConditionVariable; +Lcom/android/server/ResettableTimeout;->mOffAt:J +Lcom/google/android/collect/Lists;->newArrayList([Ljava/lang/Object;)Ljava/util/ArrayList; +Lcom/google/android/collect/Sets;->newArraySet()Landroid/util/ArraySet; +Lcom/google/android/collect/Sets;->newArraySet([Ljava/lang/Object;)Landroid/util/ArraySet; +Lcom/google/android/collect/Sets;->newHashSet()Ljava/util/HashSet; +Lcom/google/android/collect/Sets;->newHashSet([Ljava/lang/Object;)Ljava/util/HashSet; +Lcom/google/android/collect/Sets;->newSortedSet()Ljava/util/SortedSet; +Lcom/google/android/gles_jni/EGLImpl;-><init>()V +Lcom/google/android/gles_jni/GLImpl;-><init>()V Lcom/google/android/mms/ContentType;->getAudioTypes()Ljava/util/ArrayList; Lcom/google/android/mms/ContentType;->getImageTypes()Ljava/util/ArrayList; Lcom/google/android/mms/ContentType;->getVideoTypes()Ljava/util/ArrayList; Lcom/google/android/mms/ContentType;->isAudioType(Ljava/lang/String;)Z Lcom/google/android/mms/ContentType;->isDrmType(Ljava/lang/String;)Z Lcom/google/android/mms/ContentType;->isImageType(Ljava/lang/String;)Z +Lcom/google/android/mms/ContentType;->isSupportedAudioType(Ljava/lang/String;)Z +Lcom/google/android/mms/ContentType;->isSupportedImageType(Ljava/lang/String;)Z +Lcom/google/android/mms/ContentType;->isSupportedType(Ljava/lang/String;)Z +Lcom/google/android/mms/ContentType;->isSupportedVideoType(Ljava/lang/String;)Z Lcom/google/android/mms/ContentType;->isTextType(Ljava/lang/String;)Z Lcom/google/android/mms/ContentType;->isVideoType(Ljava/lang/String;)Z +Lcom/google/android/mms/InvalidHeaderValueException;-><init>(Ljava/lang/String;)V Lcom/google/android/mms/MmsException;-><init>()V Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;)V +Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;)V Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/Throwable;)V Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(I[B)V +Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V +Lcom/google/android/mms/pdu/AcknowledgeInd;->setReportAllowed(I)V +Lcom/google/android/mms/pdu/AcknowledgeInd;->setTransactionId([B)V +Lcom/google/android/mms/pdu/Base64;->decodeBase64([B)[B +Lcom/google/android/mms/pdu/CharacterSets;->getMibEnumValue(Ljava/lang/String;)I Lcom/google/android/mms/pdu/CharacterSets;->getMimeName(I)Ljava/lang/String; +Lcom/google/android/mms/pdu/DeliveryInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V +Lcom/google/android/mms/pdu/DeliveryInd;->getDate()J Lcom/google/android/mms/pdu/DeliveryInd;->getMessageId()[B +Lcom/google/android/mms/pdu/DeliveryInd;->getStatus()I +Lcom/google/android/mms/pdu/DeliveryInd;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue; Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(I[B)V Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(Ljava/lang/String;)V Lcom/google/android/mms/pdu/EncodedStringValue;-><init>([B)V +Lcom/google/android/mms/pdu/EncodedStringValue;->appendTextString([B)V Lcom/google/android/mms/pdu/EncodedStringValue;->concat([Lcom/google/android/mms/pdu/EncodedStringValue;)Ljava/lang/String; +Lcom/google/android/mms/pdu/EncodedStringValue;->copy(Lcom/google/android/mms/pdu/EncodedStringValue;)Lcom/google/android/mms/pdu/EncodedStringValue; Lcom/google/android/mms/pdu/EncodedStringValue;->encodeStrings([Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue; +Lcom/google/android/mms/pdu/EncodedStringValue;->extract(Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue; +Lcom/google/android/mms/pdu/EncodedStringValue;->getCharacterSet()I Lcom/google/android/mms/pdu/EncodedStringValue;->getString()Ljava/lang/String; +Lcom/google/android/mms/pdu/EncodedStringValue;->getTextString()[B +Lcom/google/android/mms/pdu/EncodedStringValue;->setCharacterSet(I)V +Lcom/google/android/mms/pdu/EncodedStringValue;->setTextString([B)V +Lcom/google/android/mms/pdu/GenericPdu;-><init>()V +Lcom/google/android/mms/pdu/GenericPdu;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue; Lcom/google/android/mms/pdu/GenericPdu;->getMessageType()I +Lcom/google/android/mms/pdu/GenericPdu;->getPduHeaders()Lcom/google/android/mms/pdu/PduHeaders; +Lcom/google/android/mms/pdu/GenericPdu;->mPduHeaders:Lcom/google/android/mms/pdu/PduHeaders; Lcom/google/android/mms/pdu/GenericPdu;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/GenericPdu;->setMessageType(I)V +Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>()V +Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V +Lcom/google/android/mms/pdu/MultimediaMessagePdu;->addTo(Lcom/google/android/mms/pdu/EncodedStringValue;)V Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getBody()Lcom/google/android/mms/pdu/PduBody; Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getDate()J Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getPriority()I @@ -2210,15 +4492,31 @@ Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setBody(Lcom/google/android/m Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setDate(J)V Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setPriority(I)V Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/NotificationInd;-><init>()V +Lcom/google/android/mms/pdu/NotificationInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V +Lcom/google/android/mms/pdu/NotificationInd;->getContentClass()I Lcom/google/android/mms/pdu/NotificationInd;->getContentLocation()[B +Lcom/google/android/mms/pdu/NotificationInd;->getDeliveryReport()I Lcom/google/android/mms/pdu/NotificationInd;->getExpiry()J Lcom/google/android/mms/pdu/NotificationInd;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue; Lcom/google/android/mms/pdu/NotificationInd;->getMessageClass()[B Lcom/google/android/mms/pdu/NotificationInd;->getMessageSize()J Lcom/google/android/mms/pdu/NotificationInd;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue; Lcom/google/android/mms/pdu/NotificationInd;->getTransactionId()[B +Lcom/google/android/mms/pdu/NotificationInd;->setContentClass(I)V Lcom/google/android/mms/pdu/NotificationInd;->setContentLocation([B)V +Lcom/google/android/mms/pdu/NotificationInd;->setDeliveryReport(I)V +Lcom/google/android/mms/pdu/NotificationInd;->setExpiry(J)V +Lcom/google/android/mms/pdu/NotificationInd;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/NotificationInd;->setMessageClass([B)V +Lcom/google/android/mms/pdu/NotificationInd;->setMessageSize(J)V +Lcom/google/android/mms/pdu/NotificationInd;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/NotificationInd;->setTransactionId([B)V Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(I[BI)V +Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V +Lcom/google/android/mms/pdu/NotifyRespInd;->setReportAllowed(I)V +Lcom/google/android/mms/pdu/NotifyRespInd;->setStatus(I)V +Lcom/google/android/mms/pdu/NotifyRespInd;->setTransactionId([B)V Lcom/google/android/mms/pdu/PduBody;-><init>()V Lcom/google/android/mms/pdu/PduBody;->addPart(ILcom/google/android/mms/pdu/PduPart;)V Lcom/google/android/mms/pdu/PduBody;->addPart(Lcom/google/android/mms/pdu/PduPart;)Z @@ -2227,62 +4525,1114 @@ Lcom/google/android/mms/pdu/PduBody;->getPartByContentId(Ljava/lang/String;)Lcom Lcom/google/android/mms/pdu/PduBody;->getPartByContentLocation(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart; Lcom/google/android/mms/pdu/PduBody;->getPartByFileName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart; Lcom/google/android/mms/pdu/PduBody;->getPartByName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart; +Lcom/google/android/mms/pdu/PduBody;->getPartIndex(Lcom/google/android/mms/pdu/PduPart;)I Lcom/google/android/mms/pdu/PduBody;->getPartsNum()I +Lcom/google/android/mms/pdu/PduBody;->removePart(I)Lcom/google/android/mms/pdu/PduPart; +Lcom/google/android/mms/pdu/PduComposer$BufferStack;->copy()V +Lcom/google/android/mms/pdu/PduComposer$BufferStack;->mark()Lcom/google/android/mms/pdu/PduComposer$PositionMarker; +Lcom/google/android/mms/pdu/PduComposer$BufferStack;->newbuf()V +Lcom/google/android/mms/pdu/PduComposer$BufferStack;->pop()V +Lcom/google/android/mms/pdu/PduComposer$PositionMarker;->getLength()I Lcom/google/android/mms/pdu/PduComposer;-><init>(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)V +Lcom/google/android/mms/pdu/PduComposer;->appendEncodedString(Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/PduComposer;->appendHeader(I)I +Lcom/google/android/mms/pdu/PduComposer;->appendLongInteger(J)V +Lcom/google/android/mms/pdu/PduComposer;->appendOctet(I)V +Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString(Ljava/lang/String;)V +Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString([B)V +Lcom/google/android/mms/pdu/PduComposer;->appendShortInteger(I)V +Lcom/google/android/mms/pdu/PduComposer;->appendTextString(Ljava/lang/String;)V +Lcom/google/android/mms/pdu/PduComposer;->appendTextString([B)V +Lcom/google/android/mms/pdu/PduComposer;->appendUintvarInteger(J)V +Lcom/google/android/mms/pdu/PduComposer;->appendValueLength(J)V +Lcom/google/android/mms/pdu/PduComposer;->arraycopy([BII)V Lcom/google/android/mms/pdu/PduComposer;->make()[B +Lcom/google/android/mms/pdu/PduComposer;->mContentTypeMap:Ljava/util/HashMap; +Lcom/google/android/mms/pdu/PduComposer;->mMessage:Ljava/io/ByteArrayOutputStream; +Lcom/google/android/mms/pdu/PduComposer;->mPdu:Lcom/google/android/mms/pdu/GenericPdu; +Lcom/google/android/mms/pdu/PduComposer;->mPduHeader:Lcom/google/android/mms/pdu/PduHeaders; +Lcom/google/android/mms/pdu/PduComposer;->mPosition:I +Lcom/google/android/mms/pdu/PduComposer;->mResolver:Landroid/content/ContentResolver; +Lcom/google/android/mms/pdu/PduComposer;->mStack:Lcom/google/android/mms/pdu/PduComposer$BufferStack; +Lcom/google/android/mms/pdu/PduContentTypes;->contentTypes:[Ljava/lang/String; +Lcom/google/android/mms/pdu/PduHeaders;-><init>()V +Lcom/google/android/mms/pdu/PduHeaders;->appendEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V +Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValue(I)Lcom/google/android/mms/pdu/EncodedStringValue; +Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValues(I)[Lcom/google/android/mms/pdu/EncodedStringValue; +Lcom/google/android/mms/pdu/PduHeaders;->getLongInteger(I)J +Lcom/google/android/mms/pdu/PduHeaders;->getOctet(I)I +Lcom/google/android/mms/pdu/PduHeaders;->getTextString(I)[B +Lcom/google/android/mms/pdu/PduHeaders;->setEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V +Lcom/google/android/mms/pdu/PduHeaders;->setLongInteger(JI)V +Lcom/google/android/mms/pdu/PduHeaders;->setOctet(II)V +Lcom/google/android/mms/pdu/PduParser;->$assertionsDisabled:Z +Lcom/google/android/mms/pdu/PduParser;-><init>([BZ)V +Lcom/google/android/mms/pdu/PduParser;->checkPartPosition(Lcom/google/android/mms/pdu/PduPart;)I +Lcom/google/android/mms/pdu/PduParser;->log(Ljava/lang/String;)V Lcom/google/android/mms/pdu/PduParser;->parse()Lcom/google/android/mms/pdu/GenericPdu; +Lcom/google/android/mms/pdu/PduParser;->parseContentType(Ljava/io/ByteArrayInputStream;Ljava/util/HashMap;)[B +Lcom/google/android/mms/pdu/PduParser;->parsePartHeaders(Ljava/io/ByteArrayInputStream;Lcom/google/android/mms/pdu/PduPart;I)Z +Lcom/google/android/mms/pdu/PduParser;->parseShortInteger(Ljava/io/ByteArrayInputStream;)I +Lcom/google/android/mms/pdu/PduParser;->parseUnsignedInt(Ljava/io/ByteArrayInputStream;)I +Lcom/google/android/mms/pdu/PduParser;->parseValueLength(Ljava/io/ByteArrayInputStream;)I +Lcom/google/android/mms/pdu/PduParser;->parseWapString(Ljava/io/ByteArrayInputStream;I)[B Lcom/google/android/mms/pdu/PduPart;-><init>()V Lcom/google/android/mms/pdu/PduPart;->generateLocation()Ljava/lang/String; Lcom/google/android/mms/pdu/PduPart;->getCharset()I +Lcom/google/android/mms/pdu/PduPart;->getContentDisposition()[B +Lcom/google/android/mms/pdu/PduPart;->getContentId()[B Lcom/google/android/mms/pdu/PduPart;->getContentLocation()[B +Lcom/google/android/mms/pdu/PduPart;->getContentTransferEncoding()[B Lcom/google/android/mms/pdu/PduPart;->getContentType()[B Lcom/google/android/mms/pdu/PduPart;->getData()[B +Lcom/google/android/mms/pdu/PduPart;->getDataLength()I Lcom/google/android/mms/pdu/PduPart;->getDataUri()Landroid/net/Uri; Lcom/google/android/mms/pdu/PduPart;->getFilename()[B Lcom/google/android/mms/pdu/PduPart;->getName()[B Lcom/google/android/mms/pdu/PduPart;->setCharset(I)V +Lcom/google/android/mms/pdu/PduPart;->setContentDisposition([B)V Lcom/google/android/mms/pdu/PduPart;->setContentId([B)V Lcom/google/android/mms/pdu/PduPart;->setContentLocation([B)V +Lcom/google/android/mms/pdu/PduPart;->setContentTransferEncoding([B)V Lcom/google/android/mms/pdu/PduPart;->setContentType([B)V Lcom/google/android/mms/pdu/PduPart;->setData([B)V Lcom/google/android/mms/pdu/PduPart;->setDataUri(Landroid/net/Uri;)V +Lcom/google/android/mms/pdu/PduPart;->setFilename([B)V +Lcom/google/android/mms/pdu/PduPart;->setName([B)V +Lcom/google/android/mms/pdu/PduPersister;->ADDRESS_FIELDS:[I +Lcom/google/android/mms/pdu/PduPersister;->CHARSET_COLUMN_NAME_MAP:Ljava/util/HashMap; +Lcom/google/android/mms/pdu/PduPersister;->ENCODED_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap; +Lcom/google/android/mms/pdu/PduPersister;->getByteArrayFromPartColumn(Landroid/database/Cursor;I)[B Lcom/google/android/mms/pdu/PduPersister;->getBytes(Ljava/lang/String;)[B +Lcom/google/android/mms/pdu/PduPersister;->getIntegerFromPartColumn(Landroid/database/Cursor;I)Ljava/lang/Integer; +Lcom/google/android/mms/pdu/PduPersister;->getPartContentType(Lcom/google/android/mms/pdu/PduPart;)Ljava/lang/String; Lcom/google/android/mms/pdu/PduPersister;->getPduPersister(Landroid/content/Context;)Lcom/google/android/mms/pdu/PduPersister; Lcom/google/android/mms/pdu/PduPersister;->getPendingMessages(J)Landroid/database/Cursor; Lcom/google/android/mms/pdu/PduPersister;->load(Landroid/net/Uri;)Lcom/google/android/mms/pdu/GenericPdu; +Lcom/google/android/mms/pdu/PduPersister;->loadRecipients(ILjava/util/HashSet;Ljava/util/HashMap;Z)V +Lcom/google/android/mms/pdu/PduPersister;->LONG_COLUMN_NAME_MAP:Ljava/util/HashMap; +Lcom/google/android/mms/pdu/PduPersister;->mContentResolver:Landroid/content/ContentResolver; +Lcom/google/android/mms/pdu/PduPersister;->mContext:Landroid/content/Context; +Lcom/google/android/mms/pdu/PduPersister;->MESSAGE_BOX_MAP:Ljava/util/HashMap; Lcom/google/android/mms/pdu/PduPersister;->move(Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri; +Lcom/google/android/mms/pdu/PduPersister;->mTelephonyManager:Landroid/telephony/TelephonyManager; +Lcom/google/android/mms/pdu/PduPersister;->OCTET_COLUMN_NAME_MAP:Ljava/util/HashMap; +Lcom/google/android/mms/pdu/PduPersister;->PART_PROJECTION:[Ljava/lang/String; +Lcom/google/android/mms/pdu/PduPersister;->PDU_CACHE_INSTANCE:Lcom/google/android/mms/util/PduCache; Lcom/google/android/mms/pdu/PduPersister;->persist(Lcom/google/android/mms/pdu/GenericPdu;Landroid/net/Uri;ZZLjava/util/HashMap;)Landroid/net/Uri; +Lcom/google/android/mms/pdu/PduPersister;->persistAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V Lcom/google/android/mms/pdu/PduPersister;->persistPart(Lcom/google/android/mms/pdu/PduPart;JLjava/util/HashMap;)Landroid/net/Uri; +Lcom/google/android/mms/pdu/PduPersister;->TEXT_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap; Lcom/google/android/mms/pdu/PduPersister;->toIsoString([B)Ljava/lang/String; +Lcom/google/android/mms/pdu/PduPersister;->updateAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V Lcom/google/android/mms/pdu/PduPersister;->updateHeaders(Landroid/net/Uri;Lcom/google/android/mms/pdu/SendReq;)V Lcom/google/android/mms/pdu/PduPersister;->updateParts(Landroid/net/Uri;Lcom/google/android/mms/pdu/PduBody;Ljava/util/HashMap;)V +Lcom/google/android/mms/pdu/QuotedPrintable;->decodeQuotedPrintable([B)[B +Lcom/google/android/mms/pdu/ReadOrigInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V Lcom/google/android/mms/pdu/ReadOrigInd;->getMessageId()[B +Lcom/google/android/mms/pdu/ReadOrigInd;->getReadStatus()I Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/EncodedStringValue;[BII[Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V +Lcom/google/android/mms/pdu/ReadRecInd;->getMessageId()[B Lcom/google/android/mms/pdu/ReadRecInd;->setDate(J)V +Lcom/google/android/mms/pdu/RetrieveConf;-><init>()V +Lcom/google/android/mms/pdu/RetrieveConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V +Lcom/google/android/mms/pdu/RetrieveConf;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/RetrieveConf;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue; +Lcom/google/android/mms/pdu/RetrieveConf;->getContentType()[B +Lcom/google/android/mms/pdu/RetrieveConf;->getDeliveryReport()I Lcom/google/android/mms/pdu/RetrieveConf;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue; +Lcom/google/android/mms/pdu/RetrieveConf;->getMessageClass()[B Lcom/google/android/mms/pdu/RetrieveConf;->getMessageId()[B +Lcom/google/android/mms/pdu/RetrieveConf;->getReadReport()I +Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveStatus()I +Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveText()Lcom/google/android/mms/pdu/EncodedStringValue; Lcom/google/android/mms/pdu/RetrieveConf;->getTransactionId()[B +Lcom/google/android/mms/pdu/RetrieveConf;->setContentType([B)V +Lcom/google/android/mms/pdu/RetrieveConf;->setDeliveryReport(I)V +Lcom/google/android/mms/pdu/RetrieveConf;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/RetrieveConf;->setMessageClass([B)V +Lcom/google/android/mms/pdu/RetrieveConf;->setMessageId([B)V +Lcom/google/android/mms/pdu/RetrieveConf;->setReadReport(I)V +Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveStatus(I)V +Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveText(Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/RetrieveConf;->setTransactionId([B)V +Lcom/google/android/mms/pdu/SendConf;-><init>()V +Lcom/google/android/mms/pdu/SendConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V Lcom/google/android/mms/pdu/SendConf;->getMessageId()[B Lcom/google/android/mms/pdu/SendConf;->getResponseStatus()I Lcom/google/android/mms/pdu/SendConf;->getTransactionId()[B Lcom/google/android/mms/pdu/SendReq;-><init>()V +Lcom/google/android/mms/pdu/SendReq;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V +Lcom/google/android/mms/pdu/SendReq;->addBcc(Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/SendReq;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V Lcom/google/android/mms/pdu/SendReq;->getBcc()[Lcom/google/android/mms/pdu/EncodedStringValue; +Lcom/google/android/mms/pdu/SendReq;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue; +Lcom/google/android/mms/pdu/SendReq;->getContentType()[B +Lcom/google/android/mms/pdu/SendReq;->getDeliveryReport()I +Lcom/google/android/mms/pdu/SendReq;->getExpiry()J +Lcom/google/android/mms/pdu/SendReq;->getMessageClass()[B +Lcom/google/android/mms/pdu/SendReq;->getMessageSize()J +Lcom/google/android/mms/pdu/SendReq;->getReadReport()I Lcom/google/android/mms/pdu/SendReq;->getTransactionId()[B +Lcom/google/android/mms/pdu/SendReq;->setBcc([Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/SendReq;->setCc([Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/SendReq;->setContentType([B)V Lcom/google/android/mms/pdu/SendReq;->setDeliveryReport(I)V Lcom/google/android/mms/pdu/SendReq;->setExpiry(J)V Lcom/google/android/mms/pdu/SendReq;->setMessageClass([B)V Lcom/google/android/mms/pdu/SendReq;->setMessageSize(J)V Lcom/google/android/mms/pdu/SendReq;->setReadReport(I)V Lcom/google/android/mms/pdu/SendReq;->setTo([Lcom/google/android/mms/pdu/EncodedStringValue;)V +Lcom/google/android/mms/pdu/SendReq;->setTransactionId([B)V +Lcom/google/android/mms/util/AbstractCache;-><init>()V Lcom/google/android/mms/util/AbstractCache;->get(Ljava/lang/Object;)Ljava/lang/Object; +Lcom/google/android/mms/util/AbstractCache;->purge(Ljava/lang/Object;)Ljava/lang/Object; +Lcom/google/android/mms/util/AbstractCache;->purgeAll()V +Lcom/google/android/mms/util/AbstractCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Z +Lcom/google/android/mms/util/DownloadDrmHelper;->isDrmConvertNeeded(Ljava/lang/String;)Z +Lcom/google/android/mms/util/DownloadDrmHelper;->modifyDrmFwLockFileExtension(Ljava/lang/String;)Ljava/lang/String; +Lcom/google/android/mms/util/DrmConvertSession;->close(Ljava/lang/String;)I +Lcom/google/android/mms/util/DrmConvertSession;->convert([BI)[B +Lcom/google/android/mms/util/DrmConvertSession;->open(Landroid/content/Context;Ljava/lang/String;)Lcom/google/android/mms/util/DrmConvertSession; +Lcom/google/android/mms/util/PduCache;-><init>()V Lcom/google/android/mms/util/PduCache;->getInstance()Lcom/google/android/mms/util/PduCache; Lcom/google/android/mms/util/PduCache;->isUpdating(Landroid/net/Uri;)Z Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/android/mms/util/PduCacheEntry; Lcom/google/android/mms/util/PduCache;->purgeAll()V +Lcom/google/android/mms/util/PduCacheEntry;-><init>(Lcom/google/android/mms/pdu/GenericPdu;IJ)V +Lcom/google/android/mms/util/PduCacheEntry;->getMessageBox()I Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu; +Lcom/google/android/mms/util/PduCacheEntry;->getThreadId()J +Lcom/google/android/mms/util/SqliteWrapper;->checkSQLiteException(Landroid/content/Context;Landroid/database/sqlite/SQLiteException;)V +Lcom/google/android/mms/util/SqliteWrapper;->delete(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri; +Lcom/google/android/mms/util/SqliteWrapper;->query(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor; +Lcom/google/android/mms/util/SqliteWrapper;->requery(Landroid/content/Context;Landroid/database/Cursor;)Z +Lcom/google/android/mms/util/SqliteWrapper;->update(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I +Lcom/google/android/util/AbstractMessageParser$Token$Type;->ACRONYM:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->FLICKR:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->FORMAT:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->GOOGLE_VIDEO:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->HTML:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->LINK:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->MUSIC:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->PHOTO:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->SMILEY:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->values()[Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/google/android/util/AbstractMessageParser$Token$Type;->YOUTUBE_VIDEO:Lcom/google/android/util/AbstractMessageParser$Token$Type; +Lcom/sun/nio/file/ExtendedWatchEventModifier;->FILE_TREE:Lcom/sun/nio/file/ExtendedWatchEventModifier; +Lgov/nist/core/Debug;->printStackTrace(Ljava/lang/Exception;)V +Lgov/nist/core/GenericObject;-><init>()V +Lgov/nist/core/GenericObject;->dbgPrint()V +Lgov/nist/core/GenericObject;->debugDump(I)Ljava/lang/String; +Lgov/nist/core/GenericObject;->encode()Ljava/lang/String; +Lgov/nist/core/GenericObject;->getMatcher()Lgov/nist/core/Match; +Lgov/nist/core/GenericObject;->indentation:I +Lgov/nist/core/GenericObject;->isMySubclass(Ljava/lang/Class;)Z +Lgov/nist/core/GenericObject;->match(Ljava/lang/Object;)Z +Lgov/nist/core/GenericObject;->matchExpression:Lgov/nist/core/Match; +Lgov/nist/core/GenericObject;->merge(Ljava/lang/Object;)V +Lgov/nist/core/GenericObject;->sprint(Ljava/lang/String;)V +Lgov/nist/core/GenericObject;->stringRepresentation:Ljava/lang/String; +Lgov/nist/core/GenericObjectList;-><init>()V +Lgov/nist/core/GenericObjectList;-><init>(Ljava/lang/String;)V +Lgov/nist/core/GenericObjectList;-><init>(Ljava/lang/String;Ljava/lang/Class;)V +Lgov/nist/core/GenericObjectList;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Lgov/nist/core/GenericObjectList;->concatenate(Lgov/nist/core/GenericObjectList;)V +Lgov/nist/core/GenericObjectList;->concatenate(Lgov/nist/core/GenericObjectList;Z)V +Lgov/nist/core/GenericObjectList;->debugDump(I)Ljava/lang/String; +Lgov/nist/core/GenericObjectList;->first()Lgov/nist/core/GenericObject; +Lgov/nist/core/GenericObjectList;->getIndentation()Ljava/lang/String; +Lgov/nist/core/GenericObjectList;->indentation:I +Lgov/nist/core/GenericObjectList;->isMySubclass(Ljava/lang/Class;)Z +Lgov/nist/core/GenericObjectList;->match(Ljava/lang/Object;)Z +Lgov/nist/core/GenericObjectList;->myClass:Ljava/lang/Class; +Lgov/nist/core/GenericObjectList;->next()Lgov/nist/core/GenericObject; +Lgov/nist/core/GenericObjectList;->next(Ljava/util/ListIterator;)Lgov/nist/core/GenericObject; +Lgov/nist/core/GenericObjectList;->setMyClass(Ljava/lang/Class;)V +Lgov/nist/core/GenericObjectList;->stringRep:Ljava/lang/String; +Lgov/nist/core/Host;-><init>()V +Lgov/nist/core/Host;-><init>(Ljava/lang/String;)V +Lgov/nist/core/Host;->encode()Ljava/lang/String; +Lgov/nist/core/Host;->getAddress()Ljava/lang/String; +Lgov/nist/core/Host;->getHostname()Ljava/lang/String; +Lgov/nist/core/Host;->isIPv6Reference(Ljava/lang/String;)Z +Lgov/nist/core/Host;->setAddress(Ljava/lang/String;)V +Lgov/nist/core/Host;->setHostname(Ljava/lang/String;)V +Lgov/nist/core/HostNameParser;-><init>(Lgov/nist/core/LexerCore;)V +Lgov/nist/core/HostNameParser;-><init>(Ljava/lang/String;)V +Lgov/nist/core/HostNameParser;->host()Lgov/nist/core/Host; +Lgov/nist/core/HostNameParser;->hostPort(Z)Lgov/nist/core/HostPort; +Lgov/nist/core/HostPort;-><init>()V +Lgov/nist/core/HostPort;->encode()Ljava/lang/String; +Lgov/nist/core/HostPort;->encode(Ljava/lang/StringBuffer;)Ljava/lang/StringBuffer; +Lgov/nist/core/HostPort;->getHost()Lgov/nist/core/Host; +Lgov/nist/core/HostPort;->getInetAddress()Ljava/net/InetAddress; +Lgov/nist/core/HostPort;->getPort()I +Lgov/nist/core/HostPort;->hasPort()Z +Lgov/nist/core/HostPort;->removePort()V +Lgov/nist/core/HostPort;->setHost(Lgov/nist/core/Host;)V +Lgov/nist/core/HostPort;->setPort(I)V +Lgov/nist/core/InternalErrorHandler;->handleException(Ljava/lang/Exception;)V +Lgov/nist/core/InternalErrorHandler;->handleException(Ljava/lang/String;)V +Lgov/nist/core/LexerCore;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Lgov/nist/core/LexerCore;->byteStringNoSemicolon()Ljava/lang/String; +Lgov/nist/core/LexerCore;->byteStringNoSlash()Ljava/lang/String; +Lgov/nist/core/LexerCore;->charAsString(I)Ljava/lang/String; +Lgov/nist/core/LexerCore;->comment()Ljava/lang/String; +Lgov/nist/core/LexerCore;->createParseException()Ljava/text/ParseException; +Lgov/nist/core/LexerCore;->currentLexer:Ljava/util/Hashtable; +Lgov/nist/core/LexerCore;->getBuffer()Ljava/lang/String; +Lgov/nist/core/LexerCore;->getNextId()Ljava/lang/String; +Lgov/nist/core/LexerCore;->getNextToken()Lgov/nist/core/Token; +Lgov/nist/core/LexerCore;->getPtr()I +Lgov/nist/core/LexerCore;->getRest()Ljava/lang/String; +Lgov/nist/core/LexerCore;->getString(C)Ljava/lang/String; +Lgov/nist/core/LexerCore;->isTokenChar(C)Z +Lgov/nist/core/LexerCore;->lexerTables:Ljava/util/Hashtable; +Lgov/nist/core/LexerCore;->markInputPosition()I +Lgov/nist/core/LexerCore;->match(I)Lgov/nist/core/Token; +Lgov/nist/core/LexerCore;->number()Ljava/lang/String; +Lgov/nist/core/LexerCore;->peekNextToken()Lgov/nist/core/Token; +Lgov/nist/core/LexerCore;->peekNextToken(I)[Lgov/nist/core/Token; +Lgov/nist/core/LexerCore;->quotedString()Ljava/lang/String; +Lgov/nist/core/LexerCore;->rewindInputPosition(I)V +Lgov/nist/core/LexerCore;->selectLexer(Ljava/lang/String;)V +Lgov/nist/core/LexerCore;->SPorHT()V +Lgov/nist/core/LexerCore;->startsId()Z +Lgov/nist/core/LexerCore;->ttoken()Ljava/lang/String; +Lgov/nist/core/LexerCore;->ttokenSafe()Ljava/lang/String; +Lgov/nist/core/Match;->match(Ljava/lang/String;)Z +Lgov/nist/core/NameValue;-><init>()V +Lgov/nist/core/NameValue;-><init>(Ljava/lang/String;Ljava/lang/Object;)V +Lgov/nist/core/NameValue;-><init>(Ljava/lang/String;Ljava/lang/Object;Z)V +Lgov/nist/core/NameValue;->encode()Ljava/lang/String; +Lgov/nist/core/NameValue;->encode(Ljava/lang/StringBuffer;)Ljava/lang/StringBuffer; +Lgov/nist/core/NameValue;->getName()Ljava/lang/String; +Lgov/nist/core/NameValue;->getValueAsObject()Ljava/lang/Object; +Lgov/nist/core/NameValue;->setName(Ljava/lang/String;)V +Lgov/nist/core/NameValue;->setQuotedValue()V +Lgov/nist/core/NameValue;->setSeparator(Ljava/lang/String;)V +Lgov/nist/core/NameValue;->setValueAsObject(Ljava/lang/Object;)V +Lgov/nist/core/NameValueList;-><init>()V +Lgov/nist/core/NameValueList;-><init>(Z)V +Lgov/nist/core/NameValueList;->delete(Ljava/lang/String;)Z +Lgov/nist/core/NameValueList;->encode()Ljava/lang/String; +Lgov/nist/core/NameValueList;->encode(Ljava/lang/StringBuffer;)Ljava/lang/StringBuffer; +Lgov/nist/core/NameValueList;->getNames()Ljava/util/Iterator; +Lgov/nist/core/NameValueList;->getNameValue(Ljava/lang/String;)Lgov/nist/core/NameValue; +Lgov/nist/core/NameValueList;->getParameter(Ljava/lang/String;)Ljava/lang/String; +Lgov/nist/core/NameValueList;->getValue(Ljava/lang/String;)Ljava/lang/Object; +Lgov/nist/core/NameValueList;->hasNameValue(Ljava/lang/String;)Z +Lgov/nist/core/NameValueList;->iterator()Ljava/util/Iterator; +Lgov/nist/core/NameValueList;->set(Lgov/nist/core/NameValue;)V +Lgov/nist/core/NameValueList;->set(Ljava/lang/String;Ljava/lang/Object;)V +Lgov/nist/core/NameValueList;->setSeparator(Ljava/lang/String;)V +Lgov/nist/core/net/DefaultNetworkLayer;->SINGLETON:Lgov/nist/core/net/DefaultNetworkLayer; +Lgov/nist/core/net/NetworkLayer;->createDatagramSocket()Ljava/net/DatagramSocket; +Lgov/nist/core/net/NetworkLayer;->createDatagramSocket(ILjava/net/InetAddress;)Ljava/net/DatagramSocket; +Lgov/nist/core/net/NetworkLayer;->createServerSocket(IILjava/net/InetAddress;)Ljava/net/ServerSocket; +Lgov/nist/core/net/NetworkLayer;->createSocket(Ljava/net/InetAddress;I)Ljava/net/Socket; +Lgov/nist/core/net/NetworkLayer;->createSSLServerSocket(IILjava/net/InetAddress;)Ljavax/net/ssl/SSLServerSocket; +Lgov/nist/core/net/NetworkLayer;->createSSLSocket(Ljava/net/InetAddress;I)Ljavax/net/ssl/SSLSocket; +Lgov/nist/core/ParserCore;-><init>()V +Lgov/nist/core/ParserCore;->lexer:Lgov/nist/core/LexerCore; +Lgov/nist/core/StringTokenizer;->ptr:I +Lgov/nist/core/ThreadAuditor$ThreadHandle;->getPingIntervalInMillisecs()J +Lgov/nist/core/ThreadAuditor$ThreadHandle;->ping()V +Lgov/nist/core/ThreadAuditor;-><init>()V +Lgov/nist/core/ThreadAuditor;->addCurrentThread()Lgov/nist/core/ThreadAuditor$ThreadHandle; +Lgov/nist/core/ThreadAuditor;->getPingIntervalInMillisecs()J +Lgov/nist/core/ThreadAuditor;->isEnabled()Z +Lgov/nist/core/ThreadAuditor;->setPingIntervalInMillisecs(J)V +Lgov/nist/core/Token;-><init>()V +Lgov/nist/core/Token;->getTokenType()I +Lgov/nist/core/Token;->getTokenValue()Ljava/lang/String; +Lgov/nist/javax/sip/address/GenericURI;-><init>()V +Lgov/nist/javax/sip/address/GenericURI;->encode()Ljava/lang/String; +Lgov/nist/javax/sip/address/GenericURI;->getScheme()Ljava/lang/String; +Lgov/nist/javax/sip/address/SipUri;->getHost()Ljava/lang/String; +Lgov/nist/javax/sip/address/SipUri;->getParameter(Ljava/lang/String;)Ljava/lang/String; +Lgov/nist/javax/sip/address/SipUri;->getPort()I +Lgov/nist/javax/sip/address/SipUri;->getUser()Ljava/lang/String; +Lgov/nist/javax/sip/address/SipUri;->removeParameter(Ljava/lang/String;)V +Lgov/nist/javax/sip/address/SipUri;->setParameter(Ljava/lang/String;Ljava/lang/String;)V +Lgov/nist/javax/sip/address/SipUri;->setUserParam(Ljava/lang/String;)V +Lgov/nist/javax/sip/parser/URLParser;-><init>(Ljava/lang/String;)V +Lgov/nist/javax/sip/parser/URLParser;->sipURL(Z)Lgov/nist/javax/sip/address/SipUri; +Ljava/lang/DexCache;->dexFile:J +Ljava/lang/invoke/SerializedLambda;-><init>(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V +Ljava/lang/invoke/SerializedLambda;->getCapturedArg(I)Ljava/lang/Object; +Ljava/lang/invoke/SerializedLambda;->getCapturedArgCount()I +Ljava/lang/invoke/SerializedLambda;->getCapturingClass()Ljava/lang/String; +Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceClass()Ljava/lang/String; +Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceMethodName()Ljava/lang/String; +Ljava/lang/invoke/SerializedLambda;->getFunctionalInterfaceMethodSignature()Ljava/lang/String; +Ljava/lang/invoke/SerializedLambda;->getImplClass()Ljava/lang/String; +Ljava/lang/invoke/SerializedLambda;->getImplMethodKind()I +Ljava/lang/invoke/SerializedLambda;->getImplMethodName()Ljava/lang/String; +Ljava/lang/invoke/SerializedLambda;->getImplMethodSignature()Ljava/lang/String; +Ljava/lang/invoke/SerializedLambda;->getInstantiatedMethodType()Ljava/lang/String; +Ljava/lang/UNIXProcess;->pid:I +Ljava/net/AddressCache$AddressCacheEntry;-><init>(Ljava/lang/Object;)V +Ljava/net/AddressCache$AddressCacheEntry;->expiryNanos:J +Ljava/net/AddressCache$AddressCacheEntry;->value:Ljava/lang/Object; +Ljava/net/AddressCache$AddressCacheKey;->mHostname:Ljava/lang/String; +Ljava/net/AddressCache;->cache:Llibcore/util/BasicLruCache; +Ljava/net/Inet6AddressImpl;->addressCache:Ljava/net/AddressCache; +Ljava/net/PlainSocketImpl;-><init>()V +Ljava/nio/DirectByteBuffer;->cleaner()Lsun/misc/Cleaner; +Ljava/nio/file/FileTreeWalker;->followLinks:Z +Ljava/nio/file/FileTreeWalker;->linkOptions:[Ljava/nio/file/LinkOption; +Ljava/nio/file/FileTreeWalker;->maxDepth:I +Ljava/util/zip/ZipFile$ZipEntryIterator;->nextElement()Ljava/util/zip/ZipEntry; +Ljunit/framework/TestCase;->fName:Ljava/lang/String; +Ljunit/framework/TestSuite;->isPublicTestMethod(Ljava/lang/reflect/Method;)Z +Ljunit/framework/TestSuite;->isTestMethod(Ljava/lang/reflect/Method;)Z +Llibcore/icu/DateIntervalFormat;->formatDateRange(JJILjava/lang/String;)Ljava/lang/String; +Llibcore/icu/ICU;->CACHED_PATTERNS:Llibcore/util/BasicLruCache; +Llibcore/icu/ICU;->getBestDateTimePattern(Ljava/lang/String;Ljava/util/Locale;)Ljava/lang/String; +Llibcore/icu/ICU;->getBestDateTimePatternNative(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Llibcore/icu/ICU;->getDateFormatOrder(Ljava/lang/String;)[C +Llibcore/icu/LocaleData;->firstDayOfWeek:Ljava/lang/Integer; +Llibcore/icu/LocaleData;->get(Ljava/util/Locale;)Llibcore/icu/LocaleData; +Llibcore/icu/LocaleData;->longStandAloneWeekdayNames:[Ljava/lang/String; +Llibcore/icu/LocaleData;->mapInvalidAndNullLocales(Ljava/util/Locale;)Ljava/util/Locale; +Llibcore/icu/LocaleData;->minimalDaysInFirstWeek:Ljava/lang/Integer; +Llibcore/icu/LocaleData;->shortMonthNames:[Ljava/lang/String; +Llibcore/icu/LocaleData;->shortStandAloneMonthNames:[Ljava/lang/String; +Llibcore/icu/LocaleData;->shortStandAloneWeekdayNames:[Ljava/lang/String; +Llibcore/icu/LocaleData;->timeFormat_Hm:Ljava/lang/String; +Llibcore/icu/LocaleData;->timeFormat_hm:Ljava/lang/String; +Llibcore/icu/LocaleData;->today:Ljava/lang/String; +Llibcore/icu/LocaleData;->tomorrow:Ljava/lang/String; +Llibcore/icu/LocaleData;->zeroDigit:C +Llibcore/icu/TimeZoneNames;->forLocale(Ljava/util/Locale;)[Ljava/lang/String; +Llibcore/io/AsynchronousCloseMonitor;->signalBlockedThreads(Ljava/io/FileDescriptor;)V +Llibcore/io/BlockGuardOs;-><init>(Llibcore/io/Os;)V +Llibcore/io/BlockGuardOs;->chmod(Ljava/lang/String;I)V +Llibcore/io/BlockGuardOs;->chown(Ljava/lang/String;II)V +Llibcore/io/BlockGuardOs;->close(Ljava/io/FileDescriptor;)V +Llibcore/io/BlockGuardOs;->fchmod(Ljava/io/FileDescriptor;I)V +Llibcore/io/BlockGuardOs;->fchown(Ljava/io/FileDescriptor;II)V +Llibcore/io/BlockGuardOs;->fdatasync(Ljava/io/FileDescriptor;)V +Llibcore/io/BlockGuardOs;->fstat(Ljava/io/FileDescriptor;)Landroid/system/StructStat; +Llibcore/io/BlockGuardOs;->fstatvfs(Ljava/io/FileDescriptor;)Landroid/system/StructStatVfs; +Llibcore/io/BlockGuardOs;->lchown(Ljava/lang/String;II)V +Llibcore/io/BlockGuardOs;->link(Ljava/lang/String;Ljava/lang/String;)V +Llibcore/io/BlockGuardOs;->lseek(Ljava/io/FileDescriptor;JI)J +Llibcore/io/BlockGuardOs;->lstat(Ljava/lang/String;)Landroid/system/StructStat; +Llibcore/io/BlockGuardOs;->mkdir(Ljava/lang/String;I)V +Llibcore/io/BlockGuardOs;->mkfifo(Ljava/lang/String;I)V +Llibcore/io/BlockGuardOs;->open(Ljava/lang/String;II)Ljava/io/FileDescriptor; +Llibcore/io/BlockGuardOs;->posix_fallocate(Ljava/io/FileDescriptor;JJ)V +Llibcore/io/BlockGuardOs;->pread(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;J)I +Llibcore/io/BlockGuardOs;->pread(Ljava/io/FileDescriptor;[BIIJ)I +Llibcore/io/BlockGuardOs;->pwrite(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;J)I +Llibcore/io/BlockGuardOs;->pwrite(Ljava/io/FileDescriptor;[BIIJ)I +Llibcore/io/BlockGuardOs;->read(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;)I +Llibcore/io/BlockGuardOs;->read(Ljava/io/FileDescriptor;[BII)I +Llibcore/io/BlockGuardOs;->readlink(Ljava/lang/String;)Ljava/lang/String; +Llibcore/io/BlockGuardOs;->readv(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I +Llibcore/io/BlockGuardOs;->realpath(Ljava/lang/String;)Ljava/lang/String; +Llibcore/io/BlockGuardOs;->remove(Ljava/lang/String;)V +Llibcore/io/BlockGuardOs;->rename(Ljava/lang/String;Ljava/lang/String;)V +Llibcore/io/BlockGuardOs;->stat(Ljava/lang/String;)Landroid/system/StructStat; +Llibcore/io/BlockGuardOs;->statvfs(Ljava/lang/String;)Landroid/system/StructStatVfs; +Llibcore/io/BlockGuardOs;->symlink(Ljava/lang/String;Ljava/lang/String;)V +Llibcore/io/BlockGuardOs;->write(Ljava/io/FileDescriptor;Ljava/nio/ByteBuffer;)I +Llibcore/io/BlockGuardOs;->write(Ljava/io/FileDescriptor;[BII)I +Llibcore/io/BlockGuardOs;->writev(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I +Llibcore/io/BufferIterator;->readByte()B +Llibcore/io/BufferIterator;->readByteArray([BII)V +Llibcore/io/BufferIterator;->readInt()I +Llibcore/io/BufferIterator;->readIntArray([III)V +Llibcore/io/BufferIterator;->seek(I)V +Llibcore/io/BufferIterator;->skip(I)V +Llibcore/io/DropBox;->addText(Ljava/lang/String;Ljava/lang/String;)V +Llibcore/io/ForwardingOs;-><init>(Llibcore/io/Os;)V +Llibcore/io/ForwardingOs;->access(Ljava/lang/String;I)Z +Llibcore/io/ForwardingOs;->chmod(Ljava/lang/String;I)V +Llibcore/io/ForwardingOs;->chown(Ljava/lang/String;II)V +Llibcore/io/ForwardingOs;->getenv(Ljava/lang/String;)Ljava/lang/String; +Llibcore/io/ForwardingOs;->lchown(Ljava/lang/String;II)V +Llibcore/io/ForwardingOs;->link(Ljava/lang/String;Ljava/lang/String;)V +Llibcore/io/ForwardingOs;->lstat(Ljava/lang/String;)Landroid/system/StructStat; +Llibcore/io/ForwardingOs;->mkdir(Ljava/lang/String;I)V +Llibcore/io/ForwardingOs;->mkfifo(Ljava/lang/String;I)V +Llibcore/io/ForwardingOs;->open(Ljava/lang/String;II)Ljava/io/FileDescriptor; +Llibcore/io/ForwardingOs;->os:Llibcore/io/Os; +Llibcore/io/ForwardingOs;->readlink(Ljava/lang/String;)Ljava/lang/String; +Llibcore/io/ForwardingOs;->remove(Ljava/lang/String;)V +Llibcore/io/ForwardingOs;->removexattr(Ljava/lang/String;Ljava/lang/String;)V +Llibcore/io/ForwardingOs;->rename(Ljava/lang/String;Ljava/lang/String;)V +Llibcore/io/ForwardingOs;->setenv(Ljava/lang/String;Ljava/lang/String;Z)V +Llibcore/io/ForwardingOs;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V +Llibcore/io/ForwardingOs;->setxattr(Ljava/lang/String;Ljava/lang/String;[BI)V +Llibcore/io/ForwardingOs;->stat(Ljava/lang/String;)Landroid/system/StructStat; +Llibcore/io/ForwardingOs;->statvfs(Ljava/lang/String;)Landroid/system/StructStatVfs; +Llibcore/io/ForwardingOs;->symlink(Ljava/lang/String;Ljava/lang/String;)V +Llibcore/io/ForwardingOs;->sysconf(I)J +Llibcore/io/ForwardingOs;->unlink(Ljava/lang/String;)V +Llibcore/io/IoBridge;->isConnected(Ljava/io/FileDescriptor;Ljava/net/InetAddress;III)Z +Llibcore/io/IoUtils;->closeQuietly(Ljava/io/FileDescriptor;)V +Llibcore/io/IoUtils;->closeQuietly(Ljava/lang/AutoCloseable;)V +Llibcore/io/IoUtils;->closeQuietly(Ljava/net/Socket;)V +Llibcore/io/IoUtils;->readFileAsByteArray(Ljava/lang/String;)[B +Llibcore/io/IoUtils;->readFileAsString(Ljava/lang/String;)Ljava/lang/String; +Llibcore/io/IoUtils;->setBlocking(Ljava/io/FileDescriptor;Z)V +Llibcore/io/MemoryMappedFile;->bigEndianIterator()Llibcore/io/BufferIterator; +Llibcore/io/MemoryMappedFile;->mmapRO(Ljava/lang/String;)Llibcore/io/MemoryMappedFile; +Llibcore/io/Os;->chmod(Ljava/lang/String;I)V +Llibcore/io/Os;->close(Ljava/io/FileDescriptor;)V +Llibcore/io/Os;->connect(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V +Llibcore/io/Os;->gai_strerror(I)Ljava/lang/String; +Llibcore/io/Os;->remove(Ljava/lang/String;)V +Llibcore/io/Os;->setenv(Ljava/lang/String;Ljava/lang/String;Z)V +Llibcore/io/Os;->setsockoptTimeval(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V +Llibcore/io/Os;->stat(Ljava/lang/String;)Landroid/system/StructStat; +Llibcore/io/Os;->strerror(I)Ljava/lang/String; +Llibcore/io/Os;->sysconf(I)J +Llibcore/io/Streams;->readAsciiLine(Ljava/io/InputStream;)Ljava/lang/String; +Llibcore/io/Streams;->readFully(Ljava/io/InputStream;)[B +Llibcore/io/Streams;->readFully(Ljava/io/InputStream;[B)V +Llibcore/io/Streams;->readSingleByte(Ljava/io/InputStream;)I +Llibcore/io/Streams;->skipAll(Ljava/io/InputStream;)V +Llibcore/io/Streams;->writeSingleByte(Ljava/io/OutputStream;I)V +Llibcore/net/event/NetworkEventDispatcher;->addListener(Llibcore/net/event/NetworkEventListener;)V +Llibcore/net/event/NetworkEventDispatcher;->getInstance()Llibcore/net/event/NetworkEventDispatcher; +Llibcore/net/event/NetworkEventListener;-><init>()V +Llibcore/net/http/HttpDate;->format(Ljava/util/Date;)Ljava/lang/String; +Llibcore/net/http/HttpDate;->parse(Ljava/lang/String;)Ljava/util/Date; +Llibcore/net/MimeUtils;->guessExtensionFromMimeType(Ljava/lang/String;)Ljava/lang/String; +Llibcore/net/MimeUtils;->guessMimeTypeFromExtension(Ljava/lang/String;)Ljava/lang/String; +Llibcore/net/NetworkSecurityPolicy;->isCleartextTrafficPermitted()Z +Llibcore/util/BasicLruCache;-><init>(I)V +Llibcore/util/BasicLruCache;->evictAll()V +Llibcore/util/BasicLruCache;->get(Ljava/lang/Object;)Ljava/lang/Object; +Llibcore/util/BasicLruCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; +Llibcore/util/EmptyArray;->BYTE:[B +Llibcore/util/EmptyArray;->INT:[I +Llibcore/util/EmptyArray;->OBJECT:[Ljava/lang/Object; +Llibcore/util/ZoneInfoDB$TzData;-><init>()V +Lorg/apache/harmony/dalvik/ddmc/Chunk;-><init>(ILjava/nio/ByteBuffer;)V +Lorg/apache/harmony/dalvik/ddmc/ChunkHandler;->CHUNK_ORDER:Ljava/nio/ByteOrder; +Lorg/apache/harmony/dalvik/ddmc/DdmServer;->broadcast(I)V +Lorg/apache/harmony/dalvik/ddmc/DdmServer;->sendChunk(Lorg/apache/harmony/dalvik/ddmc/Chunk;)V +Lorg/apache/harmony/dalvik/ddmc/DdmVmInternal;->getThreadStats()[B +Lorg/apache/harmony/xml/dom/ElementImpl;->localName:Ljava/lang/String; +Lorg/apache/harmony/xml/ExpatAttributes;-><init>()V +Lorg/apache/harmony/xml/ExpatParser$EntityParser;->depth:I +Lorg/apache/harmony/xml/ExpatParser;-><init>(Ljava/lang/String;Lorg/apache/harmony/xml/ExpatReader;ZLjava/lang/String;Ljava/lang/String;)V +Lorg/apache/harmony/xml/ExpatParser;->append([BII)V +Lorg/apache/harmony/xml/ExpatParser;->append([CII)V +Lorg/apache/harmony/xml/ExpatParser;->attributes:Lorg/apache/harmony/xml/ExpatAttributes; +Lorg/apache/harmony/xml/ExpatParser;->cloneAttributes()Lorg/xml/sax/Attributes; +Lorg/apache/harmony/xml/ExpatParser;->finish()V +Lorg/apache/harmony/xml/ExpatParser;->xmlReader:Lorg/apache/harmony/xml/ExpatReader; +Lorg/apache/harmony/xml/ExpatReader;-><init>()V +Lorg/apache/harmony/xml/ExpatReader;->contentHandler:Lorg/xml/sax/ContentHandler; +Lorg/apache/xalan/extensions/ExpressionContext;->getContextNode()Lorg/w3c/dom/Node; +Lorg/apache/xalan/extensions/ExpressionContext;->getErrorListener()Ljavax/xml/transform/ErrorListener; +Lorg/apache/xalan/extensions/ExpressionContext;->getVariableOrParam(Lorg/apache/xml/utils/QName;)Lorg/apache/xpath/objects/XObject; +Lorg/apache/xalan/extensions/ExpressionContext;->getXPathContext()Lorg/apache/xpath/XPathContext; +Lorg/apache/xalan/extensions/ExtensionHandler;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Lorg/apache/xalan/extensions/ExtensionHandler;->callFunction(Ljava/lang/String;Ljava/util/Vector;Ljava/lang/Object;Lorg/apache/xalan/extensions/ExpressionContext;)Ljava/lang/Object; +Lorg/apache/xalan/extensions/ExtensionHandler;->getClassForName(Ljava/lang/String;)Ljava/lang/Class; +Lorg/apache/xalan/extensions/ObjectFactory$ConfigurationError;-><init>(Ljava/lang/String;Ljava/lang/Exception;)V +Lorg/apache/xalan/extensions/ObjectFactory;->findClassLoader()Ljava/lang/ClassLoader; +Lorg/apache/xalan/extensions/ObjectFactory;->findProviderClass(Ljava/lang/String;Ljava/lang/ClassLoader;Z)Ljava/lang/Class; +Lorg/apache/xalan/processor/TransformerFactoryImpl;-><init>()V +Lorg/apache/xalan/res/XSLMessages;->createMessage(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; +Lorg/apache/xalan/res/XSLTErrorResources;-><init>()V +Lorg/apache/xalan/serialize/SerializerUtils;->outputResultTreeFragment(Lorg/apache/xml/serializer/SerializationHandler;Lorg/apache/xpath/objects/XObject;Lorg/apache/xpath/XPathContext;)V +Lorg/apache/xalan/templates/AVT;->evaluate(Lorg/apache/xpath/XPathContext;ILorg/apache/xml/utils/PrefixResolver;)Ljava/lang/String; +Lorg/apache/xalan/templates/ElemElement;->execute(Lorg/apache/xalan/transformer/TransformerImpl;)V +Lorg/apache/xalan/templates/ElemExsltFunction;->execute(Lorg/apache/xalan/transformer/TransformerImpl;[Lorg/apache/xpath/objects/XObject;)V +Lorg/apache/xalan/templates/ElemExtensionCall;->getAttribute(Ljava/lang/String;Lorg/w3c/dom/Node;Lorg/apache/xalan/transformer/TransformerImpl;)Ljava/lang/String; +Lorg/apache/xalan/templates/ElemLiteralResult;->getLiteralResultAttribute(Ljava/lang/String;)Lorg/apache/xalan/templates/AVT; +Lorg/apache/xalan/templates/ElemTemplate;->getMatch()Lorg/apache/xpath/XPath; +Lorg/apache/xalan/templates/ElemTemplate;->getName()Lorg/apache/xml/utils/QName; +Lorg/apache/xalan/templates/ElemTemplateElement;->getFirstChildElem()Lorg/apache/xalan/templates/ElemTemplateElement; +Lorg/apache/xalan/templates/ElemTemplateElement;->getNextSiblingElem()Lorg/apache/xalan/templates/ElemTemplateElement; +Lorg/apache/xalan/templates/ElemTemplateElement;->getParentElem()Lorg/apache/xalan/templates/ElemTemplateElement; +Lorg/apache/xalan/templates/ElemTemplateElement;->getStylesheetRoot()Lorg/apache/xalan/templates/StylesheetRoot; +Lorg/apache/xalan/templates/ElemTemplateElement;->getXSLToken()I +Lorg/apache/xalan/templates/ElemTextLiteral;->getChars()[C +Lorg/apache/xalan/templates/KeyDeclaration;->getName()Lorg/apache/xml/utils/QName; +Lorg/apache/xalan/templates/KeyDeclaration;->getUse()Lorg/apache/xpath/XPath; +Lorg/apache/xalan/templates/StylesheetRoot;->getDefaultRootRule()Lorg/apache/xalan/templates/ElemTemplate; +Lorg/apache/xalan/templates/StylesheetRoot;->getDefaultRule()Lorg/apache/xalan/templates/ElemTemplate; +Lorg/apache/xalan/templates/StylesheetRoot;->getDefaultTextRule()Lorg/apache/xalan/templates/ElemTemplate; +Lorg/apache/xalan/templates/StylesheetRoot;->getTemplateComposed(Lorg/apache/xml/utils/QName;)Lorg/apache/xalan/templates/ElemTemplate; +Lorg/apache/xalan/transformer/ClonerToResultTree;->cloneToResultTree(IILorg/apache/xml/dtm/DTM;Lorg/apache/xml/serializer/SerializationHandler;Z)V +Lorg/apache/xalan/transformer/DecimalToRoman;-><init>(JLjava/lang/String;JLjava/lang/String;)V +Lorg/apache/xalan/transformer/DecimalToRoman;->m_postLetter:Ljava/lang/String; +Lorg/apache/xalan/transformer/DecimalToRoman;->m_postValue:J +Lorg/apache/xalan/transformer/DecimalToRoman;->m_preLetter:Ljava/lang/String; +Lorg/apache/xalan/transformer/DecimalToRoman;->m_preValue:J +Lorg/apache/xalan/transformer/MsgMgr;->error(Ljavax/xml/transform/SourceLocator;Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;Ljava/lang/String;)V +Lorg/apache/xalan/transformer/TransformerImpl;->createSerializationHandler(Ljavax/xml/transform/Result;Lorg/apache/xalan/templates/OutputProperties;)Lorg/apache/xml/serializer/SerializationHandler; +Lorg/apache/xalan/transformer/TransformerImpl;->executeChildTemplates(Lorg/apache/xalan/templates/ElemTemplateElement;Lorg/w3c/dom/Node;Lorg/apache/xml/utils/QName;Lorg/xml/sax/ContentHandler;)V +Lorg/apache/xalan/transformer/TransformerImpl;->executeChildTemplates(Lorg/apache/xalan/templates/ElemTemplateElement;Z)V +Lorg/apache/xalan/transformer/TransformerImpl;->getCountersTable()Lorg/apache/xalan/transformer/CountersTable; +Lorg/apache/xalan/transformer/TransformerImpl;->getCurrentTemplateElements()Lorg/apache/xml/utils/ObjectStack; +Lorg/apache/xalan/transformer/TransformerImpl;->getCurrentTemplateElementsCount()I +Lorg/apache/xalan/transformer/TransformerImpl;->getMatchedNode()I +Lorg/apache/xalan/transformer/TransformerImpl;->getMatchedTemplate()Lorg/apache/xalan/templates/ElemTemplate; +Lorg/apache/xalan/transformer/TransformerImpl;->getMode()Lorg/apache/xml/utils/QName; +Lorg/apache/xalan/transformer/TransformerImpl;->getMsgMgr()Lorg/apache/xalan/transformer/MsgMgr; +Lorg/apache/xalan/transformer/TransformerImpl;->getOutputFormat()Lorg/apache/xalan/templates/OutputProperties; +Lorg/apache/xalan/transformer/TransformerImpl;->getResultTreeHandler()Lorg/apache/xml/serializer/SerializationHandler; +Lorg/apache/xalan/transformer/TransformerImpl;->getSerializationHandler()Lorg/apache/xml/serializer/SerializationHandler; +Lorg/apache/xalan/transformer/TransformerImpl;->getXPathContext()Lorg/apache/xpath/XPathContext; +Lorg/apache/xalan/transformer/TransformerImpl;->m_attrSetStack:Ljava/util/Stack; +Lorg/apache/xalan/transformer/TransformerImpl;->m_currentMatchedNodes:Lorg/apache/xml/utils/NodeVector; +Lorg/apache/xalan/transformer/TransformerImpl;->m_currentMatchTemplates:Ljava/util/Stack; +Lorg/apache/xalan/transformer/TransformerImpl;->m_currentTemplateElements:Lorg/apache/xml/utils/ObjectStack; +Lorg/apache/xalan/transformer/TransformerImpl;->m_currentTemplateRuleIsNull:Lorg/apache/xml/utils/BoolStack; +Lorg/apache/xalan/transformer/TransformerImpl;->m_inputContentHandler:Lorg/xml/sax/ContentHandler; +Lorg/apache/xalan/transformer/TransformerImpl;->m_outputTarget:Ljavax/xml/transform/Result; +Lorg/apache/xalan/transformer/TransformerImpl;->m_stringWriterObjectPool:Lorg/apache/xml/utils/ObjectPool; +Lorg/apache/xalan/transformer/TransformerImpl;->m_urlOfSource:Ljava/lang/String; +Lorg/apache/xalan/transformer/TransformerImpl;->m_xcontext:Lorg/apache/xpath/XPathContext; +Lorg/apache/xalan/transformer/TransformerImpl;->popCurrentFuncResult()Ljava/lang/Object; +Lorg/apache/xalan/transformer/TransformerImpl;->pushCurrentFuncResult(Ljava/lang/Object;)V +Lorg/apache/xalan/transformer/TransformerImpl;->pushElemTemplateElement(Lorg/apache/xalan/templates/ElemTemplateElement;)V +Lorg/apache/xalan/Version;->getVersion()Ljava/lang/String; +Lorg/apache/xalan/xslt/EnvironmentCheck;-><init>()V +Lorg/apache/xalan/xslt/EnvironmentCheck;->appendEnvironmentReport(Lorg/w3c/dom/Node;Lorg/w3c/dom/Document;Ljava/util/Hashtable;)V +Lorg/apache/xalan/xslt/EnvironmentCheck;->getEnvironmentHash()Ljava/util/Hashtable; +Lorg/apache/xalan/xslt/ObjectFactory;->findClassLoader()Ljava/lang/ClassLoader; +Lorg/apache/xalan/xslt/ObjectFactory;->newInstance(Ljava/lang/String;Ljava/lang/ClassLoader;Z)Ljava/lang/Object; +Lorg/apache/xml/dtm/Axis;->getNames(I)Ljava/lang/String; +Lorg/apache/xml/dtm/Axis;->isReverse(I)Z +Lorg/apache/xml/dtm/DTM;->getDocument()I +Lorg/apache/xml/dtm/DTM;->getDocumentRoot(I)I +Lorg/apache/xml/dtm/DTM;->getFirstChild(I)I +Lorg/apache/xml/dtm/DTM;->getNextSibling(I)I +Lorg/apache/xml/dtm/DTM;->getNode(I)Lorg/w3c/dom/Node; +Lorg/apache/xml/dtm/DTM;->getNodeName(I)Ljava/lang/String; +Lorg/apache/xml/dtm/DTM;->getNodeType(I)S +Lorg/apache/xml/dtm/DTM;->getParent(I)I +Lorg/apache/xml/dtm/DTM;->getSourceLocatorFor(I)Ljavax/xml/transform/SourceLocator; +Lorg/apache/xml/dtm/DTM;->getStringValue(I)Lorg/apache/xml/utils/XMLString; +Lorg/apache/xml/dtm/DTM;->migrateTo(Lorg/apache/xml/dtm/DTMManager;)V +Lorg/apache/xml/dtm/DTMAxisIterator;->cloneIterator()Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/DTMAxisIterator;->getLast()I +Lorg/apache/xml/dtm/DTMAxisIterator;->getNodeByPosition(I)I +Lorg/apache/xml/dtm/DTMAxisIterator;->getPosition()I +Lorg/apache/xml/dtm/DTMAxisIterator;->gotoMark()V +Lorg/apache/xml/dtm/DTMAxisIterator;->isReverse()Z +Lorg/apache/xml/dtm/DTMAxisIterator;->next()I +Lorg/apache/xml/dtm/DTMAxisIterator;->reset()Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/DTMAxisIterator;->setMark()V +Lorg/apache/xml/dtm/DTMAxisIterator;->setRestartable(Z)V +Lorg/apache/xml/dtm/DTMAxisIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/DTMException;-><init>(Ljava/lang/String;)V +Lorg/apache/xml/dtm/DTMFilter;->acceptNode(II)S +Lorg/apache/xml/dtm/DTMIterator;->cloneWithReset()Lorg/apache/xml/dtm/DTMIterator; +Lorg/apache/xml/dtm/DTMIterator;->getCurrentPos()I +Lorg/apache/xml/dtm/DTMIterator;->getDTM(I)Lorg/apache/xml/dtm/DTM; +Lorg/apache/xml/dtm/DTMIterator;->nextNode()I +Lorg/apache/xml/dtm/DTMIterator;->runTo(I)V +Lorg/apache/xml/dtm/DTMIterator;->setCurrentPos(I)V +Lorg/apache/xml/dtm/DTMIterator;->setRoot(ILjava/lang/Object;)V +Lorg/apache/xml/dtm/DTMIterator;->setShouldCacheNodes(Z)V +Lorg/apache/xml/dtm/DTMManager;->getDTM(Ljavax/xml/transform/Source;ZLorg/apache/xml/dtm/DTMWSFilter;ZZ)Lorg/apache/xml/dtm/DTM; +Lorg/apache/xml/dtm/DTMManager;->getXMLStringFactory()Lorg/apache/xml/utils/XMLStringFactory; +Lorg/apache/xml/dtm/DTMManager;->release(Lorg/apache/xml/dtm/DTM;Z)Z +Lorg/apache/xml/dtm/ref/CoroutineManager;-><init>()V +Lorg/apache/xml/dtm/ref/CoroutineManager;->co_joinCoroutineSet(I)I +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;-><init>()V +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->includeSelf()Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->reset()Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->resetPosition()Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->returnNode(I)I +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->setRestartable(Z)V +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_includeSelf:Z +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_isRestartable:Z +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_last:I +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_markedNode:I +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_position:I +Lorg/apache/xml/dtm/ref/DTMAxisIteratorBase;->_startNode:I +Lorg/apache/xml/dtm/ref/DTMAxisIterNodeList;-><init>(Lorg/apache/xml/dtm/DTM;Lorg/apache/xml/dtm/DTMAxisIterator;)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->appendChild(IZZ)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->appendTextChild(Ljava/lang/String;)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->declareNamespaceInContext(II)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->documentRegistration()V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->documentRelease()V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->ensureSizeOfIndex(II)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->error(Ljava/lang/String;)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->findGTE([IIII)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->findInSortedSuballocatedIntVector(Lorg/apache/xml/utils/SuballocatedIntVector;I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->findNamespaceContext(I)Lorg/apache/xml/utils/SuballocatedIntVector; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocument()I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentAllDeclarationsProcessed()Z +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentBaseURI()Ljava/lang/String; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentEncoding(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentRoot(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentStandalone(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentSystemIdentifier(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDocumentVersion(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getDTMIDs()Lorg/apache/xml/utils/SuballocatedIntVector; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getExpandedTypeID(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getExpandedTypeID(Ljava/lang/String;Ljava/lang/String;I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getFirstChild(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getFirstNamespaceNode(IZ)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getLastChild(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getLevel(I)S +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getLocalNameFromExpandedNameID(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getManager()Lorg/apache/xml/dtm/DTMManager; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNamespaceFromExpandedNameID(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNamespaceType(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNextAttribute(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNextNamespaceNode(IIZ)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNextSibling(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNode(I)Lorg/w3c/dom/Node; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNodeHandle(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNodeIdent(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getNodeType(I)S +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getOwnerDocument(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getParent(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getPreviousSibling(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getShouldStripWhitespace()Z +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getStringValueChunk(II[I)[C +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->getStringValueChunkCount(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->hasChildNodes(I)Z +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->indexNode(II)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isCharacterElementContentWhitespace(I)Z +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isDocumentAllDeclarationsProcessed(I)Z +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isNodeAfter(II)Z +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->isSupported(Ljava/lang/String;Ljava/lang/String;)Z +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->makeNodeHandle(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->makeNodeIdentity(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_expandedNameTable:Lorg/apache/xml/dtm/ref/ExpandedNameTable; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_exptype:Lorg/apache/xml/utils/SuballocatedIntVector; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_firstch:Lorg/apache/xml/utils/SuballocatedIntVector; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_nextsib:Lorg/apache/xml/utils/SuballocatedIntVector; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_parent:Lorg/apache/xml/utils/SuballocatedIntVector; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_prevsib:Lorg/apache/xml/utils/SuballocatedIntVector; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_size:I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_wsfilter:Lorg/apache/xml/dtm/DTMWSFilter; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->m_xstrf:Lorg/apache/xml/utils/XMLStringFactory; +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->popShouldStripWhitespace()V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->pushShouldStripWhitespace(Z)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->setDocumentBaseURI(Ljava/lang/String;)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->setFeature(Ljava/lang/String;Z)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->setShouldStripWhitespace(Z)V +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->supportsPreStripping()Z +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_exptype(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_firstch(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_level(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_nextsib(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_parent(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_prevsib(I)I +Lorg/apache/xml/dtm/ref/DTMDefaultBase;->_type(I)S +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$InternalAxisIteratorBase;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;)V +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$InternalAxisIteratorBase;->_currentNode:I +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NamespaceIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;)V +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NamespaceIterator;->next()I +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NamespaceIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$NthDescendantIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;I)V +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$SingletonIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;)V +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators$SingletonIterator;-><init>(Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;I)V +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;-><init>(Lorg/apache/xml/dtm/DTMManager;Ljavax/xml/transform/Source;ILorg/apache/xml/dtm/DTMWSFilter;Lorg/apache/xml/utils/XMLStringFactory;Z)V +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;->getAxisIterator(I)Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/ref/DTMDefaultBaseIterators;->getTypedAxisIterator(II)Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/ref/DTMDefaultBaseTraversers;->getAxisTraverser(I)Lorg/apache/xml/dtm/DTMAxisTraverser; +Lorg/apache/xml/dtm/ref/DTMManagerDefault;-><init>()V +Lorg/apache/xml/dtm/ref/DTMManagerDefault;->addDTM(Lorg/apache/xml/dtm/DTM;I)V +Lorg/apache/xml/dtm/ref/DTMManagerDefault;->addDTM(Lorg/apache/xml/dtm/DTM;II)V +Lorg/apache/xml/dtm/ref/DTMManagerDefault;->getFirstFreeDTMID()I +Lorg/apache/xml/dtm/ref/DTMManagerDefault;->getXMLReader(Ljavax/xml/transform/Source;)Lorg/xml/sax/XMLReader; +Lorg/apache/xml/dtm/ref/DTMManagerDefault;->releaseXMLReader(Lorg/xml/sax/XMLReader;)V +Lorg/apache/xml/dtm/ref/DTMNodeIterator;-><init>(Lorg/apache/xml/dtm/DTMIterator;)V +Lorg/apache/xml/dtm/ref/DTMNodeIterator;->getDTMIterator()Lorg/apache/xml/dtm/DTMIterator; +Lorg/apache/xml/dtm/ref/DTMNodeIterator;->getRoot()Lorg/w3c/dom/Node; +Lorg/apache/xml/dtm/ref/DTMNodeList;-><init>(Lorg/apache/xml/dtm/DTMIterator;)V +Lorg/apache/xml/dtm/ref/DTMNodeProxy;-><init>(Lorg/apache/xml/dtm/DTM;I)V +Lorg/apache/xml/dtm/ref/DTMNodeProxy;->getDTM()Lorg/apache/xml/dtm/DTM; +Lorg/apache/xml/dtm/ref/DTMNodeProxy;->getDTMNodeNumber()I +Lorg/apache/xml/dtm/ref/DTMNodeProxy;->getStringValue()Ljava/lang/String; +Lorg/apache/xml/dtm/ref/DTMStringPool;-><init>()V +Lorg/apache/xml/dtm/ref/DTMStringPool;->indexToString(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/DTMStringPool;->m_intToString:Ljava/util/Vector; +Lorg/apache/xml/dtm/ref/DTMStringPool;->removeAllElements()V +Lorg/apache/xml/dtm/ref/DTMStringPool;->stringToIndex(Ljava/lang/String;)I +Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getExpandedTypeID(Ljava/lang/String;Ljava/lang/String;I)I +Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getExpandedTypeID(Ljava/lang/String;Ljava/lang/String;IZ)I +Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getLocalName(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getSize()I +Lorg/apache/xml/dtm/ref/ExpandedNameTable;->getType(I)S +Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->deliverMoreNodes(Z)Ljava/lang/Object; +Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->setContentHandler(Lorg/xml/sax/ContentHandler;)V +Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->setLexicalHandler(Lorg/xml/sax/ext/LexicalHandler;)V +Lorg/apache/xml/dtm/ref/IncrementalSAXSource;->startParse(Lorg/xml/sax/InputSource;)V +Lorg/apache/xml/dtm/ref/IncrementalSAXSource_Filter;-><init>()V +Lorg/apache/xml/dtm/ref/IncrementalSAXSource_Filter;->setXMLReader(Lorg/xml/sax/XMLReader;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AncestorIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AncestorIterator;->next()I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AncestorIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$AttributeIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ChildrenIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ChildrenIterator;->setStartNode(I)Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$DescendantIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$FollowingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$FollowingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ParentIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$ParentIterator;->setNodeType(I)Lorg/apache/xml/dtm/DTMAxisIterator; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$PrecedingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$PrecedingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedAncestorIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedAttributeIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedChildrenIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedDescendantIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedFollowingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedFollowingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedPrecedingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedPrecedingSiblingIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2$TypedSingletonIterator;-><init>(Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;I)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;-><init>(Lorg/apache/xml/dtm/DTMManager;Ljavax/xml/transform/Source;ILorg/apache/xml/dtm/DTMWSFilter;Lorg/apache/xml/utils/XMLStringFactory;ZIZZZ)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyAttribute(IILorg/apache/xml/serializer/SerializationHandler;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyAttributes(ILorg/apache/xml/serializer/SerializationHandler;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyElement(IILorg/apache/xml/serializer/SerializationHandler;)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyNS(ILorg/apache/xml/serializer/SerializationHandler;Z)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->copyTextNode(ILorg/apache/xml/serializer/SerializationHandler;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->dispatchCharactersEvents(ILorg/xml/sax/ContentHandler;Z)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getFirstAttribute(I)I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getIdForNamespace(Ljava/lang/String;)I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getLocalName(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getNodeName(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getNodeNameX(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getNodeValue(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getStringValue()Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getStringValue(I)Lorg/apache/xml/utils/XMLString; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->getStringValueX(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->m_buildIdIndex:Z +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_exptype2(I)I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_exptype2Type(I)I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_firstch2(I)I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM2;->_nextsib2(I)I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->dispatchToEvents(ILorg/xml/sax/ContentHandler;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getAttributeNode(ILjava/lang/String;Ljava/lang/String;)I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getContentHandler()Lorg/xml/sax/ContentHandler; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDeclHandler()Lorg/xml/sax/ext/DeclHandler; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDocumentTypeDeclarationPublicIdentifier()Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDocumentTypeDeclarationSystemIdentifier()Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getDTDHandler()Lorg/xml/sax/DTDHandler; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getEntityResolver()Lorg/xml/sax/EntityResolver; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getErrorHandler()Lorg/xml/sax/ErrorHandler; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getLexicalHandler()Lorg/xml/sax/ext/LexicalHandler; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getNamespaceURI(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getNumberOfNodes()I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getPrefix(I)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getSourceLocatorFor(I)Ljavax/xml/transform/SourceLocator; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->getUnparsedEntityURI(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->isAttributeSpecified(I)Z +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->migrateTo(Lorg/apache/xml/dtm/DTMManager;)V +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->m_idAttributes:Ljava/util/Hashtable; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->m_parents:Lorg/apache/xml/utils/IntStack; +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->m_previous:I +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->needsTwoThreads()Z +Lorg/apache/xml/dtm/ref/sax2dtm/SAX2DTM;->setProperty(Ljava/lang/String;Ljava/lang/Object;)V +Lorg/apache/xml/dtm/ref/SecuritySupport;->getContextClassLoader()Ljava/lang/ClassLoader; +Lorg/apache/xml/dtm/ref/SecuritySupport;->getFileExists(Ljava/io/File;)Z +Lorg/apache/xml/dtm/ref/SecuritySupport;->getFileInputStream(Ljava/io/File;)Ljava/io/FileInputStream; +Lorg/apache/xml/dtm/ref/SecuritySupport;->getInstance()Lorg/apache/xml/dtm/ref/SecuritySupport; +Lorg/apache/xml/dtm/ref/SecuritySupport;->getLastModified(Ljava/io/File;)J +Lorg/apache/xml/dtm/ref/SecuritySupport;->getParentClassLoader(Ljava/lang/ClassLoader;)Ljava/lang/ClassLoader; +Lorg/apache/xml/dtm/ref/SecuritySupport;->getResourceAsStream(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/io/InputStream; +Lorg/apache/xml/dtm/ref/SecuritySupport;->getSystemClassLoader()Ljava/lang/ClassLoader; +Lorg/apache/xml/dtm/ref/SecuritySupport;->getSystemProperty(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/res/XMLErrorResources;-><init>()V +Lorg/apache/xml/res/XMLMessages;->createXMLMessage(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; +Lorg/apache/xml/serializer/CharInfo$CharKey;-><init>(C)V +Lorg/apache/xml/serializer/CharInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Z)V +Lorg/apache/xml/serializer/CharInfo;->get(I)Z +Lorg/apache/xml/serializer/CharInfo;->getCharInfo(Ljava/lang/String;Ljava/lang/String;)Lorg/apache/xml/serializer/CharInfo; +Lorg/apache/xml/serializer/CharInfo;->set(I)V +Lorg/apache/xml/serializer/dom3/LSSerializerImpl;-><init>()V +Lorg/apache/xml/serializer/DOMSerializer;->serialize(Lorg/w3c/dom/Node;)V +Lorg/apache/xml/serializer/ElemContext;->m_elementName:Ljava/lang/String; +Lorg/apache/xml/serializer/ElemContext;->m_elementURI:Ljava/lang/String; +Lorg/apache/xml/serializer/ElemContext;->m_startTagOpen:Z +Lorg/apache/xml/serializer/ElemContext;->push(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/apache/xml/serializer/ElemContext; +Lorg/apache/xml/serializer/ElemDesc;->isAttrFlagSet(Ljava/lang/String;I)Z +Lorg/apache/xml/serializer/Encodings;->convertMime2JavaEncoding(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/serializer/Encodings;->getMimeEncoding(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/serializer/Encodings;->getWriter(Ljava/io/OutputStream;Ljava/lang/String;)Ljava/io/Writer; +Lorg/apache/xml/serializer/NamespaceMappings;-><init>()V +Lorg/apache/xml/serializer/NamespaceMappings;->generateNextPrefix()Ljava/lang/String; +Lorg/apache/xml/serializer/NamespaceMappings;->lookupNamespace(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/serializer/NamespaceMappings;->lookupPrefix(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/serializer/OutputPropertiesFactory;->getDefaultMethodProperties(Ljava/lang/String;)Ljava/util/Properties; +Lorg/apache/xml/serializer/OutputPropertyUtils;->getBooleanProperty(Ljava/lang/String;Ljava/util/Properties;)Z +Lorg/apache/xml/serializer/OutputPropertyUtils;->getIntProperty(Ljava/lang/String;Ljava/util/Properties;)I +Lorg/apache/xml/serializer/SerializationHandler;->close()V +Lorg/apache/xml/serializer/SerializationHandler;->flushPending()V +Lorg/apache/xml/serializer/SerializationHandler;->setEscaping(Z)Z +Lorg/apache/xml/serializer/SerializationHandler;->setIndentAmount(I)V +Lorg/apache/xml/serializer/SerializationHandler;->setNamespaceMappings(Lorg/apache/xml/serializer/NamespaceMappings;)V +Lorg/apache/xml/serializer/Serializer;->asContentHandler()Lorg/xml/sax/ContentHandler; +Lorg/apache/xml/serializer/Serializer;->asDOMSerializer()Lorg/apache/xml/serializer/DOMSerializer; +Lorg/apache/xml/serializer/Serializer;->getOutputFormat()Ljava/util/Properties; +Lorg/apache/xml/serializer/Serializer;->getOutputStream()Ljava/io/OutputStream; +Lorg/apache/xml/serializer/Serializer;->getWriter()Ljava/io/Writer; +Lorg/apache/xml/serializer/Serializer;->reset()Z +Lorg/apache/xml/serializer/Serializer;->setOutputFormat(Ljava/util/Properties;)V +Lorg/apache/xml/serializer/Serializer;->setOutputStream(Ljava/io/OutputStream;)V +Lorg/apache/xml/serializer/Serializer;->setWriter(Ljava/io/Writer;)V +Lorg/apache/xml/serializer/SerializerBase;->fireCharEvent([CII)V +Lorg/apache/xml/serializer/SerializerBase;->fireCommentEvent([CII)V +Lorg/apache/xml/serializer/SerializerBase;->fireEndDoc()V +Lorg/apache/xml/serializer/SerializerBase;->fireEndElem(Ljava/lang/String;)V +Lorg/apache/xml/serializer/SerializerBase;->fireEscapingEvent(Ljava/lang/String;Ljava/lang/String;)V +Lorg/apache/xml/serializer/SerializerBase;->getDoctypePublic()Ljava/lang/String; +Lorg/apache/xml/serializer/SerializerBase;->getDoctypeSystem()Ljava/lang/String; +Lorg/apache/xml/serializer/SerializerBase;->getEncoding()Ljava/lang/String; +Lorg/apache/xml/serializer/SerializerBase;->getPrefixPart(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/serializer/SerializerBase;->getVersion()Ljava/lang/String; +Lorg/apache/xml/serializer/SerializerBase;->m_attributes:Lorg/apache/xml/serializer/AttributesImplSerializer; +Lorg/apache/xml/serializer/SerializerBase;->m_charsBuff:[C +Lorg/apache/xml/serializer/SerializerBase;->m_elemContext:Lorg/apache/xml/serializer/ElemContext; +Lorg/apache/xml/serializer/SerializerBase;->m_needToCallStartDocument:Z +Lorg/apache/xml/serializer/SerializerBase;->m_tracer:Lorg/apache/xml/serializer/SerializerTrace; +Lorg/apache/xml/serializer/SerializerBase;->setDoctypePublic(Ljava/lang/String;)V +Lorg/apache/xml/serializer/SerializerBase;->setDoctypeSystem(Ljava/lang/String;)V +Lorg/apache/xml/serializer/SerializerBase;->setIndent(Z)V +Lorg/apache/xml/serializer/SerializerBase;->setMediaType(Ljava/lang/String;)V +Lorg/apache/xml/serializer/SerializerBase;->setOmitXMLDeclaration(Z)V +Lorg/apache/xml/serializer/SerializerBase;->setStandalone(Ljava/lang/String;)V +Lorg/apache/xml/serializer/SerializerBase;->setStandaloneInternal(Ljava/lang/String;)V +Lorg/apache/xml/serializer/SerializerBase;->setVersion(Ljava/lang/String;)V +Lorg/apache/xml/serializer/SerializerFactory;->getSerializer(Ljava/util/Properties;)Lorg/apache/xml/serializer/Serializer; +Lorg/apache/xml/serializer/SerializerTraceWriter;-><init>(Ljava/io/Writer;Lorg/apache/xml/serializer/SerializerTrace;)V +Lorg/apache/xml/serializer/ToHTMLStream;-><init>()V +Lorg/apache/xml/serializer/ToHTMLStream;->getElemDesc(Ljava/lang/String;)Lorg/apache/xml/serializer/ElemDesc; +Lorg/apache/xml/serializer/ToSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Ljava/lang/String;)V +Lorg/apache/xml/serializer/ToSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Lorg/xml/sax/ext/LexicalHandler;Ljava/lang/String;)V +Lorg/apache/xml/serializer/ToSAXHandler;->m_lexHandler:Lorg/xml/sax/ext/LexicalHandler; +Lorg/apache/xml/serializer/ToSAXHandler;->m_saxHandler:Lorg/xml/sax/ContentHandler; +Lorg/apache/xml/serializer/ToSAXHandler;->reset()Z +Lorg/apache/xml/serializer/ToSAXHandler;->startDocumentInternal()V +Lorg/apache/xml/serializer/ToSAXHandler;->startElement(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V +Lorg/apache/xml/serializer/ToStream;->setCdataSectionElements(Ljava/lang/String;Ljava/util/Properties;)V +Lorg/apache/xml/serializer/ToStream;->setEncoding(Ljava/lang/String;)V +Lorg/apache/xml/serializer/ToStream;->setIndentAmount(I)V +Lorg/apache/xml/serializer/ToTextSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Ljava/lang/String;)V +Lorg/apache/xml/serializer/ToTextSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Lorg/xml/sax/ext/LexicalHandler;Ljava/lang/String;)V +Lorg/apache/xml/serializer/ToTextStream;-><init>()V +Lorg/apache/xml/serializer/ToUnknownStream;-><init>()V +Lorg/apache/xml/serializer/ToXMLSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Ljava/lang/String;)V +Lorg/apache/xml/serializer/ToXMLSAXHandler;-><init>(Lorg/xml/sax/ContentHandler;Lorg/xml/sax/ext/LexicalHandler;Ljava/lang/String;)V +Lorg/apache/xml/serializer/ToXMLStream;-><init>()V +Lorg/apache/xml/serializer/WriterToASCI;-><init>(Ljava/io/OutputStream;)V +Lorg/apache/xml/serializer/WriterToUTF8Buffered;-><init>(Ljava/io/OutputStream;)V +Lorg/apache/xml/utils/DefaultErrorHandler;-><init>()V +Lorg/apache/xml/utils/DefaultErrorHandler;->printLocation(Ljava/io/PrintWriter;Ljava/lang/Throwable;)V +Lorg/apache/xml/utils/DOMHelper;->isNodeAfter(Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)Z +Lorg/apache/xml/utils/DOMHelper;->isNodeTheSame(Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)Z +Lorg/apache/xml/utils/FastStringBuffer;->append(Ljava/lang/String;)V +Lorg/apache/xml/utils/FastStringBuffer;->getString(II)Ljava/lang/String; +Lorg/apache/xml/utils/FastStringBuffer;->length()I +Lorg/apache/xml/utils/IntStack;->peek()I +Lorg/apache/xml/utils/ObjectVector;->elementAt(I)Ljava/lang/Object; +Lorg/apache/xml/utils/ObjectVector;->size()I +Lorg/apache/xml/utils/PrefixResolverDefault;-><init>(Lorg/w3c/dom/Node;)V +Lorg/apache/xml/utils/PrefixResolverDefault;->getNamespaceForPrefix(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/utils/QName;-><init>(Ljava/lang/String;)V +Lorg/apache/xml/utils/QName;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Lorg/apache/xml/utils/QName;->getLocalName()Ljava/lang/String; +Lorg/apache/xml/utils/SAXSourceLocator;-><init>(Lorg/xml/sax/SAXParseException;)V +Lorg/apache/xml/utils/StringBufferPool;->free(Lorg/apache/xml/utils/FastStringBuffer;)V +Lorg/apache/xml/utils/StringBufferPool;->get()Lorg/apache/xml/utils/FastStringBuffer; +Lorg/apache/xml/utils/StringVector;->elementAt(I)Ljava/lang/String; +Lorg/apache/xml/utils/StringVector;->size()I +Lorg/apache/xml/utils/StylesheetPIHandler;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V +Lorg/apache/xml/utils/StylesheetPIHandler;->getAssociatedStylesheet()Ljavax/xml/transform/Source; +Lorg/apache/xml/utils/StylesheetPIHandler;->setBaseId(Ljava/lang/String;)V +Lorg/apache/xml/utils/StylesheetPIHandler;->setURIResolver(Ljavax/xml/transform/URIResolver;)V +Lorg/apache/xml/utils/SuballocatedIntVector;-><init>(I)V +Lorg/apache/xml/utils/SuballocatedIntVector;->elementAt(I)I +Lorg/apache/xml/utils/SuballocatedIntVector;->setElementAt(II)V +Lorg/apache/xml/utils/SuballocatedIntVector;->size()I +Lorg/apache/xml/utils/SystemIDResolver;->getAbsoluteURI(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/utils/SystemIDResolver;->getAbsoluteURI(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/utils/SystemIDResolver;->getAbsoluteURIFromRelative(Ljava/lang/String;)Ljava/lang/String; +Lorg/apache/xml/utils/SystemIDResolver;->isAbsoluteURI(Ljava/lang/String;)Z +Lorg/apache/xml/utils/URI$MalformedURIException;-><init>(Ljava/lang/String;)V +Lorg/apache/xml/utils/URI;-><init>(Ljava/lang/String;)V +Lorg/apache/xml/utils/URI;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V +Lorg/apache/xml/utils/URI;-><init>(Lorg/apache/xml/utils/URI;)V +Lorg/apache/xml/utils/URI;-><init>(Lorg/apache/xml/utils/URI;Ljava/lang/String;)V +Lorg/apache/xml/utils/URI;->getFragment()Ljava/lang/String; +Lorg/apache/xml/utils/URI;->getHost()Ljava/lang/String; +Lorg/apache/xml/utils/URI;->getPath()Ljava/lang/String; +Lorg/apache/xml/utils/URI;->getPort()I +Lorg/apache/xml/utils/URI;->getQueryString()Ljava/lang/String; +Lorg/apache/xml/utils/URI;->getScheme()Ljava/lang/String; +Lorg/apache/xml/utils/URI;->getUserinfo()Ljava/lang/String; +Lorg/apache/xml/utils/URI;->setFragment(Ljava/lang/String;)V +Lorg/apache/xml/utils/URI;->setHost(Ljava/lang/String;)V +Lorg/apache/xml/utils/URI;->setPort(I)V +Lorg/apache/xml/utils/URI;->setScheme(Ljava/lang/String;)V +Lorg/apache/xml/utils/URI;->setUserinfo(Ljava/lang/String;)V +Lorg/apache/xml/utils/WrappedRuntimeException;-><init>(Ljava/lang/Exception;)V +Lorg/apache/xml/utils/WrappedRuntimeException;->getException()Ljava/lang/Exception; +Lorg/apache/xml/utils/XML11Char;->isXML11ValidNCName(Ljava/lang/String;)Z +Lorg/apache/xml/utils/XML11Char;->isXML11ValidQName(Ljava/lang/String;)Z +Lorg/apache/xml/utils/XMLReaderManager;->getInstance()Lorg/apache/xml/utils/XMLReaderManager; +Lorg/apache/xml/utils/XMLReaderManager;->getXMLReader()Lorg/xml/sax/XMLReader; +Lorg/apache/xml/utils/XMLReaderManager;->releaseXMLReader(Lorg/xml/sax/XMLReader;)V +Lorg/apache/xml/utils/XMLString;->dispatchCharactersEvents(Lorg/xml/sax/ContentHandler;)V +Lorg/apache/xml/utils/XMLString;->equals(Lorg/apache/xml/utils/XMLString;)Z +Lorg/apache/xml/utils/XMLString;->fixWhiteSpace(ZZZ)Lorg/apache/xml/utils/XMLString; +Lorg/apache/xml/utils/XMLStringDefault;-><init>(Ljava/lang/String;)V +Lorg/apache/xml/utils/XMLStringFactory;-><init>()V +Lorg/apache/xml/utils/XMLStringFactory;->emptystr()Lorg/apache/xml/utils/XMLString; +Lorg/apache/xml/utils/XMLStringFactory;->newstr(Ljava/lang/String;)Lorg/apache/xml/utils/XMLString; +Lorg/apache/xpath/axes/ChildTestIterator;-><init>(Lorg/apache/xml/dtm/DTMAxisTraverser;)V +Lorg/apache/xpath/axes/DescendantIterator;-><init>()V +Lorg/apache/xpath/axes/LocPathIterator;->getDTM(I)Lorg/apache/xml/dtm/DTM; +Lorg/apache/xpath/axes/LocPathIterator;->getPrefixResolver()Lorg/apache/xml/utils/PrefixResolver; +Lorg/apache/xpath/axes/LocPathIterator;->getXPathContext()Lorg/apache/xpath/XPathContext; +Lorg/apache/xpath/axes/NodeSequence;->getContainedIter()Lorg/apache/xml/dtm/DTMIterator; +Lorg/apache/xpath/axes/NodeSequence;->nextNode()I +Lorg/apache/xpath/axes/OneStepIterator;-><init>(Lorg/apache/xml/dtm/DTMAxisIterator;I)V +Lorg/apache/xpath/CachedXPathAPI;-><init>()V +Lorg/apache/xpath/CachedXPathAPI;-><init>(Lorg/apache/xpath/CachedXPathAPI;)V +Lorg/apache/xpath/CachedXPathAPI;->eval(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/apache/xpath/objects/XObject; +Lorg/apache/xpath/CachedXPathAPI;->getXPathContext()Lorg/apache/xpath/XPathContext; +Lorg/apache/xpath/CachedXPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/NodeList; +Lorg/apache/xpath/CachedXPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/NodeList; +Lorg/apache/xpath/CachedXPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/Node; +Lorg/apache/xpath/CachedXPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node; +Lorg/apache/xpath/compiler/FunctionTable;-><init>()V +Lorg/apache/xpath/compiler/FunctionTable;->installFunction(Ljava/lang/String;Ljava/lang/Class;)I +Lorg/apache/xpath/Expression;->assertion(ZLjava/lang/String;)V +Lorg/apache/xpath/Expression;->error(Lorg/apache/xpath/XPathContext;Ljava/lang/String;[Ljava/lang/Object;)V +Lorg/apache/xpath/Expression;->exprGetParent()Lorg/apache/xpath/ExpressionNode; +Lorg/apache/xpath/ExpressionNode;->exprGetParent()Lorg/apache/xpath/ExpressionNode; +Lorg/apache/xpath/functions/FuncCurrent;-><init>()V +Lorg/apache/xpath/functions/FuncExtFunction;->getFunctionName()Ljava/lang/String; +Lorg/apache/xpath/functions/FuncExtFunction;->getMethodKey()Ljava/lang/Object; +Lorg/apache/xpath/functions/Function;-><init>()V +Lorg/apache/xpath/functions/WrongNumberArgsException;-><init>(Ljava/lang/String;)V +Lorg/apache/xpath/NodeSet;-><init>()V +Lorg/apache/xpath/NodeSet;-><init>(Lorg/w3c/dom/Node;)V +Lorg/apache/xpath/NodeSet;-><init>(Lorg/w3c/dom/NodeList;)V +Lorg/apache/xpath/NodeSet;-><init>(Lorg/w3c/dom/traversal/NodeIterator;)V +Lorg/apache/xpath/NodeSet;->addElement(Lorg/w3c/dom/Node;)V +Lorg/apache/xpath/NodeSet;->addNode(Lorg/w3c/dom/Node;)V +Lorg/apache/xpath/NodeSet;->contains(Lorg/w3c/dom/Node;)Z +Lorg/apache/xpath/NodeSet;->elementAt(I)Lorg/w3c/dom/Node; +Lorg/apache/xpath/NodeSet;->setShouldCacheNodes(Z)V +Lorg/apache/xpath/NodeSetDTM;-><init>(Lorg/w3c/dom/NodeList;Lorg/apache/xpath/XPathContext;)V +Lorg/apache/xpath/NodeSetDTM;-><init>(Lorg/w3c/dom/traversal/NodeIterator;Lorg/apache/xpath/XPathContext;)V +Lorg/apache/xpath/NodeSetDTM;->addNode(I)V +Lorg/apache/xpath/NodeSetDTM;->detach()V +Lorg/apache/xpath/NodeSetDTM;->getLength()I +Lorg/apache/xpath/NodeSetDTM;->item(I)I +Lorg/apache/xpath/objects/XBoolean;-><init>(Z)V +Lorg/apache/xpath/objects/XBoolean;->bool()Z +Lorg/apache/xpath/objects/XBoolean;->str()Ljava/lang/String; +Lorg/apache/xpath/objects/XBooleanStatic;-><init>(Z)V +Lorg/apache/xpath/objects/XNodeSet;-><init>(ILorg/apache/xml/dtm/DTMManager;)V +Lorg/apache/xpath/objects/XNodeSet;-><init>(Lorg/apache/xml/dtm/DTMIterator;)V +Lorg/apache/xpath/objects/XNodeSet;-><init>(Lorg/apache/xml/dtm/DTMManager;)V +Lorg/apache/xpath/objects/XNodeSet;->iterRaw()Lorg/apache/xml/dtm/DTMIterator; +Lorg/apache/xpath/objects/XNodeSet;->mutableNodeset()Lorg/apache/xpath/NodeSetDTM; +Lorg/apache/xpath/objects/XNodeSet;->nodelist()Lorg/w3c/dom/NodeList; +Lorg/apache/xpath/objects/XNumber;-><init>(D)V +Lorg/apache/xpath/objects/XNumber;->num()D +Lorg/apache/xpath/objects/XNumber;->str()Ljava/lang/String; +Lorg/apache/xpath/objects/XObject;->bool()Z +Lorg/apache/xpath/objects/XObject;->create(Ljava/lang/Object;)Lorg/apache/xpath/objects/XObject; +Lorg/apache/xpath/objects/XObject;->getType()I +Lorg/apache/xpath/objects/XObject;->getTypeString()Ljava/lang/String; +Lorg/apache/xpath/objects/XObject;->iter()Lorg/apache/xml/dtm/DTMIterator; +Lorg/apache/xpath/objects/XObject;->nodelist()Lorg/w3c/dom/NodeList; +Lorg/apache/xpath/objects/XObject;->nodeset()Lorg/w3c/dom/traversal/NodeIterator; +Lorg/apache/xpath/objects/XObject;->num()D +Lorg/apache/xpath/objects/XObject;->object()Ljava/lang/Object; +Lorg/apache/xpath/objects/XObject;->str()Ljava/lang/String; +Lorg/apache/xpath/objects/XObject;->xstr()Lorg/apache/xml/utils/XMLString; +Lorg/apache/xpath/objects/XRTreeFrag;-><init>(ILorg/apache/xpath/XPathContext;)V +Lorg/apache/xpath/objects/XRTreeFrag;->asNodeIterator()Lorg/apache/xml/dtm/DTMIterator; +Lorg/apache/xpath/objects/XRTreeFrag;->convertToNodeset()Lorg/w3c/dom/NodeList; +Lorg/apache/xpath/objects/XString;-><init>(Ljava/lang/String;)V +Lorg/apache/xpath/objects/XString;->num()D +Lorg/apache/xpath/patterns/NodeTest;->setWhatToShow(I)V +Lorg/apache/xpath/res/XPATHErrorResources;-><init>()V +Lorg/apache/xpath/res/XPATHMessages;->createXPATHMessage(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; +Lorg/apache/xpath/XPath;-><init>(Ljava/lang/String;Ljavax/xml/transform/SourceLocator;Lorg/apache/xml/utils/PrefixResolver;I)V +Lorg/apache/xpath/XPath;-><init>(Ljava/lang/String;Ljavax/xml/transform/SourceLocator;Lorg/apache/xml/utils/PrefixResolver;ILjavax/xml/transform/ErrorListener;)V +Lorg/apache/xpath/XPath;->execute(Lorg/apache/xpath/XPathContext;ILorg/apache/xml/utils/PrefixResolver;)Lorg/apache/xpath/objects/XObject; +Lorg/apache/xpath/XPath;->execute(Lorg/apache/xpath/XPathContext;Lorg/w3c/dom/Node;Lorg/apache/xml/utils/PrefixResolver;)Lorg/apache/xpath/objects/XObject; +Lorg/apache/xpath/XPath;->getPatternString()Ljava/lang/String; +Lorg/apache/xpath/XPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/NodeList; +Lorg/apache/xpath/XPathAPI;->selectNodeList(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/NodeList; +Lorg/apache/xpath/XPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;)Lorg/w3c/dom/Node; +Lorg/apache/xpath/XPathAPI;->selectSingleNode(Lorg/w3c/dom/Node;Ljava/lang/String;Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node; +Lorg/apache/xpath/XPathContext$XPathExpressionContext;->getDTMManager()Lorg/apache/xml/dtm/DTMManager; +Lorg/apache/xpath/XPathContext$XPathExpressionContext;->getXPathContext()Lorg/apache/xpath/XPathContext; +Lorg/apache/xpath/XPathContext;-><init>()V +Lorg/apache/xpath/XPathContext;-><init>(Ljava/lang/Object;)V +Lorg/apache/xpath/XPathContext;->getAxesIteratorStackStacks()Ljava/util/Stack; +Lorg/apache/xpath/XPathContext;->getContextNodeList()Lorg/apache/xml/dtm/DTMIterator; +Lorg/apache/xpath/XPathContext;->getContextNodeListsStack()Ljava/util/Stack; +Lorg/apache/xpath/XPathContext;->getCurrentExpressionNodeStack()Lorg/apache/xml/utils/IntStack; +Lorg/apache/xpath/XPathContext;->getCurrentNode()I +Lorg/apache/xpath/XPathContext;->getCurrentNodeStack()Lorg/apache/xml/utils/IntStack; +Lorg/apache/xpath/XPathContext;->getDTM(I)Lorg/apache/xml/dtm/DTM; +Lorg/apache/xpath/XPathContext;->getDTMHandleFromNode(Lorg/w3c/dom/Node;)I +Lorg/apache/xpath/XPathContext;->getDTMManager()Lorg/apache/xml/dtm/DTMManager; +Lorg/apache/xpath/XPathContext;->getExpressionContext()Lorg/apache/xalan/extensions/ExpressionContext; +Lorg/apache/xpath/XPathContext;->getNamespaceContext()Lorg/apache/xml/utils/PrefixResolver; +Lorg/apache/xpath/XPathContext;->getOwnerObject()Ljava/lang/Object; +Lorg/apache/xpath/XPathContext;->getSAXLocator()Ljavax/xml/transform/SourceLocator; +Lorg/apache/xpath/XPathContext;->getVarStack()Lorg/apache/xpath/VariableStack; +Lorg/apache/xpath/XPathContext;->m_dtmManager:Lorg/apache/xml/dtm/DTMManager; +Lorg/apache/xpath/XPathContext;->popContextNodeList()V +Lorg/apache/xpath/XPathContext;->popCurrentNode()V +Lorg/apache/xpath/XPathContext;->pushContextNodeList(Lorg/apache/xml/dtm/DTMIterator;)V +Lorg/apache/xpath/XPathContext;->pushCurrentNode(I)V +Lorg/apache/xpath/XPathContext;->reset()V +Lorg/apache/xpath/XPathContext;->setAxesIteratorStackStacks(Ljava/util/Stack;)V +Lorg/apache/xpath/XPathContext;->setContextNodeListsStack(Ljava/util/Stack;)V +Lorg/apache/xpath/XPathContext;->setCurrentExpressionNodeStack(Lorg/apache/xml/utils/IntStack;)V +Lorg/apache/xpath/XPathContext;->setCurrentNodeStack(Lorg/apache/xml/utils/IntStack;)V +Lorg/apache/xpath/XPathContext;->setSecureProcessing(Z)V +Lorg/apache/xpath/XPathContext;->setVarStack(Lorg/apache/xpath/VariableStack;)V +Lorg/ccil/cowan/tagsoup/AttributesImpl;-><init>(Lorg/xml/sax/Attributes;)V +Lorg/ccil/cowan/tagsoup/AttributesImpl;->addAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String; Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I +Lorg/ccil/cowan/tagsoup/AttributesImpl;->setAttribute(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V +Lorg/ccil/cowan/tagsoup/AttributesImpl;->setValue(ILjava/lang/String;)V +Lorg/ccil/cowan/tagsoup/AutoDetector;->autoDetectingReader(Ljava/io/InputStream;)Ljava/io/Reader; +Lorg/ccil/cowan/tagsoup/Element;-><init>(Lorg/ccil/cowan/tagsoup/ElementType;Z)V +Lorg/ccil/cowan/tagsoup/Element;->anonymize()V +Lorg/ccil/cowan/tagsoup/Element;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl; +Lorg/ccil/cowan/tagsoup/Element;->canContain(Lorg/ccil/cowan/tagsoup/Element;)Z +Lorg/ccil/cowan/tagsoup/Element;->clean()V +Lorg/ccil/cowan/tagsoup/Element;->flags()I +Lorg/ccil/cowan/tagsoup/Element;->localName()Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Element;->name()Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Element;->namespace()Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Element;->next()Lorg/ccil/cowan/tagsoup/Element; +Lorg/ccil/cowan/tagsoup/Element;->parent()Lorg/ccil/cowan/tagsoup/ElementType; +Lorg/ccil/cowan/tagsoup/Element;->preclosed:Z +Lorg/ccil/cowan/tagsoup/Element;->setAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V +Lorg/ccil/cowan/tagsoup/Element;->setNext(Lorg/ccil/cowan/tagsoup/Element;)V +Lorg/ccil/cowan/tagsoup/Element;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl; +Lorg/ccil/cowan/tagsoup/Element;->theNext:Lorg/ccil/cowan/tagsoup/Element; +Lorg/ccil/cowan/tagsoup/Element;->theType:Lorg/ccil/cowan/tagsoup/ElementType; +Lorg/ccil/cowan/tagsoup/ElementType;-><init>(Ljava/lang/String;IIILorg/ccil/cowan/tagsoup/Schema;)V +Lorg/ccil/cowan/tagsoup/ElementType;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl; +Lorg/ccil/cowan/tagsoup/ElementType;->setAttribute(Lorg/ccil/cowan/tagsoup/AttributesImpl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V Lorg/ccil/cowan/tagsoup/ElementType;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl; Lorg/ccil/cowan/tagsoup/ElementType;->theFlags:I Lorg/ccil/cowan/tagsoup/ElementType;->theLocalName:Ljava/lang/String; @@ -2292,91 +5642,500 @@ Lorg/ccil/cowan/tagsoup/ElementType;->theName:Ljava/lang/String; Lorg/ccil/cowan/tagsoup/ElementType;->theNamespace:Ljava/lang/String; Lorg/ccil/cowan/tagsoup/ElementType;->theParent:Lorg/ccil/cowan/tagsoup/ElementType; Lorg/ccil/cowan/tagsoup/ElementType;->theSchema:Lorg/ccil/cowan/tagsoup/Schema; +Lorg/ccil/cowan/tagsoup/HTMLScanner;-><init>()V Lorg/ccil/cowan/tagsoup/HTMLSchema;-><init>()V +Lorg/ccil/cowan/tagsoup/jaxp/SAXFactoryImpl;-><init>()V +Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;-><init>()V +Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;->newInstance(Ljava/util/Map;)Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl; Lorg/ccil/cowan/tagsoup/Parser;-><init>()V +Lorg/ccil/cowan/tagsoup/Parser;->bogonsEmpty:Z +Lorg/ccil/cowan/tagsoup/Parser;->CDATAElements:Z +Lorg/ccil/cowan/tagsoup/Parser;->cleanPublicid(Ljava/lang/String;)Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Parser;->defaultAttributes:Z +Lorg/ccil/cowan/tagsoup/Parser;->etagchars:[C +Lorg/ccil/cowan/tagsoup/Parser;->expandEntities(Ljava/lang/String;)Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Parser;->getInputStream(Ljava/lang/String;Ljava/lang/String;)Ljava/io/InputStream; +Lorg/ccil/cowan/tagsoup/Parser;->ignorableWhitespace:Z +Lorg/ccil/cowan/tagsoup/Parser;->ignoreBogons:Z +Lorg/ccil/cowan/tagsoup/Parser;->lookupEntity([CII)I +Lorg/ccil/cowan/tagsoup/Parser;->makeName([CII)Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Parser;->pop()V +Lorg/ccil/cowan/tagsoup/Parser;->push(Lorg/ccil/cowan/tagsoup/Element;)V +Lorg/ccil/cowan/tagsoup/Parser;->rectify(Lorg/ccil/cowan/tagsoup/Element;)V +Lorg/ccil/cowan/tagsoup/Parser;->restart(Lorg/ccil/cowan/tagsoup/Element;)V +Lorg/ccil/cowan/tagsoup/Parser;->restartablyPop()V +Lorg/ccil/cowan/tagsoup/Parser;->rootBogons:Z +Lorg/ccil/cowan/tagsoup/Parser;->schemaProperty:Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Parser;->split(Ljava/lang/String;)[Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Parser;->theAttributeName:Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Parser;->theAutoDetector:Lorg/ccil/cowan/tagsoup/AutoDetector; +Lorg/ccil/cowan/tagsoup/Parser;->theContentHandler:Lorg/xml/sax/ContentHandler; +Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeIsPresent:Z +Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeSystemId:Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Parser;->theFeatures:Ljava/util/HashMap; +Lorg/ccil/cowan/tagsoup/Parser;->theLexicalHandler:Lorg/xml/sax/ext/LexicalHandler; +Lorg/ccil/cowan/tagsoup/Parser;->theNewElement:Lorg/ccil/cowan/tagsoup/Element; +Lorg/ccil/cowan/tagsoup/Parser;->thePCDATA:Lorg/ccil/cowan/tagsoup/Element; +Lorg/ccil/cowan/tagsoup/Parser;->thePITarget:Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Parser;->theSaved:Lorg/ccil/cowan/tagsoup/Element; +Lorg/ccil/cowan/tagsoup/Parser;->theScanner:Lorg/ccil/cowan/tagsoup/Scanner; +Lorg/ccil/cowan/tagsoup/Parser;->theSchema:Lorg/ccil/cowan/tagsoup/Schema; +Lorg/ccil/cowan/tagsoup/Parser;->theStack:Lorg/ccil/cowan/tagsoup/Element; +Lorg/ccil/cowan/tagsoup/Parser;->trimquotes(Ljava/lang/String;)Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Parser;->virginStack:Z +Lorg/ccil/cowan/tagsoup/PYXScanner;-><init>()V +Lorg/ccil/cowan/tagsoup/PYXWriter;-><init>(Ljava/io/Writer;)V +Lorg/ccil/cowan/tagsoup/ScanHandler;->aname([CII)V +Lorg/ccil/cowan/tagsoup/ScanHandler;->aval([CII)V +Lorg/ccil/cowan/tagsoup/ScanHandler;->entity([CII)V +Lorg/ccil/cowan/tagsoup/ScanHandler;->eof([CII)V +Lorg/ccil/cowan/tagsoup/ScanHandler;->etag([CII)V +Lorg/ccil/cowan/tagsoup/ScanHandler;->gi([CII)V +Lorg/ccil/cowan/tagsoup/ScanHandler;->pcdata([CII)V +Lorg/ccil/cowan/tagsoup/ScanHandler;->pi([CII)V +Lorg/ccil/cowan/tagsoup/ScanHandler;->stagc([CII)V +Lorg/ccil/cowan/tagsoup/Scanner;->startCDATA()V +Lorg/ccil/cowan/tagsoup/Schema;->elementType(Ljava/lang/String;III)V +Lorg/ccil/cowan/tagsoup/Schema;->getElementType(Ljava/lang/String;)Lorg/ccil/cowan/tagsoup/ElementType; +Lorg/ccil/cowan/tagsoup/Schema;->getEntity(Ljava/lang/String;)I +Lorg/ccil/cowan/tagsoup/Schema;->getPrefix()Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Schema;->getURI()Ljava/lang/String; +Lorg/ccil/cowan/tagsoup/Schema;->parent(Ljava/lang/String;Ljava/lang/String;)V Lorg/ccil/cowan/tagsoup/Schema;->theElementTypes:Ljava/util/HashMap; Lorg/ccil/cowan/tagsoup/Schema;->theEntities:Ljava/util/HashMap; Lorg/ccil/cowan/tagsoup/Schema;->thePrefix:Ljava/lang/String; Lorg/ccil/cowan/tagsoup/Schema;->theRoot:Lorg/ccil/cowan/tagsoup/ElementType; Lorg/ccil/cowan/tagsoup/Schema;->theURI:Ljava/lang/String; -Lsun/misc/Cleaner;->clean()V -Lsun/misc/Unsafe;->addressSize()I -Lsun/misc/Unsafe;->allocateInstance(Ljava/lang/Class;)Ljava/lang/Object; -Lsun/misc/Unsafe;->allocateMemory(J)J -Lsun/misc/Unsafe;->arrayBaseOffset(Ljava/lang/Class;)I -Lsun/misc/Unsafe;->arrayIndexScale(Ljava/lang/Class;)I -Lsun/misc/Unsafe;->compareAndSwapInt(Ljava/lang/Object;JII)Z -Lsun/misc/Unsafe;->compareAndSwapLong(Ljava/lang/Object;JJJ)Z -Lsun/misc/Unsafe;->compareAndSwapObject(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z -Lsun/misc/Unsafe;->copyMemory(JJJ)V -Lsun/misc/Unsafe;->copyMemoryFromPrimitiveArray(Ljava/lang/Object;JJJ)V -Lsun/misc/Unsafe;->copyMemoryToPrimitiveArray(JLjava/lang/Object;JJ)V -Lsun/misc/Unsafe;->freeMemory(J)V -Lsun/misc/Unsafe;->fullFence()V -Lsun/misc/Unsafe;->getAndAddInt(Ljava/lang/Object;JI)I -Lsun/misc/Unsafe;->getAndAddLong(Ljava/lang/Object;JJ)J -Lsun/misc/Unsafe;->getAndSetInt(Ljava/lang/Object;JI)I -Lsun/misc/Unsafe;->getAndSetLong(Ljava/lang/Object;JJ)J -Lsun/misc/Unsafe;->getAndSetObject(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object; -Lsun/misc/Unsafe;->getArrayBaseOffsetForComponentType(Ljava/lang/Class;)I -Lsun/misc/Unsafe;->getArrayIndexScaleForComponentType(Ljava/lang/Class;)I -Lsun/misc/Unsafe;->getBoolean(Ljava/lang/Object;J)Z -Lsun/misc/Unsafe;->getByte(J)B -Lsun/misc/Unsafe;->getByte(Ljava/lang/Object;J)B -Lsun/misc/Unsafe;->getChar(J)C -Lsun/misc/Unsafe;->getChar(Ljava/lang/Object;J)C -Lsun/misc/Unsafe;->getDouble(J)D -Lsun/misc/Unsafe;->getDouble(Ljava/lang/Object;J)D -Lsun/misc/Unsafe;->getFloat(J)F -Lsun/misc/Unsafe;->getFloat(Ljava/lang/Object;J)F -Lsun/misc/Unsafe;->getInt(J)I -Lsun/misc/Unsafe;->getInt(Ljava/lang/Object;J)I -Lsun/misc/Unsafe;->getIntVolatile(Ljava/lang/Object;J)I -Lsun/misc/Unsafe;->getLong(J)J -Lsun/misc/Unsafe;->getLong(Ljava/lang/Object;J)J -Lsun/misc/Unsafe;->getLongVolatile(Ljava/lang/Object;J)J -Lsun/misc/Unsafe;->getObject(Ljava/lang/Object;J)Ljava/lang/Object; -Lsun/misc/Unsafe;->getObjectVolatile(Ljava/lang/Object;J)Ljava/lang/Object; -Lsun/misc/Unsafe;->getShort(J)S -Lsun/misc/Unsafe;->getShort(Ljava/lang/Object;J)S -Lsun/misc/Unsafe;->getUnsafe()Lsun/misc/Unsafe; -Lsun/misc/Unsafe;->INVALID_FIELD_OFFSET:I -Lsun/misc/Unsafe;->loadFence()V -Lsun/misc/Unsafe;->objectFieldOffset(Ljava/lang/reflect/Field;)J -Lsun/misc/Unsafe;->pageSize()I -Lsun/misc/Unsafe;->park(ZJ)V -Lsun/misc/Unsafe;->putBoolean(Ljava/lang/Object;JZ)V -Lsun/misc/Unsafe;->putByte(JB)V -Lsun/misc/Unsafe;->putByte(Ljava/lang/Object;JB)V -Lsun/misc/Unsafe;->putChar(JC)V -Lsun/misc/Unsafe;->putChar(Ljava/lang/Object;JC)V -Lsun/misc/Unsafe;->putDouble(JD)V -Lsun/misc/Unsafe;->putDouble(Ljava/lang/Object;JD)V -Lsun/misc/Unsafe;->putFloat(JF)V -Lsun/misc/Unsafe;->putFloat(Ljava/lang/Object;JF)V -Lsun/misc/Unsafe;->putInt(JI)V -Lsun/misc/Unsafe;->putInt(Ljava/lang/Object;JI)V -Lsun/misc/Unsafe;->putIntVolatile(Ljava/lang/Object;JI)V -Lsun/misc/Unsafe;->putLong(JJ)V -Lsun/misc/Unsafe;->putLong(Ljava/lang/Object;JJ)V -Lsun/misc/Unsafe;->putLongVolatile(Ljava/lang/Object;JJ)V -Lsun/misc/Unsafe;->putObject(Ljava/lang/Object;JLjava/lang/Object;)V -Lsun/misc/Unsafe;->putObjectVolatile(Ljava/lang/Object;JLjava/lang/Object;)V -Lsun/misc/Unsafe;->putOrderedInt(Ljava/lang/Object;JI)V -Lsun/misc/Unsafe;->putOrderedLong(Ljava/lang/Object;JJ)V -Lsun/misc/Unsafe;->putOrderedObject(Ljava/lang/Object;JLjava/lang/Object;)V -Lsun/misc/Unsafe;->putShort(JS)V -Lsun/misc/Unsafe;->putShort(Ljava/lang/Object;JS)V -Lsun/misc/Unsafe;->setMemory(JJB)V -Lsun/misc/Unsafe;->storeFence()V -Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe; -Lsun/misc/Unsafe;->THE_ONE:Lsun/misc/Unsafe; -Lsun/misc/Unsafe;->unpark(Ljava/lang/Object;)V -Lsun/misc/URLClassPath$JarLoader;->getJarFile()Ljava/util/jar/JarFile; -Lsun/misc/URLClassPath;->lmap:Ljava/util/HashMap; -Lsun/misc/URLClassPath;->loaders:Ljava/util/ArrayList; -Lsun/misc/URLClassPath;->urls:Ljava/util/Stack; -Lsun/nio/ch/DirectBuffer;->cleaner()Lsun/misc/Cleaner; -Lsun/security/x509/AlgorithmId;->get(Ljava/lang/String;)Lsun/security/x509/AlgorithmId; -Lsun/security/x509/AlgorithmId;->getName()Ljava/lang/String; -Lsun/security/x509/AVA;->hasRFC2253Keyword()Z +Lorg/ccil/cowan/tagsoup/XMLWriter;-><init>(Ljava/io/Writer;)V +Lorg/ccil/cowan/tagsoup/XMLWriter;->htmlMode:Z +Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutput(Ljava/io/Writer;)V +Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutputProperty(Ljava/lang/String;Ljava/lang/String;)V +Lorg/ccil/cowan/tagsoup/XMLWriter;->setPrefix(Ljava/lang/String;Ljava/lang/String;)V +Lorg/xml/sax/helpers/NamespaceSupport$Context;-><init>(Lorg/xml/sax/helpers/NamespaceSupport;)V +Lorg/xml/sax/helpers/ParserAdapter$AttributeListAdapter;-><init>(Lorg/xml/sax/helpers/ParserAdapter;)V +Lsun/misc/ASCIICaseInsensitiveComparator;->CASE_INSENSITIVE_ORDER:Ljava/util/Comparator; +Lsun/misc/ASCIICaseInsensitiveComparator;->lowerCaseHashCode(Ljava/lang/String;)I +Lsun/misc/BASE64Decoder;-><init>()V +Lsun/misc/BASE64Decoder;->pem_convert_array:[B +Lsun/misc/BASE64Encoder;-><init>()V +Lsun/misc/BASE64Encoder;->pem_array:[C +Lsun/misc/CEFormatException;-><init>(Ljava/lang/String;)V +Lsun/misc/CEStreamExhausted;-><init>()V +Lsun/misc/CharacterDecoder;-><init>()V +Lsun/misc/CharacterEncoder;-><init>()V +Lsun/misc/CharacterEncoder;->encodeBuffer([B)Ljava/lang/String; +Lsun/misc/CharacterEncoder;->encodeBufferPrefix(Ljava/io/OutputStream;)V +Lsun/misc/CharacterEncoder;->pStream:Ljava/io/PrintStream; +Lsun/misc/Cleaner;->create(Ljava/lang/Object;Ljava/lang/Runnable;)Lsun/misc/Cleaner; +Lsun/misc/FloatingDecimal;->$assertionsDisabled:Z +Lsun/misc/FloatingDecimal;->getHexDigit(Ljava/lang/String;I)I +Lsun/misc/FloatingDecimal;->stripLeadingZeros(Ljava/lang/String;)Ljava/lang/String; +Lsun/misc/FormattedFloatingDecimal$Form;->COMPATIBLE:Lsun/misc/FormattedFloatingDecimal$Form; +Lsun/misc/FormattedFloatingDecimal$Form;->DECIMAL_FLOAT:Lsun/misc/FormattedFloatingDecimal$Form; +Lsun/misc/FormattedFloatingDecimal$Form;->SCIENTIFIC:Lsun/misc/FormattedFloatingDecimal$Form; +Lsun/misc/FormattedFloatingDecimal;->$assertionsDisabled:Z +Lsun/misc/FpUtils;->$assertionsDisabled:Z +Lsun/misc/FpUtils;->rawCopySign(DD)D +Lsun/misc/HexDumpEncoder;-><init>()V +Lsun/misc/HexDumpEncoder;->currentByte:I +Lsun/misc/HexDumpEncoder;->offset:I +Lsun/misc/HexDumpEncoder;->thisLine:[B +Lsun/misc/HexDumpEncoder;->thisLineLength:I +Lsun/misc/IOUtils;->readFully(Ljava/io/InputStream;IZ)[B +Lsun/misc/JarIndex;-><init>([Ljava/lang/String;)V +Lsun/misc/JarIndex;->write(Ljava/io/OutputStream;)V +Lsun/misc/MessageUtils;-><init>()V +Lsun/misc/MetaIndex;->forJar(Ljava/io/File;)Lsun/misc/MetaIndex; +Lsun/misc/MetaIndex;->registerDirectory(Ljava/io/File;)V +Lsun/misc/VM;->maxDirectMemory()J +Lsun/net/ftp/FtpClient;-><init>()V +Lsun/net/util/IPAddressUtil;->isIPv4LiteralAddress(Ljava/lang/String;)Z +Lsun/net/util/IPAddressUtil;->isIPv6LiteralAddress(Ljava/lang/String;)Z +Lsun/net/www/MessageHeader;-><init>()V +Lsun/net/www/MessageHeader;-><init>(Ljava/io/InputStream;)V +Lsun/net/www/MessageHeader;->add(Ljava/lang/String;Ljava/lang/String;)V +Lsun/net/www/MessageHeader;->findValue(Ljava/lang/String;)Ljava/lang/String; +Lsun/net/www/MessageHeader;->prepend(Ljava/lang/String;Ljava/lang/String;)V +Lsun/net/www/MessageHeader;->print(Ljava/io/PrintStream;)V +Lsun/net/www/MessageHeader;->set(Ljava/lang/String;Ljava/lang/String;)V +Lsun/net/www/ParseUtil;->decode(Ljava/lang/String;)Ljava/lang/String; +Lsun/net/www/ParseUtil;->encodePath(Ljava/lang/String;Z)Ljava/lang/String; +Lsun/net/www/ParseUtil;->fileToEncodedURL(Ljava/io/File;)Ljava/net/URL; +Lsun/net/www/URLConnection;-><init>(Ljava/net/URL;)V +Lsun/net/www/URLConnection;->setProperties(Lsun/net/www/MessageHeader;)V +Lsun/nio/ch/DirectBuffer;->address()J +Lsun/nio/ch/FileChannelImpl;->unmap0(JJ)I +Lsun/nio/ch/SelectorImpl;->publicSelectedKeys:Ljava/util/Set; +Lsun/nio/ch/SelectorImpl;->selectedKeys:Ljava/util/Set; +Lsun/nio/cs/HistoricallyNamedCharset;->historicalName()Ljava/lang/String; +Lsun/nio/cs/ThreadLocalCoders;->decoderFor(Ljava/lang/Object;)Ljava/nio/charset/CharsetDecoder; +Lsun/nio/fs/BasicFileAttributesHolder;->get()Ljava/nio/file/attribute/BasicFileAttributes; +Lsun/reflect/misc/ReflectUtil;->checkPackageAccess(Ljava/lang/Class;)V +Lsun/reflect/misc/ReflectUtil;->checkPackageAccess(Ljava/lang/String;)V +Lsun/reflect/misc/ReflectUtil;->isPackageAccessible(Ljava/lang/Class;)Z +Lsun/reflect/misc/ReflectUtil;->isSubclassOf(Ljava/lang/Class;Ljava/lang/Class;)Z +Lsun/reflect/Reflection;->ensureMemberAccess(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;I)V +Lsun/reflect/Reflection;->isSubclassOf(Ljava/lang/Class;Ljava/lang/Class;)Z +Lsun/security/action/GetBooleanAction;-><init>(Ljava/lang/String;)V +Lsun/security/action/GetIntegerAction;-><init>(Ljava/lang/String;I)V +Lsun/security/action/GetPropertyAction;-><init>(Ljava/lang/String;)V +Lsun/security/action/GetPropertyAction;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Lsun/security/jca/GetInstance$Instance;->impl:Ljava/lang/Object; +Lsun/security/jca/GetInstance$Instance;->provider:Ljava/security/Provider; +Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Lsun/security/jca/GetInstance$Instance; +Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;)Lsun/security/jca/GetInstance$Instance; +Lsun/security/jca/GetInstance;->getInstance(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Object;Ljava/security/Provider;)Lsun/security/jca/GetInstance$Instance; +Lsun/security/jca/JCAUtil;->getSecureRandom()Ljava/security/SecureRandom; +Lsun/security/jca/ProviderConfig;->argument:Ljava/lang/String; +Lsun/security/jca/ProviderConfig;->CL_STRING:[Ljava/lang/Class; +Lsun/security/jca/ProviderConfig;->disableLoad()V +Lsun/security/jca/ProviderConfig;->hasArgument()Z +Lsun/security/jca/ProviderList;->getService(Ljava/lang/String;Ljava/lang/String;)Ljava/security/Provider$Service; +Lsun/security/jca/Providers;->getProviderList()Lsun/security/jca/ProviderList; +Lsun/security/jca/Providers;->startJarVerification()Ljava/lang/Object; +Lsun/security/jca/Providers;->stopJarVerification(Ljava/lang/Object;)V +Lsun/security/pkcs/ContentInfo;-><init>(Lsun/security/util/ObjectIdentifier;Lsun/security/util/DerValue;)V +Lsun/security/pkcs/ContentInfo;-><init>([B)V +Lsun/security/pkcs/ContentInfo;->DATA_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/pkcs/ContentInfo;->encode(Lsun/security/util/DerOutputStream;)V +Lsun/security/pkcs/ContentInfo;->getData()[B +Lsun/security/pkcs/ParsingException;-><init>(Ljava/lang/String;)V +Lsun/security/pkcs/PKCS7;-><init>([B)V +Lsun/security/pkcs/PKCS7;-><init>([Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/ContentInfo;[Ljava/security/cert/X509Certificate;[Ljava/security/cert/X509CRL;[Lsun/security/pkcs/SignerInfo;)V +Lsun/security/pkcs/PKCS7;-><init>([Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/ContentInfo;[Ljava/security/cert/X509Certificate;[Lsun/security/pkcs/SignerInfo;)V +Lsun/security/pkcs/PKCS7;->encodeSignedData(Ljava/io/OutputStream;)V +Lsun/security/pkcs/PKCS7;->getCertificates()[Ljava/security/cert/X509Certificate; +Lsun/security/pkcs/PKCS7;->getContentInfo()Lsun/security/pkcs/ContentInfo; +Lsun/security/pkcs/PKCS7;->getSignerInfos()[Lsun/security/pkcs/SignerInfo; +Lsun/security/pkcs/PKCS7;->verify(Lsun/security/pkcs/SignerInfo;[B)Lsun/security/pkcs/SignerInfo; +Lsun/security/pkcs/PKCS7;->verify([B)[Lsun/security/pkcs/SignerInfo; +Lsun/security/pkcs/PKCS8Key;-><init>()V +Lsun/security/pkcs/PKCS8Key;->algid:Lsun/security/x509/AlgorithmId; +Lsun/security/pkcs/PKCS8Key;->encodedKey:[B +Lsun/security/pkcs/PKCS8Key;->key:[B +Lsun/security/pkcs/PKCS9Attribute;-><init>(Ljava/lang/String;Ljava/lang/Object;)V +Lsun/security/pkcs/PKCS9Attribute;-><init>(Lsun/security/util/DerValue;)V +Lsun/security/pkcs/PKCS9Attribute;-><init>(Lsun/security/util/ObjectIdentifier;Ljava/lang/Object;)V +Lsun/security/pkcs/PKCS9Attribute;->CONTENT_TYPE_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/pkcs/PKCS9Attribute;->derEncode(Ljava/io/OutputStream;)V +Lsun/security/pkcs/PKCS9Attribute;->EMAIL_ADDRESS_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/pkcs/PKCS9Attribute;->getOID()Lsun/security/util/ObjectIdentifier; +Lsun/security/pkcs/PKCS9Attribute;->getValue()Ljava/lang/Object; +Lsun/security/pkcs/PKCS9Attribute;->MESSAGE_DIGEST_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/pkcs/PKCS9Attribute;->SIGNING_TIME_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/pkcs/PKCS9Attributes;-><init>(Lsun/security/util/DerInputStream;)V +Lsun/security/pkcs/PKCS9Attributes;-><init>(Lsun/security/util/DerInputStream;Z)V +Lsun/security/pkcs/PKCS9Attributes;-><init>([Lsun/security/pkcs/PKCS9Attribute;)V +Lsun/security/pkcs/PKCS9Attributes;->encode(BLjava/io/OutputStream;)V +Lsun/security/pkcs/PKCS9Attributes;->getAttribute(Ljava/lang/String;)Lsun/security/pkcs/PKCS9Attribute; +Lsun/security/pkcs/PKCS9Attributes;->getAttributeValue(Lsun/security/util/ObjectIdentifier;)Ljava/lang/Object; +Lsun/security/pkcs/PKCS9Attributes;->getDerEncoding()[B +Lsun/security/pkcs/SignerInfo;-><init>(Lsun/security/x509/X500Name;Ljava/math/BigInteger;Lsun/security/x509/AlgorithmId;Lsun/security/pkcs/PKCS9Attributes;Lsun/security/x509/AlgorithmId;[BLsun/security/pkcs/PKCS9Attributes;)V +Lsun/security/pkcs/SignerInfo;-><init>(Lsun/security/x509/X500Name;Ljava/math/BigInteger;Lsun/security/x509/AlgorithmId;Lsun/security/x509/AlgorithmId;[B)V +Lsun/security/pkcs/SignerInfo;->getCertificate(Lsun/security/pkcs/PKCS7;)Ljava/security/cert/X509Certificate; +Lsun/security/pkcs/SignerInfo;->getCertificateChain(Lsun/security/pkcs/PKCS7;)Ljava/util/ArrayList; +Lsun/security/pkcs/SignerInfo;->getDigestAlgorithmId()Lsun/security/x509/AlgorithmId; +Lsun/security/pkcs/SignerInfo;->getDigestEncryptionAlgorithmId()Lsun/security/x509/AlgorithmId; +Lsun/security/pkcs/SignerInfo;->getEncryptedDigest()[B +Lsun/security/provider/certpath/X509CertificatePair;->clearCache()V +Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/io/InputStream;)V +Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/io/InputStream;Ljava/lang/String;)V +Lsun/security/provider/certpath/X509CertPath;-><init>(Ljava/util/List;)V +Lsun/security/provider/certpath/X509CertPath;->certs:Ljava/util/List; +Lsun/security/provider/certpath/X509CertPath;->getEncodingsStatic()Ljava/util/Iterator; +Lsun/security/provider/X509Factory;->addToCache(Lsun/security/util/Cache;[BLjava/lang/Object;)V +Lsun/security/provider/X509Factory;->certCache:Lsun/security/util/Cache; +Lsun/security/provider/X509Factory;->crlCache:Lsun/security/util/Cache; +Lsun/security/provider/X509Factory;->getFromCache(Lsun/security/util/Cache;[B)Ljava/lang/Object; +Lsun/security/provider/X509Factory;->intern(Ljava/security/cert/X509Certificate;)Lsun/security/x509/X509CertImpl; +Lsun/security/provider/X509Factory;->intern(Ljava/security/cert/X509CRL;)Lsun/security/x509/X509CRLImpl; +Lsun/security/timestamp/TimestampToken;-><init>([B)V +Lsun/security/timestamp/TimestampToken;->getDate()Ljava/util/Date; +Lsun/security/timestamp/TimestampToken;->getHashAlgorithm()Lsun/security/x509/AlgorithmId; +Lsun/security/timestamp/TimestampToken;->getHashedMessage()[B +Lsun/security/timestamp/TimestampToken;->getNonce()Ljava/math/BigInteger; +Lsun/security/util/BitArray;-><init>(I[B)V +Lsun/security/util/BitArray;->toByteArray()[B +Lsun/security/util/Cache;-><init>()V +Lsun/security/util/Cache;->clear()V +Lsun/security/util/Cache;->get(Ljava/lang/Object;)Ljava/lang/Object; +Lsun/security/util/Cache;->newHardMemoryCache(I)Lsun/security/util/Cache; +Lsun/security/util/Cache;->put(Ljava/lang/Object;Ljava/lang/Object;)V +Lsun/security/util/Debug;->getInstance(Ljava/lang/String;)Lsun/security/util/Debug; +Lsun/security/util/Debug;->println()V +Lsun/security/util/Debug;->println(Ljava/lang/String;)V +Lsun/security/util/Debug;->toHexString(Ljava/math/BigInteger;)Ljava/lang/String; +Lsun/security/util/DerIndefLenConverter;-><init>()V +Lsun/security/util/DerIndefLenConverter;->convert([B)[B +Lsun/security/util/DerIndefLenConverter;->data:[B +Lsun/security/util/DerIndefLenConverter;->dataPos:I +Lsun/security/util/DerIndefLenConverter;->dataSize:I +Lsun/security/util/DerIndefLenConverter;->isIndefinite(I)Z +Lsun/security/util/DerIndefLenConverter;->newData:[B +Lsun/security/util/DerIndefLenConverter;->numOfTotalLenBytes:I +Lsun/security/util/DerIndefLenConverter;->parseLength()I +Lsun/security/util/DerIndefLenConverter;->parseTag()V +Lsun/security/util/DerIndefLenConverter;->parseValue(I)V +Lsun/security/util/DerIndefLenConverter;->writeLengthAndValue()V +Lsun/security/util/DerIndefLenConverter;->writeTag()V +Lsun/security/util/DerInputStream;-><init>([B)V +Lsun/security/util/DerInputStream;->available()I +Lsun/security/util/DerInputStream;->getBigInteger()Ljava/math/BigInteger; +Lsun/security/util/DerInputStream;->getBitString()[B +Lsun/security/util/DerInputStream;->getDerValue()Lsun/security/util/DerValue; +Lsun/security/util/DerInputStream;->getInteger()I +Lsun/security/util/DerInputStream;->getOctetString()[B +Lsun/security/util/DerInputStream;->getOID()Lsun/security/util/ObjectIdentifier; +Lsun/security/util/DerInputStream;->getSequence(I)[Lsun/security/util/DerValue; +Lsun/security/util/DerInputStream;->getSet(I)[Lsun/security/util/DerValue; +Lsun/security/util/DerInputStream;->getSet(IZ)[Lsun/security/util/DerValue; +Lsun/security/util/DerInputStream;->getUTCTime()Ljava/util/Date; +Lsun/security/util/DerInputStream;->getUTF8String()Ljava/lang/String; +Lsun/security/util/DerInputStream;->mark(I)V +Lsun/security/util/DerInputStream;->peekByte()I +Lsun/security/util/DerInputStream;->reset()V +Lsun/security/util/DerInputStream;->subStream(IZ)Lsun/security/util/DerInputStream; +Lsun/security/util/DerInputStream;->tag:B +Lsun/security/util/DerOutputStream;-><init>()V +Lsun/security/util/DerOutputStream;-><init>(I)V +Lsun/security/util/DerOutputStream;->putBitString([B)V +Lsun/security/util/DerOutputStream;->putBoolean(Z)V +Lsun/security/util/DerOutputStream;->putDerValue(Lsun/security/util/DerValue;)V +Lsun/security/util/DerOutputStream;->putIA5String(Ljava/lang/String;)V +Lsun/security/util/DerOutputStream;->putInteger(I)V +Lsun/security/util/DerOutputStream;->putInteger(Ljava/math/BigInteger;)V +Lsun/security/util/DerOutputStream;->putNull()V +Lsun/security/util/DerOutputStream;->putOctetString([B)V +Lsun/security/util/DerOutputStream;->putOID(Lsun/security/util/ObjectIdentifier;)V +Lsun/security/util/DerOutputStream;->putOrderedSetOf(B[Lsun/security/util/DerEncoder;)V +Lsun/security/util/DerOutputStream;->putPrintableString(Ljava/lang/String;)V +Lsun/security/util/DerOutputStream;->putSequence([Lsun/security/util/DerValue;)V +Lsun/security/util/DerOutputStream;->putUTCTime(Ljava/util/Date;)V +Lsun/security/util/DerOutputStream;->putUTF8String(Ljava/lang/String;)V +Lsun/security/util/DerOutputStream;->write(BLsun/security/util/DerOutputStream;)V +Lsun/security/util/DerOutputStream;->write(B[B)V +Lsun/security/util/DerValue;-><init>(B[B)V +Lsun/security/util/DerValue;-><init>(Ljava/io/InputStream;)V +Lsun/security/util/DerValue;-><init>(Ljava/lang/String;)V +Lsun/security/util/DerValue;-><init>([B)V +Lsun/security/util/DerValue;-><init>([BII)V +Lsun/security/util/DerValue;->buffer:Lsun/security/util/DerInputBuffer; +Lsun/security/util/DerValue;->createTag(BZB)B +Lsun/security/util/DerValue;->data:Lsun/security/util/DerInputStream; +Lsun/security/util/DerValue;->encode(Lsun/security/util/DerOutputStream;)V +Lsun/security/util/DerValue;->getAsString()Ljava/lang/String; +Lsun/security/util/DerValue;->getBigInteger()Ljava/math/BigInteger; +Lsun/security/util/DerValue;->getBitString()[B +Lsun/security/util/DerValue;->getData()Lsun/security/util/DerInputStream; +Lsun/security/util/DerValue;->getDataBytes()[B +Lsun/security/util/DerValue;->getOctetString()[B +Lsun/security/util/DerValue;->getOID()Lsun/security/util/ObjectIdentifier; +Lsun/security/util/DerValue;->getPositiveBigInteger()Ljava/math/BigInteger; +Lsun/security/util/DerValue;->getUnalignedBitString()Lsun/security/util/BitArray; +Lsun/security/util/DerValue;->isConstructed()Z +Lsun/security/util/DerValue;->isContextSpecific()Z +Lsun/security/util/DerValue;->isContextSpecific(B)Z +Lsun/security/util/DerValue;->isPrintableStringChar(C)Z +Lsun/security/util/DerValue;->resetTag(B)V +Lsun/security/util/DerValue;->tag:B +Lsun/security/util/DerValue;->toByteArray()[B +Lsun/security/util/DerValue;->toDerInputStream()Lsun/security/util/DerInputStream; +Lsun/security/util/ManifestDigester$Entry;->digest(Ljava/security/MessageDigest;)[B +Lsun/security/util/ManifestDigester$Entry;->digestWorkaround(Ljava/security/MessageDigest;)[B +Lsun/security/util/ManifestDigester;-><init>([B)V +Lsun/security/util/ManifestDigester;->get(Ljava/lang/String;Z)Lsun/security/util/ManifestDigester$Entry; +Lsun/security/util/ManifestDigester;->manifestDigest(Ljava/security/MessageDigest;)[B +Lsun/security/util/MemoryCache$HardCacheEntry;-><init>(Ljava/lang/Object;Ljava/lang/Object;J)V +Lsun/security/util/MemoryCache$SoftCacheEntry;-><init>(Ljava/lang/Object;Ljava/lang/Object;JLjava/lang/ref/ReferenceQueue;)V +Lsun/security/util/ObjectIdentifier;-><init>(Ljava/lang/String;)V +Lsun/security/util/ObjectIdentifier;-><init>([I)V +Lsun/security/util/ObjectIdentifier;->equals(Lsun/security/util/ObjectIdentifier;)Z +Lsun/security/util/ObjectIdentifier;->newInternal([I)Lsun/security/util/ObjectIdentifier; +Lsun/security/util/PropertyExpander;->expand(Ljava/lang/String;)Ljava/lang/String; +Lsun/security/util/ResourcesMgr;->getString(Ljava/lang/String;)Ljava/lang/String; +Lsun/security/util/SecurityConstants;->CREATE_CLASSLOADER_PERMISSION:Ljava/lang/RuntimePermission; +Lsun/security/util/SecurityConstants;->GET_CLASSLOADER_PERMISSION:Ljava/lang/RuntimePermission; +Lsun/security/util/SecurityConstants;->MODIFY_THREADGROUP_PERMISSION:Ljava/lang/RuntimePermission; +Lsun/security/util/SecurityConstants;->MODIFY_THREAD_PERMISSION:Ljava/lang/RuntimePermission; +Lsun/security/util/SignatureFileVerifier;->isBlockOrSF(Ljava/lang/String;)Z +Lsun/security/x509/AccessDescription;-><init>(Lsun/security/util/DerValue;)V +Lsun/security/x509/AccessDescription;->getAccessLocation()Lsun/security/x509/GeneralName; +Lsun/security/x509/AccessDescription;->getAccessMethod()Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;-><init>()V +Lsun/security/x509/AlgorithmId;-><init>(Lsun/security/util/ObjectIdentifier;)V +Lsun/security/x509/AlgorithmId;-><init>(Lsun/security/util/ObjectIdentifier;Ljava/security/AlgorithmParameters;)V +Lsun/security/x509/AlgorithmId;->derEncode(Ljava/io/OutputStream;)V +Lsun/security/x509/AlgorithmId;->DSA_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->EC_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->encode()[B +Lsun/security/x509/AlgorithmId;->encode(Lsun/security/util/DerOutputStream;)V +Lsun/security/x509/AlgorithmId;->equals(Lsun/security/x509/AlgorithmId;)Z +Lsun/security/x509/AlgorithmId;->getAlgorithmId(Ljava/lang/String;)Lsun/security/x509/AlgorithmId; +Lsun/security/x509/AlgorithmId;->getDigAlgFromSigAlg(Ljava/lang/String;)Ljava/lang/String; +Lsun/security/x509/AlgorithmId;->getEncAlgFromSigAlg(Ljava/lang/String;)Ljava/lang/String; +Lsun/security/x509/AlgorithmId;->getEncodedParams()[B +Lsun/security/x509/AlgorithmId;->getOID()Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->getParameters()Ljava/security/AlgorithmParameters; +Lsun/security/x509/AlgorithmId;->MD2_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->MD5_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->params:Lsun/security/util/DerValue; +Lsun/security/x509/AlgorithmId;->parse(Lsun/security/util/DerValue;)Lsun/security/x509/AlgorithmId; +Lsun/security/x509/AlgorithmId;->RSAEncryption_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->sha1WithRSAEncryption_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->SHA256_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->SHA384_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->SHA512_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AlgorithmId;->SHA_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AttributeNameEnumeration;-><init>()V +Lsun/security/x509/AVA;-><init>(Lsun/security/util/ObjectIdentifier;Lsun/security/util/DerValue;)V +Lsun/security/x509/AVA;->getDerValue()Lsun/security/util/DerValue; +Lsun/security/x509/AVA;->getObjectIdentifier()Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AVA;->getValueString()Ljava/lang/String; +Lsun/security/x509/AVA;->toRFC2253CanonicalString()Ljava/lang/String; +Lsun/security/x509/AVAComparator;->INSTANCE:Ljava/util/Comparator; +Lsun/security/x509/AVAKeyword;->getOID(Ljava/lang/String;ILjava/util/Map;)Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AVAKeyword;->isCompliant(I)Z +Lsun/security/x509/AVAKeyword;->keyword:Ljava/lang/String; +Lsun/security/x509/AVAKeyword;->keywordMap:Ljava/util/Map; +Lsun/security/x509/AVAKeyword;->oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/AVAKeyword;->oidMap:Ljava/util/Map; +Lsun/security/x509/CertificateAlgorithmId;-><init>(Lsun/security/x509/AlgorithmId;)V +Lsun/security/x509/CertificateExtensions;-><init>()V +Lsun/security/x509/CertificateExtensions;-><init>(Lsun/security/util/DerInputStream;)V +Lsun/security/x509/CertificateExtensions;->encode(Ljava/io/OutputStream;Z)V +Lsun/security/x509/CertificateExtensions;->get(Ljava/lang/String;)Ljava/lang/Object; +Lsun/security/x509/CertificateExtensions;->set(Ljava/lang/String;Ljava/lang/Object;)V +Lsun/security/x509/CertificateIssuerName;-><init>(Lsun/security/x509/X500Name;)V +Lsun/security/x509/CertificateSerialNumber;-><init>(I)V +Lsun/security/x509/CertificateSerialNumber;-><init>(Ljava/math/BigInteger;)V +Lsun/security/x509/CertificateSubjectName;-><init>(Lsun/security/x509/X500Name;)V +Lsun/security/x509/CertificateSubjectName;->get(Ljava/lang/String;)Ljava/lang/Object; +Lsun/security/x509/CertificateValidity;-><init>(Ljava/util/Date;Ljava/util/Date;)V +Lsun/security/x509/CertificateVersion;-><init>(I)V +Lsun/security/x509/CertificateX509Key;-><init>(Ljava/security/PublicKey;)V +Lsun/security/x509/CRLDistributionPointsExtension;->encodeThis()V +Lsun/security/x509/CRLNumberExtension;-><init>(Ljava/lang/Boolean;Ljava/lang/Object;)V +Lsun/security/x509/CRLNumberExtension;->encodeThis()V +Lsun/security/x509/CRLNumberExtension;->get(Ljava/lang/String;)Ljava/lang/Object; +Lsun/security/x509/Extension;-><init>(Lsun/security/x509/Extension;)V +Lsun/security/x509/Extension;->encode(Lsun/security/util/DerOutputStream;)V +Lsun/security/x509/Extension;->getExtensionId()Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/GeneralName;-><init>(Lsun/security/x509/GeneralNameInterface;)V +Lsun/security/x509/GeneralName;->getName()Lsun/security/x509/GeneralNameInterface; +Lsun/security/x509/GeneralName;->getType()I +Lsun/security/x509/GeneralNames;-><init>()V +Lsun/security/x509/GeneralNames;-><init>(Lsun/security/util/DerValue;)V +Lsun/security/x509/GeneralNames;->add(Lsun/security/x509/GeneralName;)Lsun/security/x509/GeneralNames; +Lsun/security/x509/GeneralNames;->encode(Lsun/security/util/DerOutputStream;)V +Lsun/security/x509/GeneralNames;->isEmpty()Z +Lsun/security/x509/KeyIdentifier;-><init>(Ljava/security/PublicKey;)V +Lsun/security/x509/KeyIdentifier;->getIdentifier()[B +Lsun/security/x509/KeyIdentifier;->octetString:[B +Lsun/security/x509/KeyUsageExtension;-><init>([Z)V +Lsun/security/x509/KeyUsageExtension;->get(Ljava/lang/String;)Ljava/lang/Object; +Lsun/security/x509/NetscapeCertTypeExtension;-><init>([B)V +Lsun/security/x509/NetscapeCertTypeExtension;->get(Ljava/lang/String;)Ljava/lang/Object; +Lsun/security/x509/OIDMap$OIDInfo;->clazz:Ljava/lang/Class; +Lsun/security/x509/OIDMap;->getClass(Lsun/security/util/ObjectIdentifier;)Ljava/lang/Class; +Lsun/security/x509/OIDMap;->nameMap:Ljava/util/Map; +Lsun/security/x509/OIDMap;->oidMap:Ljava/util/Map; +Lsun/security/x509/PKIXExtensions;->CertificateIssuer_Id:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/SerialNumber;-><init>(Lsun/security/util/DerValue;)V +Lsun/security/x509/SubjectAlternativeNameExtension;->get(Ljava/lang/String;)Ljava/lang/Object; +Lsun/security/x509/SubjectKeyIdentifierExtension;-><init>([B)V +Lsun/security/x509/UniqueIdentity;-><init>(Lsun/security/util/DerInputStream;)V +Lsun/security/x509/UniqueIdentity;-><init>(Lsun/security/util/DerValue;)V +Lsun/security/x509/UniqueIdentity;->encode(Lsun/security/util/DerOutputStream;B)V +Lsun/security/x509/URIName;->getName()Ljava/lang/String; +Lsun/security/x509/URIName;->getScheme()Ljava/lang/String; +Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;)V +Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;)V +Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V +Lsun/security/x509/X500Name;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V +Lsun/security/x509/X500Name;-><init>(Lsun/security/util/DerInputStream;)V +Lsun/security/x509/X500Name;-><init>(Lsun/security/util/DerValue;)V +Lsun/security/x509/X500Name;-><init>([B)V +Lsun/security/x509/X500Name;->allAvas()Ljava/util/List; +Lsun/security/x509/X500Name;->asX500Name(Ljavax/security/auth/x500/X500Principal;)Lsun/security/x509/X500Name; +Lsun/security/x509/X500Name;->asX500Principal()Ljavax/security/auth/x500/X500Principal; +Lsun/security/x509/X500Name;->commonName_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->countryName_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->DNQUALIFIER_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->DOMAIN_COMPONENT_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->encode(Lsun/security/util/DerOutputStream;)V +Lsun/security/x509/X500Name;->GENERATIONQUALIFIER_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->getCommonName()Ljava/lang/String; +Lsun/security/x509/X500Name;->GIVENNAME_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->INITIALS_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->ipAddress_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->isEmpty()Z +Lsun/security/x509/X500Name;->localityName_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->orgName_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->orgUnitName_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->SERIALNUMBER_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->stateName_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->streetAddress_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->SURNAME_OID:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->title_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X500Name;->userid_oid:Lsun/security/util/ObjectIdentifier; +Lsun/security/x509/X509CertImpl;-><init>(Lsun/security/util/DerValue;)V +Lsun/security/x509/X509CertImpl;-><init>(Lsun/security/x509/X509CertInfo;)V +Lsun/security/x509/X509CertImpl;-><init>([B)V +Lsun/security/x509/X509CertImpl;->algId:Lsun/security/x509/AlgorithmId; +Lsun/security/x509/X509CertImpl;->get(Ljava/lang/String;)Ljava/lang/Object; +Lsun/security/x509/X509CertImpl;->getEncodedInternal()[B +Lsun/security/x509/X509CertImpl;->parse(Lsun/security/util/DerValue;)V +Lsun/security/x509/X509CertImpl;->readOnly:Z +Lsun/security/x509/X509CertImpl;->sign(Ljava/security/PrivateKey;Ljava/lang/String;)V +Lsun/security/x509/X509CertImpl;->signature:[B +Lsun/security/x509/X509CertImpl;->signedCert:[B +Lsun/security/x509/X509CertInfo;-><init>()V +Lsun/security/x509/X509CertInfo;-><init>([B)V +Lsun/security/x509/X509CertInfo;->get(Ljava/lang/String;)Ljava/lang/Object; +Lsun/security/x509/X509CertInfo;->set(Ljava/lang/String;Ljava/lang/Object;)V +Lsun/security/x509/X509CRLEntryImpl;->getExtension(Lsun/security/util/ObjectIdentifier;)Lsun/security/x509/Extension; +Lsun/security/x509/X509CRLImpl;-><init>(Ljava/io/InputStream;)V +Lsun/security/x509/X509CRLImpl;-><init>(Lsun/security/util/DerValue;)V +Lsun/security/x509/X509CRLImpl;-><init>([B)V +Lsun/security/x509/X509CRLImpl;->getEncodedInternal()[B +Lsun/security/x509/X509Key;-><init>()V +Lsun/security/x509/X509Key;->algid:Lsun/security/x509/AlgorithmId; +Lsun/security/x509/X509Key;->encodedKey:[B +Lsun/security/x509/X509Key;->key:[B +Lsun/security/x509/X509Key;->parse(Lsun/security/util/DerValue;)Ljava/security/PublicKey; +Lsun/security/x509/X509Key;->unusedBits:I +Lsun/util/calendar/AbstractCalendar;->getDayOfWeekDateOnOrBefore(JI)J +Lsun/util/calendar/AbstractCalendar;->getTimeOfDayValue(Lsun/util/calendar/CalendarDate;)J +Lsun/util/calendar/BaseCalendar$Date;->getNormalizedYear()I +Lsun/util/calendar/BaseCalendar$Date;->setNormalizedYear(I)V +Lsun/util/calendar/CalendarDate;->getDayOfMonth()I +Lsun/util/calendar/CalendarDate;->getMonth()I +Lsun/util/calendar/CalendarDate;->getTimeOfDay()J +Lsun/util/calendar/CalendarDate;->getYear()I +Lsun/util/calendar/CalendarDate;->setDate(III)Lsun/util/calendar/CalendarDate; +Lsun/util/calendar/CalendarDate;->setDayOfMonth(I)Lsun/util/calendar/CalendarDate; +Lsun/util/calendar/CalendarDate;->setHours(I)Lsun/util/calendar/CalendarDate; +Lsun/util/calendar/CalendarDate;->setMillis(I)Lsun/util/calendar/CalendarDate; +Lsun/util/calendar/CalendarDate;->setMinutes(I)Lsun/util/calendar/CalendarDate; +Lsun/util/calendar/CalendarDate;->setSeconds(I)Lsun/util/calendar/CalendarDate; +Lsun/util/calendar/CalendarSystem;->forName(Ljava/lang/String;)Lsun/util/calendar/CalendarSystem; +Lsun/util/calendar/CalendarSystem;->getGregorianCalendar()Lsun/util/calendar/Gregorian; +Lsun/util/calendar/CalendarSystem;->getTime(Lsun/util/calendar/CalendarDate;)J +Lsun/util/calendar/CalendarSystem;->newCalendarDate(Ljava/util/TimeZone;)Lsun/util/calendar/CalendarDate; +Lsun/util/calendar/CalendarSystem;->validate(Lsun/util/calendar/CalendarDate;)Z +Lsun/util/calendar/CalendarUtils;->floorDivide(II)I +Lsun/util/calendar/CalendarUtils;->floorDivide(JJ)J +Lsun/util/calendar/CalendarUtils;->mod(II)I +Lsun/util/calendar/CalendarUtils;->mod(JJ)J +Lsun/util/calendar/Era;-><init>(Ljava/lang/String;Ljava/lang/String;JZ)V +Lsun/util/calendar/Era;->getAbbreviation()Ljava/lang/String; +Lsun/util/calendar/Era;->getName()Ljava/lang/String; +Lsun/util/calendar/Era;->getSinceDate()Lsun/util/calendar/CalendarDate; +Lsun/util/calendar/ImmutableGregorianDate;->unsupported()V +Lsun/util/calendar/LocalGregorianCalendar$Date;->getNormalizedYear()I +Lsun/util/calendar/LocalGregorianCalendar$Date;->setEra(Lsun/util/calendar/Era;)Lsun/util/calendar/LocalGregorianCalendar$Date; +Lsun/util/calendar/LocalGregorianCalendar$Date;->setNormalizedYear(I)V +Lsun/util/calendar/LocalGregorianCalendar$Date;->setYear(I)Lsun/util/calendar/LocalGregorianCalendar$Date; +Lsun/util/calendar/LocalGregorianCalendar;->newCalendarDate(Ljava/util/TimeZone;)Lsun/util/calendar/LocalGregorianCalendar$Date; +Lsun/util/calendar/LocalGregorianCalendar;->normalize(Lsun/util/calendar/CalendarDate;)Z +Lsun/util/calendar/LocalGregorianCalendar;->validate(Lsun/util/calendar/CalendarDate;)Z diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index a66681956233..86ed267eafdb 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -120,6 +120,8 @@ import android.view.autofill.AutofillManager; import android.view.autofill.AutofillManager.AutofillClient; import android.view.autofill.AutofillPopupWindow; import android.view.autofill.IAutofillWindowPresenter; +import android.view.intelligence.ContentCaptureEvent; +import android.view.intelligence.IntelligenceManager; import android.widget.AdapterView; import android.widget.Toast; import android.widget.Toolbar; @@ -821,6 +823,10 @@ public class Activity extends ContextThemeWrapper /** The autofill manager. Always access via {@link #getAutofillManager()}. */ @Nullable private AutofillManager mAutofillManager; + /** The screen observation manager. Always access via {@link #getIntelligenceManager()}. */ + @Nullable private IntelligenceManager mIntelligenceManager; + + static final class NonConfigurationInstances { Object activity; HashMap<String, Object> children; @@ -994,7 +1000,7 @@ public class Activity extends ContextThemeWrapper } /** - * (Create and) return the autofill manager + * (Creates, sets and) returns the autofill manager * * @return The autofill manager */ @@ -1006,6 +1012,43 @@ public class Activity extends ContextThemeWrapper return mAutofillManager; } + /** + * (Creates, sets, and ) returns the intelligence manager + * + * @return The intelligence manager + */ + @NonNull private IntelligenceManager getIntelligenceManager() { + if (mIntelligenceManager == null) { + mIntelligenceManager = getSystemService(IntelligenceManager.class); + } + return mIntelligenceManager; + } + + private void notifyIntelligenceManagerIfNeeded(@ContentCaptureEvent.EventType int event) { + final IntelligenceManager im = getIntelligenceManager(); + if (im == null || !im.isContentCaptureEnabled()) { + return; + } + switch (event) { + case ContentCaptureEvent.TYPE_ACTIVITY_CREATED: + //TODO(b/111276913): decide whether the InteractionSessionId should be + // saved / restored in the activity bundle. + im.onActivityCreated(mToken, getComponentName()); + break; + case ContentCaptureEvent.TYPE_ACTIVITY_DESTROYED: + im.onActivityDestroyed(); + break; + case ContentCaptureEvent.TYPE_ACTIVITY_STARTED: + case ContentCaptureEvent.TYPE_ACTIVITY_RESUMED: + case ContentCaptureEvent.TYPE_ACTIVITY_PAUSED: + case ContentCaptureEvent.TYPE_ACTIVITY_STOPPED: + im.onActivityLifecycleEvent(event); + break; + default: + Log.w(TAG, "notifyIntelligenceManagerIfNeeded(): invalid type " + event); + } + } + @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); @@ -1081,6 +1124,8 @@ public class Activity extends ContextThemeWrapper } mRestoredFromBundle = savedInstanceState != null; mCalled = true; + + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_CREATED); } /** @@ -1314,6 +1359,7 @@ public class Activity extends ContextThemeWrapper if (mAutoFillResetNeeded) { getAutofillManager().onVisibleForAutofill(); } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_STARTED); } /** @@ -1396,6 +1442,7 @@ public class Activity extends ContextThemeWrapper } } } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_RESUMED); mCalled = true; } @@ -1789,6 +1836,7 @@ public class Activity extends ContextThemeWrapper mAutoFillIgnoreFirstResumePause = false; } } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_PAUSED); mCalled = true; } @@ -1977,6 +2025,7 @@ public class Activity extends ContextThemeWrapper getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_CANCEL, mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)); } + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_STOPPED); } } @@ -2047,6 +2096,9 @@ public class Activity extends ContextThemeWrapper } getApplication().dispatchActivityDestroyed(this); + + notifyIntelligenceManagerIfNeeded(ContentCaptureEvent.TYPE_ACTIVITY_DESTROYED); + } /** @@ -6403,9 +6455,16 @@ public class Activity extends ContextThemeWrapper void dumpInner(@NonNull String prefix, @Nullable FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { - if (args != null && args.length > 0 && args[0].equals("--autofill")) { - dumpAutofillManager(prefix, writer); - return; + if (args != null && args.length > 0) { + // Handle special cases + switch (args[0]) { + case "--autofill": + dumpAutofillManager(prefix, writer); + return; + case "--intelligence": + dumpIntelligenceManager(prefix, writer); + return; + } } writer.print(prefix); writer.print("Local Activity "); writer.print(Integer.toHexString(System.identityHashCode(this))); @@ -6435,6 +6494,7 @@ public class Activity extends ContextThemeWrapper mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix); dumpAutofillManager(prefix, writer); + dumpIntelligenceManager(prefix, writer); ResourcesManager.getInstance().dump(prefix, writer); } @@ -6450,6 +6510,15 @@ public class Activity extends ContextThemeWrapper } } + void dumpIntelligenceManager(String prefix, PrintWriter writer) { + final IntelligenceManager im = getIntelligenceManager(); + if (im != null) { + im.dump(prefix, writer); + } else { + writer.print(prefix); writer.println("No IntelligenceManager"); + } + } + /** * Bit indicating that this activity is "immersive" and should not be * interrupted by notifications if possible. diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl index 4b97a15f6181..9329fbc83376 100644 --- a/core/java/android/app/AppOpsManager.aidl +++ b/core/java/android/app/AppOpsManager.aidl @@ -18,3 +18,6 @@ package android.app; parcelable AppOpsManager.PackageOps; parcelable AppOpsManager.OpEntry; + +parcelable AppOpsManager.HistoricalPackageOps; +parcelable AppOpsManager.HistoricalOpEntry; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 690bf3c30734..1e2244e11bd2 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -17,6 +17,7 @@ package android.app; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -26,6 +27,7 @@ import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.usage.UsageStatsManager; import android.content.Context; +import android.content.pm.ParceledListSlice; import android.media.AudioAttributes.AttributeUsage; import android.os.Binder; import android.os.IBinder; @@ -34,7 +36,6 @@ import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; import android.os.UserManager; -import android.provider.Settings; import android.util.ArrayMap; import com.android.internal.app.IAppOpsActiveCallback; @@ -42,8 +43,11 @@ import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.util.Preconditions; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -139,22 +143,38 @@ public class AppOpsManager { "foreground", // MODE_FOREGROUND }; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "UID_STATE_" }, value = { + UID_STATE_PERSISTENT, + UID_STATE_TOP, + UID_STATE_FOREGROUND_SERVICE, + UID_STATE_FOREGROUND, + UID_STATE_BACKGROUND, + UID_STATE_CACHED + }) + public @interface UidState {} + /** * Metrics about an op when its uid is persistent. * @hide */ + @SystemApi public static final int UID_STATE_PERSISTENT = 0; /** * Metrics about an op when its uid is at the top. * @hide */ + @SystemApi public static final int UID_STATE_TOP = 1; /** * Metrics about an op when its uid is running a foreground service. * @hide */ + @SystemApi public static final int UID_STATE_FOREGROUND_SERVICE = 2; /** @@ -167,18 +187,21 @@ public class AppOpsManager { * Metrics about an op when its uid is in the foreground for any other reasons. * @hide */ + @SystemApi public static final int UID_STATE_FOREGROUND = 3; /** * Metrics about an op when its uid is in the background for any reason. * @hide */ + @SystemApi public static final int UID_STATE_BACKGROUND = 4; /** * Metrics about an op when its uid is cached. * @hide */ + @SystemApi public static final int UID_STATE_CACHED = 5; /** @@ -1585,30 +1608,24 @@ public class AppOpsManager { * @hide */ public static int opToDefaultMode(int op) { - // STOPSHIP b/118520006: Hardcode the default values once the feature is stable. - switch (op) { - // SMS permissions - case AppOpsManager.OP_SEND_SMS: - case AppOpsManager.OP_RECEIVE_SMS: - case AppOpsManager.OP_READ_SMS: - case AppOpsManager.OP_RECEIVE_WAP_PUSH: - case AppOpsManager.OP_RECEIVE_MMS: - case AppOpsManager.OP_READ_CELL_BROADCASTS: - // CallLog permissions - case AppOpsManager.OP_READ_CALL_LOG: - case AppOpsManager.OP_WRITE_CALL_LOG: - case AppOpsManager.OP_PROCESS_OUTGOING_CALLS: { - // ActivityThread.currentApplication() is never null - if (Settings.Global.getInt(ActivityThread.currentApplication().getContentResolver(), - Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0) == 1) { - return AppOpsManager.MODE_DEFAULT; - } - } - } return sOpDefaultMode[op]; } /** + * Retrieve the default mode for the app op. + * + * @param appOp The app op name + * + * @return the default mode for the app op + * + * @hide + */ + @SystemApi + public static int opToDefaultMode(@NonNull String appOp) { + return opToDefaultMode(strOpToOp(appOp)); + } + + /** * Retrieve the human readable mode. * @hide */ @@ -1904,6 +1921,377 @@ public class AppOpsManager { } /** + * This class represents historical app op information about a package. The history + * is aggregated information about ops for a certain amount of time such + * as the times the op was accessed, the times the op was rejected, the total + * duration the app op has been accessed. + * + * @hide + */ + @TestApi + @SystemApi + public static final class HistoricalPackageOps implements Parcelable { + private final int mUid; + private final @NonNull String mPackageName; + private final @NonNull List<HistoricalOpEntry> mEntries; + + /** + * @hide + */ + public HistoricalPackageOps(int uid, @NonNull String packageName) { + mUid = uid; + mPackageName = packageName; + mEntries = new ArrayList<>(); + } + + HistoricalPackageOps(@NonNull Parcel parcel) { + mUid = parcel.readInt(); + mPackageName = parcel.readString(); + mEntries = parcel.createTypedArrayList(HistoricalOpEntry.CREATOR); + } + + /** + * @hide + */ + public void addEntry(@NonNull HistoricalOpEntry entry) { + mEntries.add(entry); + } + + /** + * Gets the package name which the data represents. + * + * @return The package name which the data represents. + */ + public @NonNull String getPackageName() { + return mPackageName; + } + + /** + * Gets the UID which the data represents. + * + * @return The UID which the data represents. + */ + public int getUid() { + return mUid; + } + + /** + * Gets number historical app op entries. + * + * @return The number historical app op entries. + * + * @see #getEntryAt(int) + */ + public int getEntryCount() { + return mEntries.size(); + } + + /** + * Gets the historical at a given index. + * + * @param index The index to lookup. + * + * @return The entry at the given index. + * + * @see #getEntryCount() + */ + public @NonNull HistoricalOpEntry getEntryAt(int index) { + return mEntries.get(index); + } + + /** + * Gets the historical entry for a given op name. + * + * @param opName The op name. + * + * @return The historical entry for that op name. + */ + public @Nullable HistoricalOpEntry getEntry(@NonNull String opName) { + final int entryCount = mEntries.size(); + for (int i = 0; i < entryCount; i++) { + final HistoricalOpEntry entry = mEntries.get(i); + if (entry.getOp().equals(opName)) { + return entry; + } + } + return null; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mUid); + parcel.writeString(mPackageName); + parcel.writeTypedList(mEntries, flags); + } + + public static final Creator<HistoricalPackageOps> CREATOR = + new Creator<HistoricalPackageOps>() { + @Override + public @NonNull HistoricalPackageOps createFromParcel(@NonNull Parcel parcel) { + return new HistoricalPackageOps(parcel); + } + + @Override + public @NonNull HistoricalPackageOps[] newArray(int size) { + return new HistoricalPackageOps[size]; + } + }; + } + + /** + * This class represents historical information about an app op. The history + * is aggregated information about the op for a certain amount of time such + * as the times the op was accessed, the times the op was rejected, the total + * duration the app op has been accessed. + * + * @hide + */ + @TestApi + @SystemApi + public static final class HistoricalOpEntry implements Parcelable { + private final int mOp; + private final long[] mAccessCount; + private final long[] mRejectCount; + private final long[] mAccessDuration; + + /** + * @hide + */ + public HistoricalOpEntry(int op) { + mOp = op; + mAccessCount = new long[_NUM_UID_STATE]; + mRejectCount = new long[_NUM_UID_STATE]; + mAccessDuration = new long[_NUM_UID_STATE]; + } + + HistoricalOpEntry(@NonNull Parcel parcel) { + mOp = parcel.readInt(); + mAccessCount = parcel.createLongArray(); + mRejectCount = parcel.createLongArray(); + mAccessDuration = parcel.createLongArray(); + } + + /** + * @hide + */ + public void addEntry(@UidState int uidState, long accessCount, + long rejectCount, long accessDuration) { + mAccessCount[uidState] = accessCount; + mRejectCount[uidState] = rejectCount; + mAccessDuration[uidState] = accessDuration; + } + + /** + * Gets the op name. + * + * @return The op name. + */ + public @NonNull String getOp() { + return sOpToString[mOp]; + } + + /** + * Gets the number times the op was accessed (performed) in the foreground. + * + * @return The times the op was accessed in the foreground. + * + * @see #getBackgroundAccessCount() + * @see #getAccessCount(int) + */ + public long getForegroundAccessCount() { + return sum(mAccessCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1); + } + + /** + * Gets the number times the op was accessed (performed) in the background. + * + * @return The times the op was accessed in the background. + * + * @see #getForegroundAccessCount() + * @see #getAccessCount(int) + */ + public long getBackgroundAccessCount() { + return sum(mAccessCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE); + } + + /** + * Gets the number times the op was accessed (performed) for a given uid state. + * + * @param uidState The UID state for which to query. Could be one of + * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP}, + * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND}, + * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}. + * + * @return The times the op was accessed for the given UID state. + * + * @see #getForegroundAccessCount() + * @see #getBackgroundAccessCount() + */ + public long getAccessCount(@UidState int uidState) { + return mAccessCount[uidState]; + } + + /** + * Gets the number times the op was rejected in the foreground. + * + * @return The times the op was rejected in the foreground. + * + * @see #getBackgroundRejectCount() + * @see #getRejectCount(int) + */ + public long getForegroundRejectCount() { + return sum(mRejectCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1); + } + + /** + * Gets the number times the op was rejected in the background. + * + * @return The times the op was rejected in the background. + * + * @see #getForegroundRejectCount() + * @see #getRejectCount(int) + */ + public long getBackgroundRejectCount() { + return sum(mRejectCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE); + } + + /** + * Gets the number times the op was rejected for a given uid state. + * + * @param uidState The UID state for which to query. Could be one of + * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP}, + * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND}, + * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}. + * + * @return The times the op was rejected for the given UID state. + * + * @see #getForegroundRejectCount() + * @see #getBackgroundRejectCount() + */ + public long getRejectCount(@UidState int uidState) { + return mRejectCount[uidState]; + } + + /** + * Gets the total duration the app op was accessed (performed) in the foreground. + * + * @return The total duration the app op was accessed in the foreground. + * + * @see #getBackgroundAccessDuration() + * @see #getAccessDuration(int) + */ + public long getForegroundAccessDuration() { + return sum(mAccessDuration, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1); + } + + /** + * Gets the total duration the app op was accessed (performed) in the background. + * + * @return The total duration the app op was accessed in the background. + * + * @see #getForegroundAccessDuration() + * @see #getAccessDuration(int) + */ + public long getBackgroundAccessDuration() { + return sum(mAccessDuration, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE); + } + + /** + * Gets the total duration the app op was accessed (performed) for a given UID state. + * + * @param uidState The UID state for which to query. Could be one of + * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP}, + * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND}, + * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}. + * + * @return The total duration the app op was accessed for the given UID state. + * + * @see #getForegroundAccessDuration() + * @see #getBackgroundAccessDuration() + */ + public long getAccessDuration(@UidState int uidState) { + return mAccessDuration[uidState]; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mOp); + parcel.writeLongArray(mAccessCount); + parcel.writeLongArray(mRejectCount); + parcel.writeLongArray(mAccessDuration); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + final HistoricalOpEntry otherInstance = (HistoricalOpEntry) other; + if (mOp != otherInstance.mOp) { + return false; + } + if (!Arrays.equals(mAccessCount, otherInstance.mAccessCount)) { + return false; + } + if (!Arrays.equals(mRejectCount, otherInstance.mRejectCount)) { + return false; + } + return Arrays.equals(mAccessDuration, otherInstance.mAccessDuration); + } + + @Override + public int hashCode() { + int result = mOp; + result = 31 * result + Arrays.hashCode(mAccessCount); + result = 31 * result + Arrays.hashCode(mRejectCount); + result = 31 * result + Arrays.hashCode(mAccessDuration); + return result; + } + + /** + * + * Computes the sum given the start and end index. + * + * @param counts The data array. + * @param start The start index (inclusive) + * @param end The end index (exclusive) + * @return The sum. + */ + private static long sum(@NonNull long[] counts, int start, int end) { + long totalCount = 0; + for (int i = start; i <= end; i++) { + totalCount += counts[i]; + } + return totalCount; + } + + public static final Creator<HistoricalOpEntry> CREATOR = new Creator<HistoricalOpEntry>() { + @Override + public @NonNull HistoricalOpEntry createFromParcel(@NonNull Parcel source) { + return new HistoricalOpEntry(source); + } + + @Override + public @NonNull HistoricalOpEntry[] newArray(int size) { + return new HistoricalOpEntry[size]; + } + }; + } + + /** * Callback for notification of changes to operation state. */ public interface OnOpChangedListener { @@ -1960,6 +2348,30 @@ public class AppOpsManager { } /** + * Retrieve current operation state for all applications. + * + * @param ops The set of operations you are interested in, or null if you want all of them. + * @hide + */ + @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) + @SystemApi + public List<AppOpsManager.PackageOps> getPackagesForOpStrs(String[] ops) { + if (ops == null) { + return getPackagesForOps(null); + } + final int[] opCodes = new int[ops.length]; + for (int i = 0; i < ops.length; ++i) { + final Integer opCode = sOpStrToOp.get(ops[i]); + if (opCode == null) { + opCodes[i] = OP_NONE; + } else { + opCodes[i] = opCode; + } + } + return getPackagesForOps(opCodes); + } + + /** * Retrieve current operation state for one application. * * @param uid The uid of the application of interest. @@ -1978,6 +2390,74 @@ public class AppOpsManager { } /** + * Retrieve historical app op stats for a package. + * + * @param uid The UID to query for. + * @param packageName The package to query for. + * @param beginTimeMillis The beginning of the interval in milliseconds since + * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non + * negative. + * @param endTimeMillis The end of the interval in milliseconds since + * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after + * {@code beginTimeMillis}. + * @param opNames The ops to query for. Pass {@code null} for all ops. + * + * @return The historical ops or {@code null} if there are no ops for this package. + * + * @throws IllegalArgumentException If any of the argument contracts is violated. + * + * @hide + */ + @TestApi + @SystemApi + @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) + public @Nullable HistoricalPackageOps getHistoricalPackagesOps( + int uid, @NonNull String packageName, @Nullable String[] opNames, + long beginTimeMillis, long endTimeMillis) { + try { + return mService.getHistoricalPackagesOps(uid, packageName, opNames, + beginTimeMillis, endTimeMillis); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Retrieve historical app op stats for all packages. + * + * @param beginTimeMillis The beginning of the interval in milliseconds since + * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non + * negative. + * @param endTimeMillis The end of the interval in milliseconds since + * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after + * {@code beginTimeMillis}. + * @param opNames The ops to query for. Pass {@code null} for all ops. + * + * @return The historical ops or an empty list if there are no ops for any package. + * + * @throws IllegalArgumentException If any of the argument contracts is violated. + * + * @hide + */ + @TestApi + @SystemApi + @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) + public @NonNull List<HistoricalPackageOps> getAllHistoricPackagesOps( + @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis) { + try { + @SuppressWarnings("unchecked") + final ParceledListSlice<HistoricalPackageOps> payload = + mService.getAllHistoricalPackagesOps(opNames, beginTimeMillis, endTimeMillis); + if (payload != null) { + return payload.getList(); + } + return Collections.emptyList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Sets given app op in the specified mode for app ops in the UID. * This applies to all apps currently in the UID or installed in * this UID in the future. @@ -2017,26 +2497,6 @@ public class AppOpsManager { } } - /** - * Resets given app op in its default mode for app ops in the UID. - * This applies to all apps currently in the UID or installed in this UID in the future. - * - * @param appOp The app op. - * @param uid The UID for which to set the app. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) - @SystemApi - public void resetUidMode(String appOp, int uid, boolean force) { - int code = strOpToOp(appOp); - if (!(opAllowsReset(code) || force)) { - return; - } - int mode = opToDefaultMode(code); - setUidMode(code, uid, mode); - } - /** @hide */ public void setUserRestriction(int code, boolean restricted, IBinder token) { setUserRestriction(code, restricted, token, /*exceptionPackages*/null); diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java index 9d68133c01da..e2f2075f0a32 100644 --- a/core/java/android/app/AutomaticZenRule.java +++ b/core/java/android/app/AutomaticZenRule.java @@ -31,7 +31,10 @@ import java.util.Objects; * Rule instance information for zen mode. */ public final class AutomaticZenRule implements Parcelable { - + /* @hide */ + private static final int ENABLED = 1; + /* @hide */ + private static final int DISABLED = 0; private boolean enabled = false; private String name; private @InterruptionFilter int interruptionFilter; @@ -39,6 +42,7 @@ public final class AutomaticZenRule implements Parcelable { private ComponentName owner; private long creationTime; private ZenPolicy mZenPolicy; + private boolean mModified = false; /** * Creates an automatic zen rule. @@ -101,8 +105,8 @@ public final class AutomaticZenRule implements Parcelable { } public AutomaticZenRule(Parcel source) { - enabled = source.readInt() == 1; - if (source.readInt() == 1) { + enabled = source.readInt() == ENABLED; + if (source.readInt() == ENABLED) { name = source.readString(); } interruptionFilter = source.readInt(); @@ -110,6 +114,7 @@ public final class AutomaticZenRule implements Parcelable { owner = source.readParcelable(null); creationTime = source.readLong(); mZenPolicy = source.readParcelable(null); + mModified = source.readInt() == ENABLED; } /** @@ -148,6 +153,14 @@ public final class AutomaticZenRule implements Parcelable { } /** + * Returns whether this rule's name has been modified by the user. + * @hide + */ + public boolean isModified() { + return mModified; + } + + /** * Gets the zen policy. */ public ZenPolicy getZenPolicy() { @@ -191,6 +204,14 @@ public final class AutomaticZenRule implements Parcelable { } /** + * Sets modified state of this rule. + * @hide + */ + public void setModified(boolean modified) { + this.mModified = modified; + } + + /** * Sets the zen policy. */ public void setZenPolicy(ZenPolicy zenPolicy) { @@ -204,7 +225,7 @@ public final class AutomaticZenRule implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(enabled ? 1 : 0); + dest.writeInt(enabled ? ENABLED : DISABLED); if (name != null) { dest.writeInt(1); dest.writeString(name); @@ -216,6 +237,7 @@ public final class AutomaticZenRule implements Parcelable { dest.writeParcelable(owner, 0); dest.writeLong(creationTime); dest.writeParcelable(mZenPolicy, 0); + dest.writeInt(mModified ? ENABLED : DISABLED); } @Override @@ -237,6 +259,7 @@ public final class AutomaticZenRule implements Parcelable { if (o == this) return true; final AutomaticZenRule other = (AutomaticZenRule) o; return other.enabled == enabled + && other.mModified == mModified && Objects.equals(other.name, name) && other.interruptionFilter == interruptionFilter && Objects.equals(other.conditionId, conditionId) @@ -248,7 +271,7 @@ public final class AutomaticZenRule implements Parcelable { @Override public int hashCode() { return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime, - mZenPolicy); + mZenPolicy, mModified); } public static final Parcelable.Creator<AutomaticZenRule> CREATOR diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 519a2749e5bb..e7597620e138 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -265,17 +265,6 @@ interface IActivityManager { void getMyMemoryState(out ActivityManager.RunningAppProcessInfo outInfo); boolean killProcessesBelowForeground(in String reason); UserInfo getCurrentUser(); - /** - * Informs ActivityManagerService that the keyguard is showing. - * - * @param showingKeyguard True if the keyguard is showing, false otherwise. - * @param showingAod True if AOD is showing, false otherwise. - * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard - * is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if - * showing is true. - */ - void setLockScreenShown(boolean showingKeyguard, boolean showingAod, - int secondaryDisplayShowing); // This is not public because you need to be very careful in how you // manage your activity to make sure it is always the uid you expect. int getLaunchedFromUid(in IBinder activityToken); diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index fcfcc2192d9e..6f11a762c6cd 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -245,16 +245,16 @@ interface IActivityTaskManager { ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType); /** - * Informs ActivityManagerService that the keyguard is showing. + * Informs ActivityTaskManagerService that the keyguard is showing. * * @param showingKeyguard True if the keyguard is showing, false otherwise. * @param showingAod True if AOD is showing, false otherwise. - * @param secondaryDisplayShowing The displayId of the secondary display on which the keyguard - * is showing, or INVALID_DISPLAY if there is no such display. Only meaningful if - * showing is true. + * @param secondaryDisplaysShowing The displayId's of the secondary displays on which the + * keyguard is showing, or {@code null} if there is no such display. Only meaningful if showing + * is {@code true}. */ void setLockScreenShown(boolean showingKeyguard, boolean showingAod, - int secondaryDisplayShowing); + in int[] secondaryDisplaysShowing); Bundle getAssistContextExtras(int requestType); boolean launchAssistIntent(in Intent intent, int requestType, in String hint, int userHandle, in Bundle args); diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 508ea3b40cce..e95f9abed908 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -66,6 +66,8 @@ import android.hardware.fingerprint.IFingerprintService; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.IHdmiControlService; import android.hardware.input.InputManager; +import android.hardware.iris.IIrisService; +import android.hardware.iris.IrisManager; import android.hardware.location.ContextHubManager; import android.hardware.radio.RadioManager; import android.hardware.usb.IUsbManager; @@ -161,6 +163,8 @@ import android.view.accessibility.CaptioningManager; import android.view.autofill.AutofillManager; import android.view.autofill.IAutoFillManager; import android.view.inputmethod.InputMethodManager; +import android.view.intelligence.IIntelligenceManager; +import android.view.intelligence.IntelligenceManager; import android.view.textclassifier.TextClassificationManager; import android.view.textservice.TextServicesManager; @@ -836,6 +840,18 @@ final class SystemServiceRegistry { } }); + registerService(Context.IRIS_SERVICE, IrisManager.class, + new CachedServiceFetcher<IrisManager>() { + @Override + public IrisManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + final IBinder binder = + ServiceManager.getServiceOrThrow(Context.IRIS_SERVICE); + IIrisService service = IIrisService.Stub.asInterface(binder); + return new IrisManager(ctx.getOuterContext(), service); + } + }); + registerService(Context.BIOMETRIC_SERVICE, BiometricManager.class, new CachedServiceFetcher<BiometricManager>() { @Override @@ -1018,6 +1034,17 @@ final class SystemServiceRegistry { return new AutofillManager(ctx.getOuterContext(), service); }}); + registerService(Context.INTELLIGENCE_MANAGER_SERVICE, IntelligenceManager.class, + new CachedServiceFetcher<IntelligenceManager>() { + @Override + public IntelligenceManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + // Get the services without throwing as this is an optional feature + IBinder b = ServiceManager.getService(Context.INTELLIGENCE_MANAGER_SERVICE); + IIntelligenceManager service = IIntelligenceManager.Stub.asInterface(b); + return new IntelligenceManager(ctx.getOuterContext(), service); + }}); + registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() { @Override public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException { diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index 096c7aa44446..78b7d48165ec 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -20,6 +20,7 @@ import static android.app.ActivityThread.isSystem; import static android.app.WindowConfigurationProto.ACTIVITY_TYPE; import static android.app.WindowConfigurationProto.APP_BOUNDS; import static android.app.WindowConfigurationProto.WINDOWING_MODE; +import static android.view.Surface.rotationToString; import android.annotation.IntDef; import android.annotation.NonNull; @@ -60,6 +61,17 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu */ private Rect mAppBounds; + /** + * The current rotation of this window container relative to the default + * orientation of the display it is on (regardless of how deep in the hierarchy + * it is). It is used by the configuration hierarchy to apply rotation-dependent + * policy during bounds calculation. + */ + private int mRotation = ROTATION_UNDEFINED; + + /** Rotation is not defined, use the parent containers rotation. */ + public static final int ROTATION_UNDEFINED = -1; + /** The current windowing mode of the configuration. */ private @WindowingMode int mWindowingMode; @@ -161,6 +173,9 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu /** Bit that indicates that the {@link #mAlwaysOnTop} changed. * @hide */ public static final int WINDOW_CONFIG_ALWAYS_ON_TOP = 1 << 4; + /** Bit that indicates that the {@link #mRotation} changed. + * @hide */ + public static final int WINDOW_CONFIG_ROTATION = 1 << 5; /** @hide */ @IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = { WINDOW_CONFIG_BOUNDS, @@ -168,6 +183,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu WINDOW_CONFIG_WINDOWING_MODE, WINDOW_CONFIG_ACTIVITY_TYPE, WINDOW_CONFIG_ALWAYS_ON_TOP, + WINDOW_CONFIG_ROTATION, }) public @interface WindowConfig {} @@ -194,6 +210,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu dest.writeInt(mWindowingMode); dest.writeInt(mActivityType); dest.writeInt(mAlwaysOnTop); + dest.writeInt(mRotation); } private void readFromParcel(Parcel source) { @@ -202,6 +219,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu mWindowingMode = source.readInt(); mActivityType = source.readInt(); mAlwaysOnTop = source.readInt(); + mRotation = source.readInt(); } @Override @@ -287,6 +305,14 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu return mBounds; } + public int getRotation() { + return mRotation; + } + + public void setRotation(int rotation) { + mRotation = rotation; + } + public void setWindowingMode(@WindowingMode int windowingMode) { mWindowingMode = windowingMode; } @@ -324,6 +350,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu setWindowingMode(other.mWindowingMode); setActivityType(other.mActivityType); setAlwaysOnTop(other.mAlwaysOnTop); + setRotation(other.mRotation); } /** Set this object to completely undefined. @@ -339,6 +366,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu setWindowingMode(WINDOWING_MODE_UNDEFINED); setActivityType(ACTIVITY_TYPE_UNDEFINED); setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED); + setRotation(ROTATION_UNDEFINED); } /** @@ -375,6 +403,10 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu changed |= WINDOW_CONFIG_ALWAYS_ON_TOP; setAlwaysOnTop(delta.mAlwaysOnTop); } + if (delta.mRotation != ROTATION_UNDEFINED && delta.mRotation != mRotation) { + changed |= WINDOW_CONFIG_ROTATION; + setRotation(delta.mRotation); + } return changed; } @@ -418,6 +450,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu changes |= WINDOW_CONFIG_ALWAYS_ON_TOP; } + if ((compareUndefined || other.mRotation != ROTATION_UNDEFINED) + && mRotation != other.mRotation) { + changes |= WINDOW_CONFIG_ROTATION; + } + return changes; } @@ -454,6 +491,8 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu if (n != 0) return n; n = mAlwaysOnTop - that.mAlwaysOnTop; if (n != 0) return n; + n = mRotation - that.mRotation; + if (n != 0) return n; // if (n != 0) return n; return n; @@ -482,6 +521,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu result = 31 * result + mWindowingMode; result = 31 * result + mActivityType; result = 31 * result + mAlwaysOnTop; + result = 31 * result + mRotation; return result; } @@ -493,6 +533,8 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu + " mWindowingMode=" + windowingModeToString(mWindowingMode) + " mActivityType=" + activityTypeToString(mActivityType) + " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop) + + " mRotation=" + (mRotation == ROTATION_UNDEFINED + ? "undefined" : rotationToString(mRotation)) + "}"; } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 92daf08dc59b..f129a717f2cd 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3845,6 +3845,11 @@ public class DevicePolicyManager { public static final int KEYGUARD_DISABLE_IRIS = 1 << 8; /** + * NOTE: Please remember to update the DevicePolicyManagerTest's testKeyguardDisabledFeatures + * CTS test when adding to the list above. + */ + + /** * Disable all biometric authentication on keyguard secure screens (e.g. PIN/Pattern/Password). */ public static final int KEYGUARD_DISABLE_BIOMETRICS = diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index fefb8d3fc139..43f902a2a7f7 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -2,6 +2,7 @@ package android.app.assist; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.app.Activity; import android.content.ComponentName; import android.content.Context; @@ -713,7 +714,11 @@ public class AssistStructure implements Parcelable { ViewNode[] mChildren; - ViewNode() { + // TODO(b/111276913): temporarily made public / @hide until we decide what will be used by + // ScreenObservation. + /** @hide */ + @SystemApi + public ViewNode() { } ViewNode(ParcelTransferReader reader, int nestingLevel) { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index e3788004cf5a..2aa32c4b9cff 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3706,6 +3706,17 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.hardware.iris.IrisManager} for handling management + * of iris authentication. + * + * @hide + * @see #getSystemService + * @see android.hardware.iris.IrisManager + */ + public static final String IRIS_SERVICE = "iris"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a * {@link android.hardware.biometrics.BiometricManager} for handling management * of face authentication. * @@ -3854,6 +3865,14 @@ public abstract class Context { public static final String AUTOFILL_MANAGER_SERVICE = "autofill"; /** + * Official published name of the intelligence service. + * + * @hide + * @see #getSystemService(String) + */ + public static final String INTELLIGENCE_MANAGER_SERVICE = "intelligence"; + + /** * Use with {@link #getSystemService(String)} to access the * {@link com.android.server.voiceinteraction.SoundTriggerService}. * @@ -4208,6 +4227,15 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.os.ThermalService} for accessing the thermal service. + * + * @see #getSystemService(String) + * @hide + */ + public static final String THERMAL_SERVICE = "thermalservice"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a * {@link android.content.pm.ShortcutManager} for accessing the launcher shortcut service. * * @see #getSystemService(String) diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java index d3652e8825b5..877dfee138da 100644 --- a/core/java/android/content/SharedPreferences.java +++ b/core/java/android/content/SharedPreferences.java @@ -57,6 +57,9 @@ public interface SharedPreferences { * * <p>This callback will be run on your main thread. * + * <p><em>Note: This callback will not be triggered when preferences are cleared via + * {@link Editor#clear()}.</em> + * * @param sharedPreferences The {@link SharedPreferences} that received * the change. * @param key The key of the preference that was changed, added, or diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 1f700f758dc8..67b86c0e6e42 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -855,6 +855,14 @@ public abstract class PackageManager { */ public static final int INSTALL_VIRTUAL_PRELOAD = 0x00010000; + /** + * Flag parameter for {@link #installPackage} to indicate that this package + * is an APEX package + * + * @hide + */ + public static final int INSTALL_APEX = 0x00020000; + /** @hide */ @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = { DONT_KILL_APP diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index a8bbeab03f0a..096301c92faa 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -25,6 +25,7 @@ import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -78,6 +79,7 @@ public final class SharedLibraryInfo implements Parcelable { private final @Type int mType; private final VersionedPackage mDeclaringPackage; private final List<VersionedPackage> mDependentPackages; + private List<SharedLibraryInfo> mDependencies; /** * Creates a new instance. @@ -91,7 +93,8 @@ public final class SharedLibraryInfo implements Parcelable { * @hide */ public SharedLibraryInfo(String path, String packageName, String name, long version, int type, - VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages) { + VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages, + List<SharedLibraryInfo> dependencies) { mPath = path; mPackageName = packageName; mName = name; @@ -99,11 +102,13 @@ public final class SharedLibraryInfo implements Parcelable { mType = type; mDeclaringPackage = declaringPackage; mDependentPackages = dependentPackages; + mDependencies = dependencies; } private SharedLibraryInfo(Parcel parcel) { this(parcel.readString(), parcel.readString(), parcel.readString(), parcel.readLong(), - parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null)); + parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null), + parcel.createTypedArrayList(SharedLibraryInfo.CREATOR)); } /** @@ -150,6 +155,47 @@ public final class SharedLibraryInfo implements Parcelable { } /** + * Add a library dependency to that library. Note that this + * should be called under the package manager lock. + * + * @hide + */ + public void addDependency(@Nullable SharedLibraryInfo info) { + if (info == null) { + // For convenience of the caller, allow null to be passed. + // This can happen when we create the dependencies of builtin + // libraries. + return; + } + if (mDependencies == null) { + mDependencies = new ArrayList<>(); + } + mDependencies.add(info); + } + + /** + * Clear all dependencies. + * + * @hide + */ + public void clearDependencies() { + mDependencies = null; + } + + /** + * Gets the libraries this library directly depends on. Note that + * the package manager prevents recursive dependencies when installing + * a package. + * + * @return The dependencies. + * + * @hide + */ + public @Nullable List<SharedLibraryInfo> getDependencies() { + return mDependencies; + } + + /** * @deprecated Use {@link #getLongVersion()} instead. */ @Deprecated @@ -232,6 +278,7 @@ public final class SharedLibraryInfo implements Parcelable { parcel.writeInt(mType); parcel.writeParcelable(mDeclaringPackage, flags); parcel.writeList(mDependentPackages); + parcel.writeTypedList(mDependencies); } private static String typeToString(int type) { diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java index 387d29e81dfc..5afc8a9721b4 100644 --- a/core/java/android/content/pm/SharedLibraryNames.java +++ b/core/java/android/content/pm/SharedLibraryNames.java @@ -22,15 +22,15 @@ package android.content.pm; */ public class SharedLibraryNames { - static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java"; + public static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java"; - static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java"; + public static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java"; - static final String ANDROID_TEST_BASE = "android.test.base"; + public static final String ANDROID_TEST_BASE = "android.test.base"; - static final String ANDROID_TEST_MOCK = "android.test.mock"; + public static final String ANDROID_TEST_MOCK = "android.test.mock"; - static final String ANDROID_TEST_RUNNER = "android.test.runner"; + public static final String ANDROID_TEST_RUNNER = "android.test.runner"; - static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy"; + public static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy"; } diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 0350effd84b8..5f2374995775 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -1064,6 +1064,17 @@ public final class AssetManager implements AutoCloseable { } } + @UnsupportedAppUsage + void setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr) { + synchronized (this) { + ensureValidLocked(); + synchronized (srcAssetManager) { + srcAssetManager.ensureValidLocked(); + nativeThemeCopy(mObject, dstThemePtr, srcAssetManager.mObject, srcThemePtr); + } + } + } + @Override protected void finalize() throws Throwable { if (DEBUG_REFS && mNumRefs != 0) { @@ -1375,7 +1386,8 @@ public final class AssetManager implements AutoCloseable { private static native void nativeThemeDestroy(long themePtr); private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId, boolean force); - static native void nativeThemeCopy(long destThemePtr, long sourceThemePtr); + private static native void nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr, + long srcAssetManagerPtr, long srcThemePtr); static native void nativeThemeClear(long themePtr); private static native int nativeThemeGetAttributeValue(long ptr, long themePtr, @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve); diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java index 6a4aae66c848..14eb11ab8863 100644 --- a/core/java/android/content/res/FontResourcesParser.java +++ b/core/java/android/content/res/FontResourcesParser.java @@ -76,6 +76,10 @@ public class FontResourcesParser { // A class represents font element in xml file which points a file in resource. public static final class FontFileResourceEntry { + public static final int RESOLVE_BY_FONT_TABLE = Typeface.RESOLVE_BY_FONT_TABLE; + public static final int UPRIGHT = 0; + public static final int ITALIC = 1; + private final @NonNull String mFileName; private int mWeight; private int mItalic; @@ -216,7 +220,7 @@ public class FontResourcesParser { int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight, Typeface.RESOLVE_BY_FONT_TABLE); int italic = array.getInt(R.styleable.FontFamilyFont_fontStyle, - Typeface.RESOLVE_BY_FONT_TABLE); + FontFileResourceEntry.RESOLVE_BY_FONT_TABLE); String variationSettings = array.getString( R.styleable.FontFamilyFont_fontVariationSettings); int ttcIndex = array.getInt(R.styleable.FontFamilyFont_ttcIndex, 0); diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index dfa30a22597e..2ad4f625ef8c 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -944,7 +944,8 @@ public class ResourcesImpl { } return Typeface.createFromResources(familyEntry, mAssets, file); } - return Typeface.createFromResources(mAssets, file, value.assetCookie); + return new Typeface.Builder(mAssets, file, false /* isAsset */, value.assetCookie) + .build(); } catch (XmlPullParserException e) { Log.e(TAG, "Failed to parse xml resource " + file, e); } catch (IOException e) { @@ -1335,7 +1336,7 @@ public class ResourcesImpl { void setTo(ThemeImpl other) { synchronized (mKey) { synchronized (other.mKey) { - AssetManager.nativeThemeCopy(mTheme, other.mTheme); + mAssets.setThemeTo(mTheme, other.mAssets, other.mTheme); mThemeResId = other.mThemeResId; mKey.setTo(other.getKey()); diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 46e66e0dbef5..444ca87a68ef 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -22,12 +22,14 @@ import android.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; +import android.hardware.camera2.params.RecommendedStreamConfigurationMap; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.utils.ArrayUtils; import android.hardware.camera2.utils.TypeReference; import android.util.Rational; import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -193,6 +195,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri private List<CaptureRequest.Key<?>> mAvailableSessionKeys; private List<CaptureRequest.Key<?>> mAvailablePhysicalRequestKeys; private List<CaptureResult.Key<?>> mAvailableResultKeys; + private ArrayList<RecommendedStreamConfigurationMap> mRecommendedConfigurations; /** * Takes ownership of the passed-in properties object @@ -313,6 +316,103 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri } /** + * <p>Retrieve camera device recommended stream configuration map + * {@link RecommendedStreamConfigurationMap} for a given use case.</p> + * + * <p>The stream configurations advertised here are efficient in terms of power and performance + * for common use cases like preview, video, snapshot, etc. The recommended maps are usually + * only small subsets of the exhaustive list provided in + * {@link #SCALER_STREAM_CONFIGURATION_MAP} and suggested for a particular use case by the + * camera device implementation. For further information about the expected configurations in + * various scenarios please refer to: + * <ul> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_PREVIEW}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_RECORD}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_VIDEO_SNAPSHOT}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_SNAPSHOT}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_RAW}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_ZSL}</li> + * </ul> + * </p> + * + * <p>For example on how this can be used by camera clients to find out the maximum recommended + * preview and snapshot resolution, consider the following pseudo-code: + * </p> + * <pre><code> + * public static Size getMaxSize(Size... sizes) { + * if (sizes == null || sizes.length == 0) { + * throw new IllegalArgumentException("sizes was empty"); + * } + * + * Size sz = sizes[0]; + * for (Size size : sizes) { + * if (size.getWidth() * size.getHeight() > sz.getWidth() * sz.getHeight()) { + * sz = size; + * } + * } + * + * return sz; + * } + * + * CameraCharacteristics characteristics = + * cameraManager.getCameraCharacteristics(cameraId); + * RecommendedStreamConfigurationMap previewConfig = + * characteristics.getRecommendedStreamConfigurationMap( + * RecommendedStreamConfigurationMap.USECASE_PREVIEW); + * RecommendedStreamConfigurationMap snapshotConfig = + * characteristics.getRecommendedStreamConfigurationMap( + * RecommendedStreamConfigurationMap.USECASE_SNAPSHOT); + * + * if ((previewConfig != null) && (snapshotConfig != null)) { + * + * Set<Size> snapshotSizeSet = snapshotConfig.getOutputSizes( + * ImageFormat.JPEG); + * Size[] snapshotSizes = new Size[snapshotSizeSet.size()]; + * snapshotSizes = snapshotSizeSet.toArray(snapshotSizes); + * Size suggestedMaxJpegSize = getMaxSize(snapshotSizes); + * + * Set<Size> previewSizeSet = snapshotConfig.getOutputSizes( + * ImageFormat.PRIVATE); + * Size[] previewSizes = new Size[previewSizeSet.size()]; + * previewSizes = previewSizeSet.toArray(previewSizes); + * Size suggestedMaxPreviewSize = getMaxSize(previewSizes); + * } + * + * </code></pre> + * + * <p>Similar logic can be used for other use cases as well.</p> + * + * <p>Support for recommended stream configurations is optional. In case there a no + * suggested configurations for the particular use case, please refer to + * {@link #SCALER_STREAM_CONFIGURATION_MAP} for the exhaustive available list.</p> + * + * @param usecase Use case id. + * + * @throws IllegalArgumentException In case the use case argument is invalid. + * @return Valid {@link RecommendedStreamConfigurationMap} or null in case the camera device + * doesn't have any recommendation for this use case or the recommended configurations + * are invalid. + */ + public RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap( + @RecommendedStreamConfigurationMap.RecommendedUsecase int usecase) { + if (((usecase >= RecommendedStreamConfigurationMap.USECASE_PREVIEW) && + (usecase <= RecommendedStreamConfigurationMap.USECASE_RAW)) || + ((usecase >= RecommendedStreamConfigurationMap.USECASE_VENDOR_START) && + (usecase < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT))) { + if (mRecommendedConfigurations == null) { + mRecommendedConfigurations = mProperties.getRecommendedStreamConfigurations(); + if (mRecommendedConfigurations == null) { + return null; + } + } + + return mRecommendedConfigurations.get(usecase); + } + + throw new IllegalArgumentException(String.format("Invalid use case: %d", usecase)); + } + + /** * <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that the * camera device can pass as part of the capture session initialization.</p> * @@ -329,7 +429,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * but clients should be aware and expect delays during their application. * An example usage scenario could look like this:</p> * <ul> - * <li>The camera client starts by quering the session parameter key list via + * <li>The camera client starts by querying the session parameter key list via * {@link android.hardware.camera2.CameraCharacteristics#getAvailableSessionKeys }.</li> * <li>Before triggering the capture session create sequence, a capture request * must be built via {@link CameraDevice#createCaptureRequest } using an @@ -1583,7 +1683,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * {@link android.graphics.ImageFormat#RAW12 RAW12}.</li> * <li>Processed (but not-stalling): any non-RAW format without a stall duration. Typically * {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}, - * {@link android.graphics.ImageFormat#NV21 NV21}, or {@link android.graphics.ImageFormat#YV12 YV12}.</li> + * {@link android.graphics.ImageFormat#NV21 NV21}, {@link android.graphics.ImageFormat#YV12 YV12}, or {@link android.graphics.ImageFormat#Y8 Y8} .</li> * </ul> * <p><b>Range of valid values:</b><br></p> * <p>For processed (and stalling) format streams, >= 1.</p> @@ -1646,6 +1746,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <li>{@link android.graphics.ImageFormat#NV21 NV21}</li> * <li>{@link android.graphics.ImageFormat#YV12 YV12}</li> * <li>Implementation-defined formats, i.e. {@link android.hardware.camera2.params.StreamConfigurationMap#isOutputSupportedFor(Class) }</li> + * <li>{@link android.graphics.ImageFormat#Y8 Y8}</li> * </ul> * <p>For full guarantees, query {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } with a * processed format -- it will return 0 for a non-stalling stream.</p> @@ -2122,6 +2223,35 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * or output will never hurt maximum frame rate (i.e. {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration getOutputStallDuration(ImageFormat.PRIVATE, size)} is always 0),</p> * <p>Attempting to configure an input stream with output streams not * listed as available in this map is not valid.</p> + * <p>Additionally, if the camera device is MONOCHROME with Y8 support, it will also support + * the following map of formats if its dependent capability + * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}) is supported:</p> + * <table> + * <thead> + * <tr> + * <th align="left">Input Format</th> + * <th align="left">Output Format</th> + * <th align="left">Capability</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td align="left">{@link android.graphics.ImageFormat#PRIVATE }</td> + * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td> + * <td align="left">PRIVATE_REPROCESSING</td> + * </tr> + * <tr> + * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td> + * <td align="left">{@link android.graphics.ImageFormat#JPEG }</td> + * <td align="left">YUV_REPROCESSING</td> + * </tr> + * <tr> + * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td> + * <td align="left">{@link android.graphics.ImageFormat#Y8 }</td> + * <td align="left">YUV_REPROCESSING</td> + * </tr> + * </tbody> + * </table> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES @@ -2297,6 +2427,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <li>{@link android.graphics.ImageFormat#YUV_420_888 }</li> * <li>{@link android.graphics.ImageFormat#RAW10 }</li> * <li>{@link android.graphics.ImageFormat#RAW12 }</li> + * <li>{@link android.graphics.ImageFormat#Y8 }</li> * </ul> * <p>All other formats may or may not have an allowed stall duration on * a per-capability basis; refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} @@ -2447,6 +2578,37 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Integer>("android.scaler.croppingType", int.class); /** + * <p>Recommended stream configurations for common client use cases.</p> + * <p>Optional subset of the android.scaler.availableStreamConfigurations that contains + * similar tuples listed as + * (i.e. width, height, format, output/input stream, usecase bit field). + * Camera devices will be able to suggest particular stream configurations which are + * power and performance efficient for specific use cases. For more information about + * retrieving the suggestions see + * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * @hide + */ + public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS = + new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.scaler.availableRecommendedStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class); + + /** + * <p>Recommended mappings of image formats that are supported by this + * camera device for input streams, to their corresponding output formats.</p> + * <p>This is a recommended subset of the complete list of mappings found in + * android.scaler.availableInputOutputFormatsMap. The same requirements apply here as well. + * The list however doesn't need to contain all available and supported mappings. Instead of + * this developers must list only recommended and efficient entries. + * If set, the information will be available in the ZERO_SHUTTER_LAG recommended stream + * configuration see + * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * @hide + */ + public static final Key<android.hardware.camera2.params.ReprocessFormatsMap> SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP = + new Key<android.hardware.camera2.params.ReprocessFormatsMap>("android.scaler.availableRecommendedInputOutputFormatsMap", android.hardware.camera2.params.ReprocessFormatsMap.class); + + /** * <p>The area of the image sensor which corresponds to active pixels after any geometric * distortion correction has been applied.</p> * <p>This is the rectangle representing the size of the active region of the sensor (i.e. @@ -3487,6 +3649,21 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Boolean>("android.depth.depthIsExclusive", boolean.class); /** + * <p>Recommended depth stream configurations for common client use cases.</p> + * <p>Optional subset of the android.depth.availableDepthStreamConfigurations that + * contains similar tuples listed as + * (i.e. width, height, format, output/input stream, usecase bit field). + * Camera devices will be able to suggest particular depth stream configurations which are + * power and performance efficient for specific use cases. For more information about + * retrieving the suggestions see + * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * @hide + */ + public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS = + new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.depth.availableRecommendedDepthStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class); + + /** * <p>String containing the ids of the underlying physical cameras.</p> * <p>For a logical camera, this is concatenation of all underlying physical camera ids. * The null terminator for physical camera id must be preserved so that the whole string diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index ce88697fa8db..ac00f1488b14 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -356,6 +356,12 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * + * <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} + * includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}) + * supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV} + * streams with {@code Y8} in all guaranteed stream combinations for the device's hardware level + * and capabilities.</p> + * * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices * support at least the following stream combinations in addition to those for diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index d4dc181e5eec..ffc22641f025 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -539,6 +539,8 @@ public abstract class CameraMetadata<TKey> { * <li>{@link android.graphics.ImageFormat#PRIVATE } will be reprocessable into both * {@link android.graphics.ImageFormat#YUV_420_888 } and * {@link android.graphics.ImageFormat#JPEG } formats.</li> + * <li>For a MONOCHROME camera supporting Y8 format, {@link android.graphics.ImageFormat#PRIVATE } will be reprocessable into + * {@link android.graphics.ImageFormat#Y8 }.</li> * <li>The maximum available resolution for PRIVATE streams * (both input/output) will match the maximum available * resolution of JPEG streams.</li> @@ -612,7 +614,7 @@ public abstract class CameraMetadata<TKey> { * then the list of resolutions for YUV_420_888 from {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } contains at * least one resolution >= 8 megapixels, with a minimum frame duration of <= 1/20 * s.</p> - * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, then those can also be + * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, {@link android.graphics.ImageFormat#Y8 }, then those can also be * captured at the same rate as the maximum-size YUV_420_888 resolution is.</p> * <p>If the device supports the PRIVATE_REPROCESSING capability, then the same guarantees * as for the YUV_420_888 format also apply to the {@link android.graphics.ImageFormat#PRIVATE } format.</p> @@ -646,6 +648,8 @@ public abstract class CameraMetadata<TKey> { * {@link android.graphics.ImageFormat#YUV_420_888 } and {@link android.graphics.ImageFormat#JPEG } formats.</li> * <li>The maximum available resolution for {@link android.graphics.ImageFormat#YUV_420_888 } streams (both input/output) will match the * maximum available resolution of {@link android.graphics.ImageFormat#JPEG } streams.</li> + * <li>For a MONOCHROME camera with Y8 format support, all the requirements mentioned + * above for YUV_420_888 apply for Y8 format as well.</li> * <li>Static metadata {@link CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL android.reprocess.maxCaptureStall}.</li> * <li>Only the below controls are effective for reprocessing requests and will be present * in capture results. The reprocess requests are from the original capture results @@ -692,8 +696,8 @@ public abstract class CameraMetadata<TKey> { * <li>The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.</li> * <li>As of Android P, the {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} entry is listed by this device.</li> * <li>A LIMITED camera with only the DEPTH_OUTPUT capability does not have to support - * normal YUV_420_888, JPEG, and PRIV-format outputs. It only has to support the DEPTH16 - * format.</li> + * normal YUV_420_888, Y8, JPEG, and PRIV-format outputs. It only has to support the + * DEPTH16 format.</li> * </ul> * <p>Generally, depth output operates at a slower frame rate than standard color capture, * so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that @@ -877,6 +881,10 @@ public abstract class CameraMetadata<TKey> { /** * <p>The camera device is a monochrome camera that doesn't contain a color filter array, * and the pixel values on U and V planes are all 128.</p> + * <p>A MONOCHROME camera must support the guaranteed stream combinations required for + * its device level and capabilities. Additionally, if the monochrome camera device + * supports Y8 format, all mandatory stream combination requirements related to {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888} apply + * to {@link android.graphics.ImageFormat#Y8 Y8} as well.</p> * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES */ public static final int REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME = 12; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 4a20468276d3..2744e9111509 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -3277,8 +3277,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * will not slow down capture rate when applying correction. FAST may be the same as OFF if * any correction at all would slow down capture rate. Every output stream will have a * similar amount of enhancement applied.</p> - * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not - * applied to any RAW output.</p> + * <p>The correction only applies to processed outputs such as YUV, Y8, JPEG, or DEPTH16; it is + * not applied to any RAW output.</p> * <p>This control will be on by default on devices that support this control. Applications * disabling distortion correction need to pay extra attention with the coordinate system of * metering regions, crop region, and face rectangles. When distortion correction is OFF, diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index a7e185c9853b..2b67f3e6adcb 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -4620,8 +4620,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * will not slow down capture rate when applying correction. FAST may be the same as OFF if * any correction at all would slow down capture rate. Every output stream will have a * similar amount of enhancement applied.</p> - * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not - * applied to any RAW output.</p> + * <p>The correction only applies to processed outputs such as YUV, Y8, JPEG, or DEPTH16; it is + * not applied to any RAW output.</p> * <p>This control will be on by default on devices that support this control. Applications * disabling distortion correction need to pay extra attention with the coordinate system of * metering regions, crop region, and face rectangles. When distortion correction is OFF, diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 0610d7a3746b..f81bd1377a7a 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -21,6 +21,7 @@ import android.graphics.ImageFormat; import android.graphics.Point; import android.graphics.Rect; import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.marshal.MarshalQueryable; @@ -38,6 +39,7 @@ import android.hardware.camera2.marshal.impl.MarshalQueryablePair; import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable; import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive; import android.hardware.camera2.marshal.impl.MarshalQueryableRange; +import android.hardware.camera2.marshal.impl.MarshalQueryableRecommendedStreamConfiguration; import android.hardware.camera2.marshal.impl.MarshalQueryableRect; import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap; import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector; @@ -50,6 +52,8 @@ import android.hardware.camera2.params.Face; import android.hardware.camera2.params.HighSpeedVideoConfiguration; import android.hardware.camera2.params.LensShadingMap; import android.hardware.camera2.params.OisSample; +import android.hardware.camera2.params.RecommendedStreamConfiguration; +import android.hardware.camera2.params.RecommendedStreamConfigurationMap; import android.hardware.camera2.params.ReprocessFormatsMap; import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.params.StreamConfigurationDuration; @@ -911,6 +915,252 @@ public class CameraMetadataNative implements Parcelable { return true; } + private void parseRecommendedConfigurations(RecommendedStreamConfiguration[] configurations, + StreamConfigurationMap fullMap, boolean isDepth, + ArrayList<ArrayList<StreamConfiguration>> /*out*/streamConfigList, + ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamDurationList, + ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamStallList, + boolean[] /*out*/supportsPrivate) { + + streamConfigList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); + streamDurationList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); + streamStallList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); + for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) { + streamConfigList.add(new ArrayList<StreamConfiguration> ()); + streamDurationList.add(new ArrayList<StreamConfigurationDuration> ()); + streamStallList.add(new ArrayList<StreamConfigurationDuration> ()); + } + + for (RecommendedStreamConfiguration c : configurations) { + int width = c.getWidth(); + int height = c.getHeight(); + int internalFormat = c.getFormat(); + int publicFormat = + (isDepth) ? StreamConfigurationMap.depthFormatToPublic(internalFormat) : + StreamConfigurationMap.imageFormatToPublic(internalFormat); + Size sz = new Size(width, height); + int usecaseBitmap = c.getUsecaseBitmap(); + + if (!c.isInput()) { + StreamConfigurationDuration minDurationConfiguration = null; + StreamConfigurationDuration stallDurationConfiguration = null; + + StreamConfiguration streamConfiguration = new StreamConfiguration(internalFormat, + width, height, /*input*/ false); + + long minFrameDuration = fullMap.getOutputMinFrameDuration(publicFormat, sz); + if (minFrameDuration > 0) { + minDurationConfiguration = new StreamConfigurationDuration(internalFormat, + width, height, minFrameDuration); + } + + long stallDuration = fullMap.getOutputStallDuration(publicFormat, sz); + if (stallDuration > 0) { + stallDurationConfiguration = new StreamConfigurationDuration(internalFormat, + width, height, stallDuration); + } + + for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) { + if ((usecaseBitmap & (1 << i)) != 0) { + ArrayList<StreamConfiguration> sc = streamConfigList.get(i); + sc.add(streamConfiguration); + + if (minFrameDuration > 0) { + ArrayList<StreamConfigurationDuration> scd = streamDurationList.get(i); + scd.add(minDurationConfiguration); + } + + if (stallDuration > 0) { + ArrayList<StreamConfigurationDuration> scs = streamStallList.get(i); + scs.add(stallDurationConfiguration); + } + + if ((supportsPrivate != null) && !supportsPrivate[i] && + (publicFormat == ImageFormat.PRIVATE)) { + supportsPrivate[i] = true; + } + } + } + } else { + if (usecaseBitmap != (1 << RecommendedStreamConfigurationMap.USECASE_ZSL)) { + throw new IllegalArgumentException("Recommended input stream configurations " + + "should only be advertised in the ZSL use case!"); + } + + ArrayList<StreamConfiguration> sc = streamConfigList.get( + RecommendedStreamConfigurationMap.USECASE_ZSL); + sc.add(new StreamConfiguration(internalFormat, + width, height, /*input*/ true)); + } + } + } + + private class StreamConfigurationData { + StreamConfiguration [] streamConfigurationArray = null; + StreamConfigurationDuration [] minDurationArray = null; + StreamConfigurationDuration [] stallDurationArray = null; + } + + public void initializeStreamConfigurationData(ArrayList<StreamConfiguration> sc, + ArrayList<StreamConfigurationDuration> scd, ArrayList<StreamConfigurationDuration> scs, + StreamConfigurationData /*out*/scData) { + if ((scData == null) || (sc == null)) { + return; + } + + scData.streamConfigurationArray = new StreamConfiguration[sc.size()]; + scData.streamConfigurationArray = sc.toArray(scData.streamConfigurationArray); + + if ((scd != null) && !scd.isEmpty()) { + scData.minDurationArray = new StreamConfigurationDuration[scd.size()]; + scData.minDurationArray = scd.toArray(scData.minDurationArray); + } else { + scData.minDurationArray = new StreamConfigurationDuration[0]; + } + + if ((scs != null) && !scs.isEmpty()) { + scData.stallDurationArray = new StreamConfigurationDuration[scs.size()]; + scData.stallDurationArray = scs.toArray(scData.stallDurationArray); + } else { + scData.stallDurationArray = new StreamConfigurationDuration[0]; + } + } + + /** + * Retrieve the list of recommended stream configurations. + * + * @return A list of recommended stream configuration maps for each common use case or null + * in case the recommended stream configurations are invalid or incomplete. + * @hide + */ + public ArrayList<RecommendedStreamConfigurationMap> getRecommendedStreamConfigurations() { + RecommendedStreamConfiguration[] configurations = getBase( + CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS); + RecommendedStreamConfiguration[] depthConfigurations = getBase( + CameraCharacteristics.DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS); + if ((configurations == null) && (depthConfigurations == null)) { + return null; + } + + StreamConfigurationMap fullMap = getStreamConfigurationMap(); + ArrayList<RecommendedStreamConfigurationMap> recommendedConfigurations = + new ArrayList<RecommendedStreamConfigurationMap> (); + + ArrayList<ArrayList<StreamConfiguration>> streamConfigList = + new ArrayList<ArrayList<StreamConfiguration>>(); + ArrayList<ArrayList<StreamConfigurationDuration>> streamDurationList = + new ArrayList<ArrayList<StreamConfigurationDuration>>(); + ArrayList<ArrayList<StreamConfigurationDuration>> streamStallList = + new ArrayList<ArrayList<StreamConfigurationDuration>>(); + boolean[] supportsPrivate = + new boolean[RecommendedStreamConfigurationMap.MAX_USECASE_COUNT]; + try { + if (configurations != null) { + parseRecommendedConfigurations(configurations, fullMap, /*isDepth*/ false, + streamConfigList, streamDurationList, streamStallList, supportsPrivate); + } + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed parsing the recommended stream configurations!"); + return null; + } + + ArrayList<ArrayList<StreamConfiguration>> depthStreamConfigList = + new ArrayList<ArrayList<StreamConfiguration>>(); + ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamDurationList = + new ArrayList<ArrayList<StreamConfigurationDuration>>(); + ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamStallList = + new ArrayList<ArrayList<StreamConfigurationDuration>>(); + if (depthConfigurations != null) { + try { + parseRecommendedConfigurations(depthConfigurations, fullMap, /*isDepth*/ true, + depthStreamConfigList, depthStreamDurationList, depthStreamStallList, + /*supportsPrivate*/ null); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed parsing the recommended depth stream configurations!"); + return null; + } + } + + ReprocessFormatsMap inputOutputFormatsMap = getBase( + CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP); + HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase( + CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); + boolean listHighResolution = isBurstSupported(); + recommendedConfigurations.ensureCapacity( + RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); + for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) { + StreamConfigurationData scData = new StreamConfigurationData(); + if (configurations != null) { + initializeStreamConfigurationData(streamConfigList.get(i), + streamDurationList.get(i), streamStallList.get(i), scData); + } + + StreamConfigurationData depthScData = new StreamConfigurationData(); + if (depthConfigurations != null) { + initializeStreamConfigurationData(depthStreamConfigList.get(i), + depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData); + } + + if ((scData.streamConfigurationArray == null) && + (depthScData.streamConfigurationArray == null)) { + recommendedConfigurations.add(null); + continue; + } + + StreamConfigurationMap map = null; + switch (i) { + case RecommendedStreamConfigurationMap.USECASE_PREVIEW: + case RecommendedStreamConfigurationMap.USECASE_RAW: + case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT: + map = new StreamConfigurationMap(scData.streamConfigurationArray, + scData.minDurationArray, scData.stallDurationArray, + /*depthconfiguration*/ null, /*depthminduration*/ null, + /*depthstallduration*/ null, /*highspeedvideoconfigurations*/ null, + /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]); + break; + case RecommendedStreamConfigurationMap.USECASE_RECORD: + map = new StreamConfigurationMap(scData.streamConfigurationArray, + scData.minDurationArray, scData.stallDurationArray, + /*depthconfiguration*/ null, /*depthminduration*/ null, + /*depthstallduration*/ null, highSpeedVideoConfigurations, + /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]); + break; + case RecommendedStreamConfigurationMap.USECASE_ZSL: + map = new StreamConfigurationMap(scData.streamConfigurationArray, + scData.minDurationArray, scData.stallDurationArray, + depthScData.streamConfigurationArray, depthScData.minDurationArray, + depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null, + inputOutputFormatsMap, listHighResolution, supportsPrivate[i]); + break; + default: + map = new StreamConfigurationMap(scData.streamConfigurationArray, + scData.minDurationArray, scData.stallDurationArray, + depthScData.streamConfigurationArray, depthScData.minDurationArray, + depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null, + /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]); + } + + recommendedConfigurations.add(new RecommendedStreamConfigurationMap(map, /*usecase*/i, + supportsPrivate[i])); + } + + return recommendedConfigurations; + } + + private boolean isBurstSupported() { + boolean ret = false; + + int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); + for (int capability : capabilities) { + if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) { + ret = true; + break; + } + } + + return ret; + } + private StreamConfigurationMap getStreamConfigurationMap() { StreamConfiguration[] configurations = getBase( CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); @@ -928,14 +1178,7 @@ public class CameraMetadataNative implements Parcelable { CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); ReprocessFormatsMap inputOutputFormatsMap = getBase( CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP); - int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); - boolean listHighResolution = false; - for (int capability : capabilities) { - if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) { - listHighResolution = true; - break; - } - } + boolean listHighResolution = isBurstSupported(); return new StreamConfigurationMap( configurations, minFrameDurations, stallDurations, depthConfigurations, depthMinFrameDurations, depthStallDurations, @@ -1399,6 +1642,7 @@ public class CameraMetadataNative implements Parcelable { new MarshalQueryableRggbChannelVector(), new MarshalQueryableBlackLevelPattern(), new MarshalQueryableHighSpeedVideoConfiguration(), + new MarshalQueryableRecommendedStreamConfiguration(), // generic parcelable marshaler (MUST BE LAST since it has lowest priority) new MarshalQueryableParcelable(), diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java new file mode 100644 index 000000000000..22a76b7346e8 --- /dev/null +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.camera2.marshal.impl; + +import android.hardware.camera2.marshal.Marshaler; +import android.hardware.camera2.marshal.MarshalQueryable; +import android.hardware.camera2.params.RecommendedStreamConfiguration; +import android.hardware.camera2.utils.TypeReference; + +import static android.hardware.camera2.impl.CameraMetadataNative.*; +import static android.hardware.camera2.marshal.MarshalHelpers.*; + +import java.nio.ByteBuffer; + +/** + * Marshaler for {@code android.scaler.availableRecommendedStreamConfigurations} custom class + * {@link RecommendedStreamConfiguration} + * + * <p>Data is stored as {@code (width, height, format, input, usecaseBitmap)} tuples (int32).</p> + */ +public class MarshalQueryableRecommendedStreamConfiguration + implements MarshalQueryable<RecommendedStreamConfiguration> { + private static final int SIZE = SIZEOF_INT32 * 5; + + private class MarshalerRecommendedStreamConfiguration + extends Marshaler<RecommendedStreamConfiguration> { + protected MarshalerRecommendedStreamConfiguration( + TypeReference<RecommendedStreamConfiguration> typeReference, int nativeType) { + super(MarshalQueryableRecommendedStreamConfiguration.this, typeReference, nativeType); + } + + @Override + public void marshal(RecommendedStreamConfiguration value, ByteBuffer buffer) { + buffer.putInt(value.getWidth()); + buffer.putInt(value.getHeight()); + buffer.putInt(value.getFormat()); + buffer.putInt(value.isInput() ? 1 : 0); + buffer.putInt(value.getUsecaseBitmap()); + } + + @Override + public RecommendedStreamConfiguration unmarshal(ByteBuffer buffer) { + int width = buffer.getInt(); + int height = buffer.getInt(); + int format = buffer.getInt(); + boolean input = buffer.getInt() != 0; + int usecaseBitmap = buffer.getInt(); + + return new RecommendedStreamConfiguration(format, width, height, input, usecaseBitmap); + } + + @Override + public int getNativeSize() { + return SIZE; + } + + } + + @Override + public Marshaler<RecommendedStreamConfiguration> createMarshaler( + TypeReference<RecommendedStreamConfiguration> managedType, int nativeType) { + return new MarshalerRecommendedStreamConfiguration(managedType, nativeType); + } + + @Override + public boolean isTypeMappingSupported(TypeReference<RecommendedStreamConfiguration> managedType, + int nativeType) { + return nativeType == + TYPE_INT32 && managedType.getType().equals(RecommendedStreamConfiguration.class); + } +} diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java new file mode 100644 index 000000000000..5dd0517ae47e --- /dev/null +++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2.params; + +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.utils.HashCodeHelpers; + +/** + * Immutable class to store the recommended stream configurations to set up + * {@link android.view.Surface Surfaces} for creating a {@link CameraCaptureSession capture session} + * with {@link CameraDevice#createCaptureSession}. + * + * @see CameraCharacteristics#getRecommendedStreamConfigurationMap + * + * @hide + */ +public final class RecommendedStreamConfiguration extends StreamConfiguration{ + + /** + * Create a new {@link RecommendedStreamConfiguration}. + * + * @param format image format + * @param width image width, in pixels (positive) + * @param height image height, in pixels (positive) + * @param input true if this is an input configuration, false for output configurations + * @param usecaseBitmap Use case bitmap + * + * @throws IllegalArgumentException + * if width/height were not positive + * or if the format was not user-defined in ImageFormat/PixelFormat + * (IMPL_DEFINED is ok) + * + * @hide + */ + public RecommendedStreamConfiguration( + final int format, final int width, final int height, final boolean input, final int + usecaseBitmap) { + super(format, width, height, input); + mUsecaseBitmap = usecaseBitmap; + } + + /** + * Return usecase bitmap. + * + * @return usecase bitmap + */ + public int getUsecaseBitmap() { + return mUsecaseBitmap; + } + + /** + * Check if this {@link RecommendedStreamConfiguration} is equal to another + * {@link RecommendedStreamConfiguration}. + * + * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p> + * + * @return {@code true} if the objects were equal, {@code false} otherwise + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (obj instanceof RecommendedStreamConfiguration) { + final RecommendedStreamConfiguration other = (RecommendedStreamConfiguration) obj; + return mFormat == other.mFormat && + mWidth == other.mWidth && + mHeight == other.mHeight && + mUsecaseBitmap == other.mUsecaseBitmap && + mInput == other.mInput; + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0, mUsecaseBitmap); + } + + private final int mUsecaseBitmap; +} diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java new file mode 100644 index 000000000000..59e4a3366995 --- /dev/null +++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2.params; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.ImageFormat; +import android.graphics.PixelFormat; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraMetadata; +import android.hardware.camera2.CaptureRequest; +import android.util.ArraySet; +import android.util.Range; +import android.util.Size; +import android.view.Surface; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; + +/** + * Immutable class to store the recommended stream configurations to set up + * {@link android.view.Surface Surfaces} for creating a + * {@link android.hardware.camera2.CameraCaptureSession capture session} with + * {@link android.hardware.camera2.CameraDevice#createCaptureSession}. + * + * <p>The recommended list does not replace or deprecate the exhaustive complete list found in + * {@link StreamConfigurationMap}. It is a suggestion about available power and performance + * efficient stream configurations for a specific use case. Per definition it is only a subset + * of {@link StreamConfigurationMap} and can be considered by developers for optimization + * purposes.</p> + * + * <p>This also duplicates the minimum frame durations and stall durations from the + * {@link StreamConfigurationMap} for each format/size combination that can be used to calculate + * effective frame rate when submitting multiple captures. + * </p> + * + * <p>An instance of this object is available by invoking + * {@link CameraCharacteristics#getRecommendedStreamConfigurationMap} and passing a respective + * usecase id. For more information about supported use case constants see + * {@link #USECASE_PREVIEW}.</p> + * + * <pre><code>{@code + * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); + * RecommendedStreamConfigurationMap configs = characteristics.getRecommendedStreamConfigurationMap( + * RecommendedStreamConfigurationMap.USECASE_PREVIEW); + * }</code></pre> + * + * @see CameraCharacteristics#getRecommendedStreamConfigurationMap + * @see CameraDevice#createCaptureSession + */ +public final class RecommendedStreamConfigurationMap { + + private static final String TAG = "RecommendedStreamConfigurationMap"; + private int mUsecase; + private boolean mSupportsPrivate; + private StreamConfigurationMap mRecommendedMap; + + /** @hide */ + public static final int MAX_USECASE_COUNT = 32; + + /** + * The recommended stream configuration map for use case preview must contain a subset of + * efficient, non-stalling configurations that must include both + * {@link android.graphics.ImageFormat#PRIVATE} and + * {@link android.graphics.ImageFormat#YUV_420_888} output formats. Even if available for the + * camera device, high speed or input configurations will be absent. + */ + public static final int USECASE_PREVIEW = 0x0; + + /** + * The recommended stream configuration map for recording must contain a subset of efficient + * video configurations that include {@link android.graphics.ImageFormat#PRIVATE} + * output format for at least all supported {@link android.media.CamcorderProfile profiles}. + * High speed configurations if supported will be available as well. Even if available for the + * camera device, input configurations will be absent. + */ + public static final int USECASE_RECORD = 0x1; + + /** + * The recommended stream configuration map for use case video snapshot must only contain a + * subset of efficient liveshot configurations that include + * {@link android.graphics.ImageFormat#JPEG} output format. The sizes will match at least + * the maximum resolution of usecase record and will not cause any preview glitches. Even + * if available for the camera device, high speed or input configurations will be absent. + */ + public static final int USECASE_VIDEO_SNAPSHOT = 0x2; + + /** + * The recommended stream configuration map for use case snapshot must contain a subset of + * efficient still capture configurations that must include + * {@link android.graphics.ImageFormat#JPEG} output format and at least one configuration with + * size approximately equal to the sensor pixel array size + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}. + * Even if available for the camera device, high speed or input configurations will be absent. + */ + public static final int USECASE_SNAPSHOT = 0x3; + + /** + * In case the device supports + * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING} and/or + * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING}, + * the recommended stream configuration map for use case ZSL must contain a subset of efficient + * configurations that include the suggested input and output format mappings. Even if + * available for the camera device, high speed configurations will be absent. + */ + public static final int USECASE_ZSL = 0x4; + + /** + * In case the device supports + * {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW}, the + * recommended stream configuration map for use case RAW must contain a subset of efficient + * configurations that include the {@link android.graphics.ImageFormat#RAW_SENSOR} and other + * RAW output formats. Even if available for the camera device, high speed and input + * configurations will be absent. + */ + public static final int USECASE_RAW = 0x5; + + /** + * Device specific use cases. + * @hide + */ + public static final int USECASE_VENDOR_START = 0x18; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"USECASE_"}, value = + {USECASE_PREVIEW, + USECASE_RECORD, + USECASE_VIDEO_SNAPSHOT, + USECASE_SNAPSHOT, + USECASE_ZSL, + USECASE_RAW }) + public @interface RecommendedUsecase {}; + + /** + * Create a new {@link RecommendedStreamConfigurationMap}. + * + * @param recommendedMap stream configuration map that contains for the specific use case + * @param usecase Recommended use case + * @param supportsPrivate Flag indicating private format support. + * + * @hide + */ + public RecommendedStreamConfigurationMap(StreamConfigurationMap recommendedMap, int usecase, + boolean supportsPrivate) { + mRecommendedMap = recommendedMap; + mUsecase = usecase; + mSupportsPrivate = supportsPrivate; + } + + /** + * Get the use case value for the recommended stream configurations. + * + * @return Use case id. + */ + public int getRecommendedUseCase() { + return mUsecase; + } + + private Set<Integer> getUnmodifiableIntegerSet(int[] intArray) { + if ((intArray != null) && (intArray.length > 0)) { + ArraySet<Integer> integerSet = new ArraySet<Integer>(); + integerSet.ensureCapacity(intArray.length); + for (int intEntry : intArray) { + integerSet.add(intEntry); + } + + return Collections.unmodifiableSet(integerSet); + } + + return null; + } + + /** + * Get the image {@code format} output formats in this stream configuration. + * + * <p> + * For more information refer to {@link StreamConfigurationMap#getOutputFormats}. + * </p> + * + * @return a non-modifiable set of Integer formats + */ + public @NonNull Set<Integer> getOutputFormats() { + return getUnmodifiableIntegerSet(mRecommendedMap.getOutputFormats()); + } + + /** + * Get the image {@code format} output formats for a reprocessing input format. + * + * <p> + * For more information refer to {@link StreamConfigurationMap#getValidOutputFormatsForInput}. + * </p> + * + * @return a non-modifiable set of Integer formats + */ + public @Nullable Set<Integer> getValidOutputFormatsForInput(int inputFormat) { + return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput( + inputFormat)); + } + + /** + * Get the image {@code format} input formats in this stream configuration. + * + * <p>All image formats returned by this function will be defined in either {@link ImageFormat} + * or in {@link PixelFormat} (and there is no possibility of collision).</p> + * + * @return a non-modifiable set of Integer formats + */ + public @Nullable Set<Integer> getInputFormats() { + return getUnmodifiableIntegerSet(mRecommendedMap.getInputFormats()); + } + + private Set<Size> getUnmodifiableSizeSet(Size[] sizeArray) { + if ((sizeArray != null) && (sizeArray.length > 0)) { + ArraySet<Size> sizeSet = new ArraySet<Size>(); + sizeSet.addAll(Arrays.asList(sizeArray)); + return Collections.unmodifiableSet(sizeSet); + } + + return null; + } + + /** + * Get the supported input sizes for this input format. + * + * <p>The format must have come from {@link #getInputFormats}; otherwise + * {@code null} is returned.</p> + * + * @param format a format from {@link #getInputFormats} + * @return a non-modifiable set of sizes, or {@code null} if the format was not available. + */ + public @Nullable Set<Size> getInputSizes(int format) { + return getUnmodifiableSizeSet(mRecommendedMap.getInputSizes(format)); + } + + /** + * Determine whether or not output surfaces with a particular user-defined format can be passed + * {@link CameraDevice#createCaptureSession createCaptureSession}. + * + * <p> + * For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}. + * </p> + * + * + * @param format an image format from either {@link ImageFormat} or {@link PixelFormat} + * @return + * {@code true} if using a {@code surface} with this {@code format} will be + * supported with {@link CameraDevice#createCaptureSession} + * + * @throws IllegalArgumentException + * if the image format was not a defined named constant + * from either {@link ImageFormat} or {@link PixelFormat} + */ + public boolean isOutputSupportedFor(int format) { + return mRecommendedMap.isOutputSupportedFor(format); + } + + /** + * Get a list of sizes compatible with the requested image {@code format}. + * + * <p> + * For more information refer to {@link StreamConfigurationMap#getOutputSizes}. + * </p> + * + * + * @param format an image format from {@link ImageFormat} or {@link PixelFormat} + * @return a non-modifiable set of supported sizes, + * or {@code null} if the {@code format} is not a supported output + */ + public @Nullable Set<Size> getOutputSizes(int format) { + return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format)); + } + + /** + * Get a list of supported high speed video recording sizes. + * <p> + * For more information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizes}. + * </p> + * + * @return a non-modifiable set of supported high speed video recording sizes + */ + public @Nullable Set<Size> getHighSpeedVideoSizes() { + return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizes()); + } + + private Set<Range<Integer>> getUnmodifiableRangeSet(Range<Integer>[] rangeArray) { + if ((rangeArray != null) && (rangeArray.length > 0)) { + ArraySet<Range<Integer>> rangeSet = new ArraySet<Range<Integer>>(); + rangeSet.addAll(Arrays.asList(rangeArray)); + return Collections.unmodifiableSet(rangeSet); + } + + return null; + } + + /** + * Get the frame per second ranges (fpsMin, fpsMax) for input high speed video size. + * + * <p> + * For further information refer to + * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor}. + * </p> + * @param size one of the sizes returned by {@link #getHighSpeedVideoSizes()} + * @return a non-modifiable set of supported high speed video recording FPS ranges The upper + * bound of returned ranges is guaranteed to be greater than or equal to 120. + * @throws IllegalArgumentException if input size does not exist in the return value of + * getHighSpeedVideoSizes + */ + public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRangesFor(Size size) { + return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRangesFor(size)); + } + + /** + * Get a list of supported high speed video recording FPS ranges. + * <p> + * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoFpsRanges}. + * </p> + * @return a non-modifiable set of supported high speed video recording FPS ranges The upper + * bound of returned ranges is guaranteed to be larger or equal to 120. + */ + public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRanges() { + return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRanges()); + } + + /** + * Get the supported video sizes for an input high speed FPS range. + * + * <p> + * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizesFor}. + * </p> + * + * @param fpsRange one of the FPS range returned by {@link #getHighSpeedVideoFpsRanges()} + * @return A non-modifiable set of video sizes to create high speed capture sessions for high + * speed streaming use cases. + * + * @throws IllegalArgumentException if input FPS range does not exist in the return value of + * getHighSpeedVideoFpsRanges + */ + public @Nullable Set<Size> getHighSpeedVideoSizesFor(Range<Integer> fpsRange) { + return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizesFor(fpsRange)); + } + + /** + * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE + * rate. + * + * <p> + * For further information refer to {@link StreamConfigurationMap#getHighResolutionOutputSizes}. + * </p> + * + * @return a non-modifiable set of supported slower high-resolution sizes, or {@code null} if + * the BURST_CAPTURE capability is not supported + */ + public @Nullable Set<Size> getHighResolutionOutputSizes(int format) { + return getUnmodifiableSizeSet(mRecommendedMap.getHighResolutionOutputSizes(format)); + } + + /** + * Get the minimum + * {@link android.hardware.camera2.CaptureRequest#SENSOR_FRAME_DURATION frame duration} + * for the format/size combination (in nanoseconds). + * + * <p> + * For further information refer to {@link StreamConfigurationMap#getOutputMinFrameDuration}. + * </p> + * + * @param format an image format from {@link ImageFormat} or {@link PixelFormat} + * @param size an output-compatible size + * @return a minimum frame duration {@code >} 0 in nanoseconds, or + * 0 if the minimum frame duration is not available. + * + * @throws IllegalArgumentException if {@code format} or {@code size} was not supported + * @throws NullPointerException if {@code size} was {@code null} + * + */ + public long getOutputMinFrameDuration(int format, Size size) { + return mRecommendedMap.getOutputMinFrameDuration(format, size); + } + + /** + * Get the stall duration for the format/size combination (in nanoseconds). + * + * <p> + * For further information refer to {@link StreamConfigurationMap#getOutputStallDuration}. + * </p> + * + * @param format an image format from {@link ImageFormat} or {@link PixelFormat} + * @param size an output-compatible size + * @return a stall duration {@code >=} 0 in nanoseconds + * + * @throws IllegalArgumentException if {@code format} or {@code size} was not supported + * @throws NullPointerException if {@code size} was {@code null} + */ + public long getOutputStallDuration(int format, Size size) { + return mRecommendedMap.getOutputStallDuration(format, size); + } + + /** + * Get a list of sizes compatible with {@code klass} to use as an output. + * + * <p>For further information refer to {@link StreamConfigurationMap#getOutputSizes(Class)}. + * </p> + * + * @param klass + * a non-{@code null} {@link Class} object reference + * @return + * a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format, + * or {@code null} if the {@code klass} is not a supported output. + * + * + * @throws NullPointerException if {@code klass} was {@code null} + * + */ + public <T> @Nullable Set<Size> getOutputSizes(Class<T> klass) { + if (mSupportsPrivate) { + return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass)); + } + + return null; + } + + /** + * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration} + * for the class/size combination (in nanoseconds). + * + * <p>For more information refer to + * {@link StreamConfigurationMap#getOutputMinFrameDuration(Class, Size)}.</p> + * + * @param klass + * a class which has a non-empty array returned by {@link #getOutputSizes(Class)} + * @param size an output-compatible size + * @return a minimum frame duration {@code >} 0 in nanoseconds, or + * 0 if the minimum frame duration is not available. + * + * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported + * @throws NullPointerException if {@code size} or {@code klass} was {@code null} + * + */ + public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) { + if (mSupportsPrivate) { + return mRecommendedMap.getOutputMinFrameDuration(klass, size); + } + + return 0; + } + + /** + * Get the stall duration for the class/size combination (in nanoseconds). + * + * <p>For more information refer to + * {@link StreamConfigurationMap#getOutputStallDuration(Class, Size)}. + * + * @param klass + * a class which has a non-empty array returned by {@link #getOutputSizes(Class)}. + * @param size an output-compatible size + * @return a minimum frame duration {@code >=} 0 in nanoseconds, or 0 if the stall duration is + * not available. + * + * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported + * @throws NullPointerException if {@code size} or {@code klass} was {@code null} + * + */ + public <T> long getOutputStallDuration(final Class<T> klass, final Size size) { + if (mSupportsPrivate) { + return mRecommendedMap.getOutputStallDuration(klass, size); + } + + return 0; + } + + /** + * Determine whether or not the {@code surface} in its current state is suitable to be included + * in a {@link CameraDevice#createCaptureSession capture session} as an output. + * + * <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}. + * </p> + * + * @param surface a non-{@code null} {@link Surface} object reference + * @return {@code true} if this is supported, {@code false} otherwise + * + * @throws NullPointerException if {@code surface} was {@code null} + * @throws IllegalArgumentException if the Surface endpoint is no longer valid + * + */ + public boolean isOutputSupportedFor(Surface surface) { + return mRecommendedMap.isOutputSupportedFor(surface); + } + +} diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java index a6fc10fdcc61..eb92291ac90b 100644 --- a/core/java/android/hardware/camera2/params/StreamConfiguration.java +++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java @@ -40,7 +40,7 @@ import android.util.Size; * * @hide */ -public final class StreamConfiguration { +public class StreamConfiguration { /** * Create a new {@link StreamConfiguration}. @@ -164,8 +164,8 @@ public final class StreamConfiguration { return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0); } - private final int mFormat; - private final int mWidth; - private final int mHeight; - private final boolean mInput; + protected int mFormat; + protected int mWidth; + protected int mHeight; + protected boolean mInput; } diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java index 414c463b4545..dd052a8db1d9 100644 --- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java +++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java @@ -98,6 +98,43 @@ public final class StreamConfigurationMap { HighSpeedVideoConfiguration[] highSpeedVideoConfigurations, ReprocessFormatsMap inputOutputFormatsMap, boolean listHighResolution) { + this(configurations, minFrameDurations, stallDurations, + depthConfigurations, depthMinFrameDurations, depthStallDurations, + highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution, + /*enforceImplementationDefined*/ true); + } + + /** + * Create a new {@link StreamConfigurationMap}. + * + * <p>The array parameters ownership is passed to this object after creation; do not + * write to them after this constructor is invoked.</p> + * + * @param configurations a non-{@code null} array of {@link StreamConfiguration} + * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if + * camera device does not support high speed video recording + * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE + * and thus needs a separate list of slow high-resolution output sizes + * @param enforceImplementationDefined a flag indicating whether + * IMPLEMENTATION_DEFINED format configuration must be present + * @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations + * were {@code null} or any subelements were {@code null} + * + * @hide + */ + public StreamConfigurationMap( + StreamConfiguration[] configurations, + StreamConfigurationDuration[] minFrameDurations, + StreamConfigurationDuration[] stallDurations, + StreamConfiguration[] depthConfigurations, + StreamConfigurationDuration[] depthMinFrameDurations, + StreamConfigurationDuration[] depthStallDurations, + HighSpeedVideoConfiguration[] highSpeedVideoConfigurations, + ReprocessFormatsMap inputOutputFormatsMap, + boolean listHighResolution, + boolean enforceImplementationDefined) { if (configurations == null) { // If no color configurations exist, ensure depth ones do @@ -169,7 +206,7 @@ public final class StreamConfigurationMap { mDepthOutputFormats.get(config.getFormat()) + 1); } - if (configurations != null && + if (configurations != null && enforceImplementationDefined && mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) { throw new AssertionError( "At least one stream configuration for IMPLEMENTATION_DEFINED must exist"); @@ -208,7 +245,7 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat */ - public final int[] getOutputFormats() { + public int[] getOutputFormats() { return getPublicFormats(/*output*/true); } @@ -232,7 +269,7 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat */ - public final int[] getValidOutputFormatsForInput(int inputFormat) { + public int[] getValidOutputFormatsForInput(int inputFormat) { if (mInputOutputFormatsMap == null) { return new int[0]; } @@ -250,7 +287,7 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat */ - public final int[] getInputFormats() { + public int[] getInputFormats() { return getPublicFormats(/*output*/false); } @@ -426,6 +463,34 @@ public final class StreamConfigurationMap { } /** + * Determine whether or not the particular stream configuration is suitable to be included + * in a {@link CameraDevice#createCaptureSession capture session} as an output. + * + * @param size stream configuration size + * @param format stream configuration format + * @return {@code true} if this is supported, {@code false} otherwise + * + * @see CameraDevice#createCaptureSession + * @see #isOutputSupportedFor(Class) + * @hide + */ + public boolean isOutputSupportedFor(Size size, int format) { + int internalFormat = imageFormatToInternal(format); + int dataspace = imageFormatToDataspace(format); + + StreamConfiguration[] configs = + dataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations; + for (StreamConfiguration config : configs) { + if ((config.getFormat() == internalFormat) && config.isOutput() && + config.getSize().equals(size)) { + return true; + } + } + + return false; + } + + /** * Get a list of sizes compatible with {@code klass} to use as an output. * * <p>Some of the supported classes may support additional formats beyond @@ -1062,8 +1127,9 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat * @see #checkArgumentFormat + * @hide */ - static int imageFormatToPublic(int format) { + public static int imageFormatToPublic(int format) { switch (format) { case HAL_PIXEL_FORMAT_BLOB: return ImageFormat.JPEG; @@ -1105,8 +1171,9 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat * @see #checkArgumentFormat + * @hide */ - static int depthFormatToPublic(int format) { + public static int depthFormatToPublic(int format) { switch (format) { case HAL_PIXEL_FORMAT_BLOB: return ImageFormat.DEPTH_POINT_CLOUD; diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 7840fd03d7ff..9db1f922bd5d 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -235,7 +235,8 @@ public abstract class DisplayManagerInternal { // If true, enables automatic brightness control. public boolean useAutoBrightness; - // If true, scales the brightness to half of desired. + // If true, scales the brightness to a fraction of desired (as defined by + // screenLowPowerBrightnessFactor). public boolean lowPowerMode; // The factor to adjust the screen brightness in low power mode in the range diff --git a/services/tests/wmtests/src/com/android/server/policy/DummyPolicyTests.java b/core/java/android/hardware/iris/IIrisService.aidl index 03fb12350127..8cf3c13b1465 100644 --- a/services/tests/wmtests/src/com/android/server/policy/DummyPolicyTests.java +++ b/core/java/android/hardware/iris/IIrisService.aidl @@ -13,34 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -package com.android.server.policy; - -import android.platform.test.annotations.Presubmit; - -import org.junit.Test; - -import androidx.test.filters.FlakyTest; +package android.hardware.iris; /** - * Dummy test for com.android.server.policy. - * TODO(b/113800711): Remove this class once the actual tests are moved from servicestests. + * Communication channel from client to the iris service. These methods are all require the + * MANAGE_BIOMETRIC signature permission. + * @hide */ -public class DummyPolicyTests { - - @Presubmit - @Test - public void preSubmitTest() {} - - @FlakyTest - @Presubmit - @Test - public void flakyPreSubmitTest() {} - - @Test - public void postSubmitTest() {} - - @FlakyTest - @Test - public void flakyPostSubmitTest() {} -} +interface IIrisService { +}
\ No newline at end of file diff --git a/core/java/android/hardware/iris/IrisManager.java b/core/java/android/hardware/iris/IrisManager.java new file mode 100644 index 000000000000..281ac4769a8d --- /dev/null +++ b/core/java/android/hardware/iris/IrisManager.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package android.hardware.iris; + +import android.annotation.SystemService; +import android.content.Context; + +/** + * A class that coordinates access to the iris authentication hardware. + * @hide + */ +@SystemService(Context.IRIS_SERVICE) +public class IrisManager { + + /** + * @hide + */ + public IrisManager(Context context, IIrisService service) { + } +} diff --git a/core/java/android/hardware/location/ContextHubBroadcastReceiver.java b/core/java/android/hardware/location/ContextHubBroadcastReceiver.java deleted file mode 100644 index e0cc8b7de634..000000000000 --- a/core/java/android/hardware/location/ContextHubBroadcastReceiver.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.hardware.location; - -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; - -/** - * A BroadcastReceiver that can be used with the Context Hub Service notifications. - * - * @hide - */ -public class ContextHubBroadcastReceiver extends BroadcastReceiver { - // The context at which this receiver operates in - private Context mContext; - - // The handler to post callbacks to when receiving Context Hub Service intents - private Handler mHandler; - - // The callback to be invoked when receiving Context Hub Service intents - private ContextHubClientCallback mCallback; - - // The string to use as the broadcast action for this receiver - private String mAction; - - // True when this receiver is registered to receive Intents, false otherwise - private boolean mRegistered = false; - - public ContextHubBroadcastReceiver(Context context, Handler handler, - ContextHubClientCallback callback, String tag) { - mContext = context; - mHandler = handler; - mCallback = callback; - mAction = tag; - } - - /** - * Registers this receiver to receive Intents from the Context Hub Service. This method must - * only be invoked when the receiver is not registered. - * - * @throws IllegalStateException if the receiver is already registered - */ - public void register() throws IllegalStateException { - if (mRegistered) { - throw new IllegalStateException( - "Cannot register ContextHubBroadcastReceiver multiple times"); - } - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(mAction); - mContext.registerReceiver(this, intentFilter, null /* broadcastPermission */, mHandler); - mRegistered = true; - } - - /** - * Unregisters this receiver. This method must only be invoked if {@link #register()} is - * previously invoked. - * - * @throws IllegalStateException if the receiver is not yet registered - */ - public void unregister() throws IllegalStateException { - if (!mRegistered) { - throw new IllegalStateException( - "Cannot unregister ContextHubBroadcastReceiver when not registered"); - } - mContext.unregisterReceiver(this); - mRegistered = false; - } - - /** - * Creates a new PendingIntent associated with this receiver. - * - * @param flags the flags {@link PendingIntent.Flags} to use for the PendingIntent - * - * @return a PendingIntent to receive notifications for this receiver - */ - public PendingIntent getPendingIntent(@PendingIntent.Flags int flags) { - return PendingIntent.getBroadcast( - mContext, 0 /* requestCode */, new Intent(mAction), flags); - } - - @Override - public void onReceive(Context context, Intent intent) { - // TODO: Implement this - } -} diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java index 56da719e7869..9f11246d7372 100644 --- a/core/java/android/hardware/location/ContextHubClient.java +++ b/core/java/android/hardware/location/ContextHubClient.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.PendingIntent; +import android.content.Intent; import android.os.RemoteException; import com.android.internal.util.Preconditions; @@ -113,7 +114,8 @@ public class ContextHubClient implements Closeable { * describes the Context Hub the intent event was for. The intent will also have an extra * {@link ContextHubManager.EXTRA_EVENT_TYPE} of type {@link ContextHubManager.Event}, which * will contain the type of the event. See {@link ContextHubManager.Event} for description of - * each event type, along with event-specific extra fields. + * each event type, along with event-specific extra fields. A client can use + * {@link ContextHubIntentEvent.fromIntent(Intent)} to parse the Intent generated by the event. * * When the intent is received, this client can be recreated through * {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo, @@ -126,10 +128,6 @@ public class ContextHubClient implements Closeable { * continued to be maintained at the Context Hub Service until * {@link #unregisterIntent(PendingIntent)} is called for registered intents. * - * See {@link ContextHubBroadcastReceiver} for a helper class to generate the - * {@link PendingIntent} through a {@link BroadcastReceiver}, and maps an {@link Intent} to a - * {@link ContextHubClientCallback}. - * * @param pendingIntent the PendingIntent to register for this client * @param nanoAppId the unique ID of the nanoapp to receive events for * @return true on success, false otherwise diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index b0b77f31c24d..9acefa567ed6 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -808,7 +808,7 @@ public final class ContextHubManager { * * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent * was not associated with a client - * @throws IllegalStateException if there were too many registered clients at the service + * @throws IllegalStateException if the client is already registered to a valid callback * @throws NullPointerException if pendingIntent, hubInfo, callback, or executor is null * * @hide @@ -818,8 +818,24 @@ public final class ContextHubManager { @NonNull PendingIntent pendingIntent, @NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback, @NonNull @CallbackExecutor Executor executor) { - // TODO: Implement this - throw new UnsupportedOperationException("Not implemented yet"); + Preconditions.checkNotNull(pendingIntent, "PendingIntent cannot be null"); + Preconditions.checkNotNull(callback, "Callback cannot be null"); + Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null"); + Preconditions.checkNotNull(executor, "Executor cannot be null"); + + ContextHubClient client = new ContextHubClient(hubInfo); + IContextHubClientCallback clientInterface = createClientCallback( + client, callback, executor); + + IContextHubClient clientProxy; + try { + clientProxy = mService.bindClient(pendingIntent, clientInterface, hubInfo.getId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + client.setClientProxy(clientProxy); + return client; } /** @@ -833,7 +849,7 @@ public final class ContextHubManager { * * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent * was not associated with a client - * @throws IllegalStateException if there were too many registered clients at the service + * @throws IllegalStateException if the client is already registered to a valid callback * @throws NullPointerException if pendingIntent, hubInfo, or callback is null * * @hide diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl index 233e857d8e67..9b0acdf14724 100644 --- a/core/java/android/hardware/location/IContextHubService.aidl +++ b/core/java/android/hardware/location/IContextHubService.aidl @@ -17,6 +17,7 @@ package android.hardware.location; // Declare any non-default types here with import statements +import android.app.PendingIntent; import android.hardware.location.ContextHubInfo; import android.hardware.location.ContextHubMessage; import android.hardware.location.NanoApp; @@ -60,6 +61,11 @@ interface IContextHubService { // Creates a client to send and receive messages IContextHubClient createClient(in IContextHubClientCallback client, int contextHubId); + // Binds an existing client to a new callback interface, provided a previously registered + // PendingIntent + IContextHubClient bindClient( + in PendingIntent pendingIntent, in IContextHubClientCallback client, int contextHubId); + // Returns a list of ContextHub objects of available hubs List<ContextHubInfo> getContextHubs(); diff --git a/core/java/android/net/INetdEventCallback.aidl b/core/java/android/net/INetdEventCallback.aidl index 1e75bf461a70..4b1a08ded9d6 100644 --- a/core/java/android/net/INetdEventCallback.aidl +++ b/core/java/android/net/INetdEventCallback.aidl @@ -28,6 +28,11 @@ oneway interface INetdEventCallback { * Reports a single DNS lookup function call. * This method must not block or perform long-running operations. * + * @param netId the ID of the network the lookup was performed on. + * @param eventType one of the EVENT_* constants in {@link INetdEventListener}. + * @param returnCode the return value of the query, may vary based on {@code eventType}. See + * {@code getaddrinfo()}, {@code gethostbyaddr()} and {@code gethostbyname()} section in + * bionic/libc/include/netdb.h. * @param hostname the name that was looked up. * @param ipAddresses (possibly a subset of) the IP addresses returned. * At most {@link #DNS_REPORTED_IP_ADDRESSES_LIMIT} addresses are logged. @@ -36,8 +41,8 @@ oneway interface INetdEventCallback { * @param timestamp the timestamp at which the query was reported by netd. * @param uid the UID of the application that performed the query. */ - void onDnsEvent(String hostname, in String[] ipAddresses, int ipAddressesCount, long timestamp, - int uid); + void onDnsEvent(int netId, int eventType, int returnCode, String hostname, + in String[] ipAddresses, int ipAddressesCount, long timestamp, int uid); /** * Represents a private DNS validation success or failure. diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 98f356722bf3..4cd000113b7e 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -393,4 +393,19 @@ public final class MacAddress implements Parcelable { } return out; } + + /** + * Checks if this MAC Address matches the provided range. + * + * @param baseAddress MacAddress representing the base address to compare with. + * @param mask MacAddress representing the mask to use during comparison. + * @return true if this MAC Address matches the given range. + * + * @hide + */ + public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) { + Preconditions.checkNotNull(baseAddress); + Preconditions.checkNotNull(mask); + return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr); + } } diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 483b7644f4d6..0c4a0b3e7cad 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -641,6 +641,13 @@ public class Environment { public static String DIRECTORY_DOCUMENTS = "Documents"; /** + * Standard directory in which to place screenshots that have been taken by + * the user. Typically used as a secondary directory under + * {@link #DIRECTORY_PICTURES}. + */ + public static String DIRECTORY_SCREENSHOTS = "Screenshots"; + + /** * List of standard storage directories. * <p> * Each of its values have its own constant: diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index 0c56d4884105..ab048c5d70d6 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -170,10 +170,18 @@ public class GraphicsEnvironment { String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS); - Log.i(TAG, "Debug layer list: " + layers); + Log.i(TAG, "Vulkan debug layer list: " + layers); if (layers != null && !layers.isEmpty()) { setDebugLayers(layers); } + + String layersGLES = + coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES); + + Log.i(TAG, "GLES debug layer list: " + layersGLES); + if (layersGLES != null && !layersGLES.isEmpty()) { + setDebugLayersGLES(layersGLES); + } } } } @@ -424,6 +432,7 @@ public class GraphicsEnvironment { private static native int getCanLoadSystemLibraries(); private static native void setLayerPaths(ClassLoader classLoader, String layerPaths); private static native void setDebugLayers(String layers); + private static native void setDebugLayersGLES(String layers); private static native void setDriverPath(String path); private static native void setAngleInfo(String path, String appPackage, String appPref, boolean devOptIn, FileDescriptor rulesFd, diff --git a/core/java/android/os/IThermalEventListener.aidl b/core/java/android/os/IThermalEventListener.aidl index 9a6de605c597..fc93b5c94330 100644 --- a/core/java/android/os/IThermalEventListener.aidl +++ b/core/java/android/os/IThermalEventListener.aidl @@ -27,6 +27,5 @@ oneway interface IThermalEventListener { * Called when a thermal throttling start/stop event is received. * @param temperature the temperature at which the event was generated. */ - void notifyThrottling( - in boolean isThrottling, in Temperature temperature); + void notifyThrottling(in Temperature temperature); } diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl index e388edaa5441..287a5edde03f 100644 --- a/core/java/android/os/IThermalService.aidl +++ b/core/java/android/os/IThermalService.aidl @@ -19,6 +19,8 @@ package android.os; import android.os.IThermalEventListener; import android.os.Temperature; +import java.util.List; + /** * {@hide} */ @@ -30,22 +32,29 @@ interface IThermalService { */ void registerThermalEventListener(in IThermalEventListener listener); /** + * Register a listener for thermal events on given temperature type. + * @param listener the IThermalEventListener to be notified. + * @param type the temperature type IThermalEventListener to be notified. + * {@hide} + */ + void registerThermalEventListenerWithType(in IThermalEventListener listener, in int type); + /** * Unregister a previously-registered listener for thermal events. * @param listener the IThermalEventListener to no longer be notified. * {@hide} */ void unregisterThermalEventListener(in IThermalEventListener listener); /** - * Send a thermal throttling start/stop notification to all listeners. - * @param temperature the temperature at which the event was generated. + * Get current temperature with its throttling status. + * @return list of android.os.Temperature * {@hide} */ - oneway void notifyThrottling( - in boolean isThrottling, in Temperature temperature); + List<Temperature> getCurrentTemperatures(); /** - * Return whether system performance is currently thermal throttling. - * @return true if thermal throttling is currently in effect + * Get current temperature with its throttling status on given temperature type. + * @param type the temperature type to query. + * @return list of android.os.Temperature * {@hide} */ - boolean isThrottling(); + List<Temperature> getCurrentTemperaturesWithType(in int type); } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index e0b2c7853eba..27c281d56f4d 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -477,6 +477,13 @@ public final class PowerManager { public static final String SHUTDOWN_BATTERY_THERMAL_STATE = "thermal,battery"; /** + * The value to pass as the 'reason' argument to android_reboot() when device temperature + * is too high. + * @hide + */ + public static final String SHUTDOWN_THERMAL_STATE = "thermal"; + + /** * The value to pass as the 'reason' argument to android_reboot() when device is running * critically low on battery. * @hide diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java index bbb8a7b5d5f6..be8f7847f6a8 100644 --- a/core/java/android/os/RemoteCallbackList.java +++ b/core/java/android/os/RemoteCallbackList.java @@ -419,9 +419,11 @@ public class RemoteCallbackList<E extends IInterface> { /** @hide */ public void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size()); - pw.print(prefix); pw.print("killed: "); pw.println(mKilled); - pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount); + synchronized (mCallbacks) { + pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size()); + pw.print(prefix); pw.print("killed: "); pw.println(mKilled); + pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount); + } } private void logExcessiveCallbacks() { diff --git a/core/java/android/os/Temperature.java b/core/java/android/os/Temperature.java index 8767731e748a..37ed52c1fd2c 100644 --- a/core/java/android/os/Temperature.java +++ b/core/java/android/os/Temperature.java @@ -16,6 +16,13 @@ package android.os; +import android.annotation.IntDef; +import android.hardware.thermal.V2_0.TemperatureType; +import android.hardware.thermal.V2_0.ThrottlingSeverity; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Temperature values used by IThermalService. */ @@ -24,24 +31,89 @@ package android.os; * @hide */ public class Temperature implements Parcelable { - /* Temperature value */ + /** Temperature value */ private float mValue; - /* A temperature type from HardwarePropertiesManager */ + /** A temperature type from ThermalHAL */ private int mType; + /** Name of this temperature */ + private String mName; + /** The level of the sensor is currently in throttling */ + private int mStatus; + + /** @hide */ + @IntDef(prefix = { "THROTTLING_" }, value = { + THROTTLING_NONE, + THROTTLING_LIGHT, + THROTTLING_MODERATE, + THROTTLING_SEVERE, + THROTTLING_CRITICAL, + THROTTLING_WARNING, + THROTTLING_SHUTDOWN, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ThrottlingStatus {} + + /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */ + public static final int THROTTLING_NONE = ThrottlingSeverity.NONE; + public static final int THROTTLING_LIGHT = ThrottlingSeverity.LIGHT; + public static final int THROTTLING_MODERATE = ThrottlingSeverity.MODERATE; + public static final int THROTTLING_SEVERE = ThrottlingSeverity.SEVERE; + public static final int THROTTLING_CRITICAL = ThrottlingSeverity.CRITICAL; + public static final int THROTTLING_WARNING = ThrottlingSeverity.WARNING; + public static final int THROTTLING_SHUTDOWN = ThrottlingSeverity.SHUTDOWN; + + /** @hide */ + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_UNKNOWN, + TYPE_CPU, + TYPE_GPU, + TYPE_BATTERY, + TYPE_SKIN, + TYPE_USB_PORT, + TYPE_POWER_AMPLIFIER, + TYPE_BCL_VOLTAGE, + TYPE_BCL_CURRENT, + TYPE_BCL_PERCENTAGE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Type {} + + /* Keep in sync with hardware/interfaces/thermal/2.0/types.hal */ + public static final int TYPE_UNKNOWN = TemperatureType.UNKNOWN; + public static final int TYPE_CPU = TemperatureType.CPU; + public static final int TYPE_GPU = TemperatureType.GPU; + public static final int TYPE_BATTERY = TemperatureType.BATTERY; + public static final int TYPE_SKIN = TemperatureType.SKIN; + public static final int TYPE_USB_PORT = TemperatureType.USB_PORT; + public static final int TYPE_POWER_AMPLIFIER = TemperatureType.POWER_AMPLIFIER; + public static final int TYPE_BCL_VOLTAGE = TemperatureType.BCL_VOLTAGE; + public static final int TYPE_BCL_CURRENT = TemperatureType.BCL_CURRENT; + public static final int TYPE_BCL_PERCENTAGE = TemperatureType.BCL_PERCENTAGE; + + /** + * Verify a valid temperature type. + * + * @return true if a temperature type is valid otherwise false. + */ + public static boolean isValidType(int type) { + return type >= TYPE_UNKNOWN && type <= TYPE_BCL_PERCENTAGE; + } public Temperature() { - this(HardwarePropertiesManager.UNDEFINED_TEMPERATURE, - Integer.MIN_VALUE); + this(Float.NaN, TYPE_UNKNOWN, "", THROTTLING_NONE); } - public Temperature(float value, int type) { + public Temperature(float value, @Type int type, String name, int status) { mValue = value; - mType = type; + mType = isValidType(type) ? type : TYPE_UNKNOWN; + mName = name; + mStatus = status; } /** * Return the temperature value. - * @return a temperature value in floating point. + * + * @return a temperature value in floating point could be NaN. */ public float getValue() { return mValue; @@ -49,18 +121,30 @@ public class Temperature implements Parcelable { /** * Return the temperature type. - * @return a temperature type: - * HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU, etc. + * + * @return a temperature type: TYPE_* */ - public int getType() { + public @Type int getType() { return mType; } - /* - * Parcel read/write code must be kept in sync with - * frameworks/native/services/thermalservice/aidl/android/os/ - * Temperature.cpp + /** + * Return the temperature name. + * + * @return a temperature name as String. + */ + public String getName() { + return mName; + } + + /** + * Return the temperature throttling status. + * + * @return a temperature throttling status: THROTTLING_* */ + public @ThrottlingStatus int getStatus() { + return mStatus; + } private Temperature(Parcel p) { readFromParcel(p); @@ -68,31 +152,36 @@ public class Temperature implements Parcelable { /** * Fill in Temperature members from a Parcel. + * * @param p the parceled Temperature object. */ public void readFromParcel(Parcel p) { mValue = p.readFloat(); mType = p.readInt(); + mName = p.readString(); + mStatus = p.readInt(); } @Override public void writeToParcel(Parcel p, int flags) { p.writeFloat(mValue); p.writeInt(mType); + p.writeString(mName); + p.writeInt(mStatus); } public static final Parcelable.Creator<Temperature> CREATOR = new Parcelable.Creator<Temperature>() { - @Override - public Temperature createFromParcel(Parcel p) { - return new Temperature(p); - } - - @Override - public Temperature[] newArray(int size) { - return new Temperature[size]; - } - }; + @Override + public Temperature createFromParcel(Parcel p) { + return new Temperature(p); + } + + @Override + public Temperature[] newArray(int size) { + return new Temperature[size]; + } + }; @Override public int describeContents() { diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 1a84197974b4..92b316914d82 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -936,6 +936,21 @@ public class UserManager { public static final String DISALLOW_AUTOFILL = "no_autofill"; /** + * Specifies if the contents of a user's screen is not allowed to be captured for artificial + * intelligence purposes. + * + * <p>Device owner and profile owner can set this restriction. When it is set by device owner, + * only the target user will be affected. + * + * <p>The default value is <code>false</code>. + * + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_INTELLIGENCE_CAPTURE = "no_intelligence_capture"; + + /** * Specifies if user switching is blocked on the current user. * * <p> This restriction can only be set by the device owner, it will be applied to all users. diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index 816a730716e1..f521c683896e 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -18,6 +18,7 @@ package android.os.storage; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.IVold; /** * Mount service local interface. @@ -111,4 +112,24 @@ public abstract class StorageManagerInternal { * @return Labels of storage volumes that are visible to the given userId. */ public abstract String[] getVisibleVolumesForUser(int userId); + + /** + * A listener for reset events in the StorageManagerService. + */ + public interface ResetListener { + /** + * A method that should be triggered internally by StorageManagerInternal + * when StorageManagerService reset happens. + * + * @param vold The binder object to vold. + */ + void onReset(IVold vold); + } + + /** + * Add a listener to listen to reset event in StorageManagerService. + * + * @param listener The listener that will be notified on reset events. + */ + public abstract void addResetListener(ResetListener listener); } diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java index a1d1c5736116..76607e9d42d2 100644 --- a/core/java/android/provider/FontsContract.java +++ b/core/java/android/provider/FontsContract.java @@ -15,8 +15,6 @@ */ package android.provider; -import static java.lang.annotation.RetentionPolicy.SOURCE; - import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -25,22 +23,22 @@ import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ProviderInfo; import android.content.pm.Signature; import android.database.Cursor; import android.graphics.Typeface; +import android.graphics.fonts.Font; +import android.graphics.fonts.FontFamily; +import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.net.Uri; -import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; import android.os.HandlerThread; import android.os.ParcelFileDescriptor; import android.os.Process; -import android.os.ResultReceiver; -import android.util.ArraySet; import android.util.Log; import android.util.LruCache; @@ -49,7 +47,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -64,11 +61,11 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; /** * Utility class to deal with Font ContentProviders. @@ -636,7 +633,34 @@ public class FontsContract { if (uriBuffer.isEmpty()) { return null; } - return new Typeface.Builder(fonts, uriBuffer).build(); + + FontFamily.Builder familyBuilder = null; + for (FontInfo fontInfo : fonts) { + final ByteBuffer buffer = uriBuffer.get(fontInfo.getUri()); + if (buffer == null) { + continue; + } + try { + final Font font = new Font.Builder(buffer) + .setWeight(fontInfo.getWeight()) + .setSlant(fontInfo.isItalic() + ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT) + .setTtcIndex(fontInfo.getTtcIndex()) + .setFontVariationSettings(fontInfo.getAxes()) + .build(); + if (familyBuilder == null) { + familyBuilder = new FontFamily.Builder(font); + } else { + familyBuilder.addFont(font); + } + } catch (IOException e) { + continue; + } + } + if (familyBuilder == null) { + return null; + } + return new Typeface.CustomFallbackBuilder(familyBuilder.build()).build(); } /** diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 19b84f19306e..291891effe4e 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -16,6 +16,7 @@ package android.provider; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; @@ -39,12 +40,16 @@ import android.graphics.Point; import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; +import android.os.Environment; import android.os.OperationCanceledException; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.UserHandle; import android.os.storage.StorageManager; import android.os.storage.StorageVolume; import android.os.storage.VolumeInfo; import android.service.media.CameraPrewarmService; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -57,8 +62,8 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -108,6 +113,15 @@ public final class MediaStore { */ public static final String PARAM_DELETE_DATA = "deletedata"; + /** {@hide} */ + public static final String PARAM_PRIMARY = "primary"; + /** {@hide} */ + public static final String PARAM_SECONDARY = "secondary"; + /** {@hide} */ + public static final String PARAM_INCLUDE_PENDING = "includePending"; + /** {@hide} */ + public static final String PARAM_PROGRESS = "progress"; + /** * Activity Action: Launch a music player. * The activity should be able to play, browse, or manipulate music files stored on the device. @@ -452,9 +466,200 @@ public final class MediaStore { public static final String UNKNOWN_STRING = "<unknown>"; /** - * Common fields for most MediaProvider tables + * Update the given {@link Uri} to also include any pending media items from + * calls such as + * {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}. + * By default no pending items are returned. + * + * @see MediaColumns#IS_PENDING + */ + public static @NonNull Uri setIncludePending(@NonNull Uri uri) { + return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_PENDING, "1").build(); + } + + /** + * Create a new pending media item using the given parameters. Pending items + * are expected to have a short lifetime, and owners should either + * {@link PendingSession#publish()} or {@link PendingSession#abandon()} a + * pending item within a few hours after first creating it. + * + * @return token which can be passed to {@link #openPending(Context, Uri)} + * to work with this pending item. + */ + public static @NonNull Uri createPending(@NonNull Context context, + @NonNull PendingParams params) { + final Uri.Builder builder = params.insertUri.buildUpon(); + if (!TextUtils.isEmpty(params.primaryDirectory)) { + builder.appendQueryParameter(PARAM_PRIMARY, params.primaryDirectory); + } + if (!TextUtils.isEmpty(params.secondaryDirectory)) { + builder.appendQueryParameter(PARAM_SECONDARY, params.secondaryDirectory); + } + return context.getContentResolver().insert(builder.build(), params.insertValues); + } + + /** + * Open a pending media item to make progress on it. You can open a pending + * item multiple times before finally calling either + * {@link PendingSession#publish()} or {@link PendingSession#abandon()}. + * + * @param uri token which was previously returned from + * {@link #createPending(Context, PendingParams)}. + */ + public static @NonNull PendingSession openPending(@NonNull Context context, @NonNull Uri uri) { + return new PendingSession(context, uri); + } + + /** + * Parameters that describe a pending media item. */ + public static class PendingParams { + /** {@hide} */ + public final Uri insertUri; + /** {@hide} */ + public final ContentValues insertValues; + /** {@hide} */ + public String primaryDirectory; + /** {@hide} */ + public String secondaryDirectory; + + /** + * Create parameters that describe a pending media item. + * + * @param insertUri the {@code content://} Uri where this pending item + * should be inserted when finally published. For example, to + * publish an image, use + * {@link MediaStore.Images.Media#getContentUri(String)}. + */ + public PendingParams(@NonNull Uri insertUri, @NonNull String displayName, + @NonNull String mimeType) { + this.insertUri = Objects.requireNonNull(insertUri); + final long now = System.currentTimeMillis() / 1000; + this.insertValues = new ContentValues(); + this.insertValues.put(MediaColumns.DISPLAY_NAME, Objects.requireNonNull(displayName)); + this.insertValues.put(MediaColumns.MIME_TYPE, Objects.requireNonNull(mimeType)); + this.insertValues.put(MediaColumns.DATE_ADDED, now); + this.insertValues.put(MediaColumns.DATE_MODIFIED, now); + this.insertValues.put(MediaColumns.IS_PENDING, 1); + } + + /** + * Optionally set the primary directory under which this pending item + * should be persisted. Only specific well-defined directories from + * {@link Environment} are allowed based on the media type being + * inserted. + * <p> + * For example, when creating pending {@link MediaStore.Images.Media} + * items, only {@link Environment#DIRECTORY_PICTURES} or + * {@link Environment#DIRECTORY_DCIM} are allowed. + * <p> + * You may leave this value undefined to store the media in a default + * location. For example, when this value is left undefined, pending + * {@link MediaStore.Audio.Media} items are stored under + * {@link Environment#DIRECTORY_MUSIC}. + */ + public void setPrimaryDirectory(@Nullable String primaryDirectory) { + this.primaryDirectory = primaryDirectory; + } + + /** + * Optionally set the secondary directory under which this pending item + * should be persisted. Any valid directory name is allowed. + * <p> + * You may leave this value undefined to store the media as a direct + * descendant of the {@link #setPrimaryDirectory(String)} location. + */ + public void setSecondaryDirectory(@Nullable String secondaryDirectory) { + this.secondaryDirectory = secondaryDirectory; + } + } + + /** + * Session actively working on a pending media item. Pending items are + * expected to have a short lifetime, and owners should either + * {@link PendingSession#publish()} or {@link PendingSession#abandon()} a + * pending item within a few hours after first creating it. + */ + public static class PendingSession implements AutoCloseable { + /** {@hide} */ + private final Context mContext; + /** {@hide} */ + private final Uri mUri; + + /** {@hide} */ + public PendingSession(Context context, Uri uri) { + mContext = Objects.requireNonNull(context); + mUri = Objects.requireNonNull(uri); + } + + /** + * Open the underlying file representing this media item. When a media + * item is successfully completed, you should + * {@link ParcelFileDescriptor#close()} and then {@link #publish()} it. + * + * @see #notifyProgress(int) + */ + public @NonNull ParcelFileDescriptor open() throws FileNotFoundException { + return mContext.getContentResolver().openFileDescriptor(mUri, "rw"); + } + + /** + * Open the underlying file representing this media item. When a media + * item is successfully completed, you should + * {@link OutputStream#close()} and then {@link #publish()} it. + * + * @see #notifyProgress(int) + */ + public @NonNull OutputStream openOutputStream() throws FileNotFoundException { + return mContext.getContentResolver().openOutputStream(mUri); + } + + /** + * Notify of current progress on this pending media item. Gallery + * applications may choose to surface progress information of this + * pending item. + * + * @param progress a percentage between 0 and 100. + */ + public void notifyProgress(@IntRange(from = 0, to = 100) int progress) { + final Uri withProgress = mUri.buildUpon() + .appendQueryParameter(PARAM_PROGRESS, Integer.toString(progress)).build(); + mContext.getContentResolver().notifyChange(withProgress, null, 0); + } + + /** + * When this media item is successfully completed, call this method to + * publish and make the final item visible to the user. + * + * @return the final {@code content://} Uri representing the newly + * published media. + */ + public @NonNull Uri publish() { + final ContentValues values = new ContentValues(); + values.put(MediaColumns.IS_PENDING, 0); + mContext.getContentResolver().update(mUri, values, null, null); + return mUri; + } + + /** + * When this media item has failed to be completed, call this method to + * destroy the pending item record and any data related to it. + */ + public void abandon() { + mContext.getContentResolver().delete(mUri, null, null); + } + + @Override + public void close() { + // No resources to close, but at least we can inform people that no + // progress is being actively made. + notifyProgress(-1); + } + } + /** + * Common fields for most MediaProvider tables + */ public interface MediaColumns extends BaseColumns { /** * Path to the file on disk. @@ -552,6 +757,17 @@ public final class MediaStore { public static final String IS_DRM = "is_drm"; /** + * Flag indicating if a media item is pending, and still being inserted + * by its owner. + * <p> + * Type: BOOLEAN + * + * @see MediaStore#createPending(Context, PendingParams) + * @see MediaStore#QUERY_ARG_INCLUDE_PENDING + */ + public static final String IS_PENDING = "is_pending"; + + /** * The width of the image/video in pixels. */ public static final String WIDTH = "width"; @@ -562,11 +778,13 @@ public final class MediaStore { public static final String HEIGHT = "height"; /** - * Package that contributed this media. - * @hide + * Package name that contributed this media. The value may be + * {@code NULL} if ownership cannot be reliably determined. + * <p> + * Type: TEXT */ public static final String OWNER_PACKAGE_NAME = "owner_package_name"; - } + } /** * Media provider table containing an index of all files in the media storage, @@ -2378,6 +2596,30 @@ public final class MediaStore { } } + /** {@hide} */ + public static @NonNull File getVolumePath(@NonNull String volumeName) + throws FileNotFoundException { + Objects.requireNonNull(volumeName); + + if (VOLUME_INTERNAL.equals(volumeName)) { + return Environment.getDataDirectory(); + } else if (VOLUME_EXTERNAL.equals(volumeName)) { + return Environment.getExternalStorageDirectory(); + } + + final StorageManager sm = AppGlobals.getInitialApplication() + .getSystemService(StorageManager.class); + for (VolumeInfo vi : sm.getVolumes()) { + if (Objects.equals(vi.getFsUuid(), volumeName)) { + final File path = vi.getPathForUser(UserHandle.myUserId()); + if (path == null) { + throw new FileNotFoundException("Failed to find path for " + vi); + } + } + } + throw new FileNotFoundException("Failed to find path for " + volumeName); + } + /** * Uri for querying the state of the media scanner. */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a4c250ce1f0b..3b5dca9e0208 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -819,6 +819,15 @@ public final class Settings { "android.settings.action.MANAGE_WRITE_SETTINGS"; /** + * Activity Action: Show screen for controlling app usage properties for an app. + * Input: Intent's extra EXTRA_PACKAGE_NAME must specify the application package name. + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_APP_USAGE_SETTINGS = + "android.settings.action.APP_USAGE_SETTINGS"; + + /** * Activity Action: Show screen of details about a particular application. * <p> * In some cases, a matching Activity may not exist, so ensure you @@ -10279,6 +10288,18 @@ public final class Settings { public static final String WIFI_LINK_SPEED_METRICS_ENABLED = "wifi_link_speed_metrics_enabled"; + /** + * Setting to enable the PNO frequency culling optimization. + * Disabled by default, and setting it to 1 will enable it. + * The value is boolean (0 or 1). + * @hide + */ + public static final String WIFI_PNO_FREQUENCY_CULLING_ENABLED = + "wifi_pno_frequency_culling_enabled"; + + private static final Validator WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR = + BOOLEAN_VALIDATOR; + /** * The maximum number of times we will retry a connection to an access * point for which we have failed in acquiring an IP address from DHCP. @@ -11481,6 +11502,24 @@ public final class Settings { public static final String NETWORK_WATCHLIST_ENABLED = "network_watchlist_enabled"; /** + * Whether or not show hidden launcher icon apps feature is enabled. + * Type: int (0 for false, 1 for true) + * Default: 0 + * @hide + */ + public static final String SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED = + "show_hidden_icon_apps_enabled"; + + /** + * Whether or not show new app installed notification is enabled. + * Type: int (0 for false, 1 for true) + * Default: 0 + * @hide + */ + public static final String SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED = + "show_new_app_installed_notification_enabled"; + + /** * Flag to keep background restricted profiles running after exiting. If disabled, * the restricted profile can be put into stopped state as soon as the user leaves it. * Type: int (0 for false, 1 for true) @@ -11695,13 +11734,20 @@ public final class Settings { public static final String ANGLE_ENABLED_APP = "angle_enabled_app"; /** - * Ordered GPU debug layer list + * Ordered GPU debug layer list for Vulkan * i.e. <layer1>:<layer2>:...:<layerN> * @hide */ public static final String GPU_DEBUG_LAYERS = "gpu_debug_layers"; /** + * Ordered GPU debug layer list for GLES + * i.e. <layer1>:<layer2>:...:<layerN> + * @hide + */ + public static final String GPU_DEBUG_LAYERS_GLES = "gpu_debug_layers_gles"; + + /** * Addition app for GPU layer discovery * @hide */ @@ -12465,6 +12511,17 @@ public final class Settings { "privileged_device_identifier_target_q_behavior_enabled"; /** + * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE + * permission check for 3P apps. + * + * STOPSHIP: Remove this once we ship with the new device identifier check enabled. + * + * @hide + */ + public static final String PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED = + "privileged_device_identifier_3p_check_relaxed"; + + /** * If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored * and restoring to lower version of platform API will be skipped. * @@ -12679,6 +12736,8 @@ public final class Settings { VALIDATORS.put(DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(REQUIRE_PASSWORD_TO_DECRYPT, BOOLEAN_VALIDATOR); VALIDATORS.put(DEVICE_DEMO_MODE, BOOLEAN_VALIDATOR); + VALIDATORS.put(WIFI_PNO_FREQUENCY_CULLING_ENABLED, + WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR); } /** diff --git a/core/java/android/service/intelligence/IIntelligenceService.aidl b/core/java/android/service/intelligence/IIntelligenceService.aidl new file mode 100644 index 000000000000..bacad8b44783 --- /dev/null +++ b/core/java/android/service/intelligence/IIntelligenceService.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.intelligence; + +import android.service.intelligence.InteractionSessionId; +import android.service.intelligence.InteractionContext; + +import android.view.intelligence.ContentCaptureEvent; + +import java.util.List; + + +/** + * Interface from the system to an intelligence service. + * + * @hide + */ +oneway interface IIntelligenceService { + + // Called when session is created (context not null) or destroyed (context null) + void onSessionLifecycle(in InteractionContext context, in InteractionSessionId sessionId); + + void onContentCaptureEvents(in InteractionSessionId sessionId, + in List<ContentCaptureEvent> events); +} diff --git a/core/java/android/service/intelligence/IntelligenceService.java b/core/java/android/service/intelligence/IntelligenceService.java new file mode 100644 index 000000000000..a2b60f044657 --- /dev/null +++ b/core/java/android/service/intelligence/IntelligenceService.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.intelligence; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.annotation.CallSuper; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.util.Log; +import android.view.intelligence.ContentCaptureEvent; + +import java.util.List; + +/** + * A service used to capture the content of the screen. + * + * <p>The data collected by this service can be analyzed and combined with other sources to provide + * contextual data in other areas of the system such as Autofill. + * + * @hide + */ +@SystemApi +public abstract class IntelligenceService extends Service { + + private static final String TAG = "IntelligenceService"; + + /** + * The {@link Intent} that must be declared as handled by the service. + * To be supported, the service must also require the + * {@link android.Manifest.permission#BIND_INTELLIGENCE_SERVICE} permission so + * that other applications can not abuse it. + */ + public static final String SERVICE_INTERFACE = + "android.service.intelligence.IntelligenceService"; + + private Handler mHandler; + + private final IIntelligenceService mInterface = new IIntelligenceService.Stub() { + + @Override + public void onSessionLifecycle(InteractionContext context, InteractionSessionId sessionId) + throws RemoteException { + if (context != null) { + mHandler.sendMessage( + obtainMessage(IntelligenceService::onCreateInteractionSession, + IntelligenceService.this, context, sessionId)); + } else { + mHandler.sendMessage( + obtainMessage(IntelligenceService::onDestroyInteractionSession, + IntelligenceService.this, sessionId)); + } + } + @Override + public void onContentCaptureEvents(InteractionSessionId sessionId, + List<ContentCaptureEvent> events) { + mHandler.sendMessage( + obtainMessage(IntelligenceService::onContentCaptureEvent, + IntelligenceService.this, sessionId, events)); + + } + }; + + @CallSuper + @Override + public void onCreate() { + super.onCreate(); + mHandler = new Handler(Looper.getMainLooper(), null, true); + } + + /** @hide */ + @Override + public final IBinder onBind(Intent intent) { + if (SERVICE_INTERFACE.equals(intent.getAction())) { + return mInterface.asBinder(); + } + Log.w(TAG, "Tried to bind to wrong intent: " + intent); + return null; + } + + /** + * Creates a new interaction session. + * + * @param context interaction context + * @param sessionId the session's Id + */ + public void onCreateInteractionSession(@NonNull InteractionContext context, + @NonNull InteractionSessionId sessionId) {} + + /** + * Notifies the service of {@link ContentCaptureEvent events} associated with a content capture + * session. + * + * @param sessionId the session's Id + * @param events the events + */ + // TODO(b/111276913): rename to onContentCaptureEvents + public abstract void onContentCaptureEvent(@NonNull InteractionSessionId sessionId, + @NonNull List<ContentCaptureEvent> events); + + /** + * Destroys the interaction session. + * + * @param sessionId the id of the session to destroy + */ + public void onDestroyInteractionSession(@NonNull InteractionSessionId sessionId) {} +} diff --git a/core/java/android/service/intelligence/InteractionContext.aidl b/core/java/android/service/intelligence/InteractionContext.aidl new file mode 100644 index 000000000000..4ce6aa45d4a1 --- /dev/null +++ b/core/java/android/service/intelligence/InteractionContext.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2018, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.intelligence; + +parcelable InteractionContext; diff --git a/core/java/android/service/intelligence/InteractionContext.java b/core/java/android/service/intelligence/InteractionContext.java new file mode 100644 index 000000000000..c1803ad259d5 --- /dev/null +++ b/core/java/android/service/intelligence/InteractionContext.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.service.intelligence; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.app.TaskInfo; +import android.content.ComponentName; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +// TODO(b/111276913): add javadocs / implement Parcelable / implement equals/hashcode/toString +/** @hide */ +@SystemApi +public final class InteractionContext implements Parcelable { + + /** + * Flag used to indicate that the app explicitly disabled content capture for the activity + * (using + * {@link android.view.intelligence.IntelligenceManager#disableContentCapture()}), + * in which case the service will just receive activity-level events. + */ + public static final int FLAG_DISABLED_BY_APP = 0x1; + + /** + * Flag used to indicate that the activity's window is tagged with + * {@link android.view.Display#FLAG_SECURE}, in which case the service will just receive + * activity-level events. + */ + public static final int FLAG_DISABLED_BY_FLAG_SECURE = 0x2; + + /** @hide */ + @IntDef(flag = true, prefix = { "FLAG_" }, value = { + FLAG_DISABLED_BY_APP, + FLAG_DISABLED_BY_FLAG_SECURE + }) + @Retention(RetentionPolicy.SOURCE) + @interface ContextCreationFlags{} + + // TODO(b/111276913): create new object for taskId + componentName / reuse on other places + private final @NonNull ComponentName mComponentName; + private final int mTaskId; + private final int mDisplayId; + private final int mFlags; + + + /** @hide */ + public InteractionContext(@NonNull ComponentName componentName, int taskId, int displayId, + int flags) { + mComponentName = Preconditions.checkNotNull(componentName); + mTaskId = taskId; + mDisplayId = displayId; + mFlags = flags; + } + + /** + * Gets the id of the {@link TaskInfo task} associated with this context. + */ + public int getTaskId() { + return mTaskId; + } + + /** + * Gets the activity associated with this context. + */ + public @NonNull ComponentName getActivityComponent() { + return mComponentName; + } + + /** + * Gets the ID of the display associated with this context, as defined by + * {G android.hardware.display.DisplayManager#getDisplay(int) DisplayManager.getDisplay()}. + */ + public int getDisplayId() { + return mDisplayId; + } + + /** + * Gets the flags associated with this context. + * + * @return any combination of {@link #FLAG_DISABLED_BY_FLAG_SECURE} and + * {@link #FLAG_DISABLED_BY_APP}. + */ + public @ContextCreationFlags int getFlags() { + return mFlags; + } + + /** + * @hide + */ + // TODO(b/111276913): dump to proto as well + public void dump(PrintWriter pw) { + pw.print("comp="); pw.print(mComponentName.flattenToShortString()); + pw.print(", taskId="); pw.print(mTaskId); + pw.print(", displayId="); pw.print(mDisplayId); + if (mFlags > 0) { + pw.print(", flags="); pw.print(mFlags); + } + } + + @Override + public String toString() { + return "Context[act=" + mComponentName.flattenToShortString() + ", taskId=" + mTaskId + + ", displayId=" + mDisplayId + ", flags=" + mFlags + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(mComponentName, flags); + parcel.writeInt(mTaskId); + parcel.writeInt(mDisplayId); + parcel.writeInt(mFlags); + } + + public static final Parcelable.Creator<InteractionContext> CREATOR = + new Parcelable.Creator<InteractionContext>() { + + @Override + public InteractionContext createFromParcel(Parcel parcel) { + final ComponentName componentName = parcel.readParcelable(null); + final int taskId = parcel.readInt(); + final int displayId = parcel.readInt(); + final int flags = parcel.readInt(); + return new InteractionContext(componentName, taskId, displayId, flags); + } + + @Override + public InteractionContext[] newArray(int size) { + return new InteractionContext[size]; + } + }; +} diff --git a/core/java/android/service/intelligence/InteractionSessionId.aidl b/core/java/android/service/intelligence/InteractionSessionId.aidl new file mode 100644 index 000000000000..a5392b684a11 --- /dev/null +++ b/core/java/android/service/intelligence/InteractionSessionId.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2018, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.intelligence; + +parcelable InteractionSessionId; diff --git a/core/java/android/service/intelligence/InteractionSessionId.java b/core/java/android/service/intelligence/InteractionSessionId.java new file mode 100644 index 000000000000..667193b14113 --- /dev/null +++ b/core/java/android/service/intelligence/InteractionSessionId.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.intelligence; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.PrintWriter; +import java.util.UUID; + +// TODO(b/111276913): add javadocs / implement equals/hashcode/string +/** @hide */ +@SystemApi +public final class InteractionSessionId implements Parcelable { + + private final @NonNull String mValue; + + /** + * Creates a new instance. + * + * @hide + */ + public InteractionSessionId() { + this(UUID.randomUUID().toString()); + } + + /** + * Creates a new instance. + * + * @param value The internal value. + * + * @hide + */ + public InteractionSessionId(@NonNull String value) { + mValue = value; + } + + /** + * @hide + */ + public String getValue() { + return mValue; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((mValue == null) ? 0 : mValue.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + final InteractionSessionId other = (InteractionSessionId) obj; + if (mValue == null) { + if (other.mValue != null) return false; + } else if (!mValue.equals(other.mValue)) { + return false; + } + return true; + } + + /** + * {@inheritDoc} + * + * <p><b>NOTE: </b>this method is only useful for debugging purposes and is not guaranteed to + * be stable, hence it should not be used to identify the session. + */ + @Override + public String toString() { + return mValue; + } + + /** @hide */ + // TODO(b/111276913): dump to proto as well + public void dump(PrintWriter pw) { + pw.print(mValue); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mValue); + } + + public static final Parcelable.Creator<InteractionSessionId> CREATOR = + new Parcelable.Creator<InteractionSessionId>() { + + @Override + public InteractionSessionId createFromParcel(Parcel parcel) { + return new InteractionSessionId(parcel.readString()); + } + + @Override + public InteractionSessionId[] newArray(int size) { + return new InteractionSessionId[size]; + } + }; +} diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java index d74a0fe8d2c1..4bd43d05ae61 100644 --- a/core/java/android/util/ArraySet.java +++ b/core/java/android/util/ArraySet.java @@ -16,14 +16,17 @@ package android.util; +import android.annotation.TestApi; +import android.annotation.UnsupportedAppUsage; + import libcore.util.EmptyArray; -import android.annotation.UnsupportedAppUsage; import java.lang.reflect.Array; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; /** * ArraySet is a generic set data structure that is designed to be more memory efficient than a @@ -357,6 +360,22 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { * @return Returns the value stored at the given index. */ public E valueAt(int index) { + if (index >= mSize) { + // The array might be slightly bigger than mSize, in which case, indexing won't fail. + throw new ArrayIndexOutOfBoundsException(index); + } + return valueAtUnchecked(index); + } + + /** + * Returns the value at the given index in the array without checking that the index is within + * bounds. This allows testing values at the end of the internal array, outside of the + * [0, mSize) bounds. + * + * @hide + */ + @TestApi + public E valueAtUnchecked(int index) { return (E) mArray[index]; } @@ -491,26 +510,40 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { return false; } + /** Returns true if the array size should be decreased. */ + private boolean shouldShrink() { + return mHashes.length > (BASE_SIZE * 2) && mSize < mHashes.length / 3; + } + + /** + * Returns the new size the array should have. Is only valid if {@link #shouldShrink} returns + * true. + */ + private int getNewShrunkenSize() { + // We don't allow it to shrink smaller than (BASE_SIZE*2) to avoid flapping between that + // and BASE_SIZE. + return mSize > (BASE_SIZE * 2) ? (mSize + (mSize >> 1)) : (BASE_SIZE * 2); + } + /** * Remove the key/value mapping at the given index. * @param index The desired index, must be between 0 and {@link #size()}-1. * @return Returns the value that was stored at this index. */ public E removeAt(int index) { + if (index >= mSize) { + // The array might be slightly bigger than mSize, in which case, indexing won't fail. + throw new ArrayIndexOutOfBoundsException(index); + } final Object old = mArray[index]; if (mSize <= 1) { // Now empty. if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0"); - freeArrays(mHashes, mArray, mSize); - mHashes = EmptyArray.INT; - mArray = EmptyArray.OBJECT; - mSize = 0; + clear(); } else { - if (mHashes.length > (BASE_SIZE * 2) && mSize < mHashes.length / 3) { - // Shrunk enough to reduce size of arrays. We don't allow it to - // shrink smaller than (BASE_SIZE*2) to avoid flapping between - // that and BASE_SIZE. - final int n = mSize > (BASE_SIZE * 2) ? (mSize + (mSize >> 1)) : (BASE_SIZE * 2); + if (shouldShrink()) { + // Shrunk enough to reduce size of arrays. + final int n = getNewShrunkenSize(); if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n); @@ -568,6 +601,62 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { } /** + * Removes all values that satisfy the predicate. This implementation avoids using the + * {@link #iterator()}. + * + * @param filter A predicate which returns true for elements to be removed + */ + @Override + public boolean removeIf(Predicate<? super E> filter) { + if (mSize == 0) { + return false; + } + + // Intentionally not using removeAt() to avoid unnecessary intermediate resizing. + + int replaceIndex = 0; + int numRemoved = 0; + for (int i = 0; i < mSize; ++i) { + if (filter.test((E) mArray[i])) { + numRemoved++; + } else { + if (replaceIndex != i) { + mArray[replaceIndex] = mArray[i]; + mHashes[replaceIndex] = mHashes[i]; + } + replaceIndex++; + } + } + + if (numRemoved == 0) { + return false; + } else if (numRemoved == mSize) { + clear(); + return true; + } + + mSize -= numRemoved; + if (shouldShrink()) { + // Shrunk enough to reduce size of arrays. + final int n = getNewShrunkenSize(); + final int[] ohashes = mHashes; + final Object[] oarray = mArray; + allocArrays(n); + + System.arraycopy(ohashes, 0, mHashes, 0, mSize); + System.arraycopy(oarray, 0, mArray, 0, mSize); + } else { + // Null out values at the end of the array. Not doing it in the loop above to avoid + // writing twice to the same index or writing unnecessarily if the array would have been + // discarded anyway. + for (int i = mSize; i < mArray.length; ++i) { + mArray[i] = null; + } + } + return true; + } + + /** * Return the number of items in this array map. */ @Override diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 2d67d79062b9..769dd1b7a0cd 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -36,6 +36,7 @@ public class FeatureFlagUtils { public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX; public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; public static final String EMERGENCY_DIAL_SHORTCUTS = "settings_emergency_dial_shortcuts"; + public static final String SAFETY_HUB = "settings_safety_hub"; public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press"; private static final Map<String, String> DEFAULT_FLAGS; @@ -51,6 +52,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false"); DEFAULT_FLAGS.put(EMERGENCY_DIAL_SHORTCUTS, "true"); DEFAULT_FLAGS.put("settings_network_and_internet_v2", "false"); + DEFAULT_FLAGS.put(SAFETY_HUB, "false"); DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false"); } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index f8bdfe214233..5c07f44cec61 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -111,9 +111,6 @@ interface IWindowManager // caller must call setNewConfiguration() sometime later. Configuration updateOrientationFromAppTokens(in Configuration currentConfig, IBinder freezeThisOneIfNeeded, int displayId); - // Notify window manager of the new display override configuration. Returns an array of stack - // ids that were affected by the update, ActivityManager should resize these stacks. - int[] setNewDisplayOverrideConfiguration(in Configuration overrideConfig, int displayId); void startFreezingScreen(int exitAnim, int enterAnim); void stopFreezingScreen(); diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java index 6fb32e36fb3f..bef9f07afb5f 100644 --- a/core/java/android/view/TouchDelegate.java +++ b/core/java/android/view/TouchDelegate.java @@ -103,13 +103,13 @@ public class TouchDelegate { } /** - * Will forward touch events to the delegate view if the event is within the bounds + * Forward touch events to the delegate view if the event is within the bounds * specified in the constructor. * * @param event The touch event to forward - * @return True if the event was forwarded to the delegate, false otherwise. + * @return True if the event was consumed by the delegate, false otherwise. */ - public boolean onTouchEvent(MotionEvent event) { + public boolean onTouchEvent(@NonNull MotionEvent event) { int x = (int)event.getX(); int y = (int)event.getY(); boolean sendToDelegate = false; @@ -139,18 +139,65 @@ public class TouchDelegate { break; } if (sendToDelegate) { - final View delegateView = mDelegateView; - if (hit) { // Offset event coordinates to be inside the target view - event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2); + event.setLocation(mDelegateView.getWidth() / 2, mDelegateView.getHeight() / 2); } else { // Offset event coordinates to be outside the target view (in case it does // something like tracking pressed state) int slop = mSlop; event.setLocation(-(slop * 2), -(slop * 2)); } - handled = delegateView.dispatchTouchEvent(event); + handled = mDelegateView.dispatchTouchEvent(event); + } + return handled; + } + + /** + * Forward hover events to the delegate view if the event is within the bounds + * specified in the constructor and touch exploration is enabled. + * + * @param event The hover event to forward + * @return True if the event was consumed by the delegate, false otherwise. + * + * @see android.view.accessibility.AccessibilityManager#isTouchExplorationEnabled + */ + public boolean onTouchExplorationHoverEvent(@NonNull MotionEvent event) { + if (mBounds == null) { + return false; + } + + final int x = (int) event.getX(); + final int y = (int) event.getY(); + boolean hit = true; + boolean handled = false; + + final boolean isInbound = mBounds.contains(x, y); + switch (event.getActionMasked()) { + case MotionEvent.ACTION_HOVER_ENTER: + mDelegateTargeted = isInbound; + break; + case MotionEvent.ACTION_HOVER_MOVE: + if (isInbound) { + mDelegateTargeted = true; + } else { + // delegated previously + if (mDelegateTargeted && !mSlopBounds.contains(x, y)) { + hit = false; + } + } + break; + case MotionEvent.ACTION_HOVER_EXIT: + mDelegateTargeted = true; + break; + } + if (mDelegateTargeted) { + if (hit) { + event.setLocation(mDelegateView.getWidth() / 2, mDelegateView.getHeight() / 2); + } else { + mDelegateTargeted = false; + } + handled = mDelegateView.dispatchHoverEvent(event); } return handled; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 1493cd7f2eda..453d7885f4d2 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -9852,12 +9852,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // We weren't called from within a direct call to fitSystemWindows, // call into it as a fallback in case we're in a class that overrides it // and has logic to perform. - if (fitSystemWindows(insets.getSystemWindowInsets())) { + if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { return insets.consumeSystemWindowInsets(); } } else { // We were called from within a direct call to fitSystemWindows. - if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { + if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { return insets.consumeSystemWindowInsets(); } } @@ -9960,7 +9960,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), outLocalInsets); - inoutInsets.set(innerInsets.getSystemWindowInsets()); + inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); return innerInsets.isSystemWindowInsetsConsumed(); } @@ -9979,7 +9979,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, || mAttachInfo == null || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 && !mAttachInfo.mOverscanRequested)) { - outLocalInsets.set(in.getSystemWindowInsets()); + outLocalInsets.set(in.getSystemWindowInsetsAsRect()); return in.consumeSystemWindowInsets().inset(outLocalInsets); } else { // The application wants to take care of fitting system window for @@ -12830,6 +12830,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Returns true if the given point, in local coordinates, is inside the hovered child. + * + * @hide + */ + protected boolean pointInHoveredChild(MotionEvent event) { + return false; + } + + /** * Dispatch a generic motion event to the view under the first pointer. * <p> * Do not call this method directly. @@ -13584,6 +13593,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #onHoverChanged */ public boolean onHoverEvent(MotionEvent event) { + // Explore by touch should dispatch events to children under pointer first if any before + // dispatching to TouchDelegate. For children non-hoverable that will not consume events, + // it should also not delegate when they got the pointer hovered. + if (mTouchDelegate != null && !pointInHoveredChild(event)) { + final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); + if (manager.isEnabled() && manager.isTouchExplorationEnabled() + && mTouchDelegate.onTouchExplorationHoverEvent(event)) { + return true; + } + } + // The root view may receive hover (or touch) events that are outside the bounds of // the window. This code ensures that we only send accessibility events for // hovers that are actually within the bounds of the root view. @@ -13598,7 +13618,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } else { if (action == MotionEvent.ACTION_HOVER_EXIT - || (action == MotionEvent.ACTION_MOVE + || (action == MotionEvent.ACTION_HOVER_MOVE && !pointInView(event.getX(), event.getY()))) { mSendingHoverAccessibilityEvents = false; sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); @@ -14710,7 +14730,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public float getCameraDistance() { final float dpi = mResources.getDisplayMetrics().densityDpi; - return -(mRenderNode.getCameraDistance() * dpi); + return mRenderNode.getCameraDistance() * dpi; } /** @@ -14756,7 +14776,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final float dpi = mResources.getDisplayMetrics().densityDpi; invalidateViewProperty(true, false); - mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); + mRenderNode.setCameraDistance(Math.abs(distance) / dpi); invalidateViewProperty(false, false); invalidateParentIfNeededAndWasQuickRejected(); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 58febb050150..1e91aa87bfb7 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2383,6 +2383,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mFirstHoverTarget != null; } + /** @hide */ + @Override + protected boolean pointInHoveredChild(MotionEvent event) { + if (mFirstHoverTarget != null) { + return isTransformedTouchPointInView(event.getX(), event.getY(), + mFirstHoverTarget.child, null); + } + return false; + } + @Override public void addChildrenForAccessibility(ArrayList<View> outChildren) { if (getAccessibilityNodeProvider() != null) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 48761486d9dc..dd1f6407682f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6877,7 +6877,7 @@ public final class ViewRootImpl implements ViewParent, RenderNode renderNode = view.mRenderNode; info[0]++; if (renderNode != null) { - info[1] += renderNode.getDebugSize(); + info[1] += renderNode.computeApproximateMemoryUsage(); } if (view instanceof ViewGroup) { diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index 8628da374930..4a7e783ffbdb 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -17,8 +17,10 @@ package android.view; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; +import android.graphics.Insets; import android.graphics.Rect; import com.android.internal.util.Preconditions; @@ -43,26 +45,24 @@ import java.util.Objects; */ public final class WindowInsets { - private Rect mSystemWindowInsets; - private Rect mWindowDecorInsets; - private Rect mStableInsets; - private Rect mTempRect; - private boolean mIsRound; - private DisplayCutout mDisplayCutout; + @NonNull private final Insets mSystemWindowInsets; + @NonNull private final Insets mWindowDecorInsets; + @NonNull private final Insets mStableInsets; + @Nullable private Rect mTempRect; + private final boolean mIsRound; + @Nullable private final DisplayCutout mDisplayCutout; /** * In multi-window we force show the navigation bar. Because we don't want that the surface size * changes in this mode, we instead have a flag whether the navigation bar size should always * be consumed, so the app is treated like there is no virtual navigation bar at all. */ - private boolean mAlwaysConsumeNavBar; + private final boolean mAlwaysConsumeNavBar; - private boolean mSystemWindowInsetsConsumed = false; - private boolean mWindowDecorInsetsConsumed = false; - private boolean mStableInsetsConsumed = false; - private boolean mDisplayCutoutConsumed = false; - - private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0); + private final boolean mSystemWindowInsetsConsumed; + private final boolean mWindowDecorInsetsConsumed; + private final boolean mStableInsetsConsumed; + private final boolean mDisplayCutoutConsumed; /** * Since new insets may be added in the future that existing apps couldn't @@ -74,21 +74,27 @@ public final class WindowInsets { public static final WindowInsets CONSUMED; static { - CONSUMED = new WindowInsets(null, null, null, false, false, null); + CONSUMED = new WindowInsets((Insets) null, null, null, false, false, null); } /** @hide */ public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets, boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) { + this(Insets.of(systemWindowInsets), Insets.of(windowDecorInsets), Insets.of(stableInsets), + isRound, alwaysConsumeNavBar, displayCutout); + } + + private WindowInsets(Insets systemWindowInsets, Insets windowDecorInsets, + Insets stableInsets, boolean isRound, boolean alwaysConsumeNavBar, + DisplayCutout displayCutout) { mSystemWindowInsetsConsumed = systemWindowInsets == null; - mSystemWindowInsets = mSystemWindowInsetsConsumed - ? EMPTY_RECT : new Rect(systemWindowInsets); + mSystemWindowInsets = mSystemWindowInsetsConsumed ? Insets.NONE : systemWindowInsets; mWindowDecorInsetsConsumed = windowDecorInsets == null; - mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : new Rect(windowDecorInsets); + mWindowDecorInsets = mWindowDecorInsetsConsumed ? Insets.NONE : windowDecorInsets; mStableInsetsConsumed = stableInsets == null; - mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : new Rect(stableInsets); + mStableInsets = mStableInsetsConsumed ? Insets.NONE : stableInsets; mIsRound = isRound; mAlwaysConsumeNavBar = alwaysConsumeNavBar; @@ -104,16 +110,21 @@ public final class WindowInsets { * @param src Source to copy insets from */ public WindowInsets(WindowInsets src) { - mSystemWindowInsets = src.mSystemWindowInsets; - mWindowDecorInsets = src.mWindowDecorInsets; - mStableInsets = src.mStableInsets; - mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed; - mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed; - mStableInsetsConsumed = src.mStableInsetsConsumed; - mIsRound = src.mIsRound; - mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar; - mDisplayCutout = src.mDisplayCutout; - mDisplayCutoutConsumed = src.mDisplayCutoutConsumed; + this(src.mSystemWindowInsetsConsumed ? null : src.mSystemWindowInsets, + src.mWindowDecorInsetsConsumed ? null : src.mWindowDecorInsets, + src.mStableInsetsConsumed ? null : src.mStableInsets, + src.mIsRound, src.mAlwaysConsumeNavBar, + displayCutoutCopyConstructorArgument(src)); + } + + private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) { + if (w.mDisplayCutoutConsumed) { + return null; + } else if (w.mDisplayCutout == null) { + return DisplayCutout.NO_CUTOUT; + } else { + return w.mDisplayCutout; + } } /** @hide */ @@ -126,22 +137,35 @@ public final class WindowInsets { * Used to provide a safe copy of the system window insets to pass through * to the existing fitSystemWindows method and other similar internals. * @hide + * + * @deprecated use {@link #getSystemWindowInsets()} instead. */ - @UnsupportedAppUsage - public Rect getSystemWindowInsets() { + @Deprecated + @NonNull + public Rect getSystemWindowInsetsAsRect() { if (mTempRect == null) { mTempRect = new Rect(); } - if (mSystemWindowInsets != null) { - mTempRect.set(mSystemWindowInsets); - } else { - // If there were no system window insets, this is just empty. - mTempRect.setEmpty(); - } + mTempRect.set(mSystemWindowInsets.left, mSystemWindowInsets.top, + mSystemWindowInsets.right, mSystemWindowInsets.bottom); return mTempRect; } /** + * Returns the system window insets in pixels. + * + * <p>The system window inset represents the area of a full-screen window that is + * partially or fully obscured by the status bar, navigation bar, IME or other system windows. + * </p> + * + * @return The system window insets + */ + @NonNull + public Insets getSystemWindowInsets() { + return mSystemWindowInsets; + } + + /** * Returns the left system window inset in pixels. * * <p>The system window inset represents the area of a full-screen window that is @@ -304,11 +328,13 @@ public final class WindowInsets { * * @return A modified copy of this WindowInsets */ + @NonNull public WindowInsets consumeDisplayCutout() { - final WindowInsets result = new WindowInsets(this); - result.mDisplayCutout = null; - result.mDisplayCutoutConsumed = true; - return result; + return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets, + mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, + mStableInsetsConsumed ? null : mStableInsets, + mIsRound, mAlwaysConsumeNavBar, + null /* displayCutout */); } @@ -349,101 +375,95 @@ public final class WindowInsets { * * @return A modified copy of this WindowInsets */ + @NonNull public WindowInsets consumeSystemWindowInsets() { - final WindowInsets result = new WindowInsets(this); - result.mSystemWindowInsets = EMPTY_RECT; - result.mSystemWindowInsetsConsumed = true; - return result; - } - - /** - * Returns a copy of this WindowInsets with selected system window insets fully consumed. - * - * @param left true to consume the left system window inset - * @param top true to consume the top system window inset - * @param right true to consume the right system window inset - * @param bottom true to consume the bottom system window inset - * @return A modified copy of this WindowInsets - * @hide pending API - */ - public WindowInsets consumeSystemWindowInsets(boolean left, boolean top, - boolean right, boolean bottom) { - if (left || top || right || bottom) { - final WindowInsets result = new WindowInsets(this); - result.mSystemWindowInsets = new Rect( - left ? 0 : mSystemWindowInsets.left, - top ? 0 : mSystemWindowInsets.top, - right ? 0 : mSystemWindowInsets.right, - bottom ? 0 : mSystemWindowInsets.bottom); - return result; - } - return this; + return new WindowInsets(null /* systemWindowInsets */, + mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, + mStableInsetsConsumed ? null : mStableInsets, + mIsRound, mAlwaysConsumeNavBar, + displayCutoutCopyConstructorArgument(this)); } + // TODO(b/119190588): replace @code with @link below /** * Returns a copy of this WindowInsets with selected system window insets replaced * with new values. * + * <p>Note: If the system window insets are already consumed, this method will return them + * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to + * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of + * whether they were consumed, and this method returns invalid non-zero consumed insets. + * * @param left New left inset in pixels * @param top New top inset in pixels * @param right New right inset in pixels * @param bottom New bottom inset in pixels * @return A modified copy of this WindowInsets - */ - public WindowInsets replaceSystemWindowInsets(int left, int top, - int right, int bottom) { - final WindowInsets result = new WindowInsets(this); - result.mSystemWindowInsets = new Rect(left, top, right, bottom); - return result; + * @deprecated use {@code Builder#Builder(WindowInsets)} with + * {@link Builder#setSystemWindowInsets(Insets)} instead. + */ + @Deprecated + @NonNull + public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) { + // Compat edge case: what should this do if the insets have already been consumed? + // On platforms prior to Q, the behavior was to override the insets with non-zero values, + // but leave them consumed, which is invalid (consumed insets must be zero). + // The behavior is now keeping them consumed and discarding the new insets. + if (mSystemWindowInsetsConsumed) { + return this; + } + return new Builder(this).setSystemWindowInsets(Insets.of(left, top, right, bottom)).build(); } + // TODO(b/119190588): replace @code with @link below /** * Returns a copy of this WindowInsets with selected system window insets replaced * with new values. * + * <p>Note: If the system window insets are already consumed, this method will return them + * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to + * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of + * whether they were consumed, and this method returns invalid non-zero consumed insets. + * * @param systemWindowInsets New system window insets. Each field is the inset in pixels * for that edge * @return A modified copy of this WindowInsets + * @deprecated use {@code Builder#Builder(WindowInsets)} with + * {@link Builder#setSystemWindowInsets(Insets)} instead. */ + @Deprecated + @NonNull public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) { - final WindowInsets result = new WindowInsets(this); - result.mSystemWindowInsets = new Rect(systemWindowInsets); - return result; + return replaceSystemWindowInsets(systemWindowInsets.left, systemWindowInsets.top, + systemWindowInsets.right, systemWindowInsets.bottom); } /** * @hide */ + @NonNull public WindowInsets consumeWindowDecorInsets() { - final WindowInsets result = new WindowInsets(this); - result.mWindowDecorInsets.set(0, 0, 0, 0); - result.mWindowDecorInsetsConsumed = true; - return result; + return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets, + null /* windowDecorInsets */, + mStableInsetsConsumed ? null : mStableInsets, + mIsRound, mAlwaysConsumeNavBar, + displayCutoutCopyConstructorArgument(this)); } /** - * @hide - */ - public WindowInsets consumeWindowDecorInsets(boolean left, boolean top, - boolean right, boolean bottom) { - if (left || top || right || bottom) { - final WindowInsets result = new WindowInsets(this); - result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left, - top ? 0 : mWindowDecorInsets.top, - right ? 0 : mWindowDecorInsets.right, - bottom ? 0 : mWindowDecorInsets.bottom); - return result; - } - return this; - } - - /** - * @hide + * Returns the stable insets in pixels. + * + * <p>The stable inset represents the area of a full-screen window that <b>may</b> be + * partially or fully obscured by the system UI elements. This value does not change + * based on the visibility state of those elements; for example, if the status bar is + * normally shown, but temporarily hidden, the stable inset will still provide the inset + * associated with the status bar being shown.</p> + * + * @return The stable insets */ - public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) { - final WindowInsets result = new WindowInsets(this); - result.mWindowDecorInsets = new Rect(left, top, right, bottom); - return result; + @NonNull + public Insets getStableInsets() { + return mStableInsets; } /** @@ -527,11 +547,13 @@ public final class WindowInsets { * * @return A modified copy of this WindowInsets */ + @NonNull public WindowInsets consumeStableInsets() { - final WindowInsets result = new WindowInsets(this); - result.mStableInsets = EMPTY_RECT; - result.mStableInsetsConsumed = true; - return result; + return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets, + mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, + null /* stableInsets */, + mIsRound, mAlwaysConsumeNavBar, + displayCutoutCopyConstructorArgument(this)); } /** @@ -555,8 +577,11 @@ public final class WindowInsets { * Returns a copy of this instance inset in the given directions. * * @see #inset(int, int, int, int) + * @deprecated use {@link #inset(Insets)} * @hide */ + @Deprecated + @NonNull public WindowInsets inset(Rect r) { return inset(r.left, r.top, r.right, r.bottom); } @@ -564,6 +589,17 @@ public final class WindowInsets { /** * Returns a copy of this instance inset in the given directions. * + * @see #inset(int, int, int, int) + * @hide + */ + @NonNull + public WindowInsets inset(Insets insets) { + return inset(insets.left, insets.top, insets.right, insets.bottom); + } + + /** + * Returns a copy of this instance inset in the given directions. + * * This is intended for dispatching insets to areas of the window that are smaller than the * current area. * @@ -579,35 +615,27 @@ public final class WindowInsets { * @param bottom the amount of insets to remove from the bottom. Must be non-negative. * * @return the inset insets - * - * @hide pending API */ - @UnsupportedAppUsage + @NonNull public WindowInsets inset(int left, int top, int right, int bottom) { Preconditions.checkArgumentNonnegative(left); Preconditions.checkArgumentNonnegative(top); Preconditions.checkArgumentNonnegative(right); Preconditions.checkArgumentNonnegative(bottom); - WindowInsets result = new WindowInsets(this); - if (!result.mSystemWindowInsetsConsumed) { - result.mSystemWindowInsets = - insetInsets(result.mSystemWindowInsets, left, top, right, bottom); - } - if (!result.mWindowDecorInsetsConsumed) { - result.mWindowDecorInsets = - insetInsets(result.mWindowDecorInsets, left, top, right, bottom); - } - if (!result.mStableInsetsConsumed) { - result.mStableInsets = insetInsets(result.mStableInsets, left, top, right, bottom); - } - if (mDisplayCutout != null) { - result.mDisplayCutout = result.mDisplayCutout.inset(left, top, right, bottom); - if (result.mDisplayCutout.isEmpty()) { - result.mDisplayCutout = null; - } - } - return result; + return new WindowInsets( + mSystemWindowInsetsConsumed ? null : + insetInsets(mSystemWindowInsets, left, top, right, bottom), + mWindowDecorInsetsConsumed ? null : + insetInsets(mWindowDecorInsets, left, top, right, bottom), + mStableInsetsConsumed ? null : + insetInsets(mStableInsets, left, top, right, bottom), + mIsRound, mAlwaysConsumeNavBar, + mDisplayCutoutConsumed + ? null : + mDisplayCutout == null + ? DisplayCutout.NO_CUTOUT + : mDisplayCutout.inset(left, top, right, bottom)); } @Override @@ -634,7 +662,7 @@ public final class WindowInsets { mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed); } - private static Rect insetInsets(Rect insets, int left, int top, int right, int bottom) { + private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) { int newLeft = Math.max(0, insets.left - left); int newTop = Math.max(0, insets.top - top); int newRight = Math.max(0, insets.right - right); @@ -642,7 +670,7 @@ public final class WindowInsets { if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) { return insets; } - return new Rect(newLeft, newTop, newRight, newBottom); + return Insets.of(newLeft, newTop, newRight, newBottom); } /** @@ -651,4 +679,122 @@ public final class WindowInsets { boolean isSystemWindowInsetsConsumed() { return mSystemWindowInsetsConsumed; } + + /** + * Builder for WindowInsets. + */ + public static class Builder { + + private Insets mSystemWindowInsets; + private Insets mStableInsets; + private DisplayCutout mDisplayCutout; + + private Insets mWindowDecorInsets; + private boolean mIsRound; + private boolean mAlwaysConsumeNavBar; + + /** + * Creates a builder where all insets are initially consumed. + */ + public Builder() { + } + + /** + * Creates a builder where all insets are initialized from {@link WindowInsets}. + * + * @param insets the instance to initialize from. + */ + public Builder(WindowInsets insets) { + mSystemWindowInsets = insets.mSystemWindowInsetsConsumed ? null + : insets.mSystemWindowInsets; + mStableInsets = insets.mStableInsetsConsumed ? null : insets.mStableInsets; + mDisplayCutout = displayCutoutCopyConstructorArgument(insets); + mWindowDecorInsets = insets.mWindowDecorInsetsConsumed ? null + : insets.mWindowDecorInsets; + mIsRound = insets.mIsRound; + mAlwaysConsumeNavBar = insets.mAlwaysConsumeNavBar; + } + + /** + * Sets system window insets in pixels. + * + * <p>The system window inset represents the area of a full-screen window that is + * partially or fully obscured by the status bar, navigation bar, IME or other system + * windows.</p> + * + * @see #getSystemWindowInsets() + * @return itself + */ + @NonNull + public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) { + Preconditions.checkNotNull(systemWindowInsets); + mSystemWindowInsets = systemWindowInsets; + return this; + } + + /** + * Sets the stable insets in pixels. + * + * <p>The stable inset represents the area of a full-screen window that <b>may</b> be + * partially or fully obscured by the system UI elements. This value does not change + * based on the visibility state of those elements; for example, if the status bar is + * normally shown, but temporarily hidden, the stable inset will still provide the inset + * associated with the status bar being shown.</p> + * + * @see #getStableInsets() + * @return itself + */ + @NonNull + public Builder setStableInsets(@NonNull Insets stableInsets) { + Preconditions.checkNotNull(stableInsets); + mStableInsets = stableInsets; + return this; + } + + /** + * Sets the display cutout. + * + * @see #getDisplayCutout() + * @param displayCutout the display cutout or null if there is none + * @return itself + */ + @NonNull + public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) { + mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT; + return this; + } + + /** @hide */ + @NonNull + public Builder setWindowDecorInsets(@NonNull Insets windowDecorInsets) { + Preconditions.checkNotNull(windowDecorInsets); + mWindowDecorInsets = windowDecorInsets; + return this; + } + + /** @hide */ + @NonNull + public Builder setRound(boolean round) { + mIsRound = round; + return this; + } + + /** @hide */ + @NonNull + public Builder setAlwaysConsumeNavBar(boolean alwaysConsumeNavBar) { + mAlwaysConsumeNavBar = alwaysConsumeNavBar; + return this; + } + + /** + * Builds a {@link WindowInsets} instance. + * + * @return the {@link WindowInsets} instance. + */ + @NonNull + public WindowInsets build() { + return new WindowInsets(mSystemWindowInsets, mWindowDecorInsets, mStableInsets, + mIsRound, mAlwaysConsumeNavBar, mDisplayCutout); + } + } } diff --git a/core/java/android/view/inspector/ChildTraverser.java b/core/java/android/view/inspector/ChildTraverser.java new file mode 100644 index 000000000000..b775de503d98 --- /dev/null +++ b/core/java/android/view/inspector/ChildTraverser.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.inspector; + +import android.annotation.NonNull; + +/** + * Interface for visiting all the child nodes of an inspectable object. + * + * Inspectable objects may return a collection of children as an array, an {@link Iterable} or an + * {@link java.util.Iterator}. This provides a unified API for traversing across all the children + * of an inspectable node. + * + * This interface is consumed by {@link InspectionHelper#traverseChildren(Object, ChildTraverser)} + * and may be implemented as a lambda. + * + * @see InspectionHelper#traverseChildren(Object, ChildTraverser) + * @hide + */ +@FunctionalInterface +public interface ChildTraverser { + /** + * Visit one child object of a parent inspectable object. + * + * The iteration interface will filter null values out before passing them to this method, but + * some child objects may not be inspectable. It is up to the implementor to determine their + * inspectablity and what to do with them. + * + * @param child A child object, guaranteed not to be null. + */ + void traverseChild(@NonNull Object child); +} diff --git a/core/java/android/view/inspector/InspectionHelper.java b/core/java/android/view/inspector/InspectionHelper.java new file mode 100644 index 000000000000..27a97040926c --- /dev/null +++ b/core/java/android/view/inspector/InspectionHelper.java @@ -0,0 +1,145 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.inspector; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +/** + * An interface for companion objects used to inspect views. + * + * Inspection helpers only need to handle the properties, name and traversal of the specific class + * they are defined for, not anything from a parent class. At runtime, the inspector instantiates + * one instance of each inspection helper, and handles visiting them in the correct inheritance + * order for each type it inspects. + * + * Properties are read from the top of the type tree to the bottom, so that classes that override + * a property in their parent class can overwrite it in the reader. In general, properties will + * cleanly inherit through their getters, and the inspector runtime will read the properties of a + * parent class via the parent's inspection helper, and the child helper will only read properties + * added or changed since the parent was defined. + * + * Only one child traversal is considered for each class. If a descendant class defines a + * different child traversal than its parent, only the bottom traversal is used. If a class does + * not define its own child traversal, but one of its ancestors does, the bottom-most ancestor's + * traversal will be used. + * + * @param <T> The type of inspectable this helper operates on + * @hide + */ +public interface InspectionHelper<T> { + /** + * Map the string names of the properties this helper knows about to integer IDs. + * + * Each helper is responsible for storing the integer IDs of all its properties. This is the + * only method that is allowed to modify the stored IDs. + * + * Calling {@link #readProperties(T, PropertyReader)} before calling this results in + * undefined behavior. + * + * @param propertyMapper A {@link PropertyMapper} or lambda which maps string names to IDs. + */ + void mapProperties(@NonNull PropertyMapper propertyMapper); + + /** + * Read the values of an instance of this helper's type into a {@link PropertyReader}. + * + * This method needs to return the property IDs stored by + * {@link #mapProperties(PropertyMapper)}. Implementations should track if their properties + * have been mapped and throw a {@link UninitializedPropertyMapException} if this method is + * called before {mapProperties}. + * + * @param inspectable A object of type {@link T} to read the properties of. + * @param propertyReader An object which receives the property IDs and values. + */ + void readProperties(@NonNull T inspectable, @NonNull PropertyReader propertyReader); + + /** + * Query if this inspectable type can potentially have child nodes. + * + * E.g.: any descendant of {@link android.view.ViewGroup} can have child nodes, but a leaf + * view like {@link android.widget.ImageView} may not. + * + * The default implementation always returns false. If an implementing class overrides this, it + * should also define {@link #traverseChildren(T, ChildTraverser)}. + * + * @return True if this inspectable type can potentially have child nodes, false otherwise. + */ + default boolean hasChildTraversal() { + return false; + } + + /** + * Traverse the child nodes of an instance of this helper's type into a {@link ChildTraverser}. + * + * This provides the ability to traverse over a variety of collection APIs (e.g.: arrays, + * {@link Iterable}, or {@link java.util.Iterator}) in a uniform fashion. The traversal must be + * in the order defined by this helper's type. If the getter returns null, the helper must + * treat it as an empty collection. + * + * The default implementation throws a {@link NoChildTraversalException}. If + * {@link #hasChildTraversal()} returns is overriden to return true, it is expected that the + * implementing class will also override this method and provide a traversal. + * + * @param inspectable An object of type {@link T} to traverse the child nodes of. + * @param childTraverser A {@link ChildTraverser} or lamba to receive the children in order. + * @throws NoChildTraversalException If there is no defined child traversal + */ + default void traverseChildren( + @NonNull T inspectable, + @SuppressWarnings("unused") @NonNull ChildTraverser childTraverser) { + throw new NoChildTraversalException(inspectable.getClass()); + } + + /** + * Get an optional name to display to developers for inspection nodes of this helper's type. + * + * The default implementation returns null, which will cause the runtime to use the class's + * simple name as defined by {@link Class#getSimpleName()} as the node name. + * + * If the type of this helper is inflated from XML, this method should be overridden to return + * the string used as the tag name for this type in XML. + * + * @return A string to use as the node name, or null to use the simple class name fallback. + */ + @Nullable + default String getNodeName() { + return null; + } + + /** + * Thrown by {@link #readProperties(Object, PropertyReader)} if called before + * {@link #mapProperties(PropertyMapper)}. + */ + class UninitializedPropertyMapException extends RuntimeException { + public UninitializedPropertyMapException() { + super("Unable to read properties of an inspectable before mapping their IDs."); + } + } + + /** + * Thrown by {@link #traverseChildren(Object, ChildTraverser)} if no child traversal exists. + */ + class NoChildTraversalException extends RuntimeException { + public NoChildTraversalException(Class cls) { + super(String.format( + "Class %s does not have a defined child traversal. Cannot traverse children.", + cls.getCanonicalName() + )); + } + } +} diff --git a/core/java/android/view/inspector/OWNERS b/core/java/android/view/inspector/OWNERS new file mode 100644 index 000000000000..0473f54e57ca --- /dev/null +++ b/core/java/android/view/inspector/OWNERS @@ -0,0 +1,3 @@ +alanv@google.com +ashleyrose@google.com +aurimas@google.com
\ No newline at end of file diff --git a/core/java/android/view/inspector/PropertyMapper.java b/core/java/android/view/inspector/PropertyMapper.java new file mode 100644 index 000000000000..35550bd45b30 --- /dev/null +++ b/core/java/android/view/inspector/PropertyMapper.java @@ -0,0 +1,130 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.inspector; + +import android.annotation.NonNull; + +/** + * An interface for mapping the string names of inspectable properties to integer identifiers. + * + * This interface is consumed by {@link InspectionHelper#mapProperties(PropertyMapper)}. + * + * Mapping properties to IDs enables quick comparisons against shadow copies of inspectable + * objects without performing a large number of string comparisons. + * + * @see InspectionHelper#mapProperties(PropertyMapper) + * @hide + */ +public interface PropertyMapper { + /** + * Map a string name to an integer ID for a primitive boolean property. + * + * @param name The name of the property + * @return An integer ID for the property + * @throws PropertyConflictException If the property name is already mapped as another type. + */ + int mapBoolean(@NonNull String name); + + /** + * Map a string name to an integer ID for a primitive byte property. + * + * @param name The name of the property + * @return An integer ID for the property + * @throws PropertyConflictException If the property name is already mapped as another type. + */ + int mapByte(@NonNull String name); + + /** + * Map a string name to an integer ID for a primitive char property. + * + * @param name The name of the property + * @return An integer ID for the property + * @throws PropertyConflictException If the property name is already mapped as another type. + */ + int mapChar(@NonNull String name); + + /** + * Map a string name to an integer ID for a primitive double property. + * + * @param name The name of the property + * @return An integer ID for the property + * @throws PropertyConflictException If the property name is already mapped as another type. + */ + int mapDouble(@NonNull String name); + + /** + * Map a string name to an integer ID for a primitive float property. + * + * @param name The name of the property + * @return An integer ID for the property + * @throws PropertyConflictException If the property name is already mapped as another type. + */ + int mapFloat(@NonNull String name); + + /** + * Map a string name to an integer ID for a primitive int property. + * + * @param name The name of the property + * @return An integer ID for the property + * @throws PropertyConflictException If the property name is already mapped as another type. + */ + int mapInt(@NonNull String name); + + /** + * Map a string name to an integer ID for a primitive long property. + * + * @param name The name of the property + * @return An integer ID for the property + * @throws PropertyConflictException If the property name is already mapped as another type. + */ + int mapLong(@NonNull String name); + + /** + * Map a string name to an integer ID for a primitive short property. + * + * @param name The name of the property + * @return An integer ID for the property + * @throws PropertyConflictException If the property name is already mapped as another type. + */ + int mapShort(@NonNull String name); + + /** + * Map a string name to an integer ID for an object property. + * + * @param name The name of the property + * @return An integer ID for the property + * @throws PropertyConflictException If the property name is already mapped as another type. + */ + int mapObject(@NonNull String name); + + /** + * Thrown from a map method if a property name is already mapped as different type. + */ + class PropertyConflictException extends RuntimeException { + public PropertyConflictException( + @NonNull String name, + @NonNull String newPropertyType, + @NonNull String existingPropertyType) { + super(String.format( + "Attempted to map property \"%s\" as type %s, but it is already mapped as %s.", + name, + newPropertyType, + existingPropertyType + )); + } + } +} diff --git a/core/java/android/view/inspector/PropertyReader.java b/core/java/android/view/inspector/PropertyReader.java new file mode 100644 index 000000000000..df81c102dbad --- /dev/null +++ b/core/java/android/view/inspector/PropertyReader.java @@ -0,0 +1,162 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.inspector; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +/** + * An interface for reading the properties of an inspectable object. + * + * Used as the parameter for {@link InspectionHelper#readProperties(Object, PropertyReader)}. + * It has separate methods for all primitive types to avoid autoboxing overhead if a concrete + * implementation is able to work with primitives. Implementations should be prepared to accept + * {null} as the value of {@link PropertyReader#readObject(int, Object)}. + * + * @see InspectionHelper#readProperties(Object, PropertyReader) + * @hide + */ +public interface PropertyReader { + /** + * Read a primitive boolean property. + * + * @param id Identifier of the property from a {@link PropertyMapper} + * @param value Value of the property + * @throws PropertyTypeMismatchException If the property ID is not mapped as a {boolean} + */ + void readBoolean(int id, boolean value); + + /** + * Read a primitive byte property. + * + * @param id Identifier of the property from a {@link PropertyMapper} + * @param value Value of the property + * @throws PropertyTypeMismatchException If the property ID is not mapped as a {byte} + */ + void readByte(int id, byte value); + + /** + * Read a primitive character property. + * + * @param id Identifier of the property from a {@link PropertyMapper} + * @param value Value of the property + * @throws PropertyTypeMismatchException If the property ID is not mapped as a {char} + */ + void readChar(int id, char value); + + /** + * Read a read a primitive double property. + * + * @param id Identifier of the property from a {@link PropertyMapper} + * @param value Value of the property + * @throws PropertyTypeMismatchException If the property ID is not mapped as a {double} + */ + void readDouble(int id, double value); + + /** + * Read a primitive float property. + * + * @param id Identifier of the property from a {@link PropertyMapper} + * @param value Value of the property + * @throws PropertyTypeMismatchException If the property ID is not mapped as a {float} + */ + void readFloat(int id, float value); + + /** + * Read a primitive integer property. + * + * @param id Identifier of the property from a {@link PropertyMapper} + * @param value Value of the property + * @throws PropertyTypeMismatchException If the property ID is not mapped as an {int} + */ + void readInt(int id, int value); + + /** + * Read a primitive long property. + * + * @param id Identifier of the property from a {@link PropertyMapper} + * @param value Value of the property + * @throws PropertyTypeMismatchException If the property ID is not mapped as a {long} + */ + void readLong(int id, long value); + + /** + * Read a primitive short property. + * + * @param id Identifier of the property from a {@link PropertyMapper} + * @param value Value of the property + * @throws PropertyTypeMismatchException If the property ID is not mapped as a {short} + */ + void readShort(int id, short value); + + /** + * Read any object as a property. + * + * If value is null, the property is marked as empty. + * + * @param id Identifier of the property from a {@link PropertyMapper} + * @param value Value of the property + * @throws PropertyTypeMismatchException If the property ID is not mapped as an object + */ + void readObject(int id, @Nullable Object value); + + /** + * Thrown if a client calls a typed read method for a property of a different type. + */ + class PropertyTypeMismatchException extends RuntimeException { + public PropertyTypeMismatchException( + int id, + @NonNull String expectedPropertyType, + @NonNull String actualPropertyType, + @Nullable String propertyName) { + super(formatMessage(id, expectedPropertyType, actualPropertyType, propertyName)); + } + + public PropertyTypeMismatchException( + int id, + @NonNull String expectedPropertyType, + @NonNull String actualPropertyType) { + super(formatMessage(id, expectedPropertyType, actualPropertyType, null)); + } + + private static @NonNull String formatMessage( + int id, + @NonNull String expectedPropertyType, + @NonNull String actualPropertyType, + @Nullable String propertyName) { + + if (propertyName == null) { + return String.format( + "Attempted to read property with ID 0x%08X as type %s, " + + "but the ID is of type %s.", + id, + expectedPropertyType, + actualPropertyType + ); + } else { + return String.format( + "Attempted to read property \"%s\" with ID 0x%08X as type %s, " + + "but the ID is of type %s.", + propertyName, + id, + expectedPropertyType, + actualPropertyType + ); + } + } + } +} diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.aidl b/core/java/android/view/intelligence/ContentCaptureEvent.aidl new file mode 100644 index 000000000000..c66a6cb0d486 --- /dev/null +++ b/core/java/android/view/intelligence/ContentCaptureEvent.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.intelligence; + +parcelable ContentCaptureEvent; diff --git a/core/java/android/view/intelligence/ContentCaptureEvent.java b/core/java/android/view/intelligence/ContentCaptureEvent.java new file mode 100644 index 000000000000..2530ae3b3124 --- /dev/null +++ b/core/java/android/view/intelligence/ContentCaptureEvent.java @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.view.intelligence; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.autofill.AutofillId; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +// TODO(b/111276913): add javadocs / implement Parcelable / implement +/** @hide */ +@SystemApi +public final class ContentCaptureEvent implements Parcelable { + + /** @hide */ + public static final int TYPE_ACTIVITY_DESTROYED = -2; + /** @hide */ + public static final int TYPE_ACTIVITY_CREATED = -1; + + /** + * Called when the activity is started. + */ + public static final int TYPE_ACTIVITY_STARTED = 1; + + /** + * Called when the activity is resumed. + */ + public static final int TYPE_ACTIVITY_RESUMED = 2; + + /** + * Called when the activity is paused. + */ + public static final int TYPE_ACTIVITY_PAUSED = 3; + + /** + * Called when the activity is stopped. + */ + public static final int TYPE_ACTIVITY_STOPPED = 4; + + /** + * Called when a node has been added to the screen and is visible to the user. + * + * <p>The metadata of the node is available through {@link #getViewNode()}. + */ + public static final int TYPE_VIEW_ADDED = 5; + + /** + * Called when a node has been removed from the screen and is not visible to the user anymore. + * + * <p>The id of the node is available through {@link #getId()}. + */ + public static final int TYPE_VIEW_REMOVED = 6; + + /** + * Called when the text of a node has been changed. + * + * <p>The id of the node is available through {@link #getId()}, and the new text is + * available through {@link #getText()}. + */ + public static final int TYPE_VIEW_TEXT_CHANGED = 7; + + // TODO(b/111276913): add event to indicate when FLAG_SECURE was changed? + + /** @hide */ + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_ACTIVITY_STARTED, + TYPE_ACTIVITY_PAUSED, + TYPE_ACTIVITY_RESUMED, + TYPE_ACTIVITY_STOPPED, + TYPE_VIEW_ADDED, + TYPE_VIEW_REMOVED, + TYPE_VIEW_TEXT_CHANGED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EventType{} + + private final int mType; + private final long mEventTime; + private final int mFlags; + + + /** @hide */ + public ContentCaptureEvent(int type, long eventTime, int flags) { + mType = type; + mEventTime = eventTime; + mFlags = flags; + } + + /** + * Gets the type of the event. + * + * @return one of {@link #TYPE_ACTIVITY_STARTED}, {@link #TYPE_ACTIVITY_RESUMED}, + * {@link #TYPE_ACTIVITY_PAUSED}, {@link #TYPE_ACTIVITY_STOPPED}, + * {@link #TYPE_VIEW_ADDED}, {@link #TYPE_VIEW_REMOVED}, or {@link #TYPE_VIEW_TEXT_CHANGED}. + */ + public @EventType int getType() { + return mType; + } + + /** + * Gets when the event was generated, in ms. + */ + public long getEventTime() { + return mEventTime; + } + + /** + * Gets optional flags associated with the event. + * + * @return either {@code 0} or + * {@link android.view.intelligence.IntelligenceManager#FLAG_USER_INPUT}. + */ + public int getFlags() { + return mFlags; + } + + /** + * Gets the whole metadata of the node associated with the event. + * + * <p>Only set on {@link #TYPE_VIEW_ADDED} events. + */ + @Nullable + public ViewNode getViewNode() { + return null; + } + + /** + * Gets the {@link AutofillId} of the node associated with the event. + * + * <p>Only set on {@link #TYPE_VIEW_REMOVED} and {@link #TYPE_VIEW_TEXT_CHANGED} events. + */ + @Nullable + public AutofillId getId() { + return null; + } + + /** + * Gets the current text of the node associated with the event. + * + * <p>Only set on {@link #TYPE_VIEW_TEXT_CHANGED} events. + */ + @Nullable + public CharSequence getText() { + return null; + } + + @Override + public String toString() { + final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=") + .append(getTypeAsString(mType)).append(", time=").append(mEventTime); + if (mFlags > 0) { + string.append(", flags=").append(mFlags); + } + return string.append(']').toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mType); + parcel.writeLong(mEventTime); + parcel.writeInt(mFlags); + } + + public static final Parcelable.Creator<ContentCaptureEvent> CREATOR = + new Parcelable.Creator<ContentCaptureEvent>() { + + @Override + public ContentCaptureEvent createFromParcel(Parcel parcel) { + final int type = parcel.readInt(); + final long eventTime = parcel.readLong(); + final int flags = parcel.readInt(); + return new ContentCaptureEvent(type, eventTime, flags); + } + + @Override + public ContentCaptureEvent[] newArray(int size) { + return new ContentCaptureEvent[size]; + } + }; + + + /** @hide */ + public static String getTypeAsString(@EventType int type) { + switch (type) { + case TYPE_ACTIVITY_STARTED: + return "ACTIVITY_STARTED"; + case TYPE_ACTIVITY_RESUMED: + return "ACTIVITY_RESUMED"; + case TYPE_ACTIVITY_PAUSED: + return "ACTIVITY_PAUSED"; + case TYPE_ACTIVITY_STOPPED: + return "ACTIVITY_STOPPED"; + case TYPE_VIEW_ADDED: + return "VIEW_ADDED"; + case TYPE_VIEW_REMOVED: + return "VIEW_REMOVED"; + case TYPE_VIEW_TEXT_CHANGED: + return "VIEW_TEXT_CHANGED"; + default: + return "UKNOWN_TYPE: " + type; + } + } +} diff --git a/core/java/android/view/intelligence/IIntelligenceManager.aidl b/core/java/android/view/intelligence/IIntelligenceManager.aidl new file mode 100644 index 000000000000..2f128de1f53d --- /dev/null +++ b/core/java/android/view/intelligence/IIntelligenceManager.aidl @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.intelligence; + +import android.content.ComponentName; +import android.os.IBinder; +import android.service.intelligence.InteractionSessionId; +import android.view.intelligence.ContentCaptureEvent; + +import com.android.internal.os.IResultReceiver; + +import java.util.List; + +/** + * {@hide} + */ +oneway interface IIntelligenceManager { + /** + * Starts a session, sending the "remote" sessionId to the receiver. + */ + void startSession(int userId, IBinder activityToken, in ComponentName componentName, + in InteractionSessionId sessionId, int flags, in IResultReceiver result); + + /** + * Finishes a session. + */ + void finishSession(int userId, in InteractionSessionId sessionId); + + /** + * Sends a batch of events + */ + void sendEvents(int userId, in InteractionSessionId sessionId, + in List<ContentCaptureEvent> events); +} diff --git a/core/java/android/view/intelligence/IntelligenceManager.java b/core/java/android/view/intelligence/IntelligenceManager.java new file mode 100644 index 000000000000..9bf6c2ce6184 --- /dev/null +++ b/core/java/android/view/intelligence/IntelligenceManager.java @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.view.intelligence; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.content.ComponentName; +import android.content.Context; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.SystemClock; +import android.service.intelligence.InteractionSessionId; +import android.util.Log; +import android.view.intelligence.ContentCaptureEvent.EventType; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.IResultReceiver; +import com.android.internal.util.Preconditions; + +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +/** + * TODO(b/111276913): add javadocs / implement + */ +@SystemService(Context.INTELLIGENCE_MANAGER_SERVICE) +public final class IntelligenceManager { + + private static final String TAG = "IntelligenceManager"; + + // TODO(b/111276913): define a way to dynamically set it (for example, using settings?) + private static final boolean VERBOSE = false; + + /** + * Used to indicate that a text change was caused by user input (for example, through IME). + */ + //TODO(b/111276913): link to notifyTextChanged() method once available + public static final int FLAG_USER_INPUT = 0x1; + + + /** + * Initial state, when there is no session. + * + * @hide + */ + public static final int STATE_UNKNOWN = 0; + + /** + * Service's startSession() was called, but server didn't confirm it was created yet. + * + * @hide + */ + public static final int STATE_WAITING_FOR_SERVER = 1; + + /** + * Session is active. + * + * @hide + */ + public static final int STATE_ACTIVE = 2; + + private final Context mContext; + + @Nullable + private final IIntelligenceManager mService; + + private final Object mLock = new Object(); + + @Nullable + @GuardedBy("mLock") + private InteractionSessionId mId; + + @GuardedBy("mLock") + private int mState = STATE_UNKNOWN; + + @GuardedBy("mLock") + private IBinder mApplicationToken; + + // TODO(b/111276913): replace by an interface name implemented by Activity, similar to + // AutofillClient + @GuardedBy("mLock") + private ComponentName mComponentName; + + /** @hide */ + public IntelligenceManager(@NonNull Context context, @Nullable IIntelligenceManager service) { + mContext = Preconditions.checkNotNull(context, "context cannot be null"); + mService = service; + } + + /** @hide */ + public void onActivityCreated(@NonNull IBinder token, @NonNull ComponentName componentName) { + if (!isContentCaptureEnabled()) return; + + synchronized (mLock) { + if (mState != STATE_UNKNOWN) { + Log.w(TAG, "ignoring onActivityStarted(" + token + ") while on state " + + getStateAsStringLocked()); + return; + } + mState = STATE_WAITING_FOR_SERVER; + mId = new InteractionSessionId(); + mApplicationToken = token; + mComponentName = componentName; + + if (VERBOSE) { + Log.v(TAG, "onActivityStarted(): token=" + token + ", act=" + componentName + + ", id=" + mId); + } + final int flags = 0; // TODO(b/111276913): get proper flags + + try { + mService.startSession(mContext.getUserId(), mApplicationToken, componentName, + mId, flags, new IResultReceiver.Stub() { + @Override + public void send(int resultCode, Bundle resultData) + throws RemoteException { + synchronized (mLock) { + if (resultCode > 0) { + mState = STATE_ACTIVE; + } else { + // TODO(b/111276913): handle other cases like disabled by + // service + mState = STATE_UNKNOWN; + } + if (VERBOSE) { + Log.v(TAG, "onActivityStarted() result: code=" + resultCode + + ", id=" + mId + + ", state=" + getStateAsStringLocked()); + } + } + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Used for intermediate events (i.e, other than created and destroyed). + * + * @hide + */ + public void onActivityLifecycleEvent(@EventType int type) { + if (!isContentCaptureEnabled()) return; + + //TODO(b/111276913): should buffer event (and call service on handler thread), instead of + // calling right away + final ContentCaptureEvent event = new ContentCaptureEvent(type, SystemClock.uptimeMillis(), + 0); + final List<ContentCaptureEvent> events = Arrays.asList(event); + + synchronized (mLock) { + //TODO(b/111276913): check session state; for example, how to handle if it's waiting for + // remote id + + if (VERBOSE) { + Log.v(TAG, "onActivityLifecycleEvent() for " + mComponentName.flattenToShortString() + + ": " + ContentCaptureEvent.getTypeAsString(type)); + } + + try { + mService.sendEvents(mContext.getUserId(), mId, events); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** @hide */ + public void onActivityDestroyed() { + if (!isContentCaptureEnabled()) return; + + synchronized (mLock) { + //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote + // id) and send it to the cache of batched commands + + if (VERBOSE) { + Log.v(TAG, "onActivityDestroyed(): state=" + getStateAsStringLocked() + + ", mId=" + mId); + } + + try { + mService.finishSession(mContext.getUserId(), mId); + mState = STATE_UNKNOWN; + mId = null; + mApplicationToken = null; + mComponentName = null; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Returns the component name of the {@code android.service.intelligence.IntelligenceService} + * that is enabled for the current user. + */ + @Nullable + public ComponentName getIntelligenceServiceComponentName() { + //TODO(b/111276913): implement + return null; + } + + /** + * Checks whether content capture is enabled for this activity. + */ + public boolean isContentCaptureEnabled() { + //TODO(b/111276913): properly implement by checking if it was explicitly disabled by + // service, or if service is not set + // (and probably renamign to isEnabledLocked() + return mService != null; + } + + /** + * Called by apps to disable content capture. + * + * <p><b>Note: </b> this call is not persisted accross reboots, so apps should typically call + * it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}. + */ + public void disableContentCapture() { + //TODO(b/111276913): implement + } + + /** + * Called by the the service {@link android.service.intelligence.IntelligenceService} + * to define whether content capture should be enabled for activities with such + * {@link android.content.ComponentName}. + * + * <p>Useful to blacklist a particular activity. + * + * @throws UnsupportedOperationException if not called by the UID that owns the + * {@link android.service.intelligence.IntelligenceService} associated with the + * current user. + * + * @hide + */ + @SystemApi + public void setActivityContentCaptureEnabled(@NonNull ComponentName activity, + boolean enabled) { + //TODO(b/111276913): implement + } + + /** + * Called by the the service {@link android.service.intelligence.IntelligenceService} + * to define whether content capture should be enabled for activities of the app with such + * {@code packageName}. + * + * <p>Useful to blacklist any activity from a particular app. + * + * @throws UnsupportedOperationException if not called by the UID that owns the + * {@link android.service.intelligence.IntelligenceService} associated with the + * current user. + * + * @hide + */ + @SystemApi + public void setPackageContentCaptureEnabled(@NonNull String packageName, boolean enabled) { + //TODO(b/111276913): implement + } + + /** + * Gets the activities where content capture was disabled by + * {@link #setActivityContentCaptureEnabled(ComponentName, boolean)}. + * + * @throws UnsupportedOperationException if not called by the UID that owns the + * {@link android.service.intelligence.IntelligenceService} associated with the + * current user. + * + * @hide + */ + @SystemApi + @NonNull + public Set<ComponentName> getContentCaptureDisabledActivities() { + //TODO(b/111276913): implement + return null; + } + + /** + * Gets the apps where content capture was disabled by + * {@link #setPackageContentCaptureEnabled(String, boolean)}. + * + * @throws UnsupportedOperationException if not called by the UID that owns the + * {@link android.service.intelligence.IntelligenceService} associated with the + * current user. + * + * @hide + */ + @SystemApi + @NonNull + public Set<String> getContentCaptureDisabledPackages() { + //TODO(b/111276913): implement + return null; + } + + /** @hide */ + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); pw.println("IntelligenceManager"); + final String prefix2 = prefix + " "; + synchronized (mLock) { + pw.print(prefix2); pw.print("mContext: "); pw.println(mContext); + pw.print(prefix2); pw.print("mService: "); pw.println(mService); + pw.print(prefix2); pw.print("user: "); pw.println(mContext.getUserId()); + pw.print(prefix2); pw.print("enabled: "); pw.println(isContentCaptureEnabled()); + pw.print(prefix2); pw.print("id: "); pw.println(mId); + pw.print(prefix2); pw.print("state: "); pw.print(mState); pw.print(" ("); + pw.print(getStateAsStringLocked()); pw.println(")"); + pw.print(prefix2); pw.print("appToken: "); pw.println(mApplicationToken); + pw.print(prefix2); pw.print("componentName: "); pw.println(mComponentName); + } + } + + @GuardedBy("mLock") + private String getStateAsStringLocked() { + return getStateAsString(mState); + } + + @NonNull + private static String getStateAsString(int state) { + switch (state) { + case STATE_UNKNOWN: + return "UNKNOWN"; + case STATE_WAITING_FOR_SERVER: + return "WAITING_FOR_SERVER"; + case STATE_ACTIVE: + return "ACTIVE"; + default: + return "INVALID:" + state; + } + } +} diff --git a/core/java/android/view/intelligence/ViewNode.java b/core/java/android/view/intelligence/ViewNode.java new file mode 100644 index 000000000000..357ecf599f7a --- /dev/null +++ b/core/java/android/view/intelligence/ViewNode.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.view.intelligence; + +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.assist.AssistStructure; +import android.view.autofill.AutofillId; + +//TODO(b/111276913): add javadocs / implement Parcelable / implement +//TODO(b/111276913): for now it's extending ViewNode directly as it needs most of its properties, +// but it might be better to create a common, abstract android.view.ViewNode class that both extend +// instead +/** @hide */ +@SystemApi +public final class ViewNode extends AssistStructure.ViewNode { + + /** @hide */ + public ViewNode() { + } + + /** + * Returns the {@link AutofillId} of this view's parent, if the parent is also part of the + * screen observation tree. + */ + @Nullable + public AutofillId getParentAutofillId() { + //TODO(b/111276913): implement + return null; + } +} diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index feef853c9b19..f96f08885f9f 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -48,6 +48,7 @@ import android.graphics.RectF; import android.graphics.RenderNode; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; import android.os.LocaleList; import android.os.Parcel; @@ -310,12 +311,12 @@ public class Editor { Drawable mDrawableForCursor = null; - @UnsupportedAppUsage - private Drawable mSelectHandleLeft; - @UnsupportedAppUsage - private Drawable mSelectHandleRight; - @UnsupportedAppUsage - private Drawable mSelectHandleCenter; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + Drawable mSelectHandleLeft; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + Drawable mSelectHandleRight; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + Drawable mSelectHandleCenter; // Global listener that detects changes in the global position of the TextView private PositionListener mPositionListener; @@ -3927,7 +3928,6 @@ public class Editor { SelectionModifierCursorController selectionController = getSelectionController(); if (selectionController.mStartHandle == null) { // As these are for initializing selectionController, hide() must be called. - selectionController.initDrawables(); selectionController.initHandles(); selectionController.hide(); } @@ -4495,13 +4495,11 @@ public class Editor { mContainer.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); mContainer.setContentView(this); - mDrawableLtr = drawableLtr; - mDrawableRtl = drawableRtl; + setDrawables(drawableLtr, drawableRtl); + mMinSize = mTextView.getContext().getResources().getDimensionPixelSize( com.android.internal.R.dimen.text_handle_min_size); - updateDrawable(); - final int handleHeight = getPreferredHeight(); mTouchOffsetY = -0.3f * handleHeight; mIdealVerticalOffset = 0.7f * handleHeight; @@ -4511,9 +4509,14 @@ public class Editor { return mIdealVerticalOffset; } - protected void updateDrawable() { - if (mIsDragging) { - // Don't update drawable during dragging. + void setDrawables(final Drawable drawableLtr, final Drawable drawableRtl) { + mDrawableLtr = drawableLtr; + mDrawableRtl = drawableRtl; + updateDrawable(true /* updateDrawableWhenDragging */); + } + + protected void updateDrawable(final boolean updateDrawableWhenDragging) { + if (!updateDrawableWhenDragging && mIsDragging) { return; } final Layout layout = mTextView.getLayout(); @@ -5030,7 +5033,7 @@ public class Editor { // Fall through. case MotionEvent.ACTION_CANCEL: mIsDragging = false; - updateDrawable(); + updateDrawable(false /* updateDrawableWhenDragging */); break; } return true; @@ -5315,7 +5318,7 @@ public class Editor { Selection.setSelection((Spannable) mTextView.getText(), mTextView.getSelectionStart(), offset); } - updateDrawable(); + updateDrawable(false /* updateDrawableWhenDragging */); if (mTextActionMode != null) { invalidateActionMode(); } @@ -5717,16 +5720,22 @@ public class Editor { } private InsertionHandleView getHandle() { - if (mSelectHandleCenter == null) { - mSelectHandleCenter = mTextView.getContext().getDrawable( - mTextView.mTextSelectHandleRes); - } if (mHandle == null) { + loadHandleDrawables(false /* overwrite */); mHandle = new InsertionHandleView(mSelectHandleCenter); } return mHandle; } + private void reloadHandleDrawable() { + if (mHandle == null) { + // No need to reload, the potentially new drawable will + // be used when the handle is created. + return; + } + mHandle.setDrawables(mSelectHandleCenter, mSelectHandleCenter); + } + @Override public void onDetached() { final ViewTreeObserver observer = mTextView.getViewTreeObserver(); @@ -5790,21 +5799,10 @@ public class Editor { if (mTextView.isInBatchEditMode()) { return; } - initDrawables(); + loadHandleDrawables(false /* overwrite */); initHandles(); } - private void initDrawables() { - if (mSelectHandleLeft == null) { - mSelectHandleLeft = mTextView.getContext().getDrawable( - mTextView.mTextSelectHandleLeftRes); - } - if (mSelectHandleRight == null) { - mSelectHandleRight = mTextView.getContext().getDrawable( - mTextView.mTextSelectHandleRightRes); - } - } - private void initHandles() { // Lazy object creation has to be done before updatePosition() is called. if (mStartHandle == null) { @@ -5824,6 +5822,16 @@ public class Editor { hideInsertionPointCursorController(); } + private void reloadHandleDrawables() { + if (mStartHandle == null) { + // No need to reload, the potentially new drawables will + // be used when the handles are created. + return; + } + mStartHandle.setDrawables(mSelectHandleLeft, mSelectHandleRight); + mEndHandle.setDrawables(mSelectHandleRight, mSelectHandleLeft); + } + public void hide() { if (mStartHandle != null) mStartHandle.hide(); if (mEndHandle != null) mEndHandle.hide(); @@ -6184,6 +6192,32 @@ public class Editor { } } + /** + * Loads the insertion and selection handle Drawables from TextView. If the handle + * drawables are already loaded, do not overwrite them unless the method parameter + * is set to true. This logic is required to avoid overwriting Drawables assigned + * to mSelectHandle[Center/Left/Right] by developers using reflection, unless they + * explicitly call the setters in TextView. + * + * @param overwrite whether to overwrite already existing nonnull Drawables + */ + void loadHandleDrawables(final boolean overwrite) { + if (mSelectHandleCenter == null || overwrite) { + mSelectHandleCenter = mTextView.getTextSelectHandle(); + if (hasInsertionController()) { + getInsertionController().reloadHandleDrawable(); + } + } + + if (mSelectHandleLeft == null || mSelectHandleRight == null || overwrite) { + mSelectHandleLeft = mTextView.getTextSelectHandleLeft(); + mSelectHandleRight = mTextView.getTextSelectHandleRight(); + if (hasSelectionController()) { + getSelectionController().reloadHandleDrawables(); + } + } + } + private class CorrectionHighlighter { private final Path mPath = new Path(); private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 6a3fc0fad4dd..9da2a4307a93 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -28,6 +28,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Color; +import android.graphics.Insets; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PixelFormat; @@ -568,7 +569,7 @@ public final class Magnifier { private Point getCurrentClampedWindowCoordinates() { final Rect windowBounds; if (mParentSurface.mIsMainWindowSurface) { - final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets(); + final Insets systemInsets = mView.getRootWindowInsets().getSystemWindowInsets(); windowBounds = new Rect(systemInsets.left, systemInsets.top, mParentSurface.mWidth - systemInsets.right, mParentSurface.mHeight - systemInsets.bottom); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 66809dbc4e45..572670fc662b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -67,6 +67,7 @@ import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.icu.text.DecimalFormatSymbols; import android.os.AsyncTask; +import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.LocaleList; @@ -799,17 +800,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // they are defined by the TextView's style and are theme-dependent. @UnsupportedAppUsage int mCursorDrawableRes; - // These six fields, could be moved to Editor, since we know their default values and we - // could condition the creation of the Editor to a non standard value. This is however - // brittle since the hardcoded values here (such as - // com.android.internal.R.drawable.text_select_handle_left) would have to be updated if the - // default style is modified. - @UnsupportedAppUsage + // Note: this might be stale if setTextSelectHandleLeft is used. We could simplify the code + // by removing it, but we would break apps targeting <= P that use it by reflection. + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) int mTextSelectHandleLeftRes; - @UnsupportedAppUsage + private Drawable mTextSelectHandleLeft; + // Note: this might be stale if setTextSelectHandleRight is used. We could simplify the code + // by removing it, but we would break apps targeting <= P that use it by reflection. + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) int mTextSelectHandleRightRes; - @UnsupportedAppUsage + private Drawable mTextSelectHandleRight; + // Note: this might be stale if setTextSelectHandle is used. We could simplify the code + // by removing it, but we would break apps targeting <= P that use it by reflection. + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) int mTextSelectHandleRes; + private Drawable mTextSelectHandle; int mTextEditSuggestionItemLayout; int mTextEditSuggestionContainerLayout; int mTextEditSuggestionHighlightStyle; @@ -3477,6 +3482,175 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Sets the Drawable corresponding to the selection handle used for + * positioning the cursor within text. The Drawable defaults to the value + * of the textSelectHandle attribute. + * Note that any change applied to the handle Drawable will not be visible + * until the handle is hidden and then drawn again. + * + * @see #setTextSelectHandle(int) + * @attr ref android.R.styleable#TextView_textSelectHandle + */ + @android.view.RemotableViewMethod + public void setTextSelectHandle(@NonNull Drawable textSelectHandle) { + Preconditions.checkNotNull(textSelectHandle, + "The text select handle should not be null."); + mTextSelectHandle = textSelectHandle; + mTextSelectHandleRes = 0; + if (mEditor != null) { + mEditor.loadHandleDrawables(true /* overwrite */); + } + } + + /** + * Sets the Drawable corresponding to the selection handle used for + * positioning the cursor within text. The Drawable defaults to the value + * of the textSelectHandle attribute. + * Note that any change applied to the handle Drawable will not be visible + * until the handle is hidden and then drawn again. + * + * @see #setTextSelectHandle(Drawable) + * @attr ref android.R.styleable#TextView_textSelectHandle + */ + @android.view.RemotableViewMethod + public void setTextSelectHandle(@DrawableRes int textSelectHandle) { + Preconditions.checkArgumentPositive(textSelectHandle, + "The text select handle should be a valid drawable resource id."); + setTextSelectHandle(mContext.getDrawable(textSelectHandle)); + } + + /** + * Returns the Drawable corresponding to the selection handle used + * for positioning the cursor within text. + * Note that any change applied to the handle Drawable will not be visible + * until the handle is hidden and then drawn again. + * + * @return the text select handle drawable + * + * @see #setTextSelectHandle(Drawable) + * @see #setTextSelectHandle(int) + * @attr ref android.R.styleable#TextView_textSelectHandle + */ + @Nullable public Drawable getTextSelectHandle() { + if (mTextSelectHandle == null && mTextSelectHandleRes != 0) { + mTextSelectHandle = mContext.getDrawable(mTextSelectHandleRes); + } + return mTextSelectHandle; + } + + /** + * Sets the Drawable corresponding to the left handle used + * for selecting text. The Drawable defaults to the value of the + * textSelectHandleLeft attribute. + * Note that any change applied to the handle Drawable will not be visible + * until the handle is hidden and then drawn again. + * + * @see #setTextSelectHandleLeft(int) + * @attr ref android.R.styleable#TextView_textSelectHandleLeft + */ + @android.view.RemotableViewMethod + public void setTextSelectHandleLeft(@NonNull Drawable textSelectHandleLeft) { + Preconditions.checkNotNull(textSelectHandleLeft, + "The left text select handle should not be null."); + mTextSelectHandleLeft = textSelectHandleLeft; + mTextSelectHandleLeftRes = 0; + if (mEditor != null) { + mEditor.loadHandleDrawables(true /* overwrite */); + } + } + + /** + * Sets the Drawable corresponding to the left handle used + * for selecting text. The Drawable defaults to the value of the + * textSelectHandleLeft attribute. + * Note that any change applied to the handle Drawable will not be visible + * until the handle is hidden and then drawn again. + * + * @see #setTextSelectHandleLeft(Drawable) + * @attr ref android.R.styleable#TextView_textSelectHandleLeft + */ + @android.view.RemotableViewMethod + public void setTextSelectHandleLeft(@DrawableRes int textSelectHandleLeft) { + Preconditions.checkArgumentPositive(textSelectHandleLeft, + "The text select left handle should be a valid drawable resource id."); + setTextSelectHandleLeft(mContext.getDrawable(textSelectHandleLeft)); + } + + /** + * Returns the Drawable corresponding to the left handle used + * for selecting text. + * Note that any change applied to the handle Drawable will not be visible + * until the handle is hidden and then drawn again. + * + * @return the left text selection handle drawable + * + * @see #setTextSelectHandleLeft(Drawable) + * @see #setTextSelectHandleLeft(int) + * @attr ref android.R.styleable#TextView_textSelectHandleLeft + */ + @Nullable public Drawable getTextSelectHandleLeft() { + if (mTextSelectHandleLeft == null && mTextSelectHandleLeftRes != 0) { + mTextSelectHandleLeft = mContext.getDrawable(mTextSelectHandleLeftRes); + } + return mTextSelectHandleLeft; + } + + /** + * Sets the Drawable corresponding to the right handle used + * for selecting text. The Drawable defaults to the value of the + * textSelectHandleRight attribute. + * Note that any change applied to the handle Drawable will not be visible + * until the handle is hidden and then drawn again. + * + * @see #setTextSelectHandleRight(int) + * @attr ref android.R.styleable#TextView_textSelectHandleRight + */ + @android.view.RemotableViewMethod + public void setTextSelectHandleRight(@NonNull Drawable textSelectHandleRight) { + Preconditions.checkNotNull(textSelectHandleRight, + "The right text select handle should not be null."); + mTextSelectHandleRight = textSelectHandleRight; + mTextSelectHandleRightRes = 0; + if (mEditor != null) { + mEditor.loadHandleDrawables(true /* overwrite */); + } + } + + /** + * Sets the Drawable corresponding to the right handle used + * for selecting text. The Drawable defaults to the value of the + * textSelectHandleRight attribute. + * Note that any change applied to the handle Drawable will not be visible + * until the handle is hidden and then drawn again. + * + * @see #setTextSelectHandleRight(Drawable) + * @attr ref android.R.styleable#TextView_textSelectHandleRight + */ + @android.view.RemotableViewMethod + public void setTextSelectHandleRight(@DrawableRes int textSelectHandleRight) { + Preconditions.checkArgumentPositive(textSelectHandleRight, + "The text select right handle should be a valid drawable resource id."); + setTextSelectHandleRight(mContext.getDrawable(textSelectHandleRight)); + } + + /** + * Returns the Drawable corresponding to the right handle used + * for selecting text. + * + * @return the right text selection handle drawable + * + * @see #setTextSelectHandleRight(Drawable) + * @see #setTextSelectHandleRight(int) + * @attr ref android.R.styleable#TextView_textSelectHandleRight + */ + @Nullable public Drawable getTextSelectHandleRight() { + if (mTextSelectHandleRight == null && mTextSelectHandleRightRes != 0) { + mTextSelectHandleRight = mContext.getDrawable(mTextSelectHandleRightRes); + } + return mTextSelectHandleRight; + } + + /** * Sets the text appearance from the specified style resource. * <p> * Use a framework-defined {@code TextAppearance} style like diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index d7031eaed4d8..3462e08a4c6a 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -191,7 +191,8 @@ public class AlertController { public static final AlertController create(Context context, DialogInterface di, Window window) { final TypedArray a = context.obtainStyledAttributes( - null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0); + null, R.styleable.AlertDialog, R.attr.alertDialogStyle, + R.style.Theme_DeviceDefault_Settings); int controllerType = a.getInt(R.styleable.AlertDialog_controllerType, 0); a.recycle(); diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 768dddd35a6d..049103bfebb2 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -17,6 +17,7 @@ package com.android.internal.app; import android.app.AppOpsManager; +import android.content.pm.ParceledListSlice; import android.os.Bundle; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsActiveCallback; @@ -40,6 +41,10 @@ interface IAppOpsService { int checkPackage(int uid, String packageName); List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops); List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops); + ParceledListSlice getAllHistoricalPackagesOps(in String[] ops, + long beginTimeMillis, long endTimeMillis); + AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int uid, String packageName, + in String[] ops, long beginTimeMillis, long endTimeMillis); List<AppOpsManager.PackageOps> getUidOps(int uid, in int[] ops); void setUidMode(int code, int uid, int mode); void setMode(int code, int uid, String packageName, int mode); diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java index e7ac5664c3ee..19d8a836fc4c 100644 --- a/core/java/com/android/internal/app/procstats/ProcessStats.java +++ b/core/java/com/android/internal/app/procstats/ProcessStats.java @@ -1396,6 +1396,11 @@ public final class ProcessStats implements Parcelable { return as; } + // See b/118826162 -- to avoid logspaming, we rate limit the WTF. + private static final long INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS = 10_000L; + private long mNextInverseProcStateWtfUptime; + private int mSkippedInverseProcStateWtfCount; + public void updateTrackingAssociationsLocked(int curSeq, long now) { final int NUM = mTrackingAssociations.size(); for (int i = NUM - 1; i >= 0; i--) { @@ -1417,12 +1422,24 @@ public final class ProcessStats implements Parcelable { } else { act.stopActive(now); if (act.mProcState < procState) { - Slog.w(TAG, "Tracking association " + act + " whose proc state " - + act.mProcState + " is better than process " + proc - + " proc state " + procState); + final long nowUptime = SystemClock.uptimeMillis(); + if (mNextInverseProcStateWtfUptime > nowUptime) { + mSkippedInverseProcStateWtfCount++; + } else { + // TODO We still see it during boot related to GMS-core. + // b/118826162 + Slog.wtf(TAG, "Tracking association " + act + " whose proc state " + + act.mProcState + " is better than process " + proc + + " proc state " + procState + + " (" + mSkippedInverseProcStateWtfCount + " skipped)"); + mSkippedInverseProcStateWtfCount = 0; + mNextInverseProcStateWtfUptime = + nowUptime + INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS; + } } } } else { + // Don't need rate limiting on it. Slog.wtf(TAG, "Tracking association without process: " + act + " in " + act.getAssociationState()); } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index aa7bdb62a87c..e2c23de70c00 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -1001,7 +1001,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind insets.getSystemWindowInsetRight(), 0); } } - mFrameOffsets.set(insets.getSystemWindowInsets()); + mFrameOffsets.set(insets.getSystemWindowInsetsAsRect()); insets = updateColorViews(insets, true /* animate */); insets = updateStatusGuard(insets); if (getForeground() != null) { diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java index 4a1c95532ba0..ba0ff01b68de 100644 --- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java +++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java @@ -313,8 +313,7 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar pullChildren(); final int vis = getWindowSystemUiVisibility(); - final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0; - final Rect systemInsets = insets.getSystemWindowInsets(); + final Rect systemInsets = insets.getSystemWindowInsetsAsRect(); // The top and bottom action bars are always within the content area. boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true); diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index b799728e4a7e..25a5a0734bf5 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -69,7 +69,7 @@ public class LockPatternView extends View { private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h) private static final boolean PROFILE_DRAWING = false; - private static final float LINE_FADE_ALPHA_MULTIPLIER = 3.5f; + private static final float LINE_FADE_ALPHA_MULTIPLIER = 1.5f; private final CellState[][] mCellStates; private final int mDotSize; diff --git a/core/java/com/android/server/net/BaseNetdEventCallback.java b/core/java/com/android/server/net/BaseNetdEventCallback.java index fdba2f3dc9e6..97247aada49d 100644 --- a/core/java/com/android/server/net/BaseNetdEventCallback.java +++ b/core/java/com/android/server/net/BaseNetdEventCallback.java @@ -26,8 +26,8 @@ import android.net.INetdEventCallback; */ public class BaseNetdEventCallback extends INetdEventCallback.Stub { @Override - public void onDnsEvent(String hostname, String[] ipAddresses, - int ipAddressesCount, long timestamp, int uid) { + public void onDnsEvent(int netId, int eventType, int returnCode, String hostname, + String[] ipAddresses, int ipAddressesCount, long timestamp, int uid) { // default no-op } diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index e07a20880b94..2e7501f0e0be 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -83,7 +83,8 @@ static jlong FontFamily_create(jlong builderPtr) { return 0; } std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>( - builder->langId, builder->variant, std::move(builder->fonts)); + builder->langId, builder->variant, std::move(builder->fonts), + true /* isCustomFallback */); if (family->getCoverage().length() == 0) { return 0; } diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index d391de75aa9a..a8b0640c3a73 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -28,6 +28,7 @@ #include "SkBlurDrawLooper.h" #include "SkColorFilter.h" +#include "SkFontTypes.h" #include "SkMaskFilter.h" #include "SkPath.h" #include "SkPathEffect.h" @@ -684,13 +685,13 @@ namespace PaintGlue { } static jint getHinting(jlong paintHandle) { - return reinterpret_cast<Paint*>(paintHandle)->getHinting() - == Paint::kNo_Hinting ? 0 : 1; + return (SkFontHinting)reinterpret_cast<Paint*>(paintHandle)->getHinting() + == kNo_SkFontHinting ? 0 : 1; } static void setHinting(jlong paintHandle, jint mode) { reinterpret_cast<Paint*>(paintHandle)->setHinting( - mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting); + mode == 0 ? kNo_SkFontHinting : kNormal_SkFontHinting); } static void setAntiAlias(jlong paintHandle, jboolean aa) { diff --git a/core/jni/android/graphics/fonts/FontFamily.cpp b/core/jni/android/graphics/fonts/FontFamily.cpp index 767e068381d9..249e4f3e9212 100644 --- a/core/jni/android/graphics/fonts/FontFamily.cpp +++ b/core/jni/android/graphics/fonts/FontFamily.cpp @@ -57,7 +57,7 @@ static void FontFamily_Builder_addFont(jlong builderPtr, jlong fontPtr) { // Regular JNI static jlong FontFamily_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, - jstring langTags, jint variant) { + jstring langTags, jint variant, jboolean isCustomFallback) { std::unique_ptr<NativeFamilyBuilder> builder(toBuilder(builderPtr)); uint32_t localeId; if (langTags == nullptr) { @@ -67,7 +67,8 @@ static jlong FontFamily_Builder_build(JNIEnv* env, jobject clazz, jlong builderP localeId = minikin::registerLocaleList(str.c_str()); } std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>( - localeId, static_cast<minikin::FamilyVariant>(variant), std::move(builder->fonts)); + localeId, static_cast<minikin::FamilyVariant>(variant), std::move(builder->fonts), + isCustomFallback); if (family->getCoverage().length() == 0) { // No coverage means minikin rejected given font for some reasons. jniThrowException(env, "java/lang/IllegalArgumentException", @@ -87,7 +88,7 @@ static jlong FontFamily_Builder_GetReleaseFunc() { static const JNINativeMethod gFontFamilyBuilderMethods[] = { { "nInitBuilder", "()J", (void*) FontFamily_Builder_initBuilder }, { "nAddFont", "(JJ)V", (void*) FontFamily_Builder_addFont }, - { "nBuild", "(JLjava/lang/String;I)J", (void*) FontFamily_Builder_build }, + { "nBuild", "(JLjava/lang/String;IZ)J", (void*) FontFamily_Builder_build }, { "nGetReleaseNativeFamily", "()J", (void*) FontFamily_Builder_GetReleaseFunc }, }; diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h index f7f13a5f0431..99b5f8592e5d 100644 --- a/core/jni/android_media_AudioFormat.h +++ b/core/jni/android_media_AudioFormat.h @@ -37,6 +37,7 @@ #define ENCODING_AAC_XHE 16 #define ENCODING_AC4 17 #define ENCODING_E_AC3_JOC 18 +#define ENCODING_DOLBY_MAT 19 #define ENCODING_INVALID 0 #define ENCODING_DEFAULT 1 @@ -85,6 +86,8 @@ static inline audio_format_t audioFormatToNative(int audioFormat) return AUDIO_FORMAT_E_AC3_JOC; case ENCODING_DEFAULT: return AUDIO_FORMAT_DEFAULT; + case ENCODING_DOLBY_MAT: + return AUDIO_FORMAT_MAT; default: return AUDIO_FORMAT_INVALID; } @@ -134,6 +137,11 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat) return ENCODING_AC4; case AUDIO_FORMAT_E_AC3_JOC: return ENCODING_E_AC3_JOC; + case AUDIO_FORMAT_MAT: + case AUDIO_FORMAT_MAT_1_0: + case AUDIO_FORMAT_MAT_2_0: + case AUDIO_FORMAT_MAT_2_1: + return ENCODING_DOLBY_MAT; case AUDIO_FORMAT_DEFAULT: return ENCODING_DEFAULT; default: diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp index e64da5ca0b24..80572f37f76c 100644 --- a/core/jni/android_os_GraphicsEnvironment.cpp +++ b/core/jni/android_os_GraphicsEnvironment.cpp @@ -58,12 +58,20 @@ void setDebugLayers_native(JNIEnv* env, jobject clazz, jstring layers) { } } +void setDebugLayersGLES_native(JNIEnv* env, jobject clazz, jstring layers) { + if (layers != nullptr) { + ScopedUtfChars layersChars(env, layers); + android::GraphicsEnv::getInstance().setDebugLayersGLES(layersChars.c_str()); + } +} + const JNINativeMethod g_methods[] = { { "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) }, { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) }, { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) }, { "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) }, { "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) }, + { "setDebugLayersGLES", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayersGLES_native) }, }; const char* const kGraphicsEnvironmentName = "android/os/GraphicsEnvironment"; diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 830ca832fb95..b2d44e73d861 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -1208,13 +1208,23 @@ static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlon // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str()); } -static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr, - jlong src_theme_ptr) { +static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr, + jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) { Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr); Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr); - if (!dst_theme->SetTo(*src_theme)) { - jniThrowException(env, "java/lang/IllegalArgumentException", - "Themes are from different AssetManagers"); + + if (dst_asset_manager_ptr != src_asset_manager_ptr) { + ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr)); + CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager)); + (void) dst_assetmanager; + + ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr)); + CHECK(src_theme->GetAssetManager() == &(*src_assetmanager)); + (void) src_assetmanager; + + dst_theme->SetTo(*src_theme); + } else { + dst_theme->SetTo(*src_theme); } } @@ -1255,10 +1265,11 @@ static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong Theme* theme = reinterpret_cast<Theme*>(theme_ptr); CHECK(theme->GetAssetManager() == &(*assetmanager)); (void) assetmanager; - (void) theme; (void) priority; (void) tag; (void) prefix; + + theme->Dump(); } static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/, @@ -1377,7 +1388,7 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate}, {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy}, {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle}, - {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy}, + {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy}, {"nativeThemeClear", "(J)V", (void*)NativeThemeClear}, {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I", (void*)NativeThemeGetAttributeValue}, diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index bb71a5d4accf..e89b5933fdc8 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -295,6 +295,22 @@ static jboolean android_view_RenderNode_setBottom(jlong renderNodePtr, int botto return SET_AND_DIRTY(setBottom, bottom, RenderNode::Y); } +static jint android_view_RenderNode_getLeft(jlong renderNodePtr) { + return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getLeft(); +} + +static jint android_view_RenderNode_getTop(jlong renderNodePtr) { + return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getTop(); +} + +static jint android_view_RenderNode_getRight(jlong renderNodePtr) { + return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getRight(); +} + +static jint android_view_RenderNode_getBottom(jlong renderNodePtr) { + return reinterpret_cast<RenderNode*>(renderNodePtr)->stagingProperties().getBottom(); +} + static jboolean android_view_RenderNode_setLeftTopRightBottom(jlong renderNodePtr, int left, int top, int right, int bottom) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); @@ -645,6 +661,10 @@ static const JNINativeMethod gMethods[] = { { "nSetTop", "(JI)Z", (void*) android_view_RenderNode_setTop }, { "nSetRight", "(JI)Z", (void*) android_view_RenderNode_setRight }, { "nSetBottom", "(JI)Z", (void*) android_view_RenderNode_setBottom }, + { "nGetLeft", "(J)I", (void*) android_view_RenderNode_getLeft }, + { "nGetTop", "(J)I", (void*) android_view_RenderNode_getTop }, + { "nGetRight", "(J)I", (void*) android_view_RenderNode_getRight }, + { "nGetBottom", "(J)I", (void*) android_view_RenderNode_getBottom }, { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom }, { "nOffsetLeftAndRight", "(JI)Z", (void*) android_view_RenderNode_offsetLeftAndRight }, { "nOffsetTopAndBottom", "(JI)Z", (void*) android_view_RenderNode_offsetTopAndBottom }, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 4e20e294350f..8e9a0bf61517 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -20,7 +20,9 @@ #include <sys/mount.h> #include <linux/fs.h> +#include <functional> #include <list> +#include <optional> #include <sstream> #include <string> @@ -70,6 +72,8 @@ namespace { +using namespace std::placeholders; + using android::String8; using android::base::StringAppendF; using android::base::StringPrintf; @@ -651,12 +655,12 @@ void SetThreadName(const char* thread_name) { static FileDescriptorTable* gOpenFdTable = NULL; static bool FillFileDescriptorVector(JNIEnv* env, - jintArray java_fds, + jintArray managed_fds, std::vector<int>* fds, std::string* error_msg) { CHECK(fds != nullptr); - if (java_fds != nullptr) { - ScopedIntArrayRO ar(env, java_fds); + if (managed_fds != nullptr) { + ScopedIntArrayRO ar(env, managed_fds); if (ar.get() == nullptr) { *error_msg = "Bad fd array"; return false; @@ -669,33 +673,142 @@ static bool FillFileDescriptorVector(JNIEnv* env, return true; } -// Utility routine to specialize a zygote child process. -static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, - jint runtime_flags, jobjectArray javaRlimits, - jlong permittedCapabilities, jlong effectiveCapabilities, - jint mount_external, jstring java_se_info, jstring java_se_name, - bool is_system_server, bool is_child_zygote, jstring instructionSet, - jstring dataDir, jstring packageName, jobjectArray packagesForUid, - jobjectArray visibleVolIds) { +[[noreturn]] +static void ZygoteFailure(JNIEnv* env, + const char* process_name, + jstring managed_process_name, + const std::string& msg) { + std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr; + if (managed_process_name != nullptr) { + scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name)); + if (scoped_managed_process_name_ptr->c_str() != nullptr) { + process_name = scoped_managed_process_name_ptr->c_str(); + } + } + + const std::string& error_msg = + (process_name == nullptr) ? msg : StringPrintf("(%s) %s", process_name, msg.c_str()); + + env->FatalError(error_msg.c_str()); + __builtin_unreachable(); +} + +static std::optional<std::string> ExtractJString(JNIEnv* env, + const char* process_name, + jstring managed_process_name, + jstring managed_string) { + if (managed_string == nullptr) { + return std::optional<std::string>(); + } else { + ScopedUtfChars scoped_string_chars(env, managed_string); + + if (scoped_string_chars.c_str() != nullptr) { + return std::optional<std::string>(scoped_string_chars.c_str()); + } else { + ZygoteFailure(env, process_name, managed_process_name, "Failed to extract JString."); + } + } +} + +// Utility routine to fork a zygote. +static pid_t ForkCommon(JNIEnv* env, bool is_system_server, + jintArray managed_fds_to_close, jintArray managed_fds_to_ignore) { + SetSignalHandlers(); + + // Block SIGCHLD prior to fork. + sigset_t sigchld; + sigemptyset(&sigchld); + sigaddset(&sigchld, SIGCHLD); + + // Curry a failure function. + auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote", + nullptr, _1); + + // Temporarily block SIGCHLD during forks. The SIGCHLD handler might + // log, which would result in the logging FDs we close being reopened. + // This would cause failures because the FDs are not whitelisted. + // + // Note that the zygote process is single threaded at this point. + if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) { + fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno))); + } + + // Close any logging related FDs before we start evaluating the list of + // file descriptors. + __android_log_close(); + stats_log_close(); + + // If this is the first fork for this zygote, create the open FD table. If + // it isn't, we just need to check whether the list of open files has changed + // (and it shouldn't in the normal case). std::string error_msg; + std::vector<int> fds_to_ignore; + if (!FillFileDescriptorVector(env, managed_fds_to_ignore, &fds_to_ignore, &error_msg)) { + fail_fn(error_msg); + } + + if (gOpenFdTable == nullptr) { + gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg); + if (gOpenFdTable == nullptr) { + fail_fn(error_msg); + } + } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) { + fail_fn(error_msg); + } + + android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level(); + + pid_t pid = fork(); + + if (pid == 0) { + // The child process. + PreApplicationInit(); - auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg) - __attribute__ ((noreturn)) { - const char* se_name_c_str = nullptr; - std::unique_ptr<ScopedUtfChars> se_name; - if (java_se_name != nullptr) { - se_name.reset(new ScopedUtfChars(env, java_se_name)); - se_name_c_str = se_name->c_str(); + // Clean up any descriptors which must be closed immediately + if (!DetachDescriptors(env, managed_fds_to_close, &error_msg)) { + fail_fn(error_msg); } - if (se_name_c_str == nullptr && is_system_server) { - se_name_c_str = "system_server"; + + // Re-open all remaining open file descriptors so that they aren't shared + // with the zygote across a fork. + if (!gOpenFdTable->ReopenOrDetach(&error_msg)) { + fail_fn(error_msg); } - const std::string& error_msg = (se_name_c_str == nullptr) - ? msg - : StringPrintf("(%s) %s", se_name_c_str, msg.c_str()); - env->FatalError(error_msg.c_str()); - __builtin_unreachable(); - }; + + // Turn fdsan back on. + android_fdsan_set_error_level(fdsan_error_level); + } + + // We blocked SIGCHLD prior to a fork, we unblock it here. + if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) { + fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno))); + } + + return pid; +} + +// Utility routine to specialize a zygote child process. +static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, + jint runtime_flags, jobjectArray rlimits, + jlong permitted_capabilities, jlong effective_capabilities, + jint mount_external, jstring managed_se_info, + jstring managed_nice_name, bool is_system_server, + bool is_child_zygote, jstring managed_instruction_set, + jstring managed_app_data_dir, jstring managed_package_name, + jobjectArray managed_pacakges_for_uid, + jobjectArray managed_visible_vol_ids) { + auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote", + managed_nice_name, _1); + auto extract_fn = std::bind(ExtractJString, env, is_system_server ? "system_server" : "zygote", + managed_nice_name, _1); + + auto se_info = extract_fn(managed_se_info); + auto nice_name = extract_fn(managed_nice_name); + auto instruction_set = extract_fn(managed_instruction_set); + auto app_data_dir = extract_fn(managed_app_data_dir); + auto package_name = extract_fn(managed_package_name); + + std::string error_msg; // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { @@ -704,56 +817,71 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi } } - if (!SetInheritable(permittedCapabilities, &error_msg)) { + if (!SetInheritable(permitted_capabilities, &error_msg)) { fail_fn(error_msg); } + if (!DropCapabilitiesBoundingSet(&error_msg)) { fail_fn(error_msg); } - bool use_native_bridge = !is_system_server && (instructionSet != NULL) - && android::NativeBridgeAvailable(); - if (use_native_bridge) { - ScopedUtfChars isa_string(env, instructionSet); - use_native_bridge = android::NeedsNativeBridge(isa_string.c_str()); - } - if (use_native_bridge && dataDir == NULL) { - // dataDir should never be null if we need to use a native bridge. - // In general, dataDir will never be null for normal applications. It can only happen in - // special cases (for isolated processes which are not associated with any app). These are - // launched by the framework and should not be emulated anyway. + bool use_native_bridge = !is_system_server && + instruction_set.has_value() && + android::NativeBridgeAvailable() && + android::NeedsNativeBridge(instruction_set.value().c_str()); + + if (use_native_bridge && !app_data_dir.has_value()) { + // The app_data_dir variable should never be empty if we need to use a + // native bridge. In general, app_data_dir will never be empty for normal + // applications. It can only happen in special cases (for isolated + // processes which are not associated with any app). These are launched by + // the framework and should not be emulated anyway. use_native_bridge = false; - ALOGW("Native bridge will not be used because dataDir == NULL."); + ALOGW("Native bridge will not be used because managed_app_data_dir == nullptr."); } - std::string package_name_str(""); - if (packageName != nullptr) { - ScopedUtfChars package(env, packageName); - package_name_str = package.c_str(); - } else if (is_system_server) { - package_name_str = "android"; + if (!package_name.has_value()) { + if (is_system_server) { + package_name.emplace("android"); + } else { + package_name.emplace(""); + } } + std::vector<std::string> packages_for_uid; - if (packagesForUid != nullptr) { - jsize count = env->GetArrayLength(packagesForUid); - for (jsize i = 0; i < count; ++i) { - jstring package_for_uid = (jstring) env->GetObjectArrayElement(packagesForUid, i); - ScopedUtfChars package(env, package_for_uid); - packages_for_uid.push_back(package.c_str()); + if (managed_pacakges_for_uid != nullptr) { + jsize count = env->GetArrayLength(managed_pacakges_for_uid); + for (jsize package_index = 0; package_index < count; ++package_index) { + jstring managed_package_for_uid = + (jstring) env->GetObjectArrayElement(managed_pacakges_for_uid, package_index); + + auto package_for_uid = extract_fn(managed_package_for_uid); + if (LIKELY(package_for_uid.has_value())) { + packages_for_uid.emplace_back(std::move(package_for_uid.value())); + } else { + fail_fn("Null string found in managed packages_for_uid."); + } } } + std::vector<std::string> visible_vol_ids; - if (visibleVolIds != nullptr) { - jsize count = env->GetArrayLength(visibleVolIds); - for (jsize i = 0; i < count; ++i) { - jstring visible_vol_id = (jstring) env->GetObjectArrayElement(visibleVolIds, i); - ScopedUtfChars vol(env, visible_vol_id); - visible_vol_ids.push_back(vol.c_str()); + if (managed_visible_vol_ids != nullptr) { + jsize count = env->GetArrayLength(managed_visible_vol_ids); + for (jsize vol_id_index = 0; vol_id_index < count; ++vol_id_index) { + jstring managed_visible_vol_id = + (jstring) env->GetObjectArrayElement(managed_visible_vol_ids, vol_id_index); + + auto visible_vol_id = extract_fn(managed_visible_vol_id); + if (LIKELY(visible_vol_id.has_value())) { + visible_vol_ids.emplace_back(std::move(visible_vol_id.value())); + } else { + fail_fn("Null string found in managed visible_vol_ids."); + } } } - bool success = MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg, - package_name_str, packages_for_uid, visible_vol_ids); - if (!success) { + + if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg, + package_name.value(), packages_for_uid, visible_vol_ids)) { ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno)); if (errno == ENOTCONN || errno == EROFS) { // When device is actively encrypting, we get ENOTCONN here @@ -769,44 +897,41 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi // If this zygote isn't root, it won't be able to create a process group, // since the directory is owned by root. if (!is_system_server && getuid() == 0) { - int rc = createProcessGroup(uid, getpid()); - if (rc != 0) { - if (rc == -EROFS) { - ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?"); - } else { - ALOGE("createProcessGroup(%d, %d) failed: %s", uid, 0/*pid*/, strerror(-rc)); - } - } + int rc = createProcessGroup(uid, getpid()); + if (rc == -EROFS) { + ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?"); + } else if (rc != 0) { + ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc)); + } } - if (!SetGids(env, javaGids, &error_msg)) { + if (!SetGids(env, gids, &error_msg)) { fail_fn(error_msg); } - if (!SetRLimits(env, javaRlimits, &error_msg)) { + if (!SetRLimits(env, rlimits, &error_msg)) { fail_fn(error_msg); } if (use_native_bridge) { - ScopedUtfChars isa_string(env, instructionSet); - ScopedUtfChars data_dir(env, dataDir); - android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str()); + // Due to the logic behind use_native_bridge we know that both app_data_dir + // and instruction_set contain values. + android::PreInitializeNativeBridge(app_data_dir.value().c_str(), + instruction_set.value().c_str()); } - int rc = setresgid(gid, gid, gid); - if (rc == -1) { + if (setresgid(gid, gid, gid) == -1) { fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); } - // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing - // uid from 0, which clears capabilities. The other alternative is to call - // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see - // b/71859146). As the result, privileged syscalls used below still need to be accessible in - // app process. + // Must be called when the new process still has CAP_SYS_ADMIN, in this case, + // before changing uid from 0, which clears capabilities. The other + // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that + // breaks SELinux domain transition (see b/71859146). As the result, + // privileged syscalls used below still need to be accessible in app process. SetUpSeccompFilter(uid); - rc = setresuid(uid, uid, uid); - if (rc == -1) { + if (setresuid(uid, uid, uid) == -1) { fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); } @@ -820,9 +945,10 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi // processes. This also ensures compliance with CTS. int dumpable = prctl(PR_GET_DUMPABLE); if (dumpable == -1) { - ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed"); + ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed"); } + if (dumpable == 2 && uid >= AID_APP) { if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) { ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno)); @@ -831,15 +957,15 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi } if (NeedsNoRandomizeWorkaround()) { - // Work around ARM kernel ASLR lossage (http://b/5817320). - int old_personality = personality(0xffffffff); - int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE); - if (new_personality == -1) { - ALOGW("personality(%d) failed: %s", new_personality, strerror(errno)); - } + // Work around ARM kernel ASLR lossage (http://b/5817320). + int old_personality = personality(0xffffffff); + int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE); + if (new_personality == -1) { + ALOGW("personality(%d) failed: %s", new_personality, strerror(errno)); + } } - if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities, + if (!SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, &error_msg)) { fail_fn(error_msg); } @@ -848,42 +974,22 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi fail_fn(error_msg); } - const char* se_info_c_str = NULL; - ScopedUtfChars* se_info = NULL; - if (java_se_info != NULL) { - se_info = new ScopedUtfChars(env, java_se_info); - se_info_c_str = se_info->c_str(); - if (se_info_c_str == NULL) { - fail_fn("se_info_c_str == NULL"); - } - } - const char* se_name_c_str = NULL; - ScopedUtfChars* se_name = NULL; - if (java_se_name != NULL) { - se_name = new ScopedUtfChars(env, java_se_name); - se_name_c_str = se_name->c_str(); - if (se_name_c_str == NULL) { - fail_fn("se_name_c_str == NULL"); - } - } - rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str); - if (rc == -1) { - fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid, - is_system_server, se_info_c_str, se_name_c_str)); + const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr; + const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr; + + if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) { + fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", + uid, is_system_server, se_info_ptr, nice_name_ptr)); } // Make it easier to debug audit logs by setting the main thread's name to the // nice name rather than "app_process". - if (se_name_c_str == NULL && is_system_server) { - se_name_c_str = "system_server"; - } - if (se_name_c_str != NULL) { - SetThreadName(se_name_c_str); + if (nice_name.has_value()) { + SetThreadName(nice_name.value().c_str()); + } else if (is_system_server) { + SetThreadName("system_server"); } - delete se_info; - delete se_name; - // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers). UnsetChldSignalHandler(); @@ -900,124 +1006,101 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi } env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, - is_system_server, is_child_zygote, instructionSet); + is_system_server, is_child_zygote, managed_instruction_set); + if (env->ExceptionCheck()) { fail_fn("Error calling post fork hooks."); } } -// Utility routine to fork zygote and specialize the child process. -static pid_t ForkCommon(JNIEnv* env, jstring java_se_name, bool is_system_server, - jintArray fdsToClose, jintArray fdsToIgnore) { - SetSignalHandlers(); - - // Block SIGCHLD prior to fork. - sigset_t sigchld; - sigemptyset(&sigchld); - sigaddset(&sigchld, SIGCHLD); +static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) { + __user_cap_header_struct capheader; + memset(&capheader, 0, sizeof(capheader)); + capheader.version = _LINUX_CAPABILITY_VERSION_3; + capheader.pid = 0; - auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg) - __attribute__ ((noreturn)) { - const char* se_name_c_str = nullptr; - std::unique_ptr<ScopedUtfChars> se_name; - if (java_se_name != nullptr) { - se_name.reset(new ScopedUtfChars(env, java_se_name)); - se_name_c_str = se_name->c_str(); - } - if (se_name_c_str == nullptr && is_system_server) { - se_name_c_str = "system_server"; + __user_cap_data_struct capdata[2]; + if (capget(&capheader, &capdata[0]) == -1) { + ALOGE("capget failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "capget failed"); } - const std::string& error_msg = (se_name_c_str == nullptr) - ? msg - : StringPrintf("(%s) %s", se_name_c_str, msg.c_str()); - env->FatalError(error_msg.c_str()); - __builtin_unreachable(); - }; - - // Temporarily block SIGCHLD during forks. The SIGCHLD handler might - // log, which would result in the logging FDs we close being reopened. - // This would cause failures because the FDs are not whitelisted. - // - // Note that the zygote process is single threaded at this point. - if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) { - fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno))); - } - - // Close any logging related FDs before we start evaluating the list of - // file descriptors. - __android_log_close(); - stats_log_close(); - std::string error_msg; + return capdata[0].effective | (static_cast<uint64_t>(capdata[1].effective) << 32); +} - // If this is the first fork for this zygote, create the open FD table. - // If it isn't, we just need to check whether the list of open files has - // changed (and it shouldn't in the normal case). - std::vector<int> fds_to_ignore; - if (!FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore, &error_msg)) { - fail_fn(error_msg); +static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gids, + bool is_child_zygote) { + jlong capabilities = 0; + + /* + * Grant the following capabilities to the Bluetooth user: + * - CAP_WAKE_ALARM + * - CAP_NET_RAW + * - CAP_NET_BIND_SERVICE (for DHCP client functionality) + * - CAP_SYS_NICE (for setting RT priority for audio-related threads) + */ + + if (multiuser_get_app_id(uid) == AID_BLUETOOTH) { + capabilities |= (1LL << CAP_WAKE_ALARM); + capabilities |= (1LL << CAP_NET_RAW); + capabilities |= (1LL << CAP_NET_BIND_SERVICE); + capabilities |= (1LL << CAP_SYS_NICE); } - if (gOpenFdTable == NULL) { - gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg); - if (gOpenFdTable == NULL) { - fail_fn(error_msg); - } - } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) { - fail_fn(error_msg); - } - - android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level(); - pid_t pid = fork(); + /* + * Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock" + */ - if (pid == 0) { - // The child process. - PreApplicationInit(); + bool gid_wakelock_found = false; + if (gid == AID_WAKELOCK) { + gid_wakelock_found = true; + } else if (gids != nullptr) { + jsize gids_num = env->GetArrayLength(gids); + ScopedIntArrayRO native_gid_proxy(env, gids); - // Clean up any descriptors which must be closed immediately - if (!DetachDescriptors(env, fdsToClose, &error_msg)) { - fail_fn(error_msg); + if (native_gid_proxy.get() == nullptr) { + RuntimeAbort(env, __LINE__, "Bad gids array"); } - // Re-open all remaining open file descriptors so that they aren't shared - // with the zygote across a fork. - if (!gOpenFdTable->ReopenOrDetach(&error_msg)) { - fail_fn(error_msg); + for (int gid_index = gids_num; --gids_num >= 0;) { + if (native_gid_proxy[gid_index] == AID_WAKELOCK) { + gid_wakelock_found = true; + break; + } } - - // Turn fdsan back on. - android_fdsan_set_error_level(fdsan_error_level); } - // We blocked SIGCHLD prior to a fork, we unblock it here. - if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) { - fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno))); + if (gid_wakelock_found) { + capabilities |= (1LL << CAP_BLOCK_SUSPEND); } - return pid; -} -static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) { - __user_cap_header_struct capheader; - memset(&capheader, 0, sizeof(capheader)); - capheader.version = _LINUX_CAPABILITY_VERSION_3; - capheader.pid = 0; + /* + * Grant child Zygote processes the following capabilities: + * - CAP_SETUID (change UID of child processes) + * - CAP_SETGID (change GID of child processes) + * - CAP_SETPCAP (change capabilities of child processes) + */ + + if (is_child_zygote) { + capabilities |= (1LL << CAP_SETUID); + capabilities |= (1LL << CAP_SETGID); + capabilities |= (1LL << CAP_SETPCAP); + } - __user_cap_data_struct capdata[2]; - if (capget(&capheader, &capdata[0]) == -1) { - ALOGE("capget failed: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "capget failed"); - } + /* + * Containers run without some capabilities, so drop any caps that are not + * available. + */ - return capdata[0].effective | - (static_cast<uint64_t>(capdata[1].effective) << 32); + return capabilities & GetEffectiveCapabilityMask(env); } } // anonymous namespace namespace android { static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) { - // security_getenforce is not allowed on app process. Initialize and cache the value before - // zygote forks. + // security_getenforce is not allowed on app process. Initialize and cache + // the value before zygote forks. g_is_security_enforced = security_getenforce(); } @@ -1028,78 +1111,35 @@ static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jcl static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, - jint mount_external, jstring se_info, jstring se_name, - jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote, - jstring instructionSet, jstring appDataDir, jstring packageName, - jobjectArray packagesForUid, jobjectArray visibleVolIds) { - jlong capabilities = 0; - - // Grant CAP_WAKE_ALARM to the Bluetooth process. - // Additionally, allow bluetooth to open packet sockets so it can start the DHCP client. - // Grant CAP_SYS_NICE to allow Bluetooth to set RT priority for - // audio-related threads. - // TODO: consider making such functionality an RPC to netd. - if (multiuser_get_app_id(uid) == AID_BLUETOOTH) { - capabilities |= (1LL << CAP_WAKE_ALARM); - capabilities |= (1LL << CAP_NET_RAW); - capabilities |= (1LL << CAP_NET_BIND_SERVICE); - capabilities |= (1LL << CAP_SYS_NICE); - } - - // Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock" - bool gid_wakelock_found = false; - if (gid == AID_WAKELOCK) { - gid_wakelock_found = true; - } else if (gids != NULL) { - jsize gids_num = env->GetArrayLength(gids); - ScopedIntArrayRO ar(env, gids); - if (ar.get() == NULL) { - RuntimeAbort(env, __LINE__, "Bad gids array"); - } - for (int i = 0; i < gids_num; i++) { - if (ar[i] == AID_WAKELOCK) { - gid_wakelock_found = true; - break; - } - } - } - if (gid_wakelock_found) { - capabilities |= (1LL << CAP_BLOCK_SUSPEND); - } - - // If forking a child zygote process, that zygote will need to be able to change - // the UID and GID of processes it forks, as well as drop those capabilities. - if (is_child_zygote) { - capabilities |= (1LL << CAP_SETUID); - capabilities |= (1LL << CAP_SETGID); - capabilities |= (1LL << CAP_SETPCAP); - } - - // Containers run without some capabilities, so drop any caps that are not - // available. - capabilities &= GetEffectiveCapabilityMask(env); + jint mount_external, jstring se_info, jstring nice_name, + jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote, + jstring instruction_set, jstring app_data_dir, jstring package_name, + jobjectArray packages_for_uid, jobjectArray visible_vol_ids) { + jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); - pid_t pid = ForkCommon(env, se_name, false, fdsToClose, fdsToIgnore); + pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, - mount_external, se_info, se_name, false, - is_child_zygote == JNI_TRUE, instructionSet, appDataDir, packageName, - packagesForUid, visibleVolIds); + mount_external, se_info, nice_name, false, + is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, + package_name, packages_for_uid, visible_vol_ids); } return pid; } static jint com_android_internal_os_Zygote_nativeForkSystemServer( JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids, - jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities, - jlong effectiveCapabilities) { - pid_t pid = ForkCommon(env, NULL, true, NULL, NULL); + jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, + jlong effective_capabilities) { + pid_t pid = ForkCommon(env, true, + /* managed_fds_to_close= */ nullptr, + /* managed_fds_to_ignore= */ nullptr); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, - permittedCapabilities, effectiveCapabilities, - MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, - false, NULL, NULL, nullptr, nullptr, nullptr); + permitted_capabilities, effective_capabilities, + MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, + false, nullptr, nullptr, nullptr, nullptr, nullptr); } else if (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); @@ -1133,7 +1173,7 @@ static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork( ScopedUtfChars path_native(env, path); const char* path_cstr = path_native.c_str(); if (!path_cstr) { - RuntimeAbort(env, __LINE__, "path_cstr == NULL"); + RuntimeAbort(env, __LINE__, "path_cstr == nullptr"); } FileDescriptorWhitelist::Get()->Allow(path_cstr); } diff --git a/core/proto/OWNERS b/core/proto/OWNERS index 2ace1ac491c7..480b1eaaf98c 100644 --- a/core/proto/OWNERS +++ b/core/proto/OWNERS @@ -11,6 +11,9 @@ yanglu@google.com yaochen@google.com yro@google.com +# Settings UI +per-file settings_enums.proto=zhfan@google.com + # Frameworks ogunwale@google.com jjaggi@google.com diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index c1f7d571d828..54333938c52d 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -26,41 +26,43 @@ enum Action { ACTION_UNKNOWN = 0; PAGE_VISIBLE = 1; PAGE_HIDE = 2; - PREF_CHANGE = 3; + + // ACTION: Settings > Any preference is changed + ACTION_SETTINGS_PREFERENCE_CHANGE = 853; } /** * Id for Settings pages. Each page must have its own unique Id. */ enum PageId { - // Unknown page. Should not be used in production code. - PAGE_UNKNOWN = 0; + // Unknown page. Should not be used in production code. + PAGE_UNKNOWN = 0; - // OPEN: Settings homepage - SETTINGS_HOMEPAGE = 1502; + // OPEN: Settings homepage + SETTINGS_HOMEPAGE = 1502; - // OPEN: Settings > System > Input & Gesture > Wake screen - SETTINGS_GESTURE_WAKE_SCREEN = 1570; + // OPEN: Settings > System > Input & Gesture > Wake screen + SETTINGS_GESTURE_WAKE_SCREEN = 1570; - // OPEN: Settings > Network & internet > Mobile network - MOBILE_NETWORK = 1571; + // OPEN: Settings > Network & internet > Mobile network + MOBILE_NETWORK = 1571; - // OPEN: Settings > Network & internet > Mobile network > Choose network - MOBILE_NETWORK_SELECT = 1581; + // OPEN: Settings > Network & internet > Mobile network > Choose network + MOBILE_NETWORK_SELECT = 1581; - // OPEN: Settings > Network & internet > Mobile network > Mobile Data > Dialog - MOBILE_DATA_DIALOG = 1582; + // OPEN: Settings > Network & internet > Mobile network > Mobile Data > Dialog + MOBILE_DATA_DIALOG = 1582; - // OPEN: Settings > Network & internet > Mobile network > Data roaming > Dialog - MOBILE_ROAMING_DIALOG = 1583; + // OPEN: Settings > Network & internet > Mobile network > Data roaming > Dialog + MOBILE_ROAMING_DIALOG = 1583; - // Settings > Display > Lock screen display > On lock screen - LOCK_SCREEN_NOTIFICATION_CONTENT = 1584; + // Settings > Display > Lock screen display > On lock screen + LOCK_SCREEN_NOTIFICATION_CONTENT = 1584; - // ConfirmDeviceCredentials > BiometricPrompt - BIOMETRIC_FRAGMENT = 1585; + // ConfirmDeviceCredentials > BiometricPrompt + BIOMETRIC_FRAGMENT = 1585; - // OPEN: Biometric Enrollment (android.settings.BIOMETRIC_ENROLL action intent) - BIOMETRIC_ENROLL_ACTIVITY = 1586; + // OPEN: Biometric Enrollment (android.settings.BIOMETRIC_ENROLL action intent) + BIOMETRIC_ENROLL_ACTIVITY = 1586; } diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index 8f289700aede..0b9e347ce5d1 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -26,6 +26,7 @@ import "frameworks/base/core/proto/android/os/kernelwake.proto"; import "frameworks/base/core/proto/android/os/pagetypeinfo.proto"; import "frameworks/base/core/proto/android/os/procrank.proto"; import "frameworks/base/core/proto/android/os/ps.proto"; +import "frameworks/base/core/proto/android/os/statsdata.proto"; import "frameworks/base/core/proto/android/os/system_properties.proto"; import "frameworks/base/core/proto/android/providers/settings.proto"; import "frameworks/base/core/proto/android/server/activitymanagerservice.proto"; @@ -301,6 +302,12 @@ message IncidentProto { (section).userdebug_and_eng_only = true ]; + optional android.os.StatsDataDumpProto stats_data = 3023 [ + (section).type = SECTION_DUMPSYS, + (section).args = "stats --proto", + (section).userdebug_and_eng_only = true + ]; + // Reserved for OEMs. extensions 50000 to 100000; } diff --git a/core/proto/android/os/statsdata.proto b/core/proto/android/os/statsdata.proto new file mode 100644 index 000000000000..25d76b869259 --- /dev/null +++ b/core/proto/android/os/statsdata.proto @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +option java_multiple_files = true; + +package android.os; + +import "frameworks/base/libs/incident/proto/android/privacy.proto"; + +// Dump of statsd report data (dumpsys stats --proto). +message StatsDataDumpProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + // The following is an android.os.statsd.ConfigMetricsReportList, which is defined + // in frameworks/base/cmds/statsd/src/stats_log.proto. It should not be imported (even weakly) + // in AOSP because it would drag with it atoms.proto, which is enormous and awkward. + repeated bytes config_metrics_report_list = 1; + +}
\ No newline at end of file diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 47dbc0716c94..69ebb59ffda4 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -394,13 +394,16 @@ message GlobalSettingsProto { // App allowed to load GPU debug layers. optional SettingProto debug_app = 1; - // Ordered GPU debug layer list + // Ordered GPU debug layer list for Vulkan // i.e. <layer1>:<layer2>:...:<layerN> optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ]; // App will load ANGLE instead of native GLES drivers. optional SettingProto angle_enabled_app = 3; // App that can provide layer libraries. optional SettingProto debug_layer_app = 4; + // Ordered GPU debug layer list for GLES + // i.e. <layer1>:<layer2>:...:<layerN> + optional SettingProto debug_layers_gles = 5; } optional Gpu gpu = 59; @@ -722,8 +725,10 @@ message GlobalSettingsProto { optional SettingProto set_install_location = 103 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto shortcut_manager_constants = 104; optional SettingProto show_first_crash_dialog = 105 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_hidden_launcher_icon_apps_enabled = 141 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto show_restart_in_crash_dialog = 106 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto show_mute_in_crash_dialog = 107 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto show_new_app_installed_notification_enabled = 142 [ (android.privacy).dest = DEST_AUTOMATIC ]; message SmartSelection { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -963,5 +968,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 141; + // Next tag = 143; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 48d1dff02971..093a86089aab 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -401,6 +401,7 @@ <protected-broadcast android:name="android.telecom.action.DEFAULT_DIALER_CHANGED" /> <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED" /> <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_CREATED" /> + <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_LOST" /> <protected-broadcast android:name="android.intent.action.CONTENT_CHANGED" /> <protected-broadcast android:name="android.provider.Telephony.MMS_DOWNLOADED" /> @@ -3018,6 +3019,14 @@ <permission android:name="android.permission.BIND_TEXTCLASSIFIER_SERVICE" android:protectionLevel="signature" /> + <!-- Must be required by a android.service.intelligence.IntelligenceService, + to ensure that only the system can bind to it. + @SystemApi @hide This is not a third-party API (intended for OEMs and system apps). + <p>Protection level: signature + --> + <permission android:name="android.permission.BIND_INTELLIGENCE_SERVICE" + android:protectionLevel="signature" /> + <!-- Must be required by hotword enrollment application, to ensure that only the system can interact with it. @hide <p>Not for use by third-party applications.</p> --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 9ea82a9b9c2e..8b7cafbbc4d3 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1130,14 +1130,13 @@ <string name="permdesc_accessFineLocation">This app can get your exact location only when it is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them. This may increase battery consumption.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_accessCoarseLocation">access approximate location - (network-based)</string> + <string name="permlab_accessCoarseLocation">access approximate location (network-based) only in the foreground</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_accessCoarseLocation" product="tablet">This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your tablet for the app to be able to use them.</string> + <string name="permdesc_accessCoarseLocation" product="tablet">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your tablet for the app to be able to use them.</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your TV for the app to be able to use them.</string> + <string name="permdesc_accessCoarseLocation" product="tv">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when when the app is in the foreground. These location services must be turned on and available on your TV for the app to be able to use them.</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_accessCoarseLocation" product="default">This app can get your location based on network sources such as cell towers and Wi-Fi networks. These location services must be turned on and available on your phone for the app to be able to use them.</string> + <string name="permdesc_accessCoarseLocation" product="default">This app can get your location based on network sources such as cell towers and Wi-Fi networks, but only when the app is in the foreground. These location services must be turned on and available on your phone for the app to be able to use them.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_accessBackgroundLocation">access location in the background</string> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index 7b3d940b91f3..716376997f81 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -187,7 +187,7 @@ <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288" /> <!-- The Netherlands, 4 digits, known premium codes listed, plus EU --> - <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223" /> + <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" /> <!-- Nigeria --> <shortcode country="ng" pattern="\\d{1,5}" free="2441" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 182f1892e8cd..d5dc9034ef85 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -370,6 +370,7 @@ public class SettingsBackupTest { Settings.Global.PRIVATE_DNS_DEFAULT_MODE, Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, + Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED, Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS, Settings.Global.RADIO_BLUETOOTH, Settings.Global.RADIO_CELL, @@ -393,7 +394,9 @@ public class SettingsBackupTest { Settings.Global.SETTINGS_USE_PSD_API, Settings.Global.SHORTCUT_MANAGER_CONSTANTS, Settings.Global.SHOW_FIRST_CRASH_DIALOG, + Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG, + Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED, Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG, Settings.Global.SHOW_TEMPERATURE_WARNING, @@ -451,6 +454,7 @@ public class SettingsBackupTest { Settings.Global.ENABLE_GPU_DEBUG_LAYERS, Settings.Global.GPU_DEBUG_APP, Settings.Global.GPU_DEBUG_LAYERS, + Settings.Global.GPU_DEBUG_LAYERS_GLES, Settings.Global.ANGLE_ENABLED_APP, Settings.Global.GPU_DEBUG_LAYER_APP, Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, @@ -485,6 +489,7 @@ public class SettingsBackupTest { Settings.Global.WIFI_IDLE_MS, Settings.Global.WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED, Settings.Global.WIFI_LINK_SPEED_METRICS_ENABLED, + Settings.Global.WIFI_PNO_FREQUENCY_CULLING_ENABLED, Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS, Settings.Global.WIFI_NETWORK_SHOW_RSSI, diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index c8e46fcdf3fd..ca6d6cfedb76 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -20,6 +20,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; import android.content.Context; +import android.graphics.Insets; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.InstrumentationRegistry; @@ -57,9 +58,8 @@ public class ViewRootImplTest { mViewRootImpl.getAttachInfo().getStableInsets().set(-10, -20, -30 , -40); final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */); - assertThat(insets.getSystemWindowInsets(), equalTo(new Rect())); - assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(), - insets.getStableInsetRight(), insets.getStableInsetBottom()), equalTo(new Rect())); + assertThat(insets.getSystemWindowInsets(), equalTo(Insets.NONE)); + assertThat(insets.getStableInsets(), equalTo(Insets.NONE)); } @Test @@ -68,10 +68,8 @@ public class ViewRootImplTest { mViewRootImpl.getAttachInfo().getStableInsets().set(10, -20, 30 , -40); final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */); - assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(0, 20, 0, 40))); - assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(), - insets.getStableInsetRight(), insets.getStableInsetBottom()), - equalTo(new Rect(10, 0, 30, 0))); + assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(0, 20, 0, 40))); + assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 0, 30, 0))); } @Test @@ -80,10 +78,8 @@ public class ViewRootImplTest { mViewRootImpl.getAttachInfo().getStableInsets().set(10, 20, 30 , 40); final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */); - assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(10, 20, 30, 40))); - assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(), - insets.getStableInsetRight(), insets.getStableInsetBottom()), - equalTo(new Rect(10, 20, 30, 40))); + assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(10, 20, 30, 40))); + assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 20, 30, 40))); } private static class ViewRootImplAccessor { diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 499ad386d058..68f24fb7b661 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -189,12 +189,14 @@ targetSdk="16"> <new-permission name="android.permission.WRITE_CALL_LOG" /> </split-permission> + <!-- STOPSHIP(b/118882117): change targetSdk to Q when SDK version finalised --> <split-permission name="android.permission.ACCESS_FINE_LOCATION" - targetSdk="28"> + targetSdk="10000"> <new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" /> </split-permission> + <!-- STOPSHIP(b/118882117): change targetSdk to Q when SDK version finalised --> <split-permission name="android.permission.ACCESS_COARSE_LOCATION" - targetSdk="28"> + targetSdk="10000"> <new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" /> </split-permission> diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index e35a3be6dbbf..3b0dc9d9f125 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -205,11 +205,70 @@ public class Canvas extends BaseCanvas { mBitmap = bitmap; } - /** @hide */ - public void insertReorderBarrier() {} + /** + * @deprecated use {@link #enableZ()} instead + * @hide */ + @Deprecated + public void insertReorderBarrier() { + enableZ(); + } - /** @hide */ - public void insertInorderBarrier() {} + /** + * @deprecated use {@link #disableZ()} instead + * @hide */ + @Deprecated + public void insertInorderBarrier() { + disableZ(); + } + + /** + * <p>Enables Z support which defaults to disabled. This allows for RenderNodes drawn with + * {@link #drawRenderNode(RenderNode)} to be re-arranged based off of their + * {@link RenderNode#getElevation()} and {@link RenderNode#getTranslationZ()} + * values. It also enables rendering of shadows for RenderNodes with an elevation or + * translationZ.</p> + * + * <p>Any draw reordering will not be moved before this call. A typical usage of this might + * look something like: + * + * <pre class="prettyprint"> + * void draw(Canvas canvas) { + * // Draw any background content + * canvas.drawColor(backgroundColor); + * + * // Begin drawing that may be reordered based off of Z + * canvas.enableZ(); + * for (RenderNode child : children) { + * canvas.drawRenderNode(child); + * } + * // End drawing that may be reordered based off of Z + * canvas.disableZ(); + * + * // Draw any overlays + * canvas.drawText("I'm on top of everything!", 0, 0, paint); + * } + * </pre> + * </p> + * + * Note: This is not impacted by any {@link #save()} or {@link #restore()} calls as it is not + * considered to be part of the current matrix or clip. + * + * See {@link #disableZ()} + */ + public void enableZ() { + } + + /** + * Disables Z support, preventing any RenderNodes drawn after this point from being + * visually reordered or having shadows rendered. + * + * Note: This is not impacted by any {@link #save()} or {@link #restore()} calls as it is not + * considered to be part of the current matrix or clip. + * + * See {@link #enableZ()} + */ + public void disableZ() { + } /** * Return true if the device that the current layer draws into is opaque @@ -2110,4 +2169,17 @@ public class Canvas extends BaseCanvas { super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset, indices, indexOffset, indexCount, paint); } + + /** + * Draws the given RenderNode. This is only supported in hardware rendering, which can be + * verified by asserting that {@link #isHardwareAccelerated()} is true. If + * {@link #isHardwareAccelerated()} is false then this throws an exception. + * + * See {@link RenderNode} for more information on what a RenderNode is and how to use it. + * + * @param renderNode The RenderNode to draw, must be non-null. + */ + public void drawRenderNode(@NonNull RenderNode renderNode) { + throw new IllegalArgumentException("Software rendering doesn't support drawRenderNode"); + } } diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index 9546a4aec330..c580c46cc888 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -16,8 +16,6 @@ package android.graphics; -import android.annotation.UnsupportedAppUsage; - public class ImageFormat { /* * these constants are chosen to be binary compatible with their previous @@ -92,20 +90,21 @@ public class ImageFormat { * </ul> * </p> * - * <pre> y_size = stride * height </pre> + * <pre> size = stride * height </pre> * * <p>For example, the {@link android.media.Image} object can provide data - * in this format from a {@link android.hardware.camera2.CameraDevice} - * through a {@link android.media.ImageReader} object if this format is - * supported by {@link android.hardware.camera2.CameraDevice}.</p> + * in this format from a {@link android.hardware.camera2.CameraDevice} (if + * supported) through a {@link android.media.ImageReader} object. The + * {@link android.media.Image#getPlanes() Image#getPlanes()} will return a + * single plane containing the pixel data. The pixel stride is always 1 in + * {@link android.media.Image.Plane#getPixelStride()}, and the + * {@link android.media.Image.Plane#getRowStride()} describes the vertical + * neighboring pixel distance (in bytes) between adjacent rows.</p> * * @see android.media.Image * @see android.media.ImageReader * @see android.hardware.camera2.CameraDevice - * - * @hide */ - @UnsupportedAppUsage public static final int Y8 = 0x20203859; /** @@ -787,6 +786,7 @@ public class ImageFormat { case DEPTH_POINT_CLOUD: case PRIVATE: case RAW_DEPTH: + case Y8: return true; } diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java index 7af006b4bdf0..fd5d62406da7 100644 --- a/graphics/java/android/graphics/RecordingCanvas.java +++ b/graphics/java/android/graphics/RecordingCanvas.java @@ -18,7 +18,6 @@ package android.graphics; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.util.Pools.SynchronizedPool; import android.view.TextureLayer; @@ -27,17 +26,20 @@ import dalvik.annotation.optimization.FastNative; /** * A Canvas implementation that records view system drawing operations for deferred rendering. - * This is intended for use with RenderNode. This class keeps a list of all the Paint and - * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being freed while + * This is used in combination with RenderNode. This class keeps a list of all the Paint and + * Bitmap objects that it draws, preventing the backing memory of Bitmaps from being released while * the RecordingCanvas is still holding a native reference to the memory. * - * @hide + * This is obtained by calling {@link RenderNode#startRecording()} and is valid until the matching + * {@link RenderNode#endRecording()} is called. It must not be retained beyond that as it is + * internally reused. */ public final class RecordingCanvas extends BaseRecordingCanvas { // The recording canvas pool should be large enough to handle a deeply nested // view hierarchy because display lists are generated recursively. private static final int POOL_LIMIT = 25; + /** @hide */ public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB private static final SynchronizedPool<RecordingCanvas> sPool = @@ -50,6 +52,7 @@ public final class RecordingCanvas extends BaseRecordingCanvas { private int mWidth; private int mHeight; + /** @hide */ static RecordingCanvas obtain(@NonNull RenderNode node, int width, int height) { if (node == null) throw new IllegalArgumentException("node cannot be null"); RecordingCanvas canvas = sPool.acquire(); @@ -65,15 +68,18 @@ public final class RecordingCanvas extends BaseRecordingCanvas { return canvas; } + /** @hide */ void recycle() { mNode = null; sPool.release(this); } + /** @hide */ long finishRecording() { return nFinishRecording(mNativeCanvasWrapper); } + /** @hide */ @Override public boolean isRecordingFor(Object o) { return o == mNode; @@ -138,12 +144,12 @@ public final class RecordingCanvas extends BaseRecordingCanvas { /////////////////////////////////////////////////////////////////////////// @Override - public void insertReorderBarrier() { + public void enableZ() { nInsertReorderBarrier(mNativeCanvasWrapper, true); } @Override - public void insertInorderBarrier() { + public void disableZ() { nInsertReorderBarrier(mNativeCanvasWrapper, false); } @@ -159,7 +165,6 @@ public final class RecordingCanvas extends BaseRecordingCanvas { * * @hide */ - @UnsupportedAppUsage public void callDrawGLFunction2(long drawGLFunction) { nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null); } @@ -178,7 +183,6 @@ public final class RecordingCanvas extends BaseRecordingCanvas { * * @hide */ - @UnsupportedAppUsage public void drawGLFunctor2(long drawGLFunctor, @Nullable Runnable releasedCallback) { nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback); } @@ -192,8 +196,8 @@ public final class RecordingCanvas extends BaseRecordingCanvas { * * @param renderNode The RenderNode to draw. */ - @UnsupportedAppUsage - public void drawRenderNode(RenderNode renderNode) { + @Override + public void drawRenderNode(@NonNull RenderNode renderNode) { nDrawRenderNode(mNativeCanvasWrapper, renderNode.mNativeRenderNode); } @@ -225,7 +229,6 @@ public final class RecordingCanvas extends BaseRecordingCanvas { * * @hide */ - @UnsupportedAppUsage public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint) { nDrawCircle(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(), @@ -254,6 +257,7 @@ public final class RecordingCanvas extends BaseRecordingCanvas { paint.getNativeContainer()); } + /** @hide */ @Override protected void throwIfCannotDraw(Bitmap bitmap) { super.throwIfCannotDraw(bitmap); diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index 320fb20e5b98..12128b3384bf 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.view.NativeVectorDrawableAnimator; import android.view.RenderNodeAnimator; +import android.view.Surface; import android.view.View; import dalvik.annotation.optimization.CriticalNative; @@ -137,7 +138,28 @@ import java.lang.annotation.RetentionPolicy; * that the RenderNode is only used on the same thread it is drawn with. For example when using * RenderNode with a custom View, then that RenderNode must only be used from the UI thread.</p> * - * @hide + * <h3>When to re-render</h3> + * <p>Many of the RenderNode mutation methods, such as {@link #setTranslationX(float)}, return + * a boolean indicating if the value actually changed or not. This is useful in detecting + * if a new frame should be rendered or not. A typical usage would look like: + * <pre class="prettyprint"> + * public void translateTo(int x, int y) { + * boolean needsUpdate = myRenderNode.setTranslationX(x); + * needsUpdate |= myRenderNode.setTranslationY(y); + * if (needsUpdate) { + * myOwningView.invalidate(); + * } + * } + * </pre> + * This is marginally faster than doing a more explicit up-front check if the value changed by + * comparing the desired value against {@link #getTranslationX()} as it minimizes JNI transitions. + * The actual mechanism of requesting a new frame to be rendered will depend on how this + * RenderNode is being drawn. If it's drawn to a containing View, as in the above snippet, + * then simply invalidating that View works. If instead the RenderNode is being drawn to a Canvas + * directly such as with {@link Surface#lockHardwareCanvas()} then a new frame needs to be drawn + * by calling {@link Surface#lockHardwareCanvas()}, re-drawing the root RenderNode or whatever + * top-level content is desired, and finally calling {@link Surface#unlockCanvasAndPost(Canvas)}. + * </p> */ public class RenderNode { @@ -147,7 +169,9 @@ public class RenderNode { RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024); } - /** Not for general use; use only if you are ThreadedRenderer or RecordingCanvas. + /** + * Not for general use; use only if you are ThreadedRenderer or RecordingCanvas. + * * @hide */ public final long mNativeRenderNode; @@ -174,9 +198,13 @@ public class RenderNode { * drawing operations, and store / apply render properties when drawn. * * @param name The name of the RenderNode, used for debugging purpose. May be null. - * * @return A new RenderNode. */ + public static @NonNull RenderNode create(@Nullable String name) { + return new RenderNode(name, null); + } + + /** @hide */ public static RenderNode create(String name, @Nullable AnimationHost animationHost) { return new RenderNode(name, animationHost); } @@ -186,6 +214,8 @@ public class RenderNode { * * Note: This will *NOT* incRef() on the native object, however it will * decRef() when it is destroyed. The caller should have already incRef'd it + * + * @hide */ public static RenderNode adopt(long nativePtr) { return new RenderNode(nativePtr); @@ -220,6 +250,8 @@ public class RenderNode { /** * Enable callbacks for position changes. + * + * @hide */ public void requestPositionUpdates(PositionUpdateListener listener) { nRequestPositionUpdates(mNativeRenderNode, listener); @@ -234,15 +266,13 @@ public class RenderNode { * {@link #endRecording()} must be called when the recording is finished in order to apply * the updated display list. * - * @param width The width of the recording viewport. This will not alter the width of the - * RenderNode itself, that must be set with {@link #setLeft(int)} and - * {@link #setRight(int)} + * @param width The width of the recording viewport. This will not alter the width of the + * RenderNode itself, that must be set with {@link #setLeft(int)} and + * {@link #setRight(int)} * @param height The height of the recording viewport. This will not alter the height of the * RenderNode itself, that must be set with {@link #setTop(int)} and * {@link #setBottom(int)}. - * * @return A canvas to record drawing operations. - * * @see #endRecording() * @see #hasDisplayList() */ @@ -261,20 +291,20 @@ public class RenderNode { * with {@link #setLeftTopRightBottom(int, int, int, int)}. */ public RecordingCanvas startRecording() { - return RecordingCanvas.obtain(this, - nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode)); + return startRecording(nGetWidth(mNativeRenderNode), nGetHeight(mNativeRenderNode)); } /** - * @deprecated use {@link #startRecording(int, int)} instead * @hide + * @deprecated use {@link #startRecording(int, int)} instead */ @Deprecated public RecordingCanvas start(int width, int height) { return startRecording(width, height); } - /**` + /** + * ` * Ends the recording for this display list. Calling this method marks * the display list valid and {@link #hasDisplayList()} will return true. * @@ -294,8 +324,8 @@ public class RenderNode { } /** - * @deprecated use {@link #endRecording()} instead * @hide + * @deprecated use {@link #endRecording()} instead */ @Deprecated public void end(RecordingCanvas canvas) { @@ -373,21 +403,52 @@ public class RenderNode { /////////////////////////////////////////////////////////////////////////// /** - * TODO + * @hide + * @deprecated use {@link #setUseCompositingLayer(boolean, Paint)} instead */ + @Deprecated public boolean setLayerType(int layerType) { return nSetLayerType(mNativeRenderNode, layerType); } /** - * TODO + * @hide + * @deprecated use {@link #setUseCompositingLayer(boolean, Paint)} instead */ + @Deprecated public boolean setLayerPaint(@Nullable Paint paint) { return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.getNativeInstance() : 0); } /** + * Controls whether or not to force this RenderNode to render to an intermediate buffer. + * Internally RenderNode will already promote itself to a composition layer if it's useful + * for performance or required for the current combination of {@link #setAlpha(float)} and + * {@link #setHasOverlappingRendering(boolean)}. + * + * The usage of this is instead to allow for either overriding of the internal behavior + * if it's measured to be necessary for the particular rendering content in question or, more + * usefully, to add a composition effect to the RenderNode via the optional paint parameter. + * + * Note: When a RenderNode is using a compositing layer it will also result in + * clipToBounds=true behavior. + * + * @param forceToLayer if true this forces the RenderNode to use an intermediate buffer. + * Default & generally recommended value is false. + * @param paint The blend mode, alpha, and ColorFilter to apply to the compositing layer. + * Only applies if forceToLayer is true. + * @return true if anything changed, false otherwise + */ + public boolean setUseCompositingLayer(boolean forceToLayer, @Nullable Paint paint) { + boolean didChange = nSetLayerType(mNativeRenderNode, forceToLayer ? 2 : 0); + didChange |= nSetLayerPaint(mNativeRenderNode, + paint != null ? paint.getNativeInstance() : 0); + return didChange; + } + + /** * Sets the clip bounds of the RenderNode. + * * @param rect the bounds to clip to. If null, the clip bounds are reset * @return True if the clip bounds changed, false otherwise */ @@ -410,19 +471,19 @@ public class RenderNode { } /** - * Sets whether the display list should be drawn immediately after the - * closest ancestor display list containing a projection receiver. + * Sets whether the RenderNode should be drawn immediately after the + * closest ancestor RenderNode containing a projection receiver. * * @param shouldProject true if the display list should be projected onto a - * containing volume. + * containing volume. */ public boolean setProjectBackwards(boolean shouldProject) { return nSetProjectBackwards(mNativeRenderNode, shouldProject); } /** - * Sets whether the display list is a projection receiver - that its parent - * DisplayList should draw any descendent DisplayLists with + * Sets whether the RenderNode is a projection receiver - that its parent + * RenderNode should draw any descendent RenderNodes with * ProjectBackwards=true directly on top of it. Default value is false. */ public boolean setProjectionReceiver(boolean shouldRecieve) { @@ -433,14 +494,18 @@ public class RenderNode { * Sets the outline, defining the shape that casts a shadow, and the path to * be clipped if setClipToOutline is set. * - * Deep copies the data into native to simplify reference ownership. + * This will make a copy of the provided {@link Outline}, so any future modifications + * to the outline will need to call {@link #setOutline(Outline)} with the modified + * outline for those changes to be applied. + * + * @param outline The outline to use for this RenderNode. */ public boolean setOutline(@Nullable Outline outline) { if (outline == null) { return nSetOutlineNone(mNativeRenderNode); } - switch(outline.mMode) { + switch (outline.mMode) { case Outline.MODE_EMPTY: return nSetOutlineEmpty(mNativeRenderNode); case Outline.MODE_ROUND_RECT: @@ -457,28 +522,63 @@ public class RenderNode { } /** + * Checks if the RenderNode has a shadow. That is, if the combination of {@link #getElevation()} + * and {@link #getTranslationZ()} is greater than zero, there is an {@link Outline} set with + * a valid shadow caster path, and the provided outline has a non-zero + * {@link Outline#getAlpha()}. + * * @return True if this RenderNode has a shadow, false otherwise */ public boolean hasShadow() { return nHasShadow(mNativeRenderNode); } - /** setSpotShadowColor */ + /** + * Sets the color of the spot shadow that is drawn when the RenderNode has a positive Z or + * elevation value and is drawn inside of a {@link Canvas#enableZ()} section. + * <p> + * By default the shadow color is black. Generally, this color will be opaque so the intensity + * of the shadow is consistent between different RenderNodes with different colors. + * <p> + * The opacity of the final spot shadow is a function of the shadow caster height, the + * alpha channel of the outlineSpotShadowColor (typically opaque), and the + * {@link android.R.attr#spotShadowAlpha} theme attribute + * + * @param color The color this RenderNode will cast for its elevation spot shadow. + */ public boolean setSpotShadowColor(int color) { return nSetSpotShadowColor(mNativeRenderNode, color); } - /** setAmbientShadowColor */ - public boolean setAmbientShadowColor(int color) { - return nSetAmbientShadowColor(mNativeRenderNode, color); - } - - /** getSpotShadowColor */ + /** + * @return The shadow color set by {@link #setSpotShadowColor(int)}, or black if nothing + * was set + */ public int getSpotShadowColor() { return nGetSpotShadowColor(mNativeRenderNode); } - /** getAmbientShadowColor */ + /** + * Sets the color of the ambient shadow that is drawn when the RenderNode has a positive Z or + * elevation value and is drawn inside of a {@link Canvas#enableZ()} section. + * <p> + * By default the shadow color is black. Generally, this color will be opaque so the intensity + * of the shadow is consistent between different RenderNodes with different colors. + * <p> + * The opacity of the final ambient shadow is a function of the shadow caster height, the + * alpha channel of the outlineAmbientShadowColor (typically opaque), and the + * {@link android.R.attr#ambientShadowAlpha} theme attribute. + * + * @param color The color this RenderNode will cast for its elevation shadow. + */ + public boolean setAmbientShadowColor(int color) { + return nSetAmbientShadowColor(mNativeRenderNode, color); + } + + /** + * @return The shadow color set by {@link #setAmbientShadowColor(int)}, or black if + * nothing was set + */ public int getAmbientShadowColor() { return nGetAmbientShadowColor(mNativeRenderNode); } @@ -503,6 +603,8 @@ public class RenderNode { /** * Controls the RenderNode's circular reveal clip. + * + * @hide */ public boolean setRevealClip(boolean shouldClip, float x, float y, float radius) { @@ -514,6 +616,7 @@ public class RenderNode { * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.) * * @param matrix A transform matrix to apply to this display list + * @hide TODO Do we want this? */ public boolean setStaticMatrix(Matrix matrix) { return nSetStaticMatrix(mNativeRenderNode, matrix.native_instance); @@ -526,6 +629,7 @@ public class RenderNode { * for the matrix parameter. * * @param matrix The matrix, null indicates that the matrix should be cleared. + * @hide TODO Do we want this? */ public boolean setAnimationMatrix(Matrix matrix) { return nSetAnimationMatrix(mNativeRenderNode, @@ -536,7 +640,6 @@ public class RenderNode { * Sets the translucency level for the display list. * * @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f - * * @see View#setAlpha(float) * @see #getAlpha() */ @@ -548,7 +651,6 @@ public class RenderNode { * Returns the translucency level of this display list. * * @return A value between 0.0f and 1.0f - * * @see #setAlpha(float) */ public float getAlpha() { @@ -562,7 +664,6 @@ public class RenderNode { * * @param hasOverlappingRendering False if the content is guaranteed to be non-overlapping, * true otherwise. - * * @see android.view.View#hasOverlappingRendering() * @see #hasOverlappingRendering() */ @@ -573,17 +674,28 @@ public class RenderNode { /** @hide */ @IntDef({USAGE_BACKGROUND}) @Retention(RetentionPolicy.SOURCE) - public @interface UsageHint {} + public @interface UsageHint { + } - /** The default usage hint */ + /** + * The default usage hint + * + * @hide + */ public static final int USAGE_UNKNOWN = 0; - /** Usage is background content */ + /** + * Usage is background content + * + * @hide + */ public static final int USAGE_BACKGROUND = 1; /** * Provides a hint on what this RenderNode's display list content contains. This hint is used * for automatic content transforms to improve accessibility or similar. + * + * @hide */ public void setUsageHint(@UsageHint int usageHint) { nSetUsageHint(mNativeRenderNode, usageHint); @@ -593,7 +705,6 @@ public class RenderNode { * Indicates whether the content of this display list overlaps. * * @return True if this display list renders content which overlaps, false otherwise. - * * @see #setHasOverlappingRendering(boolean) */ public boolean hasOverlappingRendering() { @@ -623,7 +734,6 @@ public class RenderNode { * Sets the translation value for the display list on the X axis. * * @param translationX The X axis translation value of the display list, in pixels - * * @see View#setTranslationX(float) * @see #getTranslationX() */ @@ -644,7 +754,6 @@ public class RenderNode { * Sets the translation value for the display list on the Y axis. * * @param translationY The Y axis translation value of the display list, in pixels - * * @see View#setTranslationY(float) * @see #getTranslationY() */ @@ -684,7 +793,6 @@ public class RenderNode { * Sets the rotation value for the display list around the Z axis. * * @param rotation The rotation value of the display list, in degrees - * * @see View#setRotation(float) * @see #getRotation() */ @@ -705,7 +813,6 @@ public class RenderNode { * Sets the rotation value for the display list around the X axis. * * @param rotationX The rotation value of the display list, in degrees - * * @see View#setRotationX(float) * @see #getRotationX() */ @@ -726,7 +833,6 @@ public class RenderNode { * Sets the rotation value for the display list around the Y axis. * * @param rotationY The rotation value of the display list, in degrees - * * @see View#setRotationY(float) * @see #getRotationY() */ @@ -747,7 +853,6 @@ public class RenderNode { * Sets the scale value for the display list on the X axis. * * @param scaleX The scale value of the display list - * * @see View#setScaleX(float) * @see #getScaleX() */ @@ -768,7 +873,6 @@ public class RenderNode { * Sets the scale value for the display list on the Y axis. * * @param scaleY The scale value of the display list - * * @see View#setScaleY(float) * @see #getScaleY() */ @@ -789,7 +893,6 @@ public class RenderNode { * Sets the pivot value for the display list on the X axis * * @param pivotX The pivot value of the display list on the X axis, in pixels - * * @see View#setPivotX(float) * @see #getPivotX() */ @@ -810,7 +913,6 @@ public class RenderNode { * Sets the pivot value for the display list on the Y axis * * @param pivotY The pivot value of the display list on the Y axis, in pixels - * * @see View#setPivotY(float) * @see #getPivotY() */ @@ -827,135 +929,222 @@ public class RenderNode { return nGetPivotY(mNativeRenderNode); } + /** + * @return Whether or not a pivot was explicitly set with {@link #setPivotX(float)} or + * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center + * of the RenderNode. + */ public boolean isPivotExplicitlySet() { return nIsPivotExplicitlySet(mNativeRenderNode); } - /** lint */ + /** + * Clears any pivot previously set by a call to {@link #setPivotX(float)} or + * {@link #setPivotY(float)}. After calling this {@link #isPivotExplicitlySet()} will be false + * and the pivot used for rotation will return to default of being centered on the view. + */ public boolean resetPivot() { return nResetPivot(mNativeRenderNode); } /** - * Sets the camera distance for the display list. Refer to - * {@link View#setCameraDistance(float)} for more information on how to - * use this property. + * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which + * RenderNodes are drawn) from the camera to this RenderNode. The camera's distance + * affects 3D transformations, for instance rotations around the X and Y + * axis. If the rotationX or rotationY properties are changed and this view is + * large (more than half the size of the screen), it is recommended to always + * use a camera distance that's greater than the height (X axis rotation) or + * the width (Y axis rotation) of this view.</p> + * + * <p>The distance of the camera from the drawing plane can have an affect on the + * perspective distortion of the RenderNode when it is rotated around the x or y axis. + * For example, a large distance will result in a large viewing angle, and there + * will not be much perspective distortion of the view as it rotates. A short + * distance may cause much more perspective distortion upon rotation, and can + * also result in some drawing artifacts if the rotated view ends up partially + * behind the camera (which is why the recommendation is to use a distance at + * least as far as the size of the view, if the view is to be rotated.)</p> * - * @param distance The distance in Z of the camera of the display list + * <p>The distance is expressed in pixels and must always be positive</p> * - * @see View#setCameraDistance(float) - * @see #getCameraDistance() + * @param distance The distance in pixels, must always be positive + * @see #setRotationX(float) + * @see #setRotationY(float) */ public boolean setCameraDistance(float distance) { - return nSetCameraDistance(mNativeRenderNode, distance); + if (!Float.isFinite(distance) || distance < 0.0f) { + throw new IllegalArgumentException("distance must be finite & positive, given=" + + distance); + } + // Native actually wants this to be negative not positive, so we flip it. + return nSetCameraDistance(mNativeRenderNode, -distance); } /** - * Returns the distance in Z of the camera of the display list. + * Returns the distance in Z of the camera for this RenderNode * + * @return the distance along the Z axis in pixels. * @see #setCameraDistance(float) */ public float getCameraDistance() { - return nGetCameraDistance(mNativeRenderNode); + return -nGetCameraDistance(mNativeRenderNode); } /** - * Sets the left position for the display list. + * Sets the left position for the RenderNode. * - * @param left The left position, in pixels, of the display list - * - * @see View#setLeft(int) + * @param left The left position, in pixels, of the RenderNode + * @return true if the value changed, false otherwise */ public boolean setLeft(int left) { return nSetLeft(mNativeRenderNode, left); } /** - * Sets the top position for the display list. - * - * @param top The top position, in pixels, of the display list + * Sets the top position for the RenderNode. * - * @see View#setTop(int) + * @param top The top position, in pixels, of the RenderNode + * @return true if the value changed, false otherwise. */ public boolean setTop(int top) { return nSetTop(mNativeRenderNode, top); } /** - * Sets the right position for the display list. - * - * @param right The right position, in pixels, of the display list + * Sets the right position for the RenderNode. * - * @see View#setRight(int) + * @param right The right position, in pixels, of the RenderNode + * @return true if the value changed, false otherwise. */ public boolean setRight(int right) { return nSetRight(mNativeRenderNode, right); } /** - * Sets the bottom position for the display list. + * Sets the bottom position for the RenderNode. * - * @param bottom The bottom position, in pixels, of the display list - * - * @see View#setBottom(int) + * @param bottom The bottom position, in pixels, of the RenderNode + * @return true if the value changed, false otherwise. */ public boolean setBottom(int bottom) { return nSetBottom(mNativeRenderNode, bottom); } /** - * Sets the left and top positions for the display list + * Gets the left position for the RenderNode. + * + * See {@link #setLeft(int)} + * + * @return the left position in pixels + */ + public int getLeft() { + return nGetLeft(mNativeRenderNode); + } + + /** + * Gets the top position for the RenderNode. + * + * See {@link #setTop(int)} + * + * @return the top position in pixels + */ + public int getTop() { + return nGetTop(mNativeRenderNode); + } + + /** + * Gets the right position for the RenderNode. + * + * See {@link #setRight(int)} + * + * @return the right position in pixels + */ + public int getRight() { + return nGetRight(mNativeRenderNode); + } + + /** + * Gets the bottom position for the RenderNode. + * + * See {@link #setBottom(int)} + * + * @return the bottom position in pixels + */ + public int getBottom() { + return nGetBottom(mNativeRenderNode); + } + + /** + * Gets the width of the RenderNode, which is the right - left. * - * @param left The left position of the display list, in pixels - * @param top The top position of the display list, in pixels - * @param right The right position of the display list, in pixels - * @param bottom The bottom position of the display list, in pixels + * @return the width of the RenderNode + */ + public int getWidth() { + return nGetWidth(mNativeRenderNode); + } + + /** + * Gets the height of the RenderNode, which is the bottom - top. * - * @see View#setLeft(int) - * @see View#setTop(int) - * @see View#setRight(int) - * @see View#setBottom(int) + * @return the height of the RenderNode + */ + public int getHeight() { + return nGetHeight(mNativeRenderNode); + } + + /** + * Sets the left, top, right, and bottom of the RenderNode. + * + * @param left The left position of the RenderNode, in pixels + * @param top The top position of the RenderNode, in pixels + * @param right The right position of the RenderNode, in pixels + * @param bottom The bottom position of the RenderNode, in pixels + * @return true if any values changed, false otherwise. + * @see #setLeft(int) + * @see #setTop(int) + * @see #setRight(int) + * @see #setBottom(int) */ public boolean setLeftTopRightBottom(int left, int top, int right, int bottom) { return nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom); } /** - * Offsets the left and right positions for the display list + * Offsets the left and right positions for the RenderNode * - * @param offset The amount that the left and right positions of the display - * list are offset, in pixels - * - * @see View#offsetLeftAndRight(int) + * @param offset The amount that the left and right positions are offset in pixels + * @return true if any values changed, false otherwise. */ public boolean offsetLeftAndRight(int offset) { return nOffsetLeftAndRight(mNativeRenderNode, offset); } /** - * Offsets the top and bottom values for the display list - * - * @param offset The amount that the top and bottom positions of the display - * list are offset, in pixels + * Offsets the top and bottom values for the RenderNode * - * @see View#offsetTopAndBottom(int) + * @param offset The amount that the left and right positions are offset in pixels + * @return true if any values changed, false otherwise. */ public boolean offsetTopAndBottom(int offset) { return nOffsetTopAndBottom(mNativeRenderNode, offset); } /** - * Outputs the display list to the log. This method exists for use by + * Outputs the RenderNode to the log. This method exists for use by * tools to output display lists for selected nodes to the log. + * + * @hide TODO: Expose? Should the shape of this be different than forced dump to logcat? */ public void output() { nOutput(mNativeRenderNode); } /** - * Gets the size of the DisplayList for debug purposes. + * Gets the approximate memory usage of the RenderNode for debug purposes. Does not include + * the memory usage of any child RenderNodes nor any bitmaps, only the memory usage of + * this RenderNode and any data it owns. */ - public int getDebugSize() { + public int computeApproximateMemoryUsage() { return nGetDebugSize(mNativeRenderNode); } @@ -995,13 +1184,16 @@ public class RenderNode { * For now this interface exists to de-couple RenderNode from anything View-specific in a * bit of a kludge. * - * @hide */ + * @hide + */ public interface AnimationHost { - /** checkstyle */ + /** @hide */ void registerAnimatingRenderNode(RenderNode animator); - /** checkstyle */ + + /** @hide */ void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator); - /** checkstyle */ + + /** @hide */ boolean isAttached(); } @@ -1039,14 +1231,18 @@ public class RenderNode { private static native long nCreate(String name); private static native long nGetNativeFinalizer(); + private static native void nOutput(long renderNode); + private static native int nGetDebugSize(long renderNode); + private static native void nRequestPositionUpdates(long renderNode, PositionUpdateListener callback); // Animations private static native void nAddAnimator(long renderNode, long animatorPtr); + private static native void nEndAllAnimators(long renderNode); @@ -1069,8 +1265,10 @@ public class RenderNode { @CriticalNative private static native void nGetTransformMatrix(long renderNode, long nativeMatrix); + @CriticalNative private static native void nGetInverseTransformMatrix(long renderNode, long nativeMatrix); + @CriticalNative private static native boolean nHasIdentityMatrix(long renderNode); @@ -1078,135 +1276,208 @@ public class RenderNode { @CriticalNative private static native boolean nOffsetTopAndBottom(long renderNode, int offset); + @CriticalNative private static native boolean nOffsetLeftAndRight(long renderNode, int offset); + @CriticalNative private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top, int right, int bottom); + @CriticalNative - private static native boolean nSetBottom(long renderNode, int bottom); + private static native boolean nSetLeft(long renderNode, int left); + + @CriticalNative + private static native boolean nSetTop(long renderNode, int top); + @CriticalNative private static native boolean nSetRight(long renderNode, int right); + @CriticalNative - private static native boolean nSetTop(long renderNode, int top); + private static native boolean nSetBottom(long renderNode, int bottom); + @CriticalNative - private static native boolean nSetLeft(long renderNode, int left); + private static native int nGetLeft(long renderNode); + + @CriticalNative + private static native int nGetTop(long renderNode); + + @CriticalNative + private static native int nGetRight(long renderNode); + + @CriticalNative + private static native int nGetBottom(long renderNode); + @CriticalNative private static native boolean nSetCameraDistance(long renderNode, float distance); + @CriticalNative private static native boolean nSetPivotY(long renderNode, float pivotY); + @CriticalNative private static native boolean nSetPivotX(long renderNode, float pivotX); + @CriticalNative private static native boolean nResetPivot(long renderNode); + @CriticalNative private static native boolean nSetLayerType(long renderNode, int layerType); + @CriticalNative private static native boolean nSetLayerPaint(long renderNode, long paint); + @CriticalNative private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds); + @CriticalNative private static native boolean nSetClipBounds(long renderNode, int left, int top, int right, int bottom); + @CriticalNative private static native boolean nSetClipBoundsEmpty(long renderNode); + @CriticalNative private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject); + @CriticalNative private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve); + @CriticalNative private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top, int right, int bottom, float radius, float alpha); + @CriticalNative private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath, float alpha); + @CriticalNative private static native boolean nSetOutlineEmpty(long renderNode); + @CriticalNative private static native boolean nSetOutlineNone(long renderNode); + @CriticalNative private static native boolean nHasShadow(long renderNode); + @CriticalNative private static native boolean nSetSpotShadowColor(long renderNode, int color); + @CriticalNative private static native boolean nSetAmbientShadowColor(long renderNode, int color); + @CriticalNative private static native int nGetSpotShadowColor(long renderNode); + @CriticalNative private static native int nGetAmbientShadowColor(long renderNode); + @CriticalNative private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline); + @CriticalNative private static native boolean nSetRevealClip(long renderNode, boolean shouldClip, float x, float y, float radius); + @CriticalNative private static native boolean nSetAlpha(long renderNode, float alpha); + @CriticalNative private static native boolean nSetHasOverlappingRendering(long renderNode, boolean hasOverlappingRendering); + @CriticalNative private static native void nSetUsageHint(long renderNode, int usageHint); + @CriticalNative private static native boolean nSetElevation(long renderNode, float lift); + @CriticalNative private static native boolean nSetTranslationX(long renderNode, float translationX); + @CriticalNative private static native boolean nSetTranslationY(long renderNode, float translationY); + @CriticalNative private static native boolean nSetTranslationZ(long renderNode, float translationZ); + @CriticalNative private static native boolean nSetRotation(long renderNode, float rotation); + @CriticalNative private static native boolean nSetRotationX(long renderNode, float rotationX); + @CriticalNative private static native boolean nSetRotationY(long renderNode, float rotationY); + @CriticalNative private static native boolean nSetScaleX(long renderNode, float scaleX); + @CriticalNative private static native boolean nSetScaleY(long renderNode, float scaleY); + @CriticalNative private static native boolean nSetStaticMatrix(long renderNode, long nativeMatrix); + @CriticalNative private static native boolean nSetAnimationMatrix(long renderNode, long animationMatrix); @CriticalNative private static native boolean nHasOverlappingRendering(long renderNode); + @CriticalNative private static native boolean nGetClipToOutline(long renderNode); + @CriticalNative private static native float nGetAlpha(long renderNode); + @CriticalNative private static native float nGetCameraDistance(long renderNode); + @CriticalNative private static native float nGetScaleX(long renderNode); + @CriticalNative private static native float nGetScaleY(long renderNode); + @CriticalNative private static native float nGetElevation(long renderNode); + @CriticalNative private static native float nGetTranslationX(long renderNode); + @CriticalNative private static native float nGetTranslationY(long renderNode); + @CriticalNative private static native float nGetTranslationZ(long renderNode); + @CriticalNative private static native float nGetRotation(long renderNode); + @CriticalNative private static native float nGetRotationX(long renderNode); + @CriticalNative private static native float nGetRotationY(long renderNode); + @CriticalNative private static native boolean nIsPivotExplicitlySet(long renderNode); + @CriticalNative private static native float nGetPivotX(long renderNode); + @CriticalNative private static native float nGetPivotY(long renderNode); + @CriticalNative private static native int nGetWidth(long renderNode); + @CriticalNative private static native int nGetHeight(long renderNode); + @CriticalNative private static native boolean nSetAllowForceDark(long renderNode, boolean allowForceDark); + @CriticalNative private static native boolean nGetAllowForceDark(long renderNode); } diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 5c0c38ee7666..7e8bfb300c1a 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -27,10 +27,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; +import android.graphics.fonts.Font; +import android.graphics.fonts.FontFamily; import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.graphics.fonts.SystemFonts; -import android.net.Uri; import android.os.Build; import android.provider.FontRequest; import android.provider.FontsContract; @@ -50,13 +51,10 @@ import libcore.util.NativeAllocationRegistry; import java.io.File; import java.io.FileDescriptor; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -126,7 +124,8 @@ public class Typeface { // We cannot support sSystemFallbackMap since we will migrate to public FontFamily API. @UnsupportedAppUsage - static final Map<String, FontFamily[]> sSystemFallbackMap = Collections.emptyMap(); + static final Map<String, android.graphics.FontFamily[]> sSystemFallbackMap = + Collections.emptyMap(); /** * @hide @@ -164,6 +163,9 @@ public class Typeface { private int[] mSupportedAxes; private static final int[] EMPTY_AXES = {}; + // The underlying font families. + private final FontFamily[] mFamilies; + @UnsupportedAppUsage private static void setDefault(Typeface t) { sDefaultTypeface = t; @@ -192,38 +194,6 @@ public class Typeface { /** * @hide - * Used by Resources to load a font resource of type font file. - */ - @Nullable - public static Typeface createFromResources(AssetManager mgr, String path, int cookie) { - synchronized (sDynamicCacheLock) { - final String key = Builder.createAssetUid( - mgr, path, 0 /* ttcIndex */, null /* axes */, - RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */, - DEFAULT_FAMILY); - Typeface typeface = sDynamicTypefaceCache.get(key); - if (typeface != null) return typeface; - - FontFamily fontFamily = new FontFamily(); - // TODO: introduce ttc index and variation settings to resource type font. - if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */, - 0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */, - RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) { - if (!fontFamily.freeze()) { - return null; - } - FontFamily[] families = {fontFamily}; - typeface = createFromFamiliesWithDefault(families, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); - sDynamicTypefaceCache.put(key, typeface); - return typeface; - } - } - return null; - } - - /** - * @hide * Used by Resources to load a font resource of type xml. */ @Nullable @@ -258,21 +228,34 @@ public class Typeface { // family is FontFamilyFilesResourceEntry final FontFamilyFilesResourceEntry filesEntry = (FontFamilyFilesResourceEntry) entry; - FontFamily fontFamily = new FontFamily(); - for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) { - if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(), - 0 /* resourceCookie */, false /* isAsset */, fontFile.getTtcIndex(), - fontFile.getWeight(), fontFile.getItalic(), - FontVariationAxis.fromFontVariationSettings(fontFile.getVariationSettings()))) { - return null; + try { + FontFamily.Builder familyBuilder = null; + for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) { + final Font.Builder fontBuilder = new Font.Builder(mgr, fontFile.getFileName(), + false /* isAsset */, 0 /* cookie */) + .setTtcIndex(fontFile.getTtcIndex()) + .setFontVariationSettings(fontFile.getVariationSettings()); + if (fontFile.getWeight() != Typeface.RESOLVE_BY_FONT_TABLE) { + fontBuilder.setWeight(fontFile.getWeight()); + } + if (fontFile.getItalic() != Typeface.RESOLVE_BY_FONT_TABLE) { + fontBuilder.setSlant(fontFile.getItalic() == FontFileResourceEntry.ITALIC + ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT); + } + + if (familyBuilder == null) { + familyBuilder = new FontFamily.Builder(fontBuilder.build()); + } else { + familyBuilder.addFont(fontBuilder.build()); + } } + if (familyBuilder == null) { + return Typeface.DEFAULT; + } + typeface = new Typeface.CustomFallbackBuilder(familyBuilder.build()).build(); + } catch (IOException e) { + typeface = Typeface.DEFAULT; } - if (!fontFamily.freeze()) { - return null; - } - FontFamily[] familyChain = { fontFamily }; - typeface = createFromFamiliesWithDefault(familyChain, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); synchronized (sDynamicCacheLock) { final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */, @@ -339,15 +322,11 @@ public class Typeface { /** @hide */ public static final int BOLD_WEIGHT = 700; - private int mTtcIndex; - private FontVariationAxis[] mAxes; - - private AssetManager mAssetManager; - private String mPath; - private FileDescriptor mFd; + // Kept for generating asset cache key. + private final AssetManager mAssetManager; + private final String mPath; - private FontsContract.FontInfo[] mFonts; - private Map<Uri, ByteBuffer> mFontBuffers; + private final Font.Builder mFontBuilder; private String mFallbackFamilyName; @@ -360,7 +339,9 @@ public class Typeface { * @param path The file object refers to the font file. */ public Builder(@NonNull File path) { - mPath = path.getAbsolutePath(); + mFontBuilder = new Font.Builder(path); + mAssetManager = null; + mPath = null; } /** @@ -372,7 +353,9 @@ public class Typeface { * @param fd The file descriptor. The passed fd must be mmap-able. */ public Builder(@NonNull FileDescriptor fd) { - mFd = fd; + mFontBuilder = new Font.Builder(fd); + mAssetManager = null; + mPath = null; } /** @@ -381,7 +364,9 @@ public class Typeface { * @param path The full path to the font file. */ public Builder(@NonNull String path) { - mPath = path; + mFontBuilder = new Font.Builder(new File(path)); + mAssetManager = null; + mPath = null; } /** @@ -391,27 +376,22 @@ public class Typeface { * @param path The file name of the font data in the asset directory */ public Builder(@NonNull AssetManager assetManager, @NonNull String path) { - mAssetManager = Preconditions.checkNotNull(assetManager); - mPath = Preconditions.checkStringNotEmpty(path); + this(assetManager, path, true /* is asset */, 0 /* cookie */); } /** - * Constracts a builder from an array of FontsContract.FontInfo. - * - * Since {@link FontsContract.FontInfo} holds information about TTC indices and - * variation settings, there is no need to call {@link #setTtcIndex} or - * {@link #setFontVariationSettings}. Similary, {@link FontsContract.FontInfo} holds - * weight and italic information, so {@link #setWeight} and {@link #setItalic} are used - * for style matching during font selection. + * Constructs a builder from an asset manager and a file path in an asset directory. * - * @param fonts The array of {@link FontsContract.FontInfo} - * @param buffers The mapping from URI to buffers to be used during building. + * @param assetManager The application's asset manager + * @param path The file name of the font data in the asset directory + * @param cookie a cookie for the asset * @hide */ - public Builder(@NonNull FontsContract.FontInfo[] fonts, - @NonNull Map<Uri, ByteBuffer> buffers) { - mFonts = fonts; - mFontBuffers = buffers; + public Builder(@NonNull AssetManager assetManager, @NonNull String path, boolean isAsset, + int cookie) { + mFontBuilder = new Font.Builder(assetManager, path, isAsset, cookie); + mAssetManager = assetManager; + mPath = path; } /** @@ -423,6 +403,7 @@ public class Typeface { */ public Builder setWeight(@IntRange(from = 1, to = 1000) int weight) { mWeight = weight; + mFontBuilder.setWeight(weight); return this; } @@ -434,7 +415,8 @@ public class Typeface { * @param italic {@code true} if the font is italic. Otherwise {@code false}. */ public Builder setItalic(boolean italic) { - mItalic = italic ? STYLE_ITALIC : STYLE_NORMAL; + mItalic = italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT; + mFontBuilder.setSlant(mItalic); return this; } @@ -446,11 +428,7 @@ public class Typeface { * collection, do not call this method or specify 0. */ public Builder setTtcIndex(@IntRange(from = 0) int ttcIndex) { - if (mFonts != null) { - throw new IllegalArgumentException( - "TTC index can not be specified for FontResult source."); - } - mTtcIndex = ttcIndex; + mFontBuilder.setTtcIndex(ttcIndex); return this; } @@ -462,14 +440,7 @@ public class Typeface { * format. */ public Builder setFontVariationSettings(@Nullable String variationSettings) { - if (mFonts != null) { - throw new IllegalArgumentException( - "Font variation settings can not be specified for FontResult source."); - } - if (mAxes != null) { - throw new IllegalStateException("Font variation settings are already set."); - } - mAxes = FontVariationAxis.fromFontVariationSettings(variationSettings); + mFontBuilder.setFontVariationSettings(variationSettings); return this; } @@ -479,14 +450,7 @@ public class Typeface { * @param axes An array of font variation axis tag-value pairs. */ public Builder setFontVariationSettings(@Nullable FontVariationAxis[] axes) { - if (mFonts != null) { - throw new IllegalArgumentException( - "Font variation settings can not be specified for FontResult source."); - } - if (mAxes != null) { - throw new IllegalStateException("Font variation settings are already set."); - } - mAxes = axes; + mFontBuilder.setFontVariationSettings(axes); return this; } @@ -579,97 +543,55 @@ public class Typeface { * @return Newly created Typeface. May return null if some parameters are invalid. */ public Typeface build() { - if (mFd != null) { // Builder is created with file descriptor. - try (FileInputStream fis = new FileInputStream(mFd)) { - FileChannel channel = fis.getChannel(); - long size = channel.size(); - ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size); - - final FontFamily fontFamily = new FontFamily(); - if (!fontFamily.addFontFromBuffer(buffer, mTtcIndex, mAxes, mWeight, mItalic)) { - fontFamily.abortCreation(); - return resolveFallbackTypeface(); - } - if (!fontFamily.freeze()) { - return resolveFallbackTypeface(); - } - FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight, - mItalic); - } catch (IOException e) { - return resolveFallbackTypeface(); - } - } else if (mAssetManager != null) { // Builder is created with asset manager. - final String key = createAssetUid( - mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic, + try { + final Font font = mFontBuilder.build(); + final String key = mAssetManager == null ? null : createAssetUid( + mAssetManager, mPath, font.getTtcIndex(), font.getAxes(), + font.getStyle().getWeight(), font.getStyle().getSlant(), mFallbackFamilyName); - synchronized (sDynamicCacheLock) { - Typeface typeface = sDynamicTypefaceCache.get(key); - if (typeface != null) return typeface; - final FontFamily fontFamily = new FontFamily(); - if (!fontFamily.addFontFromAssetManager(mAssetManager, mPath, mTtcIndex, - true /* isAsset */, mTtcIndex, mWeight, mItalic, mAxes)) { - fontFamily.abortCreation(); - return resolveFallbackTypeface(); - } - if (!fontFamily.freeze()) { - return resolveFallbackTypeface(); + if (key != null) { + // Dynamic cache lookup is only for assets. + synchronized (sDynamicCacheLock) { + final Typeface typeface = sDynamicTypefaceCache.get(key); + if (typeface != null) { + return typeface; + } } - FontFamily[] families = { fontFamily }; - typeface = createFromFamiliesWithDefault(families, mFallbackFamilyName, - mWeight, mItalic); - sDynamicTypefaceCache.put(key, typeface); - return typeface; - } - } else if (mPath != null) { // Builder is created with file path. - final FontFamily fontFamily = new FontFamily(); - if (!fontFamily.addFont(mPath, mTtcIndex, mAxes, mWeight, mItalic)) { - fontFamily.abortCreation(); - return resolveFallbackTypeface(); } - if (!fontFamily.freeze()) { - return resolveFallbackTypeface(); + final FontFamily family = new FontFamily.Builder(font).build(); + final int weight = mWeight == RESOLVE_BY_FONT_TABLE + ? font.getStyle().getWeight() : mWeight; + final int slant = mItalic == RESOLVE_BY_FONT_TABLE + ? font.getStyle().getSlant() : mItalic; + final CustomFallbackBuilder builder = new CustomFallbackBuilder(family) + .setStyle(new FontStyle(weight, slant)); + if (mFallbackFamilyName != null) { + builder.setSystemFallback(mFallbackFamilyName); } - FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight, - mItalic); - } else if (mFonts != null) { - final FontFamily fontFamily = new FontFamily(); - boolean atLeastOneFont = false; - for (FontsContract.FontInfo font : mFonts) { - final ByteBuffer fontBuffer = mFontBuffers.get(font.getUri()); - if (fontBuffer == null) { - continue; // skip + final Typeface typeface = builder.build(); + if (key != null) { + synchronized (sDynamicCacheLock) { + sDynamicTypefaceCache.put(key, typeface); } - final boolean success = fontFamily.addFontFromBuffer(fontBuffer, - font.getTtcIndex(), font.getAxes(), font.getWeight(), - font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL); - if (!success) { - fontFamily.abortCreation(); - return null; - } - atLeastOneFont = true; - } - if (!atLeastOneFont) { - // No fonts are avaialble. No need to create new Typeface and returns fallback - // Typeface instead. - fontFamily.abortCreation(); - return null; } - fontFamily.freeze(); - FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight, - mItalic); + return typeface; + } catch (IOException | IllegalArgumentException e) { + return resolveFallbackTypeface(); } - - // Must not reach here. - throw new IllegalArgumentException("No source was set."); } } /** * A builder class for creating new Typeface instance. * + * There are two font fallback mechanisms, custom font fallback and system font fallback. + * The custom font fallback is a simple ordered list. The text renderer tries to see if it can + * render a character with the first font and if that font does not support the character, try + * next one and so on. It will keep trying until end of the custom fallback chain. The maximum + * length of the custom fallback chain is 64. + * The system font fallback is a system pre-defined fallback chain. The system fallback is + * processed only when no matching font is found in the custom font fallback. + * * <p> * Examples, * 1) Create Typeface from single ttf file. @@ -703,72 +625,85 @@ public class Typeface { * Font font = new Font.Builder("your_font_file.ttf").build(); * FontFamily family = new FontFamily.Builder(font).build(); * Typeface typeface = new Typeface.CustomFallbackBuilder(family) - * .setFallback("serif") // Set serif font family as the fallback. + * .setSystemFallback("serif") // Set serif font family as the fallback. + * .build(); + * </code> + * </pre> + * 4) Create Typeface from single ttf file and set another ttf file for the fallback. + * <pre> + * <code> + * Font font = new Font.Builder("English.ttf").build(); + * FontFamily family = new FontFamily.Builder(font).build(); + * + * Font fallbackFont = new Font.Builder("Arabic.ttf").build(); + * FontFamily fallbackFamily = new FontFamily.Builder(fallbackFont).build(); + * Typeface typeface = new Typeface.CustomFallbackBuilder(family) + * .addCustomFallback(fallbackFamily) // Specify fallback family. + * .setSystemFallback("serif") // Set serif font family as the fallback. * .build(); * </code> * </pre> * </p> */ public static class CustomFallbackBuilder { - // TODO: Remove package modifier once android.graphics.FontFamily is deprecated. - private final android.graphics.fonts.FontFamily mFamily; + private static final int MAX_CUSTOM_FALLBACK = 64; + private final ArrayList<FontFamily> mFamilies = new ArrayList<>(); private String mFallbackName = null; - private @IntRange(from = 0, to = 1000) int mWeight = 400; - private boolean mItalic = false; + private @Nullable FontStyle mStyle; /** * Constructs a builder with a font family. * * @param family a family object */ - // TODO: Remove package modifier once android.graphics.FontFamily is deprecated. - public CustomFallbackBuilder(@NonNull android.graphics.fonts.FontFamily family) { + public CustomFallbackBuilder(@NonNull FontFamily family) { Preconditions.checkNotNull(family); - mFamily = family; + mFamilies.add(family); } /** * Sets a system fallback by name. * + * For more information about fallback, see class description. + * * @param familyName a family name to be used for fallback if the provided fonts can not be * used */ - public CustomFallbackBuilder setFallback(@NonNull String familyName) { + public CustomFallbackBuilder setSystemFallback(@NonNull String familyName) { Preconditions.checkNotNull(familyName); mFallbackName = familyName; return this; } /** - * Sets a weight of the Typeface. + * Sets a font style of the Typeface. * - * If the font family doesn't have a font of given weight, system will select the closest + * If the font family doesn't have a font of given style, system will select the closest * font from font family. For example, if a font family has fonts of 300 weight and 700 * weight then setWeight(400) is called, system will select the font of 300 weight. * - * @see Font#FONT_WEIGHT_THIN - * @see Font#FONT_WEIGHT_EXTRA_LIGHT - * @see Font#FONT_WEIGHT_LIGHT - * @see Font#FONT_WEIGHT_NORMAL - * @see Font#FONT_WEIGHT_MEDIUM - * @see Font#FONT_WEIGHT_SEMI_BOLD - * @see Font#FONT_WEIGHT_BOLD - * @see Font#FONT_WEIGHT_EXTRA_BOLD - * @see Font#FONT_WEIGHT_BLACK - * @param weight a weight value + * @param style a font style */ - public CustomFallbackBuilder setWeight(@IntRange(from = 0, to = 1000) int weight) { - mWeight = weight; + public CustomFallbackBuilder setStyle(@NonNull FontStyle style) { + mStyle = style; return this; } /** - * Sets a italic style of the Typeface. + * Append a font family to the end of the custom font fallback. + * + * You can set up to 64 custom fallback families including the first font family you passed + * to the constructor. + * For more information about fallback, see class description. * - * @param italic true if italic, otherwise false + * @param family a fallback family + * @throws IllegalArgumentException if you give more than 64 custom fallback families */ - public CustomFallbackBuilder setItalic(boolean italic) { - mItalic = italic; + public CustomFallbackBuilder addCustomFallback(@NonNull FontFamily family) { + Preconditions.checkNotNull(family); + Preconditions.checkArgument(mFamilies.size() < MAX_CUSTOM_FALLBACK, + "Custom fallback limit exceeded(" + MAX_CUSTOM_FALLBACK + ")"); + mFamilies.add(family); return this; } @@ -778,14 +713,23 @@ public class Typeface { * @return the Typeface object */ public Typeface build() { - final android.graphics.fonts.FontFamily[] fallback = - SystemFonts.getSystemFallback(mFallbackName); - final long[] ptrArray = new long[fallback.length + 1]; - ptrArray[0] = mFamily.getNativePtr(); + final int userFallbackSize = mFamilies.size(); + final FontFamily[] fallback = SystemFonts.getSystemFallback(mFallbackName); + final FontFamily[] fullFamilies = new FontFamily[fallback.length + userFallbackSize]; + final long[] ptrArray = new long[fallback.length + userFallbackSize]; + for (int i = 0; i < userFallbackSize; ++i) { + ptrArray[i] = mFamilies.get(i).getNativePtr(); + fullFamilies[i] = mFamilies.get(i); + } for (int i = 0; i < fallback.length; ++i) { - ptrArray[i + 1] = fallback[i].getNativePtr(); + ptrArray[i + userFallbackSize] = fallback[i].getNativePtr(); + fullFamilies[i + userFallbackSize] = fallback[i]; } - return new Typeface(nativeCreateFromArray(ptrArray, mWeight, mItalic ? 1 : 0)); + final int weight = mStyle == null ? 400 : mStyle.getWeight(); + final int italic = + (mStyle == null || mStyle.getSlant() == FontStyle.FONT_SLANT_UPRIGHT) ? 0 : 1; + + return new Typeface(nativeCreateFromArray(ptrArray, weight, italic), fullFamilies); } } @@ -850,7 +794,7 @@ public class Typeface { } } - typeface = new Typeface(nativeCreateFromTypeface(ni, style)); + typeface = new Typeface(nativeCreateFromTypeface(ni, style), family.mFamilies); styles.put(style, typeface); } return typeface; @@ -919,7 +863,7 @@ public class Typeface { typeface = new Typeface( nativeCreateFromTypefaceWithExactStyle( - base.native_instance, weight, italic)); + base.native_instance, weight, italic), base.mFamilies); innerCache.put(key, typeface); } return typeface; @@ -928,8 +872,9 @@ public class Typeface { /** @hide */ public static Typeface createFromTypefaceWithVariation(@Nullable Typeface family, @NonNull List<FontVariationAxis> axes) { - final long ni = family == null ? 0 : family.native_instance; - return new Typeface(nativeCreateFromTypefaceWithVariation(ni, axes)); + final Typeface base = family == null ? Typeface.DEFAULT : family; + return new Typeface(nativeCreateFromTypefaceWithVariation(base.native_instance, axes), + base.mFamilies); } /** @@ -1015,7 +960,7 @@ public class Typeface { */ @Deprecated @UnsupportedAppUsage - private static Typeface createFromFamilies(FontFamily[] families) { + private static Typeface createFromFamilies(android.graphics.FontFamily[] families) { long[] ptrArray = new long[families.length]; for (int i = 0; i < families.length; i++) { ptrArray[i] = families[i].mNativePtr; @@ -1029,14 +974,13 @@ public class Typeface { * * @param families array of font families */ - private static Typeface createFromFamilies( - @Nullable android.graphics.fonts.FontFamily[] families) { + private static Typeface createFromFamilies(@Nullable FontFamily[] families) { final long[] ptrArray = new long[families.length]; for (int i = 0; i < families.length; ++i) { ptrArray[i] = families[i].getNativePtr(); } return new Typeface(nativeCreateFromArray(ptrArray, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE), families); } /** @@ -1044,8 +988,8 @@ public class Typeface { * TODO: Remove private API use in supportlib: http://b/72665240 */ @UnsupportedAppUsage - private static Typeface createFromFamiliesWithDefault(FontFamily[] families, int weight, - int italic) { + private static Typeface createFromFamiliesWithDefault( + android.graphics.FontFamily[] families, int weight, int italic) { return createFromFamiliesWithDefault(families, DEFAULT_FAMILY, weight, italic); } @@ -1063,7 +1007,7 @@ public class Typeface { * @param families array of font families */ @UnsupportedAppUsage - private static Typeface createFromFamiliesWithDefault(FontFamily[] families, + private static Typeface createFromFamiliesWithDefault(android.graphics.FontFamily[] families, String fallbackName, int weight, int italic) { android.graphics.fonts.FontFamily[] fallback = SystemFonts.getSystemFallback(fallbackName); long[] ptrArray = new long[families.length + fallback.length]; @@ -1084,6 +1028,19 @@ public class Typeface { } native_instance = ni; + mFamilies = new FontFamily[0]; + sRegistry.registerNativeAllocation(this, native_instance); + mStyle = nativeGetStyle(ni); + mWeight = nativeGetWeight(ni); + } + + private Typeface(long ni, @NonNull FontFamily[] families) { + if (ni == 0) { + throw new IllegalStateException("native typeface cannot be made"); + } + + native_instance = ni; + mFamilies = families; sRegistry.registerNativeAllocation(this, native_instance); mStyle = nativeGetStyle(ni); mWeight = nativeGetWeight(ni); @@ -1097,9 +1054,9 @@ public class Typeface { /** @hide */ @VisibleForTesting public static void initSystemDefaultTypefaces(Map<String, Typeface> systemFontMap, - Map<String, android.graphics.fonts.FontFamily[]> fallbacks, + Map<String, FontFamily[]> fallbacks, FontConfig.Alias[] aliases) { - for (Map.Entry<String, android.graphics.fonts.FontFamily[]> entry : fallbacks.entrySet()) { + for (Map.Entry<String, FontFamily[]> entry : fallbacks.entrySet()) { systemFontMap.put(entry.getKey(), createFromFamilies(entry.getValue())); } @@ -1110,7 +1067,8 @@ public class Typeface { final Typeface base = systemFontMap.get(alias.getToName()); final int weight = alias.getWeight(); final Typeface newFace = weight == 400 ? base : - new Typeface(nativeCreateWeightAlias(base.native_instance, weight)); + new Typeface(nativeCreateWeightAlias(base.native_instance, weight), + base.mFamilies); systemFontMap.put(alias.getName(), newFace); } } diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index 0a8c68559c8c..7f165bfc6a7d 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -151,7 +151,21 @@ public final class Font { * @param path the file name of the font data in the asset directory */ public Builder(@NonNull AssetManager am, @NonNull String path) { - final long nativeAsset = nGetNativeAsset(am, path, true /* is asset */, 0 /* cookie */); + this(am, path, true /* is asset */, 0 /* cookie */); + } + + /** + * Constructs a builder from an asset manager and a file path in an asset directory. + * + * @param am the application's asset manager + * @param path the file name of the font data in the asset directory + * @param isAsset true if the undelying data is in asset + * @param cookie set asset cookie + * @hide + */ + public Builder(@NonNull AssetManager am, @NonNull String path, boolean isAsset, + int cookie) { + final long nativeAsset = nGetNativeAsset(am, path, isAsset, cookie); if (nativeAsset == 0) { mException = new FileNotFoundException("Unable to open " + path); return; @@ -293,7 +307,7 @@ public final class Font { * will resolve the style by reading font tables. * * For example, if you want to use italic font as upright font, call {@code - * setSlant(false)} explicitly. + * setSlant(FontStyle.FONT_SLANT_UPRIGHT)} explicitly. * * @return this builder */ @@ -447,23 +461,14 @@ public final class Font { } /** - * Get a weight value associated with this font. + * Get a style associated with this font. * * @see Builder#setWeight(int) - * @return a weight value - */ - public @IntRange(from = 0, to = 1000)int getWeight() { - return mFontStyle.getWeight(); - } - - /** - * Get a slant value associated with this font. - * - * @see Builder#setSlant(boolean) - * @return a slant value + * @see Builder#setSlant(int) + * @return a font style */ - public @FontStyle.FontSlant int getSlant() { - return mFontStyle.getSlant(); + public FontStyle getStyle() { + return mFontStyle; } /** diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java index 52a37da47cff..c0f1b163ea11 100644 --- a/graphics/java/android/graphics/fonts/FontFamily.java +++ b/graphics/java/android/graphics/fonts/FontFamily.java @@ -108,29 +108,31 @@ public final class FontFamily { * @return a font family */ public @NonNull FontFamily build() { - return build("", FontConfig.Family.VARIANT_DEFAULT); + return build("", FontConfig.Family.VARIANT_DEFAULT, true /* isCustomFallback */); } /** @hide */ - public @NonNull FontFamily build(@NonNull String langTags, int variant) { + public @NonNull FontFamily build(@NonNull String langTags, int variant, + boolean isCustomFallback) { final long builderPtr = nInitBuilder(); for (int i = 0; i < mFonts.size(); ++i) { nAddFont(builderPtr, mFonts.get(i).getNativePtr()); } - final long ptr = nBuild(builderPtr, langTags, variant); + final long ptr = nBuild(builderPtr, langTags, variant, isCustomFallback); final FontFamily family = new FontFamily(mFonts, ptr); sFamilyRegistory.registerNativeAllocation(family, ptr); return family; } private static int makeStyleIdentifier(@NonNull Font font) { - return font.getWeight() | (font.getSlant() << 16); + return font.getStyle().getWeight() | (font.getStyle().getSlant() << 16); } private static native long nInitBuilder(); @CriticalNative private static native void nAddFont(long builderPtr, long fontPtr); - private static native long nBuild(long builderPtr, String langTags, int variant); + private static native long nBuild(long builderPtr, String langTags, int variant, + boolean isCustomFallback); @CriticalNative private static native long nGetReleaseNativeFamily(); } diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 750adb2757c8..4a9cf14d04a5 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -208,7 +208,7 @@ public final class SystemFonts { b.addFont(font); } } - return b == null ? null : b.build(languageTags, variant); + return b == null ? null : b.build(languageTags, variant, false /* isCustomFallback */); } private static void appendNamedFamily(@NonNull FontConfig.Family xmlFamily, diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 04cc5bb30ade..9e6948878b1d 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -21,6 +21,7 @@ #include <algorithm> #include <iterator> #include <set> +#include <map> #include "android-base/logging.h" #include "android-base/stringprintf.h" @@ -161,6 +162,13 @@ void AssetManager2::DumpToLog() const { LOG(INFO) << base::StringPrintf("PG (%02x): ", package_group.dynamic_ref_table.mAssignedPackageId) << list; + + for (size_t i = 0; i < 256; i++) { + if (package_group.dynamic_ref_table.mLookupTable[i] != 0) { + LOG(INFO) << base::StringPrintf(" e[0x%02x] -> 0x%02x", (uint8_t) i, + package_group.dynamic_ref_table.mLookupTable[i]); + } + } } } @@ -869,6 +877,17 @@ void AssetManager2::InvalidateCaches(uint32_t diff) { } } +uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) { + for (auto& package_group : package_groups_) { + for (auto& package2 : package_group.packages_) { + if (package2.loaded_package_ == package) { + return package_group.dynamic_ref_table.mAssignedPackageId; + } + } + } + return 0; +} + std::unique_ptr<Theme> AssetManager2::NewTheme() { return std::unique_ptr<Theme>(new Theme(this)); } @@ -1054,44 +1073,231 @@ void Theme::Clear() { } } -bool Theme::SetTo(const Theme& o) { +void Theme::SetTo(const Theme& o) { if (this == &o) { - return true; + return; } type_spec_flags_ = o.type_spec_flags_; - const bool copy_only_system = asset_manager_ != o.asset_manager_; + if (asset_manager_ == o.asset_manager_) { + // The theme comes from the same asset manager so all theme data can be copied exactly + for (size_t p = 0; p < packages_.size(); p++) { + const Package *package = o.packages_[p].get(); + if (package == nullptr) { + // The other theme doesn't have this package, clear ours. + packages_[p].reset(); + continue; + } - for (size_t p = 0; p < packages_.size(); p++) { - const Package* package = o.packages_[p].get(); - if (package == nullptr || (copy_only_system && p != 0x01)) { - // The other theme doesn't have this package, clear ours. - packages_[p].reset(); - continue; + if (packages_[p] == nullptr) { + // The other theme has this package, but we don't. Make one. + packages_[p].reset(new Package()); + } + + for (size_t t = 0; t < package->types.size(); t++) { + const ThemeType *type = package->types[t].get(); + if (type == nullptr) { + // The other theme doesn't have this type, clear ours. + packages_[p]->types[t].reset(); + continue; + } + + // Create a new type and update it to theirs. + const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry)); + void *copied_data = malloc(type_alloc_size); + memcpy(copied_data, type, type_alloc_size); + packages_[p]->types[t].reset(reinterpret_cast<ThemeType *>(copied_data)); + } } + } else { + std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies; + typedef std::map<int, int> SourceToDestinationRuntimePackageMap; + std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map; + + // Determine which ApkAssets are loaded in both theme AssetManagers + std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets(); + for (size_t i = 0; i < src_assets.size(); i++) { + const ApkAssets* src_asset = src_assets[i]; + + std::vector<const ApkAssets*> dest_assets = asset_manager_->GetApkAssets(); + for (size_t j = 0; j < dest_assets.size(); j++) { + const ApkAssets* dest_asset = dest_assets[j]; + + // Map the runtime package of the source apk asset to the destination apk asset + if (src_asset->GetPath() == dest_asset->GetPath()) { + const std::vector<std::unique_ptr<const LoadedPackage>>& src_packages = + src_asset->GetLoadedArsc()->GetPackages(); + const std::vector<std::unique_ptr<const LoadedPackage>>& dest_packages = + dest_asset->GetLoadedArsc()->GetPackages(); + + SourceToDestinationRuntimePackageMap package_map; + + // The source and destination package should have the same number of packages loaded in + // the same order. + const size_t N = src_packages.size(); + CHECK(N == dest_packages.size()) + << " LoadedArsc " << src_asset->GetPath() << " differs number of packages."; + for (size_t p = 0; p < N; p++) { + auto& src_package = src_packages[p]; + auto& dest_package = dest_packages[p]; + CHECK(src_package->GetPackageName() == dest_package->GetPackageName()) + << " Package " << src_package->GetPackageName() << " differs in load order."; + + int src_package_id = o.asset_manager_->GetAssignedPackageId(src_package.get()); + int dest_package_id = asset_manager_->GetAssignedPackageId(dest_package.get()); + package_map[src_package_id] = dest_package_id; + } - if (packages_[p] == nullptr) { - // The other theme has this package, but we don't. Make one. - packages_[p].reset(new Package()); + src_to_dest_asset_cookies.insert(std::pair<ApkAssetsCookie, ApkAssetsCookie>(i, j)); + src_asset_cookie_id_map.insert( + std::pair<ApkAssetsCookie, SourceToDestinationRuntimePackageMap>(i, package_map)); + break; + } + } + } + + // Reset the data in the destination theme + for (size_t p = 0; p < packages_.size(); p++) { + if (packages_[p] != nullptr) { + packages_[p].reset(); + } } - for (size_t t = 0; t < package->types.size(); t++) { - const ThemeType* type = package->types[t].get(); + for (size_t p = 0; p < packages_.size(); p++) { + const Package *package = o.packages_[p].get(); + if (package == nullptr) { + continue; + } + + for (size_t t = 0; t < package->types.size(); t++) { + const ThemeType *type = package->types[t].get(); + if (type == nullptr) { + continue; + } + + for (size_t e = 0; e < type->entry_count; e++) { + const ThemeEntry &entry = type->entries[e]; + if (entry.value.dataType == Res_value::TYPE_NULL && + entry.value.data != Res_value::DATA_NULL_EMPTY) { + continue; + } + + // The package id of the attribute needs to be rewritten to the package id of the value in + // the destination + int attribute_dest_package_id = p; + if (attribute_dest_package_id != 0x01) { + // Find the cookie of the attribute resource id + FindEntryResult attribute_entry_result; + ApkAssetsCookie attribute_cookie = + o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , false, + &attribute_entry_result); + + // Determine the package id of the attribute in the destination AssetManager + auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie); + if (attribute_package_map == src_asset_cookie_id_map.end()) { + continue; + } + auto attribute_dest_package = attribute_package_map->second.find( + attribute_dest_package_id); + if (attribute_dest_package == attribute_package_map->second.end()) { + continue; + } + attribute_dest_package_id = attribute_dest_package->second; + } + + // If the attribute value represents an attribute or reference, the package id of the + // value needs to be rewritten to the package id of the value in the destination + uint32_t attribue_data = entry.value.data; + if (entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE + || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE + || entry.value.dataType == Res_value::TYPE_ATTRIBUTE + || entry.value.dataType == Res_value::TYPE_REFERENCE) { + + // Determine the package id of the reference in the destination AssetManager + auto value_package_map = src_asset_cookie_id_map.find(entry.cookie); + if (value_package_map == src_asset_cookie_id_map.end()) { + continue; + } + + auto value_dest_package = value_package_map->second.find( + get_package_id(entry.value.data)); + if (value_dest_package == value_package_map->second.end()) { + continue; + } + + attribue_data = fix_package_id(entry.value.data, value_dest_package->second); + } + + // Lazily instantiate the destination package + std::unique_ptr<Package>& dest_package = packages_[attribute_dest_package_id]; + if (dest_package == nullptr) { + dest_package.reset(new Package()); + } + + // Lazily instantiate and resize the destination type + util::unique_cptr<ThemeType>& dest_type = dest_package->types[t]; + if (dest_type == nullptr || dest_type->entry_count < type->entry_count) { + const size_t type_alloc_size = sizeof(ThemeType) + + (type->entry_count * sizeof(ThemeEntry)); + void* dest_data = malloc(type_alloc_size); + memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry)); + + // Copy the existing destination type values if the type is resized + if (dest_type != nullptr) { + memcpy(dest_data, type, sizeof(ThemeType) + + (dest_type->entry_count * sizeof(ThemeEntry))); + } + + dest_type.reset(reinterpret_cast<ThemeType *>(dest_data)); + dest_type->entry_count = type->entry_count; + } + + // Find the cookie of the value in the destination + auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie); + if (value_dest_cookie == src_to_dest_asset_cookies.end()) { + continue; + } + + dest_type->entries[e].cookie = value_dest_cookie->second; + dest_type->entries[e].value.dataType = entry.value.dataType; + dest_type->entries[e].value.data = attribue_data; + dest_type->entries[e].type_spec_flags = entry.type_spec_flags; + } + } + } + } +} + +void Theme::Dump() const { + base::ScopedLogSeverity _log(base::INFO); + LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_); + + for (int p = 0; p < packages_.size(); p++) { + auto& package = packages_[p]; + if (package == nullptr) { + continue; + } + + for (int t = 0; t < package->types.size(); t++) { + auto& type = package->types[t]; if (type == nullptr) { - // The other theme doesn't have this type, clear ours. - packages_[p]->types[t].reset(); continue; } - // Create a new type and update it to theirs. - const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry)); - void* copied_data = malloc(type_alloc_size); - memcpy(copied_data, type, type_alloc_size); - packages_[p]->types[t].reset(reinterpret_cast<ThemeType*>(copied_data)); + for (int e = 0; e < type->entry_count; e++) { + auto& entry = type->entries[e]; + if (entry.value.dataType == Res_value::TYPE_NULL && + entry.value.data != Res_value::DATA_NULL_EMPTY) { + continue; + } + + LOG(INFO) << base::StringPrintf(" entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)", + make_resid(p, t, e), entry.value.data, + entry.value.dataType, entry.cookie); + } } } - return true; } } // namespace android diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index dc4a0a706bae..388548b174f9 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -6998,18 +6998,28 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const { } status_t DynamicRefTable::lookupResourceValue(Res_value* value) const { - uint8_t resolvedType; - - if (value->dataType == Res_value::TYPE_ATTRIBUTE - || value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) { - resolvedType = Res_value::TYPE_ATTRIBUTE; - - } else if (value->dataType == Res_value::TYPE_REFERENCE - || value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE) { - resolvedType = Res_value::TYPE_REFERENCE; + uint8_t resolvedType = Res_value::TYPE_REFERENCE; + switch (value->dataType) { + case Res_value::TYPE_ATTRIBUTE: + resolvedType = Res_value::TYPE_ATTRIBUTE; + // fallthrough + case Res_value::TYPE_REFERENCE: + // Only resolve non-dynamic references and attributes if the package is loaded as a + // library or if a shared library is attempting to retrieve its own resource + if (!(mAppAsLib || (Res_GETPACKAGE(value->data) + 1) == 0)) { + return NO_ERROR; + } - } else { - return NO_ERROR; + // If the package is loaded as shared library, the resource reference + // also need to be fixed. + break; + case Res_value::TYPE_DYNAMIC_ATTRIBUTE: + resolvedType = Res_value::TYPE_ATTRIBUTE; + // fallthrough + case Res_value::TYPE_DYNAMIC_REFERENCE: + break; + default: + return NO_ERROR; } status_t err = lookupResourceId(&value->data); diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 2f0ee01639fe..5312b062473a 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -74,6 +74,8 @@ struct FindEntryResult; // AssetManager2 is the main entry point for accessing assets and resources. // AssetManager2 provides caching of resources retrieved via the underlying ApkAssets. class AssetManager2 { + friend Theme; + public: struct ResourceName { const char* package = nullptr; @@ -285,6 +287,9 @@ class AssetManager2 { // been seen while traversing bag parents. const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids); + // Retrieve the assigned package id of the package if loaded into this AssetManager + uint8_t GetAssignedPackageId(const LoadedPackage* package); + // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must // have a longer lifetime. std::vector<const ApkAssets*> apk_assets_; @@ -355,11 +360,14 @@ class Theme { bool ApplyStyle(uint32_t resid, bool force = false); // Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme. - // Returns false if the AssetManagers of the Themes were not compatible. - bool SetTo(const Theme& o); + // If `o` does not have the same AssetManager as this theme, only attributes from ApkAssets loaded + // into both AssetManagers will be copied to this theme. + void SetTo(const Theme& o); void Clear(); + void Dump() const; + inline const AssetManager2* GetAssetManager() const { return asset_manager_; } diff --git a/libs/androidfw/tests/DynamicRefTable_test.cpp b/libs/androidfw/tests/DynamicRefTable_test.cpp index df44e343b2b4..5acc46a3c0d9 100644 --- a/libs/androidfw/tests/DynamicRefTable_test.cpp +++ b/libs/androidfw/tests/DynamicRefTable_test.cpp @@ -40,6 +40,26 @@ TEST(DynamicRefTableTest, LookupSharedLibSelfReferences) { EXPECT_EQ(value2.data, 0x02010000); }; +TEST(DynamicRefTableTest, LookupSharedLibSelfAttributes) { + // Shared library + DynamicRefTable shared_table(0x03, /* appAsLib */ false); + shared_table.addMapping(0x00, 0x03); + Res_value value; + value.dataType = Res_value::TYPE_ATTRIBUTE; + value.data = 0x00010000; + ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR); + EXPECT_EQ(value.data, 0x03010000); + + // App loaded as a shared library + DynamicRefTable shared_app_table(0x04, /* appAsLib */ true); + shared_app_table.addMapping(0x7f, 0x04); + Res_value value2; + value2.dataType = Res_value::TYPE_ATTRIBUTE; + value2.data = 0x7f010000; + ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR); + EXPECT_EQ(value2.data, 0x04010000); +}; + TEST(DynamicRefTableTest, LookupDynamicReferences) { // Shared library DynamicRefTable shared_table(0x2, /* appAsLib */ false); @@ -51,24 +71,46 @@ TEST(DynamicRefTableTest, LookupDynamicReferences) { ASSERT_EQ(shared_table.lookupResourceValue(&value), NO_ERROR); EXPECT_EQ(value.data, 0x05010000); - // App loaded as a shared library + // Regular application + DynamicRefTable app_table(0x7f, /* appAsLib */ false); + app_table.addMapping(0x03, 0x05); + Res_value value3; + value3.dataType = Res_value::TYPE_DYNAMIC_REFERENCE; + value3.data = 0x03010000; + ASSERT_EQ(app_table.lookupResourceValue(&value3), NO_ERROR); + EXPECT_EQ(value3.data, 0x05010000); +}; + +TEST(DynamicRefTableTest, LookupDynamicAttributes) { +// App loaded as a shared library DynamicRefTable shared_app_table(0x2, /* appAsLib */ true); shared_app_table.addMapping(0x03, 0x05); shared_app_table.addMapping(0x7f, 0x2); Res_value value2; - value2.dataType = Res_value::TYPE_DYNAMIC_REFERENCE; + value2.dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE; value2.data = 0x03010000; ASSERT_EQ(shared_app_table.lookupResourceValue(&value2), NO_ERROR); EXPECT_EQ(value2.data, 0x05010000); +} +TEST(DynamicRefTableTest, DoNotLookupNonDynamicReferences) { // Regular application DynamicRefTable app_table(0x7f, /* appAsLib */ false); - app_table.addMapping(0x03, 0x05); - Res_value value3; - value3.dataType = Res_value::TYPE_REFERENCE; - value3.data = 0x03010000; - ASSERT_EQ(app_table.lookupResourceValue(&value3), NO_ERROR); - EXPECT_EQ(value3.data, 0x05010000); + Res_value value; + value.dataType = Res_value::TYPE_REFERENCE; + value.data = 0x03010000; + ASSERT_EQ(app_table.lookupResourceValue(&value), NO_ERROR); + EXPECT_EQ(value.data, 0x03010000); +}; + +TEST(DynamicRefTableTest, DoNotLookupNonDynamicAttributes) { + // App with custom package id + DynamicRefTable custom_app_table(0x8f, /* appAsLib */ false); + Res_value value2; + value2.dataType = Res_value::TYPE_ATTRIBUTE; + value2.data = 0x03010000; + ASSERT_EQ(custom_app_table.lookupResourceValue(&value2), NO_ERROR); + EXPECT_EQ(value2.data, 0x03010000); }; } // namespace android
\ No newline at end of file diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp index 55d53edf6a2b..2c39ceead123 100644 --- a/libs/androidfw/tests/Theme_test.cpp +++ b/libs/androidfw/tests/Theme_test.cpp @@ -21,12 +21,14 @@ #include "TestHelpers.h" #include "androidfw/ResourceUtils.h" #include "data/lib_one/R.h" +#include "data/lib_two/R.h" #include "data/libclient/R.h" #include "data/styles/R.h" #include "data/system/R.h" namespace app = com::android::app; namespace lib_one = com::android::lib_one; +namespace lib_two = com::android::lib_two; namespace libclient = com::android::libclient; namespace android { @@ -263,7 +265,7 @@ TEST_F(ThemeTest, CopyThemeSameAssetManager) { ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree)); // Copy the theme to theme_one. - ASSERT_TRUE(theme_one->SetTo(*theme_two)); + theme_one->SetTo(*theme_two); // Clear theme_two to make sure we test that there WAS a copy. theme_two->Clear(); @@ -279,12 +281,14 @@ TEST_F(ThemeTest, CopyThemeSameAssetManager) { EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags); } -TEST_F(ThemeTest, OnlyCopySystemThemeWhenAssetManagersDiffer) { +TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) { AssetManager2 assetmanager_one; - assetmanager_one.SetApkAssets({system_assets_.get(), style_assets_.get()}); + assetmanager_one.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(), + libclient_assets_.get()}); AssetManager2 assetmanager_two; - assetmanager_two.SetApkAssets({system_assets_.get(), style_assets_.get()}); + assetmanager_two.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(), + style_assets_.get()}); auto theme_one = assetmanager_one.NewTheme(); ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne)); @@ -292,17 +296,34 @@ TEST_F(ThemeTest, OnlyCopySystemThemeWhenAssetManagersDiffer) { auto theme_two = assetmanager_two.NewTheme(); ASSERT_TRUE(theme_two->ApplyStyle(R::style::Theme_One)); ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo)); + ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03), + false /*force*/)); + ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02), + false /*force*/)); - EXPECT_TRUE(theme_one->SetTo(*theme_two)); + theme_one->SetTo(*theme_two); Res_value value; uint32_t flags; - // No app resources. - EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags)); + // System resources (present in destination asset manager) + EXPECT_EQ(0, theme_one->GetAttribute(R::attr::foreground, &value, &flags)); + + // The cookie of the style asset is 3 in the source and 2 in the destination. + // Check that the cookie has been rewritten to the destination values + EXPECT_EQ(2, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags)); + + // The cookie of the lib_one asset is 2 in the source and 1 in the destination. + // The package id of the lib_one package is 0x03 in the source and 0x02 in the destination + // Check that the cookie and packages have been rewritten to the destination values + EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value, + &flags)); + EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value, + &flags)); - // Only system. - EXPECT_NE(kInvalidCookie, theme_one->GetAttribute(R::attr::foreground, &value, &flags)); + // attr2 references an attribute in lib_one. Check that the resolution of the attribute value is + // correct after the value of attr2 had its package id rewritten to the destination package id + EXPECT_EQ(700, value.data); } } // namespace android diff --git a/libs/androidfw/tests/data/lib_two/R.h b/libs/androidfw/tests/data/lib_two/R.h index c04a9d3b4de0..92b9cc10e7a8 100644 --- a/libs/androidfw/tests/data/lib_two/R.h +++ b/libs/androidfw/tests/data/lib_two/R.h @@ -24,12 +24,24 @@ namespace android { namespace lib_two { struct R { + struct attr { + enum : uint32_t { + attr3 = 0x02010000, // default + }; + }; + struct string { enum : uint32_t { LibraryString = 0x02020000, // default foo = 0x02020001, // default }; }; + + struct style { + enum : uint32_t { + Theme = 0x02030000, // default + }; + }; }; } // namespace lib_two diff --git a/libs/androidfw/tests/data/lib_two/lib_two.apk b/libs/androidfw/tests/data/lib_two/lib_two.apk Binary files differindex ad44f9c21e31..486c23000276 100644 --- a/libs/androidfw/tests/data/lib_two/lib_two.apk +++ b/libs/androidfw/tests/data/lib_two/lib_two.apk diff --git a/libs/androidfw/tests/data/lib_two/res/values/values.xml b/libs/androidfw/tests/data/lib_two/res/values/values.xml index f4eea2610cab..340d14c34c5d 100644 --- a/libs/androidfw/tests/data/lib_two/res/values/values.xml +++ b/libs/androidfw/tests/data/lib_two/res/values/values.xml @@ -15,9 +15,17 @@ --> <resources> + <public type="attr" name="attr3" id="0x00010000" /> + <attr name="attr3" format="integer" /> + <public type="string" name="LibraryString" id="0x00020000" /> <string name="LibraryString">Hi from library two</string> <public type="string" name="foo" id="0x00020001" /> <string name="foo">Foo from lib_two</string> + + <public type="style" name="Theme" id="0x02030000" /> + <style name="Theme"> + <item name="com.android.lib_two:attr3">800</item> + </style> </resources> diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index f0053a48ae3d..17d2db71ab58 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -176,7 +176,7 @@ cc_defaults { "pipeline/skia/SkiaRecordingCanvas.cpp", "pipeline/skia/SkiaVulkanPipeline.cpp", "pipeline/skia/VectorDrawableAtlas.cpp", - "pipeline/skia/VkFunctorDrawable.cpp", + "pipeline/skia/VkInteropFunctorDrawable.cpp", "renderstate/RenderState.cpp", "renderthread/CacheManager.cpp", "renderthread/CanvasContext.cpp", diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 2e5aef5347d5..9c707bab95f1 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -732,14 +732,10 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, float totalAdvance) { if (count <= 0 || paint.nothingToDraw()) return; - // Set align to left for drawing, as we don't want individual - // glyphs centered or right-aligned; the offset above takes - // care of all alignment. SkPaint paintCopy(paint); if (mPaintFilter) { mPaintFilter->filter(&paintCopy); } - paintCopy.setTextAlign(SkPaint::kLeft_Align); SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); // Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and // older. @@ -763,14 +759,10 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, const SkPaint& paint, const SkPath& path, size_t start, size_t end) { - // Set align to left for drawing, as we don't want individual - // glyphs centered or right-aligned; the offsets take care of - // that portion of the alignment. SkPaint paintCopy(paint); if (mPaintFilter) { mPaintFilter->filter(&paintCopy); } - paintCopy.setTextAlign(SkPaint::kLeft_Align); SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); const int N = end - start; diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 753557c2e120..75a6e722dd8a 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -286,7 +286,6 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) { } void Bitmap::getSkBitmap(SkBitmap* outBitmap) { - outBitmap->setHasHardwareMipMap(mHasHardwareMipMap); if (isHardware()) { outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(), info().colorType(), info().alphaType(), nullptr)); @@ -321,7 +320,6 @@ sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { SkBitmap skiaBitmap; skiaBitmap.setInfo(info(), rowBytes()); skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0); - skiaBitmap.setHasHardwareMipMap(mHasHardwareMipMap); // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap // internally and ~Bitmap won't be invoked. // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here. diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp index 2ca40b96c0ba..05dc340e9ef3 100644 --- a/libs/hwui/hwui/MinikinSkia.cpp +++ b/libs/hwui/hwui/MinikinSkia.cpp @@ -139,7 +139,7 @@ std::shared_ptr<minikin::MinikinFont> MinikinFontSkia::createFontWithVariation( uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) { uint32_t flags = paint->getFlags(); - SkPaint::Hinting hinting = paint->getHinting(); + SkFontHinting hinting = (SkFontHinting)paint->getHinting(); // select only flags that might affect text layout flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag | SkPaint::kSubpixelText_Flag | SkPaint::kEmbeddedBitmapText_Flag | @@ -150,7 +150,7 @@ uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) { void MinikinFontSkia::unpackPaintFlags(SkPaint* paint, uint32_t paintFlags) { paint->setFlags(paintFlags & SkPaint::kAllFlags); - paint->setHinting(static_cast<SkPaint::Hinting>(paintFlags >> 16)); + paint->setHinting(static_cast<SkFontHinting>(paintFlags >> 16)); } void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font, diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index 31d3c0d00b36..c1a3b6d1143b 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -86,6 +86,14 @@ public: const Typeface* getAndroidTypeface() const { return mTypeface; } + enum Align { + kLeft_Align, + kCenter_Align, + kRight_Align, + }; + Align getTextAlign() const { return mAlign; } + void setTextAlign(Align align) { mAlign = align; } + private: float mLetterSpacing = 0; float mWordSpacing = 0; @@ -98,6 +106,7 @@ private: // object. Thus, following pointer can never be a dangling pointer. Note that // nullptr is valid: it means the default typeface. const Typeface* mTypeface = nullptr; + Align mAlign = kLeft_Align; }; } // namespace android diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp index 29cc890682f0..bdbf5cacaaf0 100644 --- a/libs/hwui/hwui/PaintImpl.cpp +++ b/libs/hwui/hwui/PaintImpl.cpp @@ -34,7 +34,8 @@ Paint::Paint(const Paint& paint) , mMinikinLocaleListId(paint.mMinikinLocaleListId) , mFamilyVariant(paint.mFamilyVariant) , mHyphenEdit(paint.mHyphenEdit) - , mTypeface(paint.mTypeface) {} + , mTypeface(paint.mTypeface) + , mAlign(paint.mAlign) {} Paint::Paint(const SkPaint& paint) : SkPaint(paint) @@ -55,6 +56,7 @@ Paint& Paint::operator=(const Paint& other) { mFamilyVariant = other.mFamilyVariant; mHyphenEdit = other.mHyphenEdit; mTypeface = other.mTypeface; + mAlign = other.mAlign; return *this; } @@ -64,6 +66,6 @@ bool operator==(const Paint& a, const Paint& b) { a.mFontFeatureSettings == b.mFontFeatureSettings && a.mMinikinLocaleListId == b.mMinikinLocaleListId && a.mFamilyVariant == b.mFamilyVariant && a.mHyphenEdit == b.mHyphenEdit && - a.mTypeface == b.mTypeface; + a.mTypeface == b.mTypeface && a.mAlign == b.mAlign; } } // namespace android diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 3fa73a4dadda..45022e733979 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -24,7 +24,7 @@ #include "RenderNode.h" #include "pipeline/skia/AnimatedDrawables.h" #include "pipeline/skia/GLFunctorDrawable.h" -#include "pipeline/skia/VkFunctorDrawable.h" +#include "pipeline/skia/VkInteropFunctorDrawable.h" namespace android { namespace uirenderer { @@ -81,6 +81,11 @@ void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, } void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { + if (mCurrentBarrier && enableReorder) { + // Already in a re-order section, nothing to do + return; + } + if (nullptr != mCurrentBarrier) { // finish off the existing chunk SkDrawable* drawable = @@ -89,9 +94,8 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { drawDrawable(drawable); } if (enableReorder) { - mCurrentBarrier = (StartReorderBarrierDrawable*) - mDisplayList->allocateDrawable<StartReorderBarrierDrawable>( - mDisplayList.get()); + mCurrentBarrier = mDisplayList->allocateDrawable<StartReorderBarrierDrawable>( + mDisplayList.get()); drawDrawable(mCurrentBarrier); } } @@ -120,8 +124,8 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, uirenderer::GlFunctorLifecycleListener* listener) { FunctorDrawable* functorDrawable; if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, listener, - asSkCanvas()); + functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor, + listener, asSkCanvas()); } else { functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener, asSkCanvas()); diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 2ca110f0d0b1..7fc41acefe8a 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -22,7 +22,7 @@ #include "SkiaProfileRenderer.h" #include "renderstate/RenderState.h" #include "renderthread/Frame.h" -#include "VkFunctorDrawable.h" +#include "VkInteropFunctorDrawable.h" #include <SkSurface.h> #include <SkTypes.h> @@ -144,7 +144,7 @@ bool SkiaVulkanPipeline::isContextReady() { } void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) { - VkFunctorDrawable::vkInvokeFunctor(functor); + VkInteropFunctorDrawable::vkInvokeFunctor(functor); } sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread, diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp index 6486ddb05aac..2a6a9f5b4771 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "VkFunctorDrawable.h" +#include "VkInteropFunctorDrawable.h" #include <private/hwui/DrawGlInfo.h> #include "renderthread/EglManager.h" @@ -64,7 +64,7 @@ private: } }; -void VkFunctorDrawable::vkInvokeFunctor(Functor* functor) { +void VkInteropFunctorDrawable::vkInvokeFunctor(Functor* functor) { ScopedDrawRequest _drawRequest{}; sGLDrawThread->queue().runSync([&]() { EGLDisplay display = sEglManager.eglDisplay(); @@ -78,7 +78,7 @@ void VkFunctorDrawable::vkInvokeFunctor(Functor* functor) { #define FENCE_TIMEOUT 2000000000 -void VkFunctorDrawable::onDraw(SkCanvas* canvas) { +void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { ATRACE_CALL(); if (canvas->getGrContext() == nullptr) { @@ -202,7 +202,7 @@ void VkFunctorDrawable::onDraw(SkCanvas* canvas) { canvas->restore(); } -VkFunctorDrawable::~VkFunctorDrawable() { +VkInteropFunctorDrawable::~VkInteropFunctorDrawable() { if (mListener.get() != nullptr) { ScopedDrawRequest _drawRequest{}; sGLDrawThread->queue().runSync([&]() { @@ -211,7 +211,7 @@ VkFunctorDrawable::~VkFunctorDrawable() { } } -void VkFunctorDrawable::syncFunctor() const { +void VkInteropFunctorDrawable::syncFunctor() const { ScopedDrawRequest _drawRequest{}; sGLDrawThread->queue().runSync([&]() { (*mFunctor)(DrawGlInfo::kModeSync, nullptr); diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h index e37f6fb85090..3269cfbb8fe3 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h @@ -30,11 +30,12 @@ namespace skiapipeline { * This drawable wraps a Vulkan functor enabling it to be recorded into a list * of Skia drawing commands. */ -class VkFunctorDrawable : public FunctorDrawable { +class VkInteropFunctorDrawable : public FunctorDrawable { public: - VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) + VkInteropFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, + SkCanvas* canvas) : FunctorDrawable(functor, listener, canvas) {} - virtual ~VkFunctorDrawable(); + virtual ~VkInteropFunctorDrawable(); void syncFunctor() const override; diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp index fd8c252ff318..9a1ee54bff49 100644 --- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp +++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp @@ -46,7 +46,6 @@ class ListViewAnimation : public TestListViewSceneBase { SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor) < 128 * 3; paint.setColor(bgDark ? Color::White : Color::Grey_700); - paint.setTextAlign(SkPaint::kCenter_Align); paint.setTextSize(size / 2); char charToShow = 'A' + (rand() % 26); const SkPoint pos[] = {{SkIntToScalar(size / 2), diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp index 9428f532434a..5f5a92e55bf2 100644 --- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp +++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp @@ -81,11 +81,11 @@ void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options // mean and stddev which doesn't make sense for our usage std::vector<BenchmarkReporter::Run> reports; BenchmarkReporter::Run report; - report.benchmark_name = info.name; + report.run_name = info.name; report.iterations = static_cast<int64_t>(opts.count); report.real_accumulated_time = durationInS; report.cpu_accumulated_time = durationInS; - report.items_per_second = opts.count / durationInS; + report.counters["items_per_second"] = opts.count / durationInS; reports.push_back(report); reporter->ReportRuns(reports); @@ -94,13 +94,13 @@ void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options // in that test case than percentiles. if (!opts.renderOffscreen) { for (auto& ri : REPORTS) { - reports[0].benchmark_name = info.name; - reports[0].benchmark_name += ri.suffix; + reports[0].run_name = info.name; + reports[0].run_name += ri.suffix; durationInS = proxy->frameTimePercentile(ri.percentile) / 1000.0; reports[0].real_accumulated_time = durationInS; reports[0].cpu_accumulated_time = durationInS; reports[0].iterations = 1; - reports[0].items_per_second = 0; + reports[0].counters["items_per_second"] = 0; reporter->ReportRuns(reports); } } diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index b34f2700f520..3e3e65188761 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -273,6 +273,11 @@ public final class AudioFormat implements Parcelable { * supports {@link #ENCODING_E_AC3} but not {@link #ENCODING_E_AC3_JOC}. **/ public static final int ENCODING_E_AC3_JOC = 18; + /** Audio data format: Dolby MAT (Metadata-enhanced Audio Transmission) + * Dolby MAT bitstreams are used to transmit Dolby TrueHD, channel-based PCM, or PCM with + * metadata (object audio) over HDMI (e.g. Dolby Atmos content). + **/ + public static final int ENCODING_DOLBY_MAT = 19; /** @hide */ public static String toLogFriendlyEncoding(int enc) { @@ -313,6 +318,8 @@ public final class AudioFormat implements Parcelable { return "ENCODING_AC4"; case ENCODING_E_AC3_JOC: return "ENCODING_E_AC3_JOC"; + case ENCODING_DOLBY_MAT: + return "ENCODING_DOLBY_MAT"; default : return "invalid encoding " + enc; } @@ -520,26 +527,27 @@ public final class AudioFormat implements Parcelable { public static boolean isValidEncoding(int audioFormat) { switch (audioFormat) { - case ENCODING_PCM_16BIT: - case ENCODING_PCM_8BIT: - case ENCODING_PCM_FLOAT: - case ENCODING_AC3: - case ENCODING_E_AC3: - case ENCODING_DTS: - case ENCODING_DTS_HD: - case ENCODING_MP3: - case ENCODING_AAC_LC: - case ENCODING_AAC_HE_V1: - case ENCODING_AAC_HE_V2: - case ENCODING_IEC61937: - case ENCODING_DOLBY_TRUEHD: - case ENCODING_AAC_ELD: - case ENCODING_AAC_XHE: - case ENCODING_AC4: - case ENCODING_E_AC3_JOC: - return true; - default: - return false; + case ENCODING_PCM_16BIT: + case ENCODING_PCM_8BIT: + case ENCODING_PCM_FLOAT: + case ENCODING_AC3: + case ENCODING_E_AC3: + case ENCODING_DTS: + case ENCODING_DTS_HD: + case ENCODING_MP3: + case ENCODING_AAC_LC: + case ENCODING_AAC_HE_V1: + case ENCODING_AAC_HE_V2: + case ENCODING_IEC61937: + case ENCODING_DOLBY_TRUEHD: + case ENCODING_AAC_ELD: + case ENCODING_AAC_XHE: + case ENCODING_AC4: + case ENCODING_E_AC3_JOC: + case ENCODING_DOLBY_MAT: + return true; + default: + return false; } } @@ -547,26 +555,27 @@ public final class AudioFormat implements Parcelable { public static boolean isPublicEncoding(int audioFormat) { switch (audioFormat) { - case ENCODING_PCM_16BIT: - case ENCODING_PCM_8BIT: - case ENCODING_PCM_FLOAT: - case ENCODING_AC3: - case ENCODING_E_AC3: - case ENCODING_DTS: - case ENCODING_DTS_HD: - case ENCODING_MP3: - case ENCODING_AAC_LC: - case ENCODING_AAC_HE_V1: - case ENCODING_AAC_HE_V2: - case ENCODING_IEC61937: - case ENCODING_DOLBY_TRUEHD: - case ENCODING_AAC_ELD: - case ENCODING_AAC_XHE: - case ENCODING_AC4: - case ENCODING_E_AC3_JOC: - return true; - default: - return false; + case ENCODING_PCM_16BIT: + case ENCODING_PCM_8BIT: + case ENCODING_PCM_FLOAT: + case ENCODING_AC3: + case ENCODING_E_AC3: + case ENCODING_DTS: + case ENCODING_DTS_HD: + case ENCODING_MP3: + case ENCODING_AAC_LC: + case ENCODING_AAC_HE_V1: + case ENCODING_AAC_HE_V2: + case ENCODING_IEC61937: + case ENCODING_DOLBY_TRUEHD: + case ENCODING_AAC_ELD: + case ENCODING_AAC_XHE: + case ENCODING_AC4: + case ENCODING_E_AC3_JOC: + case ENCODING_DOLBY_MAT: + return true; + default: + return false; } } @@ -575,29 +584,30 @@ public final class AudioFormat implements Parcelable { public static boolean isEncodingLinearPcm(int audioFormat) { switch (audioFormat) { - case ENCODING_PCM_16BIT: - case ENCODING_PCM_8BIT: - case ENCODING_PCM_FLOAT: - case ENCODING_DEFAULT: - return true; - case ENCODING_AC3: - case ENCODING_E_AC3: - case ENCODING_DTS: - case ENCODING_DTS_HD: - case ENCODING_MP3: - case ENCODING_AAC_LC: - case ENCODING_AAC_HE_V1: - case ENCODING_AAC_HE_V2: - case ENCODING_IEC61937: // wrapped in PCM but compressed - case ENCODING_DOLBY_TRUEHD: - case ENCODING_AAC_ELD: - case ENCODING_AAC_XHE: - case ENCODING_AC4: - case ENCODING_E_AC3_JOC: - return false; - case ENCODING_INVALID: - default: - throw new IllegalArgumentException("Bad audio format " + audioFormat); + case ENCODING_PCM_16BIT: + case ENCODING_PCM_8BIT: + case ENCODING_PCM_FLOAT: + case ENCODING_DEFAULT: + return true; + case ENCODING_AC3: + case ENCODING_E_AC3: + case ENCODING_DTS: + case ENCODING_DTS_HD: + case ENCODING_MP3: + case ENCODING_AAC_LC: + case ENCODING_AAC_HE_V1: + case ENCODING_AAC_HE_V2: + case ENCODING_IEC61937: // wrapped in PCM but compressed + case ENCODING_DOLBY_TRUEHD: + case ENCODING_AAC_ELD: + case ENCODING_AAC_XHE: + case ENCODING_AC4: + case ENCODING_E_AC3_JOC: + case ENCODING_DOLBY_MAT: + return false; + case ENCODING_INVALID: + default: + throw new IllegalArgumentException("Bad audio format " + audioFormat); } } @@ -605,29 +615,30 @@ public final class AudioFormat implements Parcelable { public static boolean isEncodingLinearFrames(int audioFormat) { switch (audioFormat) { - case ENCODING_PCM_16BIT: - case ENCODING_PCM_8BIT: - case ENCODING_PCM_FLOAT: - case ENCODING_IEC61937: // same size as stereo PCM - case ENCODING_DEFAULT: - return true; - case ENCODING_AC3: - case ENCODING_E_AC3: - case ENCODING_DTS: - case ENCODING_DTS_HD: - case ENCODING_MP3: - case ENCODING_AAC_LC: - case ENCODING_AAC_HE_V1: - case ENCODING_AAC_HE_V2: - case ENCODING_DOLBY_TRUEHD: - case ENCODING_AAC_ELD: - case ENCODING_AAC_XHE: - case ENCODING_AC4: - case ENCODING_E_AC3_JOC: - return false; - case ENCODING_INVALID: - default: - throw new IllegalArgumentException("Bad audio format " + audioFormat); + case ENCODING_PCM_16BIT: + case ENCODING_PCM_8BIT: + case ENCODING_PCM_FLOAT: + case ENCODING_IEC61937: // same size as stereo PCM + case ENCODING_DEFAULT: + return true; + case ENCODING_AC3: + case ENCODING_E_AC3: + case ENCODING_DTS: + case ENCODING_DTS_HD: + case ENCODING_MP3: + case ENCODING_AAC_LC: + case ENCODING_AAC_HE_V1: + case ENCODING_AAC_HE_V2: + case ENCODING_DOLBY_TRUEHD: + case ENCODING_AAC_ELD: + case ENCODING_AAC_XHE: + case ENCODING_AC4: + case ENCODING_E_AC3_JOC: + case ENCODING_DOLBY_MAT: + return false; + case ENCODING_INVALID: + default: + throw new IllegalArgumentException("Bad audio format " + audioFormat); } } /** @@ -867,6 +878,7 @@ public final class AudioFormat implements Parcelable { case ENCODING_AAC_XHE: case ENCODING_AC4: case ENCODING_E_AC3_JOC: + case ENCODING_DOLBY_MAT: mEncoding = encoding; break; case ENCODING_INVALID: @@ -1083,7 +1095,8 @@ public final class AudioFormat implements Parcelable { ENCODING_AAC_ELD, ENCODING_AAC_XHE, ENCODING_AC4, - ENCODING_E_AC3_JOC } + ENCODING_E_AC3_JOC, + ENCODING_DOLBY_MAT } ) @Retention(RetentionPolicy.SOURCE) public @interface Encoding {} @@ -1098,6 +1111,7 @@ public final class AudioFormat implements Parcelable { ENCODING_DOLBY_TRUEHD, ENCODING_AC4, ENCODING_E_AC3_JOC, + ENCODING_DOLBY_MAT, }; /** @hide */ @@ -1109,7 +1123,8 @@ public final class AudioFormat implements Parcelable { ENCODING_AAC_LC, ENCODING_DOLBY_TRUEHD, ENCODING_AC4, - ENCODING_E_AC3_JOC } + ENCODING_E_AC3_JOC, + ENCODING_DOLBY_MAT } ) @Retention(RetentionPolicy.SOURCE) public @interface SurroundSoundEncoding {} @@ -1141,6 +1156,8 @@ public final class AudioFormat implements Parcelable { return "Dolby AC-4"; case ENCODING_E_AC3_JOC: return "Dolby Atmos in Dolby Digital Plus"; + case ENCODING_DOLBY_MAT: + return "Dolby MAT"; default: return "Unknown surround sound format"; } diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index e019f4203993..00a393a902b4 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -958,4 +958,16 @@ public class MediaMetadataRetriever */ public static final int METADATA_KEY_COLOR_RANGE = 37; // Add more here... + + /** + * This key retrieves the sample rate, if available. + * @hide + */ + public static final int METADATA_KEY_SAMPLERATE = 38; + + /** + * This key retrieves the bits per sample, if available. + * @hide + */ + public static final int METADATA_KEY_BITS_PER_SAMPLE = 39; } diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java index b51caa5adb3b..74701920988c 100644 --- a/media/java/android/media/MediaPlayer2.java +++ b/media/java/android/media/MediaPlayer2.java @@ -23,9 +23,7 @@ import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.SurfaceTexture; -import android.net.Uri; import android.os.Handler; -import android.os.Parcel; import android.os.PersistableBundle; import android.view.Surface; import android.view.SurfaceHolder; @@ -34,7 +32,6 @@ import dalvik.system.CloseGuard; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; @@ -241,47 +238,6 @@ public abstract class MediaPlayer2 implements AutoCloseable return new MediaPlayer2Impl(context); } - private static final String[] decodeMediaPlayer2Uri(String location) { - Uri uri = Uri.parse(location); - if (!"mediaplayer2".equals(uri.getScheme())) { - return new String[] {location}; - } - - List<String> uris = uri.getQueryParameters("uri"); - if (uris.isEmpty()) { - return new String[] {location}; - } - - List<String> keys = uri.getQueryParameters("key"); - List<String> values = uri.getQueryParameters("value"); - if (keys.size() != values.size()) { - return new String[] {uris.get(0)}; - } - - List<String> ls = new ArrayList(); - ls.add(uris.get(0)); - for (int i = 0; i < keys.size() ; i++) { - ls.add(keys.get(i)); - ls.add(values.get(i)); - } - - return ls.toArray(new String[ls.size()]); - } - - private static final String encodeMediaPlayer2Uri(String uri, String[] keys, String[] values) { - Uri.Builder builder = new Uri.Builder(); - builder.scheme("mediaplayer2").path("/").appendQueryParameter("uri", uri); - if (keys == null || values == null || keys.length != values.length) { - return builder.build().toString(); - } - for (int i = 0; i < keys.length ; i++) { - builder - .appendQueryParameter("key", keys[i]) - .appendQueryParameter("value", values[i]); - } - return builder.build().toString(); - } - /** * @hide */ @@ -291,12 +247,6 @@ public abstract class MediaPlayer2 implements AutoCloseable } /** - * Returns a {@link MediaPlayerBase} implementation which runs based on - * this MediaPlayer2 instance. - */ - public abstract MediaPlayerBase getMediaPlayerBase(); - - /** * Releases the resources held by this {@code MediaPlayer2} object. * * It is considered good practice to call this method when you're @@ -342,8 +292,7 @@ public abstract class MediaPlayer2 implements AutoCloseable * Starts or resumes playback. If playback had previously been paused, * playback will continue from where it was paused. If playback had * reached end of stream and been paused, or never started before, - * playback will start at the beginning. If the source had not been - * prepared, the player will prepare the source and play. + * playback will start at the beginning. * * @return a token which can be used to cancel the operation later with {@link #cancel}. */ @@ -404,9 +353,8 @@ public abstract class MediaPlayer2 implements AutoCloseable /** * Gets the current buffered media source position received through progressive downloading. - * The received buffering percentage indicates how much of the content has been buffered - * or played. For example a buffering update of 80 percent when half the content - * has already been played indicates that the next 30 percent of the + * For example a buffering update of 8000 milliseconds when 5000 milliseconds of the content + * has already been played indicates that the next 3000 milliseconds of the * content to play has been buffered. * * @return the current buffered media source position in milliseconds @@ -416,7 +364,6 @@ public abstract class MediaPlayer2 implements AutoCloseable /** * MediaPlayer2 has not been prepared or just has been reset. * In this state, MediaPlayer2 doesn't fetch data. - * @hide */ public static final int PLAYER_STATE_IDLE = 1001; @@ -424,26 +371,23 @@ public abstract class MediaPlayer2 implements AutoCloseable * MediaPlayer2 has been just prepared. * In this state, MediaPlayer2 just fetches data from media source, * but doesn't actively render data. - * @hide */ public static final int PLAYER_STATE_PREPARED = 1002; /** * MediaPlayer2 is paused. - * In this state, MediaPlayer2 doesn't actively render data. - * @hide + * In this state, MediaPlayer2 has allocated resources to construct playback + * pipeline, but it doesn't actively render data. */ public static final int PLAYER_STATE_PAUSED = 1003; /** * MediaPlayer2 is actively playing back data. - * @hide */ public static final int PLAYER_STATE_PLAYING = 1004; /** * MediaPlayer2 has hit some fatal error and cannot continue playback. - * @hide */ public static final int PLAYER_STATE_ERROR = 1005; @@ -469,7 +413,7 @@ public abstract class MediaPlayer2 implements AutoCloseable /** * Sets the audio attributes for this MediaPlayer2. * See {@link AudioAttributes} for how to build and configure an instance of this class. - * You must call this method before {@link #prepare()} in order + * You must call this method before {@link #play()} and {@link #pause()} in order * for the audio attributes to become effective thereafter. * @param attributes a non-null set of audio attributes * @return a token which can be used to cancel the operation later with {@link #cancel}. @@ -547,7 +491,7 @@ public abstract class MediaPlayer2 implements AutoCloseable public abstract Object setPlayerVolume(float volume); /** - * Returns the current volume of this player to this player. + * Returns the current volume of this player. * Note that it does not take into account the associated stream volume. * @return the player volume. */ @@ -561,24 +505,9 @@ public abstract class MediaPlayer2 implements AutoCloseable } /** - * Create a request parcel which can be routed to the native media - * player using {@link #invoke(Parcel, Parcel)}. The Parcel - * returned has the proper InterfaceToken set. The caller should - * not overwrite that token, i.e it can only append data to the - * Parcel. - * - * @return A parcel suitable to hold a request for the native - * player. - * {@hide} - */ - public Parcel newRequest() { - return null; - } - - /** * Insert a task in the command queue to help the client to identify whether a batch * of commands has been finished. When this command is processed, a notification - * {@code EventCallback.onCommandLabelReached} will be fired with the + * {@link EventCallback#onCommandLabelReached onCommandLabelReached} will be fired with the * given {@code label}. * * @see EventCallback#onCommandLabelReached @@ -595,16 +524,13 @@ public abstract class MediaPlayer2 implements AutoCloseable * portion of the media. * * Either a surface holder or surface must be set if a display or video sink - * is needed. Not calling this method or {@link #setSurface(Surface)} + * is needed. Not calling this method or {@link #setSurface(Surface)} * when playing back a video will result in only the audio track being played. * A null surface holder or surface will result in only the audio track being * played. * * @param sh the SurfaceHolder to use for video display - * @throws IllegalStateException if the internal player engine has not been - * initialized or has been released. * @return a token which can be used to cancel the operation later with {@link #cancel}. - * @hide */ public abstract Object setDisplay(SurfaceHolder sh); @@ -624,56 +550,44 @@ public abstract class MediaPlayer2 implements AutoCloseable * * @param surface The {@link Surface} to be used for the video portion of * the media. - * @throws IllegalStateException if the internal player engine has not been - * initialized or has been released. * @return a token which can be used to cancel the operation later with {@link #cancel}. */ // This is an asynchronous call. public abstract Object setSurface(Surface surface); - /* Do not change these video scaling mode values below without updating - * their counterparts in system/window.h! Please do not forget to update - * {@link #isVideoScalingModeSupported} when new video scaling modes - * are added. - */ /** - * Specifies a video scaling mode. The content is stretched to the - * surface rendering area. When the surface has the same aspect ratio - * as the content, the aspect ratio of the content is maintained; - * otherwise, the aspect ratio of the content is not maintained when video - * is being rendered. - * There is no content cropping with this video scaling mode. - */ - public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; - - /** - * Specifies a video scaling mode. The content is scaled, maintaining - * its aspect ratio. The whole surface area is always used. When the - * aspect ratio of the content is the same as the surface, no content - * is cropped; otherwise, content is cropped to fit the surface. - * @hide + * Set the low-level power management behavior for this MediaPlayer2. This + * can be used when the MediaPlayer2 is not playing through a SurfaceHolder + * set with {@link #setDisplay(SurfaceHolder)} and thus can use the + * high-level {@link #setScreenOnWhilePlaying(boolean)} feature. + * + * <p>This function has the MediaPlayer2 access the low-level power manager + * service to control the device's power usage while playing is occurring. + * The parameter is a combination of {@link android.os.PowerManager} wake flags. + * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK} + * permission. + * By default, no attempt is made to keep the device awake during playback. + * + * @param context the Context to use + * @param mode the power/wake mode to set + * @return a token which can be used to cancel the operation later with {@link #cancel}. + * @see android.os.PowerManager */ - public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; + // This is an asynchronous call. + public abstract Object setWakeMode(Context context, int mode); /** - * Sets video scaling mode. To make the target video scaling mode - * effective during playback, this method must be called after - * data source is set. If not called, the default video - * scaling mode is {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}. - * - * <p> The supported video scaling modes are: - * <ul> - * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT} - * </ul> + * Control whether we should use the attached SurfaceHolder to keep the + * screen on while video playback is occurring. This is the preferred + * method over {@link #setWakeMode} where possible, since it doesn't + * require that the application have permission for low-level wake lock + * access. * - * @param mode target video scaling mode. Must be one of the supported - * video scaling modes; otherwise, IllegalArgumentException will be thrown. + * @param screenOn Supply true to keep the screen on, false to allow it to turn off. * @return a token which can be used to cancel the operation later with {@link #cancel}. - * - * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT - * @hide */ - public abstract Object setVideoScalingMode(int mode); + // This is an asynchronous call. + public abstract Object setScreenOnWhilePlaying(boolean screenOn); /** * Cancels a pending command. @@ -702,7 +616,7 @@ public abstract class MediaPlayer2 implements AutoCloseable * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and * does not correspond to a valid audio device. */ - // This is an asynchronous call. + // This is a synchronous call. @Override public abstract boolean setPreferredDevice(AudioDeviceInfo deviceInfo); @@ -747,36 +661,6 @@ public abstract class MediaPlayer2 implements AutoCloseable AudioRouting.OnRoutingChangedListener listener); /** - * Set the low-level power management behavior for this MediaPlayer2. - * - * <p>This function has the MediaPlayer2 access the low-level power manager - * service to control the device's power usage while playing is occurring. - * The parameter is a combination of {@link android.os.PowerManager} wake flags. - * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK} - * permission. - * By default, no attempt is made to keep the device awake during playback. - * - * @param context the Context to use - * @param mode the power/wake mode to set - * @see android.os.PowerManager - * @hide - */ - public abstract void setWakeMode(Context context, int mode); - - /** - * Control whether we should use the attached SurfaceHolder to keep the - * screen on while video playback is occurring. This is the preferred - * method over {@link #setWakeMode} where possible, since it doesn't - * require that the application have permission for low-level wake lock - * access. - * - * @param screenOn Supply true to keep the screen on, false to allow it - * to turn off. - * @hide - */ - public abstract void setScreenOnWhilePlaying(boolean screenOn); - - /** * Returns the width of the video. * * @return the width of the video, or 0 if there is no video, @@ -1719,17 +1603,20 @@ public abstract class MediaPlayer2 implements AutoCloseable */ public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 31; - /** The player just completed a call {@link #setVideoScalingMode}. + /** The player just completed a call {@link #setDisplay}. + * @see EventCallback#onCallCompleted + */ + public static final int CALL_COMPLETED_SET_DISPLAY = 33; + + /** The player just completed a call {@link #setWakeMode}. * @see EventCallback#onCallCompleted - * @hide */ - public static final int CALL_COMPLETED_SET_VIDEO_SCALING_MODE = 32; + public static final int CALL_COMPLETED_SET_WAKE_MODE = 34; - /** The player just completed a call {@link #setDisplay}. + /** The player just completed a call {@link #setScreenOnWhilePlaying}. * @see EventCallback#onCallCompleted - * @hide */ - public static final int CALL_COMPLETED_SET_DISPLAY = 33; + public static final int CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING = 35; /** * The start of the methods which have separate call complete callback. @@ -1776,8 +1663,9 @@ public abstract class MediaPlayer2 implements AutoCloseable CALL_COMPLETED_SKIP_TO_NEXT, CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, CALL_COMPLETED_SET_BUFFERING_PARAMS, - CALL_COMPLETED_SET_VIDEO_SCALING_MODE, CALL_COMPLETED_SET_DISPLAY, + CALL_COMPLETED_SET_WAKE_MODE, + CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING, CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, CALL_COMPLETED_PREPARE_DRM, }) diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java index ef8db1d4dcba..6697a4f9916c 100644 --- a/media/java/android/media/MediaPlayer2Impl.java +++ b/media/java/android/media/MediaPlayer2Impl.java @@ -19,11 +19,11 @@ package android.media; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.ContentProvider; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; -import android.graphics.SurfaceTexture; import android.graphics.Rect; import android.media.MediaPlayer2Proto.PlayerMessage; import android.media.MediaPlayer2Proto.Value; @@ -34,8 +34,6 @@ import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.PowerManager; -import android.os.SystemProperties; -import android.provider.Settings; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -78,18 +76,22 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { native_init(); } + private static final int NEXT_SOURCE_STATE_ERROR = -1; + private static final int NEXT_SOURCE_STATE_INIT = 0; + private static final int NEXT_SOURCE_STATE_PREPARING = 1; + private static final int NEXT_SOURCE_STATE_PREPARED = 2; + private final static String TAG = "MediaPlayer2Impl"; private Context mContext; - private long mNativeContext; // accessed by native methods + private long mNativeContext; // accessed by native methods private long mNativeSurfaceTexture; // accessed by native methods - private int mListenerContext; // accessed by native methods + private int mListenerContext; // accessed by native methods private SurfaceHolder mSurfaceHolder; private PowerManager.WakeLock mWakeLock = null; private boolean mScreenOnWhilePlaying; private boolean mStayAwake; - private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; private final Object mSrcLock = new Object(); //--- guarded by |mSrcLock| start @@ -134,7 +136,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { /** * Default constructor. - * <p>When done with the MediaPlayer2Impl, you should call {@link #close()}, + * <p>When done with the MediaPlayer2Impl, you should call {@link #close()}, * to free the resources. If not released, too many MediaPlayer2Impl instances may * result in an exception.</p> */ @@ -152,45 +154,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } @Override - public MediaPlayerBase getMediaPlayerBase() { - return null; - } - - /** - * Releases the resources held by this {@code MediaPlayer2} object. - * - * It is considered good practice to call this method when you're - * done using the MediaPlayer2. In particular, whenever an Activity - * of an application is paused (its onPause() method is called), - * or stopped (its onStop() method is called), this method should be - * invoked to release the MediaPlayer2 object, unless the application - * has a special need to keep the object around. In addition to - * unnecessary resources (such as memory and instances of codecs) - * being held, failure to call this method immediately if a - * MediaPlayer2 object is no longer needed may also lead to - * continuous battery consumption for mobile devices, and playback - * failure for other applications if no multiple instances of the - * same codec are supported on a device. Even if multiple instances - * of the same codec are supported, some performance degradation - * may be expected when unnecessary multiple instances are used - * at the same time. - * - * {@code close()} may be safely called after a prior {@code close()}. - * This class implements the Java {@code AutoCloseable} interface and - * may be used with try-with-resources. - */ - @Override public void close() { super.close(); release(); } - /** - * Starts or resumes playback. If playback had previously been paused, - * playback will continue from where it was paused. If playback had - * been stopped, or never started before, playback will start at the - * beginning. - */ @Override public Object play() { return addTask(new Task(CALL_COMPLETED_PLAY, false) { @@ -204,14 +172,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native void _start() throws IllegalStateException; - /** - * Prepares the player for playback, asynchronously. - * - * After setting the datasource and the display surface, you need to either - * call prepare(). For streams, you should call prepare(), - * which returns immediately, rather than blocking until enough data has been - * buffered. - */ @Override public Object prepare() { return addTask(new Task(CALL_COMPLETED_PREPARE, true) { @@ -224,9 +184,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { public native void _prepare(); - /** - * Pauses playback. Call play() to resume. - */ @Override public Object pause() { return addTask(new Task(CALL_COMPLETED_PAUSE, false) { @@ -241,11 +198,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native void _pause() throws IllegalStateException; - /** - * Tries to play next data source if applicable. - * - * @throws IllegalStateException if it is called in an invalid state - */ @Override public Object skipToNext() { return addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) { @@ -259,32 +211,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { }); } - /** - * Gets the current playback position. - * - * @return the current position in milliseconds - */ @Override public native long getCurrentPosition(); - /** - * Gets the duration of the file. - * - * @return the duration in milliseconds, if no duration is available - * (for example, if streaming live content), -1 is returned. - */ @Override public native long getDuration(); - /** - * Gets the current buffered media source position received through progressive downloading. - * The received buffering percentage indicates how much of the content has been buffered - * or played. For example a buffering update of 80 percent when half the content - * has already been played indicates that the next 30 percent of the - * content to play has been buffered. - * - * @return the current buffered media source position in milliseconds - */ @Override public long getBufferedPosition() { // Use cached buffered percent for now. @@ -298,14 +230,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native int native_getState(); - /** - * Sets the audio attributes for this MediaPlayer2. - * See {@link AudioAttributes} for how to build and configure an instance of this class. - * You must call this method before {@link #prepare()} in order - * for the audio attributes to become effective thereafter. - * @param attributes a non-null set of audio attributes - * @throws IllegalArgumentException if the attributes are null or invalid. - */ @Override public Object setAudioAttributes(@NonNull AudioAttributes attributes) { return addTask(new Task(CALL_COMPLETED_SET_AUDIO_ATTRIBUTES, false) { @@ -326,11 +250,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { return attributes; } - /** - * Sets the data source as described by a DataSourceDesc. - * - * @param dsd the descriptor of data source you want to play - */ @Override public Object setDataSource(@NonNull DataSourceDesc dsd) { return addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) { @@ -351,12 +270,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { }); } - /** - * Sets a single data source as described by a DataSourceDesc which will be played - * after current data source is finished. - * - * @param dsd the descriptor of data source you want to play after current one - */ @Override public Object setNextDataSource(@NonNull DataSourceDesc dsd) { return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) { @@ -374,11 +287,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { }); } - /** - * Sets a list of data sources to be played sequentially after current data source is done. - * - * @param dsds the list of data sources you want to play after current one - */ @Override public Object setNextDataSources(@NonNull List<DataSourceDesc> dsds) { return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCES, false) { @@ -428,16 +336,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - /** - * Configures the player to loop on the current data source. - * @param loop true if the current data source is meant to loop. - */ @Override public Object loopCurrent(boolean loop) { return addTask(new Task(CALL_COMPLETED_LOOP_CURRENT, false) { @Override void process() { - // TODO: set the looping mode, send notification setLooping(loop); } }); @@ -445,57 +348,29 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native void setLooping(boolean looping); - /** - * Sets the volume of the audio of the media to play, expressed as a linear multiplier - * on the audio samples. - * Note that this volume is specific to the player, and is separate from stream volume - * used across the platform.<br> - * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified - * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player. - * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}. - */ @Override public Object setPlayerVolume(float volume) { return addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) { @Override void process() { mVolume = volume; - _setVolume(volume); + native_setVolume(volume); } }); } - private native void _setVolume(float volume); + private native void native_setVolume(float volume); - /** - * Returns the current volume of this player to this player. - * Note that it does not take into account the associated stream volume. - * @return the player volume. - */ @Override public float getPlayerVolume() { return mVolume; } - /** - * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}. - */ @Override public float getMaxPlayerVolume() { return 1.0f; } - private static final int NEXT_SOURCE_STATE_ERROR = -1; - private static final int NEXT_SOURCE_STATE_INIT = 0; - private static final int NEXT_SOURCE_STATE_PREPARING = 1; - private static final int NEXT_SOURCE_STATE_PREPARED = 2; - - /* - * Update the MediaPlayer2Impl SurfaceTexture. - * Call after setting a new display surface. - */ - private native void _setVideoSurface(Surface surface); - /* Do not change these values (starting with INVOKE_ID) without updating * their counterparts in include/media/mediaplayer2.h! */ @@ -504,7 +379,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3; private static final int INVOKE_ID_SELECT_TRACK = 4; private static final int INVOKE_ID_DESELECT_TRACK = 5; - private static final int INVOKE_ID_SET_VIDEO_SCALE_MODE = 6; private static final int INVOKE_ID_GET_SELECTED_TRACK = 7; /** @@ -518,7 +392,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { * native player. */ private PlayerMessage invoke(PlayerMessage msg) { - byte[] ret = _invoke(msg.toByteArray()); + byte[] ret = native_invoke(msg.toByteArray()); if (ret == null) { return null; } @@ -529,7 +403,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - private native byte[] _invoke(byte[] request); + private native byte[] native_invoke(byte[] request); @Override public Object notifyWhenCommandLabelReached(Object label) { @@ -559,7 +433,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } else { surface = null; } - _setVideoSurface(surface); + native_setVideoSurface(surface); updateSurfaceScreenOn(); } }); @@ -574,49 +448,13 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface"); } mSurfaceHolder = null; - _setVideoSurface(surface); + native_setVideoSurface(surface); updateSurfaceScreenOn(); } }); } - /** - * Sets video scaling mode. To make the target video scaling mode - * effective during playback, this method must be called after - * data source is set. If not called, the default video - * scaling mode is {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT}. - * - * <p> The supported video scaling modes are: - * <ul> - * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT} - * <li> {@link #VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING} - * </ul> - * - * @param mode target video scaling mode. Must be one of the supported - * video scaling modes; otherwise, IllegalArgumentException will be thrown. - * - * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT - * @see MediaPlayer2#VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING - * @hide - */ - @Override - public Object setVideoScalingMode(int mode) { - return addTask(new Task(CALL_COMPLETED_SET_VIDEO_SCALING_MODE, false) { - @Override - void process() { - if (!isVideoScalingModeSupported(mode)) { - final String msg = "Scaling mode " + mode + " is not supported"; - throw new IllegalArgumentException(msg); - } - PlayerMessage request = PlayerMessage.newBuilder() - .addValues(Value.newBuilder() - .setInt32Value(INVOKE_ID_SET_VIDEO_SCALE_MODE)) - .addValues(Value.newBuilder().setInt32Value(mode)) - .build(); - invoke(request); - } - }); - } + private native void native_setVideoSurface(Surface surface); @Override public boolean cancelCommand(Object token) { @@ -632,26 +470,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - private Object addTask(Task task) { - synchronized (mTaskLock) { - mPendingTasks.add(task); - processPendingTask_l(); - } - return task; - } - - @GuardedBy("mTaskLock") - private void processPendingTask_l() { - if (mCurrentTask != null) { - return; - } - if (!mPendingTasks.isEmpty()) { - Task task = mPendingTasks.remove(0); - mCurrentTask = task; - mTaskHandler.post(task); - } - } - private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd, long srcId) throws IOException { checkArgument(dsd != null, "the DataSourceDesc cannot be null"); @@ -875,9 +693,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { boolean isCurrent, long srcId, Media2DataSource dataSource, long startPos, long endPos); - /** - * @return true if there is a next data source, false otherwise. - */ + // return true if there is a next data source, false otherwise. // This function should be always called on |mHandlerThread|. private boolean prepareNextDataSource() { if (Looper.myLooper() != mHandlerThread.getLooper()) { @@ -975,30 +791,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native void nativePlayNextDataSource(long srcId); - - private int getAudioStreamType() { - if (mStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { - mStreamType = _getAudioStreamType(); - } - return mStreamType; - } - - private native int _getAudioStreamType() throws IllegalStateException; - - //-------------------------------------------------------------------------- // Explicit Routing //-------------------- private AudioDeviceInfo mPreferredDevice = null; - /** - * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route - * the output from this MediaPlayer2. - * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source. - * If deviceInfo is null, default routing is restored. - * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and - * does not correspond to a valid audio device. - */ @Override public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) { if (deviceInfo != null && !deviceInfo.isSink()) { @@ -1014,10 +811,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { return status; } - /** - * Returns the selected output specified by {@link #setPreferredDevice}. Note that this - * is not guaranteed to correspond to the actual device being used for playback. - */ @Override public AudioDeviceInfo getPreferredDevice() { synchronized (this) { @@ -1025,12 +818,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - /** - * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer2 - * Note: The query is only valid if the MediaPlayer2 is currently playing. - * If the player is not playing, the returned device can be null or correspond to previously - * selected device when the player was last active. - */ @Override public AudioDeviceInfo getRoutedDevice() { int deviceId = native_getRoutedDeviceId(); @@ -1047,9 +834,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { return null; } - /* - * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler. - */ + // Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler. @GuardedBy("mRoutingChangeListeners") private void enableNativeRoutingCallbacksLocked(boolean enabled) { if (mRoutingChangeListeners.size() == 0) { @@ -1057,23 +842,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - /** - * The list of AudioRouting.OnRoutingChangedListener interfaces added (with - * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)} - * by an app to receive (re)routing notifications. - */ + // The list of AudioRouting.OnRoutingChangedListener interfaces added with + // addOnRoutingChangedListener by an app to receive (re)routing notifications. @GuardedBy("mRoutingChangeListeners") private ArrayMap<AudioRouting.OnRoutingChangedListener, NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>(); - /** - * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing - * changes on this MediaPlayer2. - * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive - * notifications of rerouting events. - * @param handler Specifies the {@link Handler} object for the thread on which to execute - * the callback. If <code>null</code>, the handler on the main looper will be used. - */ @Override public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, Handler handler) { @@ -1087,12 +861,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - /** - * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added - * to receive rerouting notifications. - * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface - * to remove. - */ @Override public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) { synchronized (mRoutingChangeListeners) { @@ -1107,70 +875,59 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native final int native_getRoutedDeviceId(); private native final void native_enableDeviceCallback(boolean enabled); - /** - * Set the low-level power management behavior for this MediaPlayer2. This - * can be used when the MediaPlayer2 is not playing through a SurfaceHolder - * set with {@link #setDisplay(SurfaceHolder)} and thus can use the - * high-level {@link #setScreenOnWhilePlaying(boolean)} feature. - * - * <p>This function has the MediaPlayer2 access the low-level power manager - * service to control the device's power usage while playing is occurring. - * The parameter is a combination of {@link android.os.PowerManager} wake flags. - * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK} - * permission. - * By default, no attempt is made to keep the device awake during playback. - * - * @param context the Context to use - * @param mode the power/wake mode to set - * @see android.os.PowerManager - * @hide - */ @Override - public void setWakeMode(Context context, int mode) { - boolean washeld = false; + public Object setWakeMode(Context context, int mode) { + return addTask(new Task(CALL_COMPLETED_SET_WAKE_MODE, false) { + @Override + void process() { + boolean washeld = false; - /* Disable persistant wakelocks in media player based on property */ - if (SystemProperties.getBoolean("audio.offload.ignore_setawake", false) == true) { - Log.w(TAG, "IGNORING setWakeMode " + mode); - return; - } + if (mWakeLock != null) { + if (mWakeLock.isHeld()) { + washeld = true; + mWakeLock.release(); + } + mWakeLock = null; + } - if (mWakeLock != null) { - if (mWakeLock.isHeld()) { - washeld = true; - mWakeLock.release(); + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + ActivityManager am = + (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List<RunningAppProcessInfo> runningAppsProcInfo = am.getRunningAppProcesses(); + int pid = android.os.Process.myPid(); + String name = "pid " + String.valueOf(pid); + if (runningAppsProcInfo != null) { + for (RunningAppProcessInfo procInfo : runningAppsProcInfo) { + if (procInfo.pid == pid) { + name = procInfo.processName; + break; + } + } + } + mWakeLock = pm.newWakeLock(mode | PowerManager.ON_AFTER_RELEASE, name); + mWakeLock.setReferenceCounted(false); + if (washeld) { + mWakeLock.acquire(); + } } - mWakeLock = null; - } - - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(mode|PowerManager.ON_AFTER_RELEASE, MediaPlayer2Impl.class.getName()); - mWakeLock.setReferenceCounted(false); - if (washeld) { - mWakeLock.acquire(); - } + }); } - /** - * Control whether we should use the attached SurfaceHolder to keep the - * screen on while video playback is occurring. This is the preferred - * method over {@link #setWakeMode} where possible, since it doesn't - * require that the application have permission for low-level wake lock - * access. - * - * @param screenOn Supply true to keep the screen on, false to allow it - * to turn off. - * @hide - */ @Override - public void setScreenOnWhilePlaying(boolean screenOn) { - if (mScreenOnWhilePlaying != screenOn) { - if (screenOn && mSurfaceHolder == null) { - Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder"); + public Object setScreenOnWhilePlaying(boolean screenOn) { + return addTask(new Task(CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING, false) { + @Override + void process() { + if (mScreenOnWhilePlaying != screenOn) { + if (screenOn && mSurfaceHolder == null) { + Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective" + + " without a SurfaceHolder"); + } + mScreenOnWhilePlaying = screenOn; + updateSurfaceScreenOn(); + } } - mScreenOnWhilePlaying = screenOn; - updateSurfaceScreenOn(); - } + }); } private void stayAwake(boolean awake) { @@ -1191,42 +948,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - /** - * Returns the width of the video. - * - * @return the width of the video, or 0 if there is no video, - * no display surface was set, or the width has not been determined - * yet. The {@code EventCallback} can be registered via - * {@link #setEventCallback(Executor, EventCallback)} to provide a - * notification {@code EventCallback.onVideoSizeChanged} when the width - * is available. - */ @Override public native int getVideoWidth(); - /** - * Returns the height of the video. - * - * @return the height of the video, or 0 if there is no video, - * no display surface was set, or the height has not been determined - * yet. The {@code EventCallback} can be registered via - * {@link #setEventCallback(Executor, EventCallback)} to provide a - * notification {@code EventCallback.onVideoSizeChanged} when the height - * is available. - */ @Override public native int getVideoHeight(); - /** - * Return Metrics data about the current player. - * - * @return a {@link PersistableBundle} containing the set of attributes and values - * available for the media being handled by this instance of MediaPlayer2 - * The attributes are descibed in {@link MetricsConstants}. - * - * Additional vendor-specific fields may also be present in - * the return value. - */ @Override public PersistableBundle getMetrics() { PersistableBundle bundle = native_getMetrics(); @@ -1235,27 +962,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native PersistableBundle native_getMetrics(); - /** - * Checks whether the MediaPlayer2 is playing. - * - * @return true if currently playing, false otherwise - * @throws IllegalStateException if the internal player engine has not been - * initialized or has been released. - * @hide - */ @Override public native boolean isPlaying(); - /** - * Gets the current buffering management params used by the source component. - * Calling it only after {@code setDataSource} has been called. - * Each type of data source might have different set of default params. - * - * @return the current buffering management params used by the source component. - * @throws IllegalStateException if the internal player engine has not been - * initialized, or {@code setDataSource} has not been called. - * @hide - */ @Override @NonNull public native BufferingParams getBufferingParams(); @@ -3388,13 +3097,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { // Modular DRM end - /* - * Test whether a given video scaling mode is supported. - */ - private boolean isVideoScalingModeSupported(int mode) { - return (mode == VIDEO_SCALING_MODE_SCALE_TO_FIT || - mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING); - } private static class TimedTextUtil { // These keys must be in sync with the keys in TextDescription2.h @@ -3450,6 +3152,26 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } + private Object addTask(Task task) { + synchronized (mTaskLock) { + mPendingTasks.add(task); + processPendingTask_l(); + } + return task; + } + + @GuardedBy("mTaskLock") + private void processPendingTask_l() { + if (mCurrentTask != null) { + return; + } + if (!mPendingTasks.isEmpty()) { + Task task = mPendingTasks.remove(0); + mCurrentTask = task; + mTaskHandler.post(task); + } + } + private abstract class Task implements Runnable { private final int mMediaCallType; private final boolean mNeedToWaitForEventToComplete; diff --git a/media/jni/Android.bp b/media/jni/Android.bp index fa9ab1f72688..0f531c9e61e8 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -123,14 +123,12 @@ cc_library_shared { "libcutils", "libmedia_helper", "libmedia_player2_util", - "libmediadrm", "libmediaextractor", "libmediametrics", "libmediaplayer2", "libmediaplayer2-protos", "libmediandk_utils", "libmediautils", - "libnetd_client", // for setNetworkForUser "libprotobuf-cpp-lite", "libstagefright_esds", "libstagefright_foundation", @@ -139,7 +137,7 @@ cc_library_shared { "libstagefright_mpeg2support", "libstagefright_nuplayer2", "libstagefright_player2", - "libstagefright_rtsp", + "libstagefright_rtsp_player2", "libstagefright_timedtext2", "libmedia2_jni_core", ], diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 7cf8828c0623..8637adae3aa5 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -543,7 +543,7 @@ static String8 JStringToString8(JNIEnv *env, jstring const &jstr) { import jav.util.Iterator; HashMap<k, v> hm; - Set<Entry<k, v> > s = hm.entrySet(); + Set<Entry<k, v>> s = hm.entrySet(); Iterator i = s.iterator(); Entry e = s.next(); */ @@ -613,10 +613,10 @@ static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> } static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env, - List<Vector<uint8_t> > list) { + List<Vector<uint8_t>> list) { jclass clazz = gFields.arraylistClassId; jobject arrayList = env->NewObject(clazz, gFields.arraylist.init); - List<Vector<uint8_t> >::iterator iter = list.begin(); + List<Vector<uint8_t>>::iterator iter = list.begin(); while (iter != list.end()) { jbyteArray byteArray = VectorToJByteArray(env, *iter); env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray); @@ -1216,7 +1216,7 @@ static jobject android_media_MediaDrm_getSecureStops( return NULL; } - List<Vector<uint8_t> > secureStops; + List<Vector<uint8_t>> secureStops; status_t err = drm->getSecureStops(secureStops); @@ -1237,7 +1237,7 @@ static jobject android_media_MediaDrm_getSecureStopIds( return NULL; } - List<Vector<uint8_t> > secureStopIds; + List<Vector<uint8_t>> secureStopIds; status_t err = drm->getSecureStopIds(secureStopIds); diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp index 61c28eddfeac..f60e7dae4b26 100644 --- a/media/jni/android_media_MediaPlayer2.cpp +++ b/media/jni/android_media_MediaPlayer2.cpp @@ -893,20 +893,6 @@ android_media_MediaPlayer2_reset(JNIEnv *env, jobject thiz) process_media_player_call( env, thiz, mp->reset(), NULL, NULL ); } -static jint -android_media_MediaPlayer2_getAudioStreamType(JNIEnv *env, jobject thiz) -{ - sp<MediaPlayer2> mp = getMediaPlayer(env, thiz); - if (mp == NULL ) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return 0; - } - audio_stream_type_t streamtype; - process_media_player_call( env, thiz, mp->getAudioStreamType(&streamtype), NULL, NULL ); - ALOGV("getAudioStreamType: %d (streamtype)", streamtype); - return (jint) streamtype; -} - static jboolean android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, jobject) { @@ -1467,7 +1453,7 @@ static const JNINativeMethod gMethods[] = { (void *)android_media_MediaPlayer2_handleDataSourceCallback }, {"nativePlayNextDataSource", "(J)V", (void *)android_media_MediaPlayer2_playNextDataSource}, - {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer2_setVideoSurface}, + {"native_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer2_setVideoSurface}, {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams}, {"_setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams}, {"_prepare", "()V", (void *)android_media_MediaPlayer2_prepare}, @@ -1487,13 +1473,12 @@ static const JNINativeMethod gMethods[] = { {"getDuration", "()J", (void *)android_media_MediaPlayer2_getDuration}, {"_release", "()V", (void *)android_media_MediaPlayer2_release}, {"_reset", "()V", (void *)android_media_MediaPlayer2_reset}, - {"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer2_getAudioStreamType}, {"setParameter", "(ILjava/lang/Object;)Z", (void *)android_media_MediaPlayer2_setParameter}, {"getParameter", "(I)Ljava/lang/Object;", (void *)android_media_MediaPlayer2_getParameter}, {"setLooping", "(Z)V", (void *)android_media_MediaPlayer2_setLooping}, {"isLooping", "()Z", (void *)android_media_MediaPlayer2_isLooping}, - {"_setVolume", "(F)V", (void *)android_media_MediaPlayer2_setVolume}, - {"_invoke", "([B)[B", (void *)android_media_MediaPlayer2_invoke}, + {"native_setVolume", "(F)V", (void *)android_media_MediaPlayer2_setVolume}, + {"native_invoke", "([B)[B", (void *)android_media_MediaPlayer2_invoke}, {"native_init", "()V", (void *)android_media_MediaPlayer2_native_init}, {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer2_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer2_native_finalize}, diff --git a/media/native/midi/midi.cpp b/media/native/midi/midi.cpp index 78ca0ab2486e..a5bdba8569b8 100644 --- a/media/native/midi/midi.cpp +++ b/media/native/midi/midi.cpp @@ -338,7 +338,8 @@ public: numMessageBytes = std::min(maxBytes, numMessageBytes); memcpy(buffer, readBuffer + 1, numMessageBytes); if (timestampPtr != nullptr) { - *timestampPtr = *(uint64_t*)(readBuffer + readCount - sizeof(uint64_t)); + memcpy(timestampPtr, readBuffer + readCount - sizeof(uint64_t), + sizeof(*timestampPtr)); } } *numBytesReceivedPtr = numMessageBytes; diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp index 1b1bf8d4b34a..8f13497b2673 100644 --- a/packages/CarSystemUI/Android.bp +++ b/packages/CarSystemUI/Android.bp @@ -30,7 +30,7 @@ android_app { "SystemUIPluginLib", "SystemUISharedLib", "SettingsLib", - "android.car.user", + "android.car.userlib", "androidx.car_car", "androidx.legacy_legacy-support-v4", "androidx.recyclerview_recyclerview", diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index 8f33a7016b39..11366848874a 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -38,6 +38,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.Handler; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.storage.StorageManager; import android.provider.Settings; @@ -77,6 +78,10 @@ import java.util.Map; public class Assistant extends NotificationAssistantService { private static final String TAG = "ExtAssistant"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + public static final boolean AUTO_DEMOTE_NOTIFICATIONS = SystemProperties.getBoolean( + "debug.demote_notifs", false); + public static final boolean AGE_NOTIFICATIONS = SystemProperties.getBoolean( + "debug.age_notifs", false); private static final String TAG_ASSISTANT = "assistant"; private static final String TAG_IMPRESSION = "impression-set"; @@ -230,16 +235,19 @@ public class Assistant extends NotificationAssistantService { @NonNull ArrayList<Notification.Action> smartActions, @NonNull ArrayList<CharSequence> smartReplies) { Bundle signals = new Bundle(); + if (!smartActions.isEmpty()) { signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions); } if (!smartReplies.isEmpty()) { signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies); } - if (mNotificationCategorizer.shouldSilence(entry)) { - final int importance = entry.getImportance() < IMPORTANCE_LOW ? entry.getImportance() - : IMPORTANCE_LOW; - signals.putInt(KEY_IMPORTANCE, importance); + if (AUTO_DEMOTE_NOTIFICATIONS) { + if (mNotificationCategorizer.shouldSilence(entry)) { + final int importance = entry.getImportance() < IMPORTANCE_LOW + ? entry.getImportance() : IMPORTANCE_LOW; + signals.putInt(KEY_IMPORTANCE, importance); + } } return new Adjustment( @@ -445,13 +453,15 @@ public class Assistant extends NotificationAssistantService { protected final class AgingCallback implements Callback { @Override public void sendAdjustment(String key, int newImportance) { - NotificationEntry entry = mLiveNotifications.get(key); - if (entry != null) { - Bundle bundle = new Bundle(); - bundle.putInt(KEY_IMPORTANCE, newImportance); - Adjustment adjustment = new Adjustment(entry.getSbn().getPackageName(), key, bundle, - "aging", entry.getSbn().getUserId()); - adjustNotification(adjustment); + if (AGE_NOTIFICATIONS) { + NotificationEntry entry = mLiveNotifications.get(key); + if (entry != null) { + Bundle bundle = new Bundle(); + bundle.putInt(KEY_IMPORTANCE, newImportance); + Adjustment adjustment = new Adjustment(entry.getSbn().getPackageName(), key, + bundle, "aging", entry.getSbn().getUserId()); + adjustNotification(adjustment); + } } } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java index 1eb423e53267..74c7b5809337 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.provider.Settings; import android.util.Log; /** @@ -29,11 +30,11 @@ public class PackageInstalledReceiver extends BroadcastReceiver { private static final String TAG = PackageInstalledReceiver.class.getSimpleName(); private static final boolean DEBUG = false; - private static final boolean APP_INSTALLED_NOTIFICATION_ENABLED = false; @Override public void onReceive(Context context, Intent intent) { - if (!APP_INSTALLED_NOTIFICATION_ENABLED) { + if (Settings.Global.getInt(context.getContentResolver(), + Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED, 0) == 0) { return; } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index c996620c1a30..b46c288bdb00 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -672,6 +672,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.GPU_DEBUG_LAYER_APP, GlobalSettingsProto.Gpu.DEBUG_LAYER_APP); + dumpSetting(s, p, + Settings.Global.GPU_DEBUG_LAYERS_GLES, + GlobalSettingsProto.Gpu.DEBUG_LAYERS_GLES); p.end(gpuToken); final long hdmiToken = p.start(GlobalSettingsProto.HDMI); @@ -1117,6 +1120,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.SHOW_FIRST_CRASH_DIALOG, GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG); + dumpSetting(s, p, + Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, + GlobalSettingsProto.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED); // Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated. dumpSetting(s, p, Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG, @@ -1124,6 +1130,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG, GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG); + dumpSetting(s, p, + Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED, + GlobalSettingsProto.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED); final long smartSelectToken = p.start(GlobalSettingsProto.SMART_SELECTION); dumpSetting(s, p, diff --git a/packages/SimAppDialog/res/drawable/illo_sim_app_dialog.xml b/packages/SimAppDialog/res/drawable/illo_sim_app_dialog.xml new file mode 100644 index 000000000000..8dd88b4bc0b0 --- /dev/null +++ b/packages/SimAppDialog/res/drawable/illo_sim_app_dialog.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!-- Empty drawable as this is not displayed by default. Must be provided by resource overlay. --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" /> diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml index 5bcce4d108a8..12f9bb6b13ea 100644 --- a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml +++ b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml @@ -37,6 +37,22 @@ android:text="@string/install_carrier_app_description_default" android:layout_width="match_parent" android:layout_height="wrap_content"/> - </LinearLayout> + + <com.android.setupwizardlib.view.FillContentLayout + android:id="@+id/illo_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:visibility="gone"> + + <ImageView + android:src="@drawable/illo_sim_app_dialog" + style="@style/SuwContentIllustration" + android:contentDescription="@string/install_carrier_app_image_content_description" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + + </com.android.setupwizardlib.view.FillContentLayout> +</LinearLayout> </com.android.setupwizardlib.GlifLayout> diff --git a/packages/SimAppDialog/res/values/bools.xml b/packages/SimAppDialog/res/values/bools.xml new file mode 100644 index 000000000000..4953d5e3816b --- /dev/null +++ b/packages/SimAppDialog/res/values/bools.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- + Whether to show an illustration on the screen asking the user to download the carrier app. + May be set to true in a resource overlay as long as a drawable asset with ID + illo_sim_app_dialog is provided, along with a content description for accessibility with + string ID install_carrier_app_image_content_description. + --> + <bool name="show_sim_app_dialog_illo">false</bool> +</resources> diff --git a/packages/SimAppDialog/res/values/strings.xml b/packages/SimAppDialog/res/values/strings.xml index 87941cb25396..9e8359c7d62e 100644 --- a/packages/SimAppDialog/res/values/strings.xml +++ b/packages/SimAppDialog/res/values/strings.xml @@ -32,4 +32,6 @@ <string name="install_carrier_app_defer_action">Not now</string> <!-- Name of the button for downloading the carrier app [CHAR LIMIT=25] --> <string name="install_carrier_app_download_action">Download app</string> -</resources>
\ No newline at end of file + <!-- Empty placeholder string for an illustration content description that is supplied via resource overlay. [DO NOT TRANSLATE] --> + <string name="install_carrier_app_image_content_description" translatable="false" /> +</resources> diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java index 9e9b80d39ed7..8e8d9f741a81 100644 --- a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java +++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java @@ -65,6 +65,11 @@ public class InstallCarrierAppActivity extends Activity implements View.OnClickL Button downloadButton = findViewById(R.id.download_button); downloadButton.setOnClickListener(this); + // Show/hide illo depending on whether one was provided in a resource overlay + boolean showIllo = getResources().getBoolean(R.bool.show_sim_app_dialog_illo); + View illoContainer = findViewById(R.id.illo_container); + illoContainer.setVisibility(showIllo ? View.VISIBLE : View.GONE); + // Include carrier name in description text if its present in the intent Intent intent = getIntent(); if (intent != null) { diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index b770d5c88324..a00baaddb4b1 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -66,7 +66,7 @@ android_library { libs: [ "telephony-common", "android.car", - "android.car.user", + "android.car.userlib", ], aaptflags: [ @@ -120,7 +120,7 @@ android_library { "android.test.runner", "telephony-common", "android.car", - "android.car.user", + "android.car.userlib", "android.test.base", ], aaptflags: [ @@ -146,7 +146,7 @@ android_app { libs: [ "telephony-common", "android.car", - "android.car.user", + "android.car.userlib", ], dxflags: ["--multi-dex"], @@ -183,7 +183,7 @@ android_app { libs: [ "telephony-common", "android.car", - "android.car.user", + "android.car.userlib", ], srcs: [ diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md index 33c5551605c0..a8ce196cc359 100644 --- a/packages/SystemUI/README.md +++ b/packages/SystemUI/README.md @@ -164,7 +164,7 @@ Draws decorations about the screen in software (e.g. rounded corners, cutouts). ### [com.android.systemui.biometrics.BiometricDialogImpl](/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java) -Fingerprint UI. +Biometric UI. --- diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java index 0d758df11efc..dfa38babd63b 100644 --- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java @@ -497,7 +497,7 @@ public class RecentsView extends FrameLayout { @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { - mSystemInsets.set(insets.getSystemWindowInsets()); + mSystemInsets.set(insets.getSystemWindowInsetsAsRect()); mTaskStackView.setSystemInsets(mSystemInsets); requestLayout(); return insets; diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index 04623478804c..9baeaaac9b38 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -64,6 +64,7 @@ <item name="android:paddingBottom">@dimen/bottom_text_spacing_digital</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamilyLight</item> <item name="android:fontFeatureSettings">@*android:string/config_headlineFontFeatureSettings</item> + <item name="android:ellipsize">none</item> </style> <style name="BouncerSecurityContainer"> diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml new file mode 100644 index 000000000000..8247c27ff850 --- /dev/null +++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="#bbbbbb" /> + <padding android:padding="@dimen/ongoing_appops_chip_bg_padding" /> + <corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml new file mode 100644 index 000000000000..5e952e3c4413 --- /dev/null +++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<com.android.systemui.privacy.OngoingPrivacyChip + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/privacy_chip" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_margin="@dimen/ongoing_appops_chip_margin" + android:gravity="center_vertical|end" + android:orientation="horizontal" + android:paddingStart="@dimen/ongoing_appops_chip_side_padding" + android:paddingEnd="@dimen/ongoing_appops_chip_side_padding" + android:background="@drawable/privacy_chip_bg" + android:focusable="true"> + + <LinearLayout + android:id="@+id/icons_container" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:gravity="center_vertical|start" + /> + + <TextView + android:id="@+id/app_name" + android:layout_height="match_parent" + android:layout_width="wrap_content" + android:gravity="center_vertical|end" + /> +</com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml new file mode 100644 index 000000000000..b5e24a04f85e --- /dev/null +++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fillViewport ="true" + android:orientation="vertical"> + + <LinearLayout + android:id="@+id/dialog_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="@dimen/ongoing_appops_dialog_content_padding"> + + <LinearLayout + android:id="@+id/icons_container" + android:layout_width="match_parent" + android:layout_height="@dimen/ongoing_appops_dialog_icon_height" + android:orientation="horizontal" + android:gravity="center" + android:importantForAccessibility="no" + /> + + <LinearLayout + android:id="@+id/text_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:gravity="start" + /> + </LinearLayout> + +</ScrollView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/ongoing_privacy_text_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_text_item.xml new file mode 100644 index 000000000000..5595b130e041 --- /dev/null +++ b/packages/SystemUI/res/layout/ongoing_privacy_text_item.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textDirection="locale" + android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" +/>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml index 680112c73c0d..007070e3ffba 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml @@ -46,6 +46,8 @@ android:layout_weight="1" android:gravity="center_vertical|center_horizontal" /> + <include layout="@layout/ongoing_privacy_chip" /> + <com.android.systemui.BatteryMeterView android:id="@+id/battery" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index b31dc50be5d1..d8648fa01d25 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -147,7 +147,7 @@ <!-- The number of milliseconds before the ambient notification auto-dismisses. This will override the default pulse length. --> - <integer name="ambient_notification_decay">6000</integer> + <integer name="ambient_notification_decay">10000</integer> <!-- Minimum display time for a heads up notification, in milliseconds. --> <integer name="ambient_notification_minimum_time">2000</integer> @@ -461,5 +461,7 @@ <bool name="config_pipEnableDismissDragToEdge">true</bool> <!-- SystemUI Plugins that can be loaded on user builds. --> - <string-array name="config_pluginWhitelist" translatable="false" /> + <string-array name="config_pluginWhitelist" translatable="false"> + <item>com.android.systemui</item> + </string-array> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index f77d9234463e..525421a6870a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -932,4 +932,19 @@ <!-- How much we expand the touchable region of the status bar below the notch to catch touches that just start below the notch. --> <dimen name="display_cutout_touchable_region_size">12dp</dimen> + + <!-- Height of icons in Ongoing App Ops dialog. Both App Op icon and application icon --> + <dimen name="ongoing_appops_dialog_icon_height">48dp</dimen> + <!-- Margin between text lines in Ongoing App Ops dialog --> + <dimen name="ongoing_appops_dialog_text_margin">15dp</dimen> + <!-- Padding around Ongoing App Ops dialog content --> + <dimen name="ongoing_appops_dialog_content_padding">24dp</dimen> + <!-- Margins around the Ongoing App Ops chip. In landscape, the side margins are 0 --> + <dimen name="ongoing_appops_chip_margin">12dp</dimen> + <!-- Start and End padding for Ongoing App Ops chip --> + <dimen name="ongoing_appops_chip_side_padding">6dp</dimen> + <!-- Padding between background of Ongoing App Ops chip and content --> + <dimen name="ongoing_appops_chip_bg_padding">4dp</dimen> + <!-- Radius of Ongoing App Ops chip corners --> + <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index d67841213c7e..6f5d6577f700 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2131,7 +2131,7 @@ <string name="app_info">App info</string> <!-- Action label for switching to a browser for an instant app [CHAR LIMIT=20] --> - <string name="go_to_web">Go to web</string> + <string name="go_to_web">Go to browser</string> <!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] --> <string name="mobile_data">Mobile data</string> @@ -2238,4 +2238,39 @@ app for debugging. Will not be seen by users. [CHAR LIMIT=20] --> <string name="heap_dump_tile_name">Dump SysUI Heap</string> + <!-- Content description for ongoing privacy chip. Use with a single app [CHAR LIMIT=NONE]--> + <string name="ongoing_privacy_chip_content_single_app"><xliff:g id="app" example="Example App">%1$s</xliff:g> is using your <xliff:g id="types_list" example="camera, location">%2$s</xliff:g>.</string> + + <!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]--> + <string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string> + + <!-- Action on Ongoing Privacy Dialog to open application [CHAR LIMIT=10]--> + <string name="ongoing_privacy_dialog_open_app">Open app</string> + + <!-- Action on Ongoing Privacy Dialog to dismiss [CHAR LIMIT=10]--> + <string name="ongoing_privacy_dialog_cancel">Cancel</string> + + <!-- Action on Ongoing Privacy Dialog to dismiss [CHAR LIMIT=10]--> + <string name="ongoing_privacy_dialog_okay">Okay</string> + + <!-- Action on Ongoing Privacy Dialog to open privacy hub [CHAR LIMIT=10]--> + <string name="ongoing_privacy_dialog_open_settings">Settings</string> + + <!-- Text for item in Ongoing Privacy Dialog when only one app is using a particular type of app op [CHAR LIMIT=NONE] --> + <string name="ongoing_privacy_dialog_app_item"><xliff:g id="app" example="Example App">%1$s</xliff:g> is using your <xliff:g id="type" example="camera">%2$s</xliff:g> for the last <xliff:g id="time" example="3">%3$d</xliff:g> min</string> + + <!-- Text for item in Ongoing Privacy Dialog when only multiple apps are using a particular type of app op [CHAR LIMIT=NONE] --> + <string name="ongoing_privacy_dialog_apps_item"><xliff:g id="apps" example="Camera, Phone">%1$s</xliff:g> are using your <xliff:g id="type" example="camera">%2$s</xliff:g></string> + + <!-- Text for Ongoing Privacy Dialog when a single app is using app ops [CHAR LIMIT=NONE] --> + <string name="ongoing_privacy_dialog_single_app"><xliff:g id="app" example="Example App">%1$s</xliff:g> is using your <xliff:g id="types_list" example="camera, location">%2$s</xliff:g></string> + + <!-- Text for camera app op [CHAR LIMIT=12]--> + <string name="privacy_type_camera">camera</string> + + <!-- Text for location app op [CHAR LIMIT=12]--> + <string name="privacy_type_location">location</string> + + <!-- Text for microphone app op [CHAR LIMIT=12]--> + <string name="privacy_type_microphone">microphone</string> </resources> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java index 8cc6091f52f5..8e7fadb5c7cb 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java @@ -158,6 +158,10 @@ public class PluginInstanceManager<T extends Plugin> { // If a plugin is detected in the stack of a crash then this will be called for that // plugin, if the plugin causing a crash cannot be identified, they are all disabled // assuming one of them must be bad. + if (mWhitelistedPlugins.contains(info.mPackage)) { + // Don't disable whitelisted plugins as they are a part of the OS. + return; + } Log.w(TAG, "Disabling plugin " + info.mPackage + "/" + info.mClass); mManager.getPluginEnabler().setEnabled(new ComponentName(info.mPackage, info.mClass), false); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java index 208f4fedfe27..3f907a8aa348 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManager.java @@ -27,6 +27,8 @@ public interface PluginManager { // must be one of the channels created in NotificationChannels.java String NOTIFICATION_CHANNEL_ID = "ALR"; + String[] getWhitelistedPlugins(); + <T extends Plugin> T getOneShotPlugin(Class<T> cls); <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java index 82e8b3e48cfc..dc2a9bd5105b 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java @@ -210,6 +210,10 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage Uri uri = intent.getData(); ComponentName component = ComponentName.unflattenFromString( uri.toString().substring(10)); + if (mWhitelistedPlugins.contains(component.getPackageName())) { + // Don't disable whitelisted plugins as they are a part of the OS. + return; + } getPluginEnabler().setEnabled(component, false); mContext.getSystemService(NotificationManager.class).cancel(component.getClassName(), SystemMessage.NOTE_PLUGIN); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 2bc0e45c725d..e051317b96b6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -15,54 +15,164 @@ */ package com.android.keyguard; -import static android.view.Display.INVALID_DISPLAY; +import static android.view.Display.DEFAULT_DISPLAY; +import android.annotation.Nullable; import android.app.Presentation; import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnDismissListener; import android.graphics.Point; +import android.hardware.display.DisplayManager; import android.media.MediaRouter; import android.media.MediaRouter.RouteInfo; import android.os.Bundle; -import android.util.Slog; +import android.util.Log; +import android.util.SparseArray; import android.view.Display; import android.view.View; import android.view.WindowManager; +import java.util.function.BooleanSupplier; + // TODO(multi-display): Support multiple external displays public class KeyguardDisplayManager { protected static final String TAG = "KeyguardDisplayManager"; private static boolean DEBUG = KeyguardConstants.DEBUG; private final ViewMediatorCallback mCallback; + private final MediaRouter mMediaRouter; + private final DisplayManager mDisplayService; private final Context mContext; - Presentation mPresentation; private boolean mShowing; + private final SparseArray<Presentation> mPresentations = new SparseArray<>(); + + private final DisplayManager.DisplayListener mDisplayListener = + new DisplayManager.DisplayListener() { + + @Override + public void onDisplayAdded(int displayId) { + final Display display = mDisplayService.getDisplay(displayId); + if (mShowing) { + notifyIfChanged(() -> showPresentation(display)); + } + } + + @Override + public void onDisplayChanged(int displayId) { + if (displayId == DEFAULT_DISPLAY) return; + final Display display = mDisplayService.getDisplay(displayId); + if (display != null && mShowing) { + final Presentation presentation = mPresentations.get(displayId); + if (presentation != null && !presentation.getDisplay().equals(display)) { + hidePresentation(displayId); + showPresentation(display); + } + } + } + + @Override + public void onDisplayRemoved(int displayId) { + notifyIfChanged(() -> hidePresentation(displayId)); + } + }; + public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) { mContext = context; mCallback = callback; - mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE); + mMediaRouter = mContext.getSystemService(MediaRouter.class); + mDisplayService = mContext.getSystemService(DisplayManager.class); + mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */); + } + + /** + * @param display The display to show the presentation on. + * @return {@code true} if a presentation was added. + * {@code false} if the presentation cannot be added on that display or the presentation + * was already there. + */ + private boolean showPresentation(Display display) { + if (display == null || display.getDisplayId() == DEFAULT_DISPLAY) return false; + if (DEBUG) Log.i(TAG, "Keyguard enabled on display: " + display); + final int displayId = display.getDisplayId(); + Presentation presentation = mPresentations.get(displayId); + if (presentation == null) { + presentation = new KeyguardPresentation(mContext, display); + presentation.setOnDismissListener(dialog -> { + if (null != mPresentations.get(displayId)) { + mPresentations.remove(displayId); + } + }); + try { + presentation.show(); + } catch (WindowManager.InvalidDisplayException ex) { + Log.w(TAG, "Invalid display:", ex); + presentation = null; + } + if (presentation != null) { + mPresentations.append(displayId, presentation); + return true; + } + } + return false; + } + + /** + * @param displayId The id of the display to hide the presentation off. + * @return {@code true} if the a presentation was removed. + * {@code false} if the presentation was not added before. + */ + private boolean hidePresentation(int displayId) { + final Presentation presentation = mPresentations.get(displayId); + if (presentation != null) { + presentation.dismiss(); + mPresentations.remove(displayId); + return true; + } + return false; + } + + private void notifyIfChanged(BooleanSupplier updateMethod) { + if (updateMethod.getAsBoolean()) { + final int[] displayList = getPresentationDisplayIds(); + mCallback.onSecondaryDisplayShowingChanged(displayList); + } + } + + /** + * @return An array of displayId's on which a {@link KeyguardPresentation} is showing on. + */ + @Nullable + private int[] getPresentationDisplayIds() { + final int size = mPresentations.size(); + if (size == 0) return null; + + final int[] displayIds = new int[size]; + for (int i = mPresentations.size() - 1; i >= 0; i--) { + final Presentation presentation = mPresentations.valueAt(i); + if (presentation != null) { + displayIds[i] = presentation.getDisplay().getDisplayId(); + } + } + return displayIds; } public void show() { if (!mShowing) { - if (DEBUG) Slog.v(TAG, "show"); + if (DEBUG) Log.v(TAG, "show"); mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY); - updateDisplays(true); + notifyIfChanged(() -> updateDisplays(true /* showing */)); } mShowing = true; } public void hide() { if (mShowing) { - if (DEBUG) Slog.v(TAG, "hide"); + if (DEBUG) Log.v(TAG, "hide"); mMediaRouter.removeCallback(mMediaRouterCallback); - updateDisplays(false); + notifyIfChanged(() -> updateDisplays(false /* showing */)); } mShowing = false; } @@ -71,71 +181,38 @@ public class KeyguardDisplayManager { new MediaRouter.SimpleCallback() { @Override public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { - if (DEBUG) Slog.d(TAG, "onRouteSelected: type=" + type + ", info=" + info); - updateDisplays(mShowing); + if (DEBUG) Log.d(TAG, "onRouteSelected: type=" + type + ", info=" + info); + notifyIfChanged(() -> updateDisplays(mShowing)); } @Override public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { - if (DEBUG) Slog.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info); - updateDisplays(mShowing); + if (DEBUG) Log.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info); + notifyIfChanged(() -> updateDisplays(mShowing)); } @Override public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { - if (DEBUG) Slog.d(TAG, "onRoutePresentationDisplayChanged: info=" + info); - updateDisplays(mShowing); - } - }; - - private OnDismissListener mOnDismissListener = new OnDismissListener() { - - @Override - public void onDismiss(DialogInterface dialog) { - mPresentation = null; + if (DEBUG) Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info); + notifyIfChanged(() -> updateDisplays(mShowing)); } }; - protected void updateDisplays(boolean showing) { - Presentation originalPresentation = mPresentation; + protected boolean updateDisplays(boolean showing) { + boolean changed = false; if (showing) { - MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute( - MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY); - boolean useDisplay = route != null - && route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE; - Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null; - - if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) { - if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay()); - mPresentation.dismiss(); - mPresentation = null; - } - - if (mPresentation == null && presentationDisplay != null) { - if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay); - mPresentation = new KeyguardPresentation(mContext, presentationDisplay, - R.style.keyguard_presentation_theme); - mPresentation.setOnDismissListener(mOnDismissListener); - try { - mPresentation.show(); - } catch (WindowManager.InvalidDisplayException ex) { - Slog.w(TAG, "Invalid display:", ex); - mPresentation = null; - } + final Display[] displays = mDisplayService.getDisplays(); + for (Display display : displays) { + changed |= showPresentation(display); } } else { - if (mPresentation != null) { - mPresentation.dismiss(); - mPresentation = null; + changed = mPresentations.size() > 0; + for (int i = mPresentations.size() - 1; i >= 0; i--) { + mPresentations.valueAt(i).dismiss(); } + mPresentations.clear(); } - - // mPresentation is only updated when the display changes - if (mPresentation != originalPresentation) { - final int displayId = mPresentation != null - ? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY; - mCallback.onSecondaryDisplayShowingChanged(displayId); - } + return changed; } private final static class KeyguardPresentation extends Presentation { @@ -157,9 +234,10 @@ public class KeyguardDisplayManager { } }; - public KeyguardPresentation(Context context, Display display, int theme) { - super(context, display, theme); + KeyguardPresentation(Context context, Display display) { + super(context, display, R.style.keyguard_presentation_theme); getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + setCancelable(false); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index 50b98a10b7f0..79966f78373c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -17,6 +17,8 @@ package com.android.keyguard; import static android.app.slice.Slice.HINT_LIST_ITEM; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; import android.animation.LayoutTransition; import android.animation.ObjectAnimator; @@ -80,6 +82,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe private float mDarkAmount = 0; private LiveData<Slice> mLiveData; + private int mDisplayId = INVALID_DISPLAY; private int mIconSize; /** * Runnable called whenever the view contents change. @@ -129,6 +132,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe protected void onAttachedToWindow() { super.onAttachedToWindow(); + mDisplayId = getDisplay().getDisplayId(); // Make sure we always have the most current slice mLiveData.observeForever(this); Dependency.get(ConfigurationController.class).addCallback(this); @@ -138,7 +142,10 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mLiveData.removeObserver(this); + // TODO(b/117344873) Remove below work around after this issue be fixed. + if (mDisplayId == DEFAULT_DISPLAY) { + mLiveData.removeObserver(this); + } Dependency.get(ConfigurationController.class).removeCallback(this); } diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java index 41b86a7450a3..a07c5cbde956 100644 --- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java @@ -96,9 +96,9 @@ public interface ViewMediatorCallback { int getBouncerPromptReason(); /** - * Invoked when the secondary display showing a keyguard window changes. + * Invoked when the secondary displays showing a keyguard window changes. */ - void onSecondaryDisplayShowingChanged(int displayId); + void onSecondaryDisplayShowingChanged(int[] displayId); /** * Consumes a message that was enqueued to be displayed on the next time the bouncer shows up. diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 3fe99445f49d..e3584cf7493e 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -33,10 +33,11 @@ import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; + import com.android.systemui.classifier.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; public class SwipeHelper implements Gefingerpoken { static final String TAG = "com.android.systemui.SwipeHelper"; @@ -604,13 +605,15 @@ public class SwipeHelper implements Gefingerpoken { } // don't let items that can't be dismissed be dragged more than // maxScrollDistance - if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) { + if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissedInDirection(mCurrView, + delta > 0)) { float size = getSize(mCurrView); float maxScrollDistance = MAX_SCROLL_SIZE_FRACTION * size; if (absDelta >= size) { delta = delta > 0 ? maxScrollDistance : -maxScrollDistance; } else { - delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2)); + delta = maxScrollDistance * (float) Math.sin( + (delta / size) * (Math.PI / 2)); } } @@ -674,9 +677,11 @@ public class SwipeHelper implements Gefingerpoken { } public boolean isDismissGesture(MotionEvent ev) { + float translation = getTranslation(mCurrView); return ev.getActionMasked() == MotionEvent.ACTION_UP + && !mFalsingManager.isUnlockingDisabled() && !isFalseGesture(ev) && (swipedFastEnough() || swipedFarEnough()) - && mCallback.canChildBeDismissed(mCurrView); + && mCallback.canChildBeDismissedInDirection(mCurrView, translation > 0); } public boolean isFalseGesture(MotionEvent ev) { @@ -707,6 +712,16 @@ public class SwipeHelper implements Gefingerpoken { boolean canChildBeDismissed(View v); + /** + * Returns true if the provided child can be dismissed by a swipe in the given direction. + * + * @param isRightOrDown {@code true} if the swipe direction is right or down, + * {@code false} if it is left or up. + */ + default boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) { + return canChildBeDismissed(v); + } + boolean isAntiFalsingNeeded(); void onBeginDrag(View v); diff --git a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java index 69e347c9476d..4010c43f675e 100644 --- a/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java +++ b/packages/SystemUI/src/com/android/systemui/analytics/DataCollector.java @@ -16,6 +16,9 @@ package com.android.systemui.analytics; +import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session; +import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent; + import android.content.Context; import android.database.ContentObserver; import android.hardware.Sensor; @@ -36,9 +39,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session; -import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent; - /** * Tracks touch, sensor and phone events when the lockscreen is on. If the phone is unlocked * the data containing these events is saved to a file. This data is collected @@ -53,6 +53,8 @@ public class DataCollector implements SensorEventListener { private static final String COLLECT_BAD_TOUCHES = "data_collector_collect_bad_touches"; private static final String ALLOW_REJECTED_TOUCH_REPORTS = "data_collector_allow_rejected_touch_reports"; + private static final String DISABLE_UNLOCKING_FOR_FALSING_COLLECTION = + "data_collector_disable_unlocking"; private static final long TIMEOUT_MILLIS = 11000; // 11 seconds. public static final boolean DEBUG = false; @@ -65,11 +67,11 @@ public class DataCollector implements SensorEventListener { private SensorLoggerSession mCurrentSession = null; private boolean mEnableCollector = false; - private boolean mTimeoutActive = false; private boolean mCollectBadTouches = false; private boolean mCornerSwiping = false; private boolean mTrackingStarted = false; private boolean mAllowReportRejectedTouch = false; + private boolean mDisableUnlocking = false; private static DataCollector sInstance = null; @@ -98,6 +100,11 @@ public class DataCollector implements SensorEventListener { mSettingsObserver, UserHandle.USER_ALL); + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(DISABLE_UNLOCKING_FOR_FALSING_COLLECTION), false, + mSettingsObserver, + UserHandle.USER_ALL); + updateConfiguration(); } @@ -118,6 +125,9 @@ public class DataCollector implements SensorEventListener { mAllowReportRejectedTouch = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt( mContext.getContentResolver(), ALLOW_REJECTED_TOUCH_REPORTS, 0); + mDisableUnlocking = mEnableCollector && Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt( + mContext.getContentResolver(), + DISABLE_UNLOCKING_FOR_FALSING_COLLECTION, 0); } private boolean sessionEntrypoint() { @@ -144,7 +154,7 @@ public class DataCollector implements SensorEventListener { SensorLoggerSession session = mCurrentSession; mCurrentSession = null; - if (mEnableCollector) { + if (mEnableCollector || mDisableUnlocking) { session.end(System.currentTimeMillis(), result); queueSession(session); } @@ -183,11 +193,11 @@ public class DataCollector implements SensorEventListener { byte[] b = Session.toByteArray(currentSession.toProto()); String dir = mContext.getFilesDir().getAbsolutePath(); if (currentSession.getResult() != Session.SUCCESS) { - if (!mCollectBadTouches) { + if (!mDisableUnlocking && !mCollectBadTouches) { return; } dir += "/bad_touches"; - } else { + } else if (!mDisableUnlocking) { dir += "/good_touches"; } @@ -208,19 +218,6 @@ public class DataCollector implements SensorEventListener { public synchronized void onSensorChanged(SensorEvent event) { if (isEnabled() && mCurrentSession != null) { mCurrentSession.addSensorEvent(event, System.nanoTime()); - enforceTimeout(); - } - } - - private void enforceTimeout() { - if (mTimeoutActive) { - if (System.currentTimeMillis() - mCurrentSession.getStartTimestampMillis() - > TIMEOUT_MILLIS) { - onSessionEnd(Session.UNKNOWN); - if (DEBUG) { - Log.i(TAG, "Analytics timed out."); - } - } } } @@ -233,9 +230,12 @@ public class DataCollector implements SensorEventListener { * rejected touch report. */ public boolean isEnabled() { - return mEnableCollector || mAllowReportRejectedTouch; + return mEnableCollector || mAllowReportRejectedTouch || mDisableUnlocking; } + public boolean isUnlockingDisabled() { + return mDisableUnlocking; + } /** * @return true if the full data set for data gathering should be collected - including * extensive sensor data, which is is not normally included with rejected touch reports. @@ -450,7 +450,6 @@ public class DataCollector implements SensorEventListener { } mCurrentSession.addMotionEvent(event); mCurrentSession.setTouchArea(width, height); - enforceTimeout(); } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java index 3d578c39d3c4..2c61da343763 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java @@ -201,6 +201,9 @@ public class FalsingManager implements SensorEventListener { return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled(); } + public boolean isUnlockingDisabled() { + return mDataCollector.isUnlockingDisabled(); + } /** * @return true if the classifier determined that this is not a human interacting with the phone */ diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index c5664605dcef..5d99c571ee20 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -141,7 +141,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } private void updateBrightnessAndReady() { - if (mRegistered) { + if (mRegistered || mDebugBrightnessBucket != -1) { int sensorValue = mDebugBrightnessBucket == -1 ? mLastSensorValue : mDebugBrightnessBucket; int brightness = computeBrightness(sensorValue); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 4988f07ca3f3..fe1b35609ae5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -17,7 +17,6 @@ package com.android.systemui.keyguard; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; -import static android.view.Display.INVALID_DISPLAY; import static com.android.internal.telephony.IccCardConstants.State.ABSENT; import static com.android.internal.telephony.IccCardConstants.State.PIN_REQUIRED; @@ -95,6 +94,7 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; /** * Mediates requests related to the keyguard. This includes queries about the @@ -246,8 +246,8 @@ public class KeyguardViewMediator extends SystemUI { // AOD is enabled and status bar is in AOD state. private boolean mAodShowing; - // display id of the secondary display on which we have put a keyguard window - private int mSecondaryDisplayShowing = INVALID_DISPLAY; + // display ids of the external display on which we have put a keyguard window + private int[] mSecondaryDisplaysShowing; /** Cached value of #isInputRestricted */ private boolean mInputRestricted; @@ -700,9 +700,9 @@ public class KeyguardViewMediator extends SystemUI { } @Override - public void onSecondaryDisplayShowingChanged(int displayId) { + public void onSecondaryDisplayShowingChanged(int[] displayIds) { synchronized (KeyguardViewMediator.this) { - setShowingLocked(mShowing, mAodShowing, displayId, false); + setShowingLocked(mShowing, mAodShowing, displayIds, false); } } }; @@ -749,10 +749,10 @@ public class KeyguardViewMediator extends SystemUI { setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled( KeyguardUpdateMonitor.getCurrentUser()), - mAodShowing, mSecondaryDisplayShowing, true /* forceCallbacks */); + mAodShowing, mSecondaryDisplaysShowing, true /* forceCallbacks */); } else { // The system's keyguard is disabled or missing. - setShowingLocked(false, mAodShowing, mSecondaryDisplayShowing, true); + setShowingLocked(false, mAodShowing, mSecondaryDisplaysShowing, true); } mStatusBarKeyguardViewManager = @@ -1776,11 +1776,11 @@ public class KeyguardViewMediator extends SystemUI { } private void updateActivityLockScreenState(boolean showing, boolean aodShowing, - int secondaryDisplayShowing) { + int[] secondaryDisplaysShowing) { mUiOffloadThread.submit(() -> { try { ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing, - secondaryDisplayShowing); + secondaryDisplaysShowing); } catch (RemoteException e) { } }); @@ -1895,7 +1895,8 @@ public class KeyguardViewMediator extends SystemUI { if (!mHiding) { // Tell ActivityManager that we canceled the keyguardExitAnimation. - setShowingLocked(mShowing, mAodShowing, mSecondaryDisplayShowing, true /* force */); + setShowingLocked(mShowing, mAodShowing, mSecondaryDisplaysShowing, + true /* force */); return; } mHiding = false; @@ -2164,22 +2165,23 @@ public class KeyguardViewMediator extends SystemUI { } private void setShowingLocked(boolean showing, boolean aodShowing) { - setShowingLocked(showing, aodShowing, mSecondaryDisplayShowing, + setShowingLocked(showing, aodShowing, mSecondaryDisplaysShowing, false /* forceCallbacks */); } - private void setShowingLocked(boolean showing, boolean aodShowing, int secondaryDisplayShowing, - boolean forceCallbacks) { + private void setShowingLocked(boolean showing, boolean aodShowing, + int[] secondaryDisplaysShowing, boolean forceCallbacks) { final boolean notifyDefaultDisplayCallbacks = showing != mShowing || aodShowing != mAodShowing || forceCallbacks; - if (notifyDefaultDisplayCallbacks || secondaryDisplayShowing != mSecondaryDisplayShowing) { + if (notifyDefaultDisplayCallbacks + || !Arrays.equals(secondaryDisplaysShowing, mSecondaryDisplaysShowing)) { mShowing = showing; mAodShowing = aodShowing; - mSecondaryDisplayShowing = secondaryDisplayShowing; + mSecondaryDisplaysShowing = secondaryDisplaysShowing; if (notifyDefaultDisplayCallbacks) { notifyDefaultDisplayCallbacks(showing); } - updateActivityLockScreenState(showing, aodShowing, secondaryDisplayShowing); + updateActivityLockScreenState(showing, aodShowing, secondaryDisplaysShowing); } } diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index 568a03954b36..35ae899e0cc1 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -399,8 +399,8 @@ public class PowerUI extends SystemUI { if (b != null) { mThermalService = IThermalService.Stub.asInterface(b); try { - mThermalService.registerThermalEventListener( - new ThermalEventListener()); + mThermalService.registerThermalEventListenerWithType( + new ThermalEventListener(), Temperature.TYPE_SKIN); } catch (RemoteException e) { // Should never happen. } @@ -552,7 +552,7 @@ public class PowerUI extends SystemUI { // Thermal event received from vendor thermal management subsystem private final class ThermalEventListener extends IThermalEventListener.Stub { - @Override public void notifyThrottling(boolean isThrottling, Temperature temp) { + @Override public void notifyThrottling(Temperature temp) { // Trigger an update of the temperature warning. Only one // callback can be enabled at a time, so remove any existing // callback; updateTemperatureWarning will schedule another one. diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt new file mode 100644 index 000000000000..3953139d43fd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.privacy + +import android.app.ActivityManager +import android.app.AppOpsManager +import android.content.Context +import android.graphics.Color +import android.os.UserHandle +import android.os.UserManager +import android.util.AttributeSet +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import com.android.systemui.Dependency +import com.android.systemui.R +import com.android.systemui.appops.AppOpItem +import com.android.systemui.appops.AppOpsController + +class OngoingPrivacyChip @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttrs: Int = 0, + defStyleRes: Int = 0 +) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) { + + companion object { + val OPS = intArrayOf(AppOpsManager.OP_CAMERA, + AppOpsManager.OP_RECORD_AUDIO, + AppOpsManager.OP_COARSE_LOCATION, + AppOpsManager.OP_FINE_LOCATION) + } + + private lateinit var appName: TextView + private lateinit var iconsContainer: LinearLayout + private var privacyList = emptyList<PrivacyItem>() + private val appOpsController = Dependency.get(AppOpsController::class.java) + private val userManager = context.getSystemService(UserManager::class.java) + private val currentUser = ActivityManager.getCurrentUser() + private val currentUserIds = userManager.getProfiles(currentUser).map { it.id } + private var listening = false + + var builder = PrivacyDialogBuilder(context, privacyList) + + private val callback = object : AppOpsController.Callback { + override fun onActiveStateChanged( + code: Int, + uid: Int, + packageName: String, + active: Boolean + ) { + val userId = UserHandle.getUserId(uid) + if (userId in currentUserIds) { + updatePrivacyList() + } + } + } + + override fun onFinishInflate() { + super.onFinishInflate() + + appName = findViewById(R.id.app_name) + iconsContainer = findViewById(R.id.icons_container) + } + + fun setListening(listen: Boolean) { + if (listening == listen) return + listening = listen + if (listening) { + appOpsController.addCallback(OPS, callback) + updatePrivacyList() + } else { + appOpsController.removeCallback(OPS, callback) + } + } + + private fun updatePrivacyList() { + privacyList = currentUserIds.flatMap { appOpsController.getActiveAppOpsForUser(it) } + .mapNotNull { toPrivacyItem(it) } + builder = PrivacyDialogBuilder(context, privacyList) + updateView() + } + + private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? { + val type: PrivacyType = when (appOpItem.code) { + AppOpsManager.OP_CAMERA -> PrivacyType.TYPE_CAMERA + AppOpsManager.OP_COARSE_LOCATION -> PrivacyType.TYPE_LOCATION + AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION + AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE + else -> return null + } + val app = PrivacyApplication(appOpItem.packageName, context) + return PrivacyItem(type, app, appOpItem.timeStarted) + } + + // Should only be called if the builder icons or app changed + private fun updateView() { + fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) { + iconsContainer.removeAllViews() + dialogBuilder.generateIcons().forEach { + it.mutate() + it.setTint(Color.WHITE) + iconsContainer.addView(ImageView(context).apply { + setImageDrawable(it) + maxHeight = this@OngoingPrivacyChip.height + }) + } + } + + if (privacyList.isEmpty()) { + visibility = GONE + return + } else { + generateContentDescription() + visibility = VISIBLE + setIcons(builder, iconsContainer) + appName.visibility = GONE + builder.app?.let { + appName.apply { + setText(it.applicationName) + setTextColor(Color.WHITE) + visibility = VISIBLE + } + } + } + requestLayout() + } + + private fun generateContentDescription() { + val typesText = builder.generateTypesText() + if (builder.app != null) { + contentDescription = context.getString(R.string.ongoing_privacy_chip_content_single_app, + builder.app?.applicationName, typesText) + } else { + contentDescription = context.getString( + R.string.ongoing_privacy_chip_content_multiple_apps, typesText) + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt new file mode 100644 index 000000000000..1d0e16ed3334 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.privacy + +import android.app.AlertDialog +import android.app.Dialog +import android.content.Context +import android.content.DialogInterface +import android.graphics.drawable.Drawable +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import com.android.systemui.Dependency +import com.android.systemui.R +import com.android.systemui.plugins.ActivityStarter + +class OngoingPrivacyDialog constructor( + val context: Context, + val dialogBuilder: PrivacyDialogBuilder +) { + + val iconHeight = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_dialog_icon_height) + val textMargin = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_dialog_text_margin) + val iconColor = context.resources.getColor( + com.android.internal.R.color.text_color_primary, context.theme) + + fun createDialog(): Dialog { + val builder = AlertDialog.Builder(context) + .setNeutralButton(R.string.ongoing_privacy_dialog_open_settings, null) + if (dialogBuilder.app != null) { + builder.setPositiveButton(R.string.ongoing_privacy_dialog_open_app, + object : DialogInterface.OnClickListener { + val intent = context.packageManager + .getLaunchIntentForPackage(dialogBuilder.app.packageName) + + override fun onClick(dialog: DialogInterface?, which: Int) { + Dependency.get(ActivityStarter::class.java).startActivity(intent, false) + } + }) + builder.setNegativeButton(R.string.ongoing_privacy_dialog_cancel, null) + } else { + builder.setPositiveButton(R.string.ongoing_privacy_dialog_okay, null) + } + builder.setView(getContentView()) + return builder.create() + } + + fun getContentView(): View { + val layoutInflater = LayoutInflater.from(context) + val contentView = layoutInflater.inflate(R.layout.ongoing_privacy_dialog_content, null) + + val iconsContainer = contentView.findViewById(R.id.icons_container) as LinearLayout + val textContainer = contentView.findViewById(R.id.text_container) as LinearLayout + + addIcons(dialogBuilder, iconsContainer) + val lm = ViewGroup.MarginLayoutParams( + ViewGroup.MarginLayoutParams.WRAP_CONTENT, + ViewGroup.MarginLayoutParams.WRAP_CONTENT) + lm.topMargin = textMargin + val now = System.currentTimeMillis() + dialogBuilder.generateText(now).forEach { + val text = layoutInflater.inflate(R.layout.ongoing_privacy_text_item, null) as TextView + text.setText(it) + textContainer.addView(text, lm) + } + return contentView + } + + private fun addIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: LinearLayout) { + + fun LinearLayout.addIcon(icon: Drawable) { + val image = ImageView(context).apply { + setImageDrawable(icon.apply { + setBounds(0, 0, iconHeight, iconHeight) + maxHeight = this@addIcon.height + }) + adjustViewBounds = true + } + addView(image, LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.MATCH_PARENT) + } + + dialogBuilder.generateIcons().forEach { + it.mutate() + it.setTint(iconColor) + iconsContainer.addIcon(it) + } + dialogBuilder.app.let { + it?.icon?.let { iconsContainer.addIcon(it) } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt new file mode 100644 index 000000000000..2f86f78d7669 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.privacy + +import android.content.Context +import com.android.systemui.R +import java.lang.IllegalStateException +import java.lang.Math.max + +class PrivacyDialogBuilder(val context: Context, itemsList: List<PrivacyItem>) { + companion object { + val MILLIS_IN_MINUTE: Long = 1000 * 60 + } + + private val itemsByType: Map<PrivacyType, List<PrivacyItem>> + val app: PrivacyApplication? + + init { + itemsByType = itemsList.groupBy { it.privacyType } + val apps = itemsList.map { it.application }.distinct() + val singleApp = apps.size == 1 + app = if (singleApp) apps.get(0) else null + } + + private fun buildTextForItem(type: PrivacyType, now: Long): String { + val items = itemsByType.getOrDefault(type, emptyList<PrivacyItem>()) + return when (items.size) { + 0 -> throw IllegalStateException("List cannot be empty") + 1 -> { + val item = items.get(0) + val minutesUsed = max(((now - item.timeStarted) / MILLIS_IN_MINUTE).toInt(), 1) + context.getString(R.string.ongoing_privacy_dialog_app_item, + item.application.applicationName, type.getName(context), minutesUsed) + } + else -> { + val apps = items.map { it.application.applicationName }.joinToString() + context.getString(R.string.ongoing_privacy_dialog_apps_item, + apps, type.getName(context)) + } + } + } + + private fun buildTextForApp(types: Set<PrivacyType>): List<String> { + app?.let { + val typesText = types.map { it.getName(context) }.sorted().joinToString() + return listOf(context.getString(R.string.ongoing_privacy_dialog_single_app, + it.applicationName, typesText)) + } ?: throw IllegalStateException("There has to be a single app") + } + + fun generateText(now: Long): List<String> { + if (app == null || itemsByType.keys.size == 1) { + return itemsByType.keys.map { buildTextForItem(it, now) } + } else { + return buildTextForApp(itemsByType.keys) + } + } + + fun generateTypesText() = itemsByType.keys.map { it.getName(context) }.sorted().joinToString() + + fun generateIcons() = itemsByType.keys.map { it.getIcon(context) } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt new file mode 100644 index 000000000000..f4099021a0bd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.privacy + +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.graphics.drawable.Drawable +import com.android.systemui.R + +typealias Privacy = PrivacyType + +enum class PrivacyType(val nameId: Int, val iconId: Int) { + TYPE_CAMERA(R.string.privacy_type_camera, com.android.internal.R.drawable.ic_camera), + TYPE_LOCATION(R.string.privacy_type_location, R.drawable.stat_sys_location), + TYPE_MICROPHONE(R.string.privacy_type_microphone, R.drawable.ic_mic_26dp); + + fun getName(context: Context) = context.resources.getString(nameId) + + fun getIcon(context: Context) = context.resources.getDrawable(iconId, null) +} + +data class PrivacyItem( + val privacyType: PrivacyType, + val application: PrivacyApplication, + val timeStarted: Long +) + +data class PrivacyApplication(val packageName: String, val context: Context) { + var icon: Drawable? = null + var applicationName: String + + init { + try { + val app: ApplicationInfo = context.packageManager + .getApplicationInfo(packageName, 0) + icon = context.packageManager.getApplicationIcon(app) + applicationName = context.packageManager.getApplicationLabel(app) as String + } catch (e: PackageManager.NameNotFoundException) { + applicationName = packageName + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 326df498c984..3ee6195858d6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter; import android.annotation.ColorInt; import android.app.ActivityManager; import android.app.AlarmManager; +import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -31,6 +32,7 @@ import android.graphics.Color; import android.graphics.Rect; import android.media.AudioManager; import android.os.Handler; +import android.os.Looper; import android.provider.AlarmClock; import android.service.notification.ZenModeConfig; import android.text.format.DateUtils; @@ -39,6 +41,7 @@ import android.util.Log; import android.util.Pair; import android.view.View; import android.view.WindowInsets; +import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.RelativeLayout; @@ -52,11 +55,14 @@ import com.android.systemui.Dependency; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.privacy.OngoingPrivacyChip; +import com.android.systemui.privacy.OngoingPrivacyDialog; import com.android.systemui.qs.QSDetail.Callback; import com.android.systemui.statusbar.phone.PhoneStatusBarView; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager; import com.android.systemui.statusbar.phone.StatusIconContainer; +import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.Clock; import com.android.systemui.statusbar.policy.DarkIconDispatcher; import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; @@ -118,6 +124,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements private BatteryMeterView mBatteryMeterView; private Clock mClockView; private DateView mDateView; + private OngoingPrivacyChip mPrivacyChip; private NextAlarmController mAlarmController; private ZenModeController mZenController; @@ -185,6 +192,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements mClockView = findViewById(R.id.clock); mClockView.setOnClickListener(this); mDateView = findViewById(R.id.date); + mPrivacyChip = findViewById(R.id.privacy_chip); + mPrivacyChip.setOnClickListener(this); } private void updateStatusText() { @@ -263,6 +272,13 @@ public class QuickStatusBarHeader extends RelativeLayout implements newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE; mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor); mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor); + + MarginLayoutParams lm = (MarginLayoutParams) mPrivacyChip.getLayoutParams(); + int sideMargins = lm.leftMargin; + int topBottomMargins = (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) + ? 0 : sideMargins; + lm.setMargins(sideMargins, topBottomMargins, sideMargins, topBottomMargins); + mPrivacyChip.setLayoutParams(lm); } @Override @@ -421,6 +437,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements return; } mHeaderQsPanel.setListening(listening); + mPrivacyChip.setListening(listening); mListening = listening; if (listening) { @@ -443,6 +460,19 @@ public class QuickStatusBarHeader extends RelativeLayout implements } else if (v == mBatteryMeterView) { Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(new Intent( Intent.ACTION_POWER_USAGE_SUMMARY),0); + } else if (v == mPrivacyChip) { + Handler mUiHandler = new Handler(Looper.getMainLooper()); + mUiHandler.post(() -> { + Dialog mDialog = new OngoingPrivacyDialog(mContext, + mPrivacyChip.getBuilder()).createDialog(); + mDialog.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + SystemUIDialog.setShowForAllUsers(mDialog, true); + SystemUIDialog.registerDismissListener(mDialog); + SystemUIDialog.setWindowOnTop(mDialog); + mUiHandler.post(() -> mDialog.show()); + mHost.collapsePanels(); + }); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java index 8526afd34514..8a86826cd01d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java @@ -128,7 +128,8 @@ public class DragDownHelper implements Gefingerpoken { } return true; case MotionEvent.ACTION_UP: - if (!isFalseTouch() && mDragDownCallback.onDraggedDown(mStartingChild, + if (!mFalsingManager.isUnlockingDisabled() && !isFalseTouch() + && mDragDownCallback.onDraggedDown(mStartingChild, (int) (y - mInitialTouchY))) { if (mStartingChild == null) { cancelExpansion(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index a00eac4adea0..960d22185652 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -51,6 +51,7 @@ import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.phone.KeyguardIndicationTextView; import com.android.systemui.statusbar.phone.LockIcon; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -66,7 +67,7 @@ import java.util.IllegalFormatConversionException; /** * Controls the indications and error messages shown on the Keyguard */ -public class KeyguardIndicationController { +public class KeyguardIndicationController implements StateListener { private static final String TAG = "KeyguardIndication"; private static final boolean DEBUG_CHARGING_SPEED = false; @@ -154,6 +155,19 @@ public class KeyguardIndicationController { mContext.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM, new IntentFilter(Intent.ACTION_TIME_TICK), null, Dependency.get(Dependency.TIME_TICK_HANDLER)); + + Dependency.get(StatusBarStateController.class).addListener(this); + } + + /** + * Used by {@link com.android.systemui.statusbar.phone.StatusBar} to give the indication + * controller a chance to unregister itself as a receiver. + * + * //TODO: This can probably be converted to a fragment and not have to be manually recreated + */ + public void destroy() { + mContext.unregisterReceiver(mTickReceiver); + Dependency.get(StatusBarStateController.class).removeListener(this); } /** @@ -518,6 +532,16 @@ public class KeyguardIndicationController { updateAlphas(); } + @Override + public void onStateChanged(int newState) { + // don't care + } + + @Override + public void onDozingChanged(boolean isDozing) { + setDozing(isDozing); + } + protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback { public static final int HIDE_DELAY_MS = 5000; private int mLastSuccessiveErrorMessage = -1; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java index bc662e3d8855..8994568d12a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java @@ -15,6 +15,7 @@ package com.android.systemui.statusbar; import android.content.pm.UserInfo; +import android.os.SystemProperties; import android.service.notification.StatusBarNotification; import android.util.SparseArray; @@ -25,6 +26,8 @@ public interface NotificationLockscreenUserManager { String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action"; + boolean AUTO_DEMOTE_NOTIFICATIONS = SystemProperties.getBoolean("debug.demote_notifs", false); + boolean shouldAllowLockscreenRemoteInput(); /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 427d169d6b90..010846912622 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -292,9 +292,16 @@ public class NotificationLockscreenUserManagerImpl implements Log.wtf(TAG, "mEntryManager was null!", new Throwable()); return false; } - return mShowLockscreenNotifications - && getEntryManager().getNotificationData().getImportance(sbn.getKey()) - >= IMPORTANCE_DEFAULT; + boolean exceedsPriorityThreshold; + if (AUTO_DEMOTE_NOTIFICATIONS) { + exceedsPriorityThreshold = + getEntryManager().getNotificationData().getImportance(sbn.getKey()) + >= IMPORTANCE_DEFAULT; + } else { + exceedsPriorityThreshold = + !getEntryManager().getNotificationData().isAmbient(sbn.getKey()); + } + return mShowLockscreenNotifications && exceedsPriorityThreshold; } private void setShowLockscreenNotifications(boolean show) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java index b5fbde136c87..5dfd5d0da4af 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java @@ -29,9 +29,11 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dependency; import com.android.systemui.UiOffloadThread; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import java.util.ArrayList; @@ -42,7 +44,7 @@ import java.util.Collections; * Handles notification logging, in particular, logging which notifications are visible and which * are not. */ -public class NotificationLogger { +public class NotificationLogger implements StateListener { private static final String TAG = "NotificationLogger"; /** The minimum delay in ms between reports of notification visibility. */ @@ -63,7 +65,7 @@ public class NotificationLogger { protected IStatusBarService mBarService; private long mLastVisibilityReportUptimeMs; private NotificationListContainer mListContainer; - private Object mDozingLock = new Object(); + private final Object mDozingLock = new Object(); private boolean mDozing; protected final OnChildLocationsChangedListener mNotificationLocationsChangedListener = @@ -146,6 +148,8 @@ public class NotificationLogger { public NotificationLogger() { mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + // Not expected to be destroyed, don't need to unsubscribe + Dependency.get(StatusBarStateController.class).addListener(this); } public void setUpWithContainer(NotificationListContainer listContainer) { @@ -175,7 +179,7 @@ public class NotificationLogger { mNotificationLocationsChangedListener.onChildLocationsChanged(); } - public void setDozing(boolean dozing) { + private void setDozing(boolean dozing) { synchronized (mDozingLock) { mDozing = dozing; } @@ -258,6 +262,16 @@ public class NotificationLogger { return mVisibilityReporter; } + @Override + public void onStateChanged(int newState) { + // don't care about state change + } + + @Override + public void onDozingChanged(boolean isDozing) { + setDozing(isDozing); + } + /** * A listener that is notified when some child locations might have changed. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 6193de59d1d0..965fb137badf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -1499,9 +1499,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } private void updateIconVisibilities() { - boolean visible = isChildInGroup() - || isBelowSpeedBump() - || mIconsVisible; + boolean visible = isChildInGroup() || mIconsVisible; for (NotificationContentView l : mLayouts) { l.setIconsVisible(visible); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 003f158d7822..c3bf16e0f796 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -1107,7 +1107,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mIsClipped = clipped; } - if (mAmbientState.isDarkAtAll()) { + if (mPulsing) { + setClipBounds(null); + } else if (mAmbientState.isDarkAtAll()) { setClipBounds(mBackgroundAnimationRect); } else if (clipped) { setClipBounds(mRequestedClipBounds); @@ -5641,6 +5643,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd public boolean canChildBeDismissed(View v) { return NotificationStackScrollLayout.this.canChildBeDismissed(v); } + + @Override + public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) { + return (isLayoutRtl() ? !isRightOrDown : isRightOrDown) && canChildBeDismissed(v); + } }; // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index a0597dc66d14..94b2cdeea898 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -20,13 +20,17 @@ import android.annotation.NonNull; import android.os.Handler; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.Dependency; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; +import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarStateController.StateListener; /** * Controller which handles all the doze animations of the scrims. */ -public class DozeScrimController { +public class DozeScrimController implements StateListener { private static final String TAG = "DozeScrimController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -83,8 +87,11 @@ public class DozeScrimController { public DozeScrimController(DozeParameters dozeParameters) { mDozeParameters = dozeParameters; + //Never expected to be destroyed + Dependency.get(StatusBarStateController.class).addListener(this); } + @VisibleForTesting public void setDozing(boolean dozing) { if (mDozing == dozing) return; mDozing = dozing; @@ -181,4 +188,14 @@ public class DozeScrimController { public ScrimController.Callback getScrimCallback() { return mScrimCallback; } + + @Override + public void onStateChanged(int newState) { + // don't care + } + + @Override + public void onDozingChanged(boolean isDozing) { + setDozing(isDozing); + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java index 462201c6dac2..b3d0bf8abf62 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java @@ -35,7 +35,7 @@ public class KeyguardDismissUtil implements KeyguardDismissHandler { } /** - * Executes an action that requres the screen to be unlocked. + * Executes an action that requires the screen to be unlocked. * * <p>Must be called after {@link #setDismissHandler}. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java index c08366a95f08..6b12dd9519e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java @@ -16,22 +16,24 @@ package com.android.systemui.statusbar.phone; -import android.annotation.NonNull; import android.app.Notification; import android.os.SystemClock; import android.service.notification.StatusBarNotification; -import androidx.annotation.Nullable; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.AmbientPulseManager; import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarStateController.StateListener; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.NotificationData; -import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -48,7 +50,7 @@ import java.util.Objects; * A class to handle notifications and their corresponding groups. */ public class NotificationGroupManager implements OnHeadsUpChangedListener, - OnAmbientChangedListener { + OnAmbientChangedListener, StateListener { private static final String TAG = "NotificationGroupManager"; private static final long ALERT_TRANSFER_TIMEOUT = 300; @@ -62,10 +64,8 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, private boolean mIsUpdatingUnchangedGroup; private HashMap<String, NotificationData.Entry> mPendingNotifications; - private final StateListener mStateListener = this::setStatusBarState; - public NotificationGroupManager() { - Dependency.get(StatusBarStateController.class).addListener(mStateListener); + Dependency.get(StatusBarStateController.class).addListener(this); } public void setOnGroupChangeListener(OnGroupChangeListener listener) { @@ -185,6 +185,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * specific alert state logic based off when the state changes. * @param isDozing if the device is dozing. */ + @VisibleForTesting public void setDozing(boolean isDozing) { if (mIsDozing != isDozing) { for (NotificationGroup group : mGroupMap.values()) { @@ -732,6 +733,16 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, mPendingNotifications = pendingNotifications; } + @Override + public void onStateChanged(int newState) { + setStatusBarState(newState); + } + + @Override + public void onDozingChanged(boolean isDozing) { + setDozing(isDozing); + } + public static class NotificationGroup { public final HashMap<String, NotificationData.Entry> children = new HashMap<>(); public NotificationData.Entry summary; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index c6097d980c70..f50e9a2c3d08 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -20,6 +20,7 @@ import com.android.internal.util.ContrastColorUtil; import com.android.internal.widget.ViewClippingUtil; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.NotificationData; @@ -48,7 +49,8 @@ public class NotificationIconAreaController implements DarkReceiver { @Override public void onTuningChanged(String key, String newValue) { if (key.equals(LOW_PRIORITY)) { - mShowLowPriority = "1".equals(newValue); + mShowLowPriority = "1".equals(newValue) + || !NotificationLockscreenUserManager.AUTO_DEMOTE_NOTIFICATIONS; if (mNotificationScrollLayout != null) { updateStatusBarIcons(); } @@ -228,13 +230,14 @@ public class NotificationIconAreaController implements DarkReceiver { private void updateShelfIcons() { updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons, - false /* showAmbient */, !mFullyDark /* showLowPriority */, + true /* showAmbient */, !mFullyDark /* showLowPriority */, false /* hideDismissed */, mFullyDark /* hideRepliedMessages */); } public void updateStatusBarIcons() { updateIconsForLayout(entry -> entry.icon, mNotificationIcons, - false /* showAmbient */, false /* showLowPriority */, true /* hideDismissed */, + false /* showAmbient */, mShowLowPriority /* showLowPriority */, + true /* hideDismissed */, true /* hideRepliedMessages */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 31facb79045e..f4c2e27ca272 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -582,7 +582,7 @@ public class NotificationPanelView extends PanelView implements int stackScrollerPadding; if (mBarState != StatusBarState.KEYGUARD) { stackScrollerPadding = (mQs != null ? mQs.getHeader().getHeight() : 0) + mQsPeekHeight - + mQsNotificationTopPadding; + + mQsNotificationTopPadding; } else { int totalHeight = getHeight(); int bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding); @@ -754,7 +754,7 @@ public class NotificationPanelView extends PanelView implements mQsExpandImmediate = true; mNotificationStackScroller.setShouldShowShelfOnly(true); } - if (isFullyCollapsed()){ + if (isFullyCollapsed()) { expand(true /* animate */); } else { flingSettings(0 /* velocity */, FLING_EXPAND); @@ -921,7 +921,7 @@ public class NotificationPanelView extends PanelView implements } private boolean flingExpandsQs(float vel) { - if (isFalseTouch()) { + if (mFalsingManager.isUnlockingDisabled() || isFalseTouch()) { return false; } if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) { @@ -1046,11 +1046,11 @@ public class NotificationPanelView extends PanelView implements final boolean stylusButtonClickDrag = action == MotionEvent.ACTION_DOWN && (event.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY) - || event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY)); + || event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY)); final boolean mouseButtonClickDrag = action == MotionEvent.ACTION_DOWN && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY) - || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY)); + || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY)); return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag; } @@ -1321,12 +1321,12 @@ public class NotificationPanelView extends PanelView implements private final ValueAnimator.AnimatorUpdateListener mStatusBarAnimateAlphaListener = new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue(); - updateHeaderKeyguardAlpha(); - } - }; + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mKeyguardStatusBarAnimateAlpha = (float) animation.getAnimatedValue(); + updateHeaderKeyguardAlpha(); + } + }; private void animateKeyguardStatusBarIn(long duration) { mKeyguardStatusBar.setVisibility(View.VISIBLE); @@ -1382,7 +1382,7 @@ public class NotificationPanelView extends PanelView implements if (keyguardFadingAway) { mKeyguardStatusView.animate() .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay()) - .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration()/2) + .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2) .start(); } } else if (mBarState == StatusBarState.SHADE_LOCKED @@ -1425,8 +1425,8 @@ public class NotificationPanelView extends PanelView implements updateEmptyShadeView(); mQsNavbarScrim.setVisibility(mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling && mQsScrimEnabled - ? View.VISIBLE - : View.INVISIBLE); + ? View.VISIBLE + : View.INVISIBLE); if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) { mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */); } @@ -1459,7 +1459,8 @@ public class NotificationPanelView extends PanelView implements setAccessibilityPaneTitle(determineAccessibilityPaneTitle()); } - if (mQsFullyExpanded && mFalsingManager.shouldEnforceBouncer()) { + if (!mFalsingManager.isUnlockingDisabled() && mQsFullyExpanded + && mFalsingManager.shouldEnforceBouncer()) { mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */, false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */); } @@ -2130,8 +2131,7 @@ public class NotificationPanelView extends PanelView implements } }, null, true /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */); - } - else { + } else { mKeyguardBottomArea.launchLeftAffordance(); } } else { @@ -2588,7 +2588,7 @@ public class NotificationPanelView extends PanelView implements x = Math.min(rightMost, Math.max(leftMost, x)); setVerticalPanelTranslation(x - (mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2)); - } + } private void resetVerticalPanelPosition() { setVerticalPanelTranslation(0f); @@ -2716,8 +2716,8 @@ public class NotificationPanelView extends PanelView implements String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null) ? null : resolveInfo.activityInfo.packageName; return packageToLaunch != null && - (keyguardIsShowing || !isForegroundApp(packageToLaunch)) && - !mAffordanceHelper.isSwipingInProgress(); + (keyguardIsShowing || !isForegroundApp(packageToLaunch)) + && !mAffordanceHelper.isSwipingInProgress(); } /** @@ -2884,13 +2884,14 @@ public class NotificationPanelView extends PanelView implements } public void setStatusAccessibilityImportance(int mode) { - mKeyguardStatusView.setImportantForAccessibility(mode); + mKeyguardStatusView.setImportantForAccessibility(mode); } /** * TODO: this should be removed. * It's not correct to pass this view forward because other classes will end up adding * children to it. Theme will be out of sync. + * * @return bottom area view */ public KeyguardBottomAreaView getKeyguardBottomAreaView() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index f29b7cab5cbc..021b4307aca4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -670,6 +670,10 @@ public abstract class PanelView extends FrameLayout { * @return whether a fling should expands the panel; contracts otherwise */ protected boolean flingExpands(float vel, float vectorVel, float x, float y) { + if (mFalsingManager.isUnlockingDisabled()) { + return true; + } + if (isFalseTouch(x, y)) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 2337857eda1e..6279d50a5952 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -586,7 +586,6 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationLogger = Dependency.get(NotificationLogger.class); mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class); mNotificationListener = Dependency.get(NotificationListener.class); - mGroupManager = Dependency.get(NotificationGroupManager.class); mNetworkController = Dependency.get(NetworkController.class); mUserSwitcherController = Dependency.get(UserSwitcherController.class); mScreenLifecycle = Dependency.get(ScreenLifecycle.class); @@ -1096,6 +1095,9 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onThemeChanged() { // Recreate Indication controller because internal references changed + if (mKeyguardIndicationController != null) { + mKeyguardIndicationController.destroy(); + } mKeyguardIndicationController = SystemUIFactory.getInstance().createKeyguardIndicationController(mContext, mStatusBarWindow.findViewById(R.id.keyguard_indication_area), @@ -1104,7 +1106,6 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardIndicationController .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD); - mKeyguardIndicationController.setDozing(mDozing); if (mStatusBarKeyguardViewManager != null) { mStatusBarKeyguardViewManager.onThemeChanged(); } @@ -3247,12 +3248,8 @@ public class StatusBar extends SystemUI implements DemoMode, boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup()) || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && sleepingFromKeyguard); - mDozeScrimController.setDozing(mDozing); - mKeyguardIndicationController.setDozing(mDozing); mNotificationPanel.setDozing(mDozing, animate, mWakeUpTouchLocation, mDozeServiceHost.wasPassivelyInterrupted()); - mNotificationLogger.setDozing(mDozing); - mGroupManager.setDozing(mDozing); updateQsExpansionEnabled(); Trace.endSection(); } @@ -3442,13 +3439,6 @@ public class StatusBar extends SystemUI implements DemoMode, updateQsExpansionEnabled(); mKeyguardViewMediator.setAodShowing(mDozing); - //TODO: make these folks listeners of StatusBarStateController.onDozingChanged - mStatusBarWindowController.setDozing(mDozing); - mStatusBarKeyguardViewManager.setDozing(mDozing); - if (mAmbientIndicationContainer instanceof DozeReceiver) { - ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing); - } - mEntryManager.updateNotifications(); updateDozingState(); updateScrimController(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index df99a9c13855..484fe110b28a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -59,7 +59,8 @@ import java.util.ArrayList; * which is in turn, reported to this class by the current * {@link com.android.keyguard.KeyguardViewBase}. */ -public class StatusBarKeyguardViewManager implements RemoteInputController.Callback { +public class StatusBarKeyguardViewManager implements RemoteInputController.Callback, + StatusBarStateController.StateListener { // When hiding the Keyguard with timing supplied from WindowManager, better be early than late. private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3; @@ -150,6 +151,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLockPatternUtils = lockPatternUtils; mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback); + Dependency.get(StatusBarStateController.class).addListener(this); } public void registerStatusBar(StatusBar statusBar, @@ -334,7 +336,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb updateStates(); } - public void setDozing(boolean dozing) { + private void setDozing(boolean dozing) { if (mDozing != dozing) { mDozing = dozing; if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) { @@ -781,6 +783,16 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } } + @Override + public void onStateChanged(int newState) { + // Nothing + } + + @Override + public void onDozingChanged(boolean isDozing) { + setDozing(isDozing); + } + private static class DismissWithActionRequest { final OnDismissAction dismissAction; final Runnable cancelAction; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java index 4c24a21fc4b0..f81ffe9ecb76 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java @@ -38,6 +38,7 @@ import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkControllerImpl; import com.android.systemui.statusbar.policy.SecurityController; +import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import java.util.ArrayList; import java.util.List; @@ -88,11 +89,13 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba mNetworkController = Dependency.get(NetworkController.class); mSecurityController = Dependency.get(SecurityController.class); + Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST); mNetworkController.addCallback(this); mSecurityController.addCallback(this); } public void destroy() { + Dependency.get(TunerService.class).removeTunable(this); mNetworkController.removeCallback(this); mSecurityController.removeCallback(this); } @@ -137,6 +140,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba mBlockWifi = blockWifi || mForceBlockWifi; // Re-register to get new callbacks. mNetworkController.removeCallback(this); + mNetworkController.addCallback(this); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java index 0d37b550d4e0..11de9413b13f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java @@ -76,7 +76,6 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat private final State mCurrentState = new State(); private OtherwisedCollapsedListener mListener; - private final StateListener mStateListener = this::setStatusBarState; private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class); public StatusBarWindowController(Context context) { @@ -564,6 +563,18 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat } } + private final StateListener mStateListener = new StateListener() { + @Override + public void onStateChanged(int newState) { + setStatusBarState(newState); + } + + @Override + public void onDozingChanged(boolean isDozing) { + setDozing(isDozing); + } + }; + /** * Custom listener to pipe data back to plugins about whether or not the status bar would be * collapsed if not for the plugin. diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java index 0826054f3740..ecb830c48ccc 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java @@ -29,6 +29,8 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.view.View; +import com.android.internal.util.ArrayUtils; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.PluginEnablerImpl; import com.android.systemui.shared.plugins.PluginEnabler; @@ -77,6 +79,7 @@ public class PluginFragment extends PreferenceFragment { } private void loadPrefs() { + PluginManager manager = Dependency.get(PluginManager.class); PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getContext()); screen.setOrderingAsAdded(false); Context prefContext = getPreferenceManager().getContext(); @@ -103,6 +106,10 @@ public class PluginFragment extends PreferenceFragment { PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES); apps.forEach(app -> { if (!plugins.containsKey(app.packageName)) return; + if (ArrayUtils.contains(manager.getWhitelistedPlugins(), app.packageName)) { + // Don't manage whitelisted plugins, they are part of the OS. + return; + } SwitchPreference pref = new PluginPreference(prefContext, app, mPluginEnabler); pref.setSummary("Plugins: " + toString(plugins.get(app.packageName))); screen.addPreference(pref); diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index aac37a290edc..b32bf99ad53d 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -39,7 +39,7 @@ LOCAL_JAVA_LIBRARIES := \ telephony-common \ android.test.base \ android.car \ - android.car.user + android.car.userlib LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui:com.android.keyguard diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt new file mode 100644 index 000000000000..7204d310a76d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.privacy + +import android.support.test.filters.SmallTest +import android.support.test.runner.AndroidJUnit4 +import com.android.systemui.SysuiTestCase +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class PrivacyDialogBuilderTest : SysuiTestCase() { + + companion object { + val MILLIS_IN_MINUTE: Long = 1000 * 60 + val NOW = 4 * MILLIS_IN_MINUTE + } + + @Test + fun testGenerateText_multipleApps() { + val bar2 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication( + "Bar", context), 2 * MILLIS_IN_MINUTE) + val bar3 = PrivacyItem(Privacy.TYPE_LOCATION, PrivacyApplication( + "Bar", context), 3 * MILLIS_IN_MINUTE) + val foo0 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication( + "Foo", context), 0) + val baz1 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication( + "Baz", context), 1 * MILLIS_IN_MINUTE) + + val items = listOf(bar2, foo0, baz1, bar3) + + val textBuilder = PrivacyDialogBuilder(context, items) + + val textList = textBuilder.generateText(NOW) + assertEquals(2, textList.size) + assertEquals("Bar, Foo, Baz are using your camera", textList[0]) + assertEquals("Bar is using your location for the last 1 min", textList[1]) + } + + @Test + fun testGenerateText_singleApp() { + val bar2 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication( + "Bar", context), 0) + val bar1 = PrivacyItem(Privacy.TYPE_LOCATION, PrivacyApplication( + "Bar", context), 0) + + val items = listOf(bar2, bar1) + + val textBuilder = PrivacyDialogBuilder(context, items) + val textList = textBuilder.generateText(NOW) + assertEquals(1, textList.size) + assertEquals("Bar is using your camera, location", textList[0]) + } + + @Test + fun testGenerateText_singleApp_singleType() { + val bar2 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication( + "Bar", context), 2 * MILLIS_IN_MINUTE) + val items = listOf(bar2) + val textBuilder = PrivacyDialogBuilder(context, items) + val textList = textBuilder.generateText(NOW) + assertEquals(1, textList.size) + assertEquals("Bar is using your camera for the last 2 min", textList[0]) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java index 5bf60400089b..5cc3b3c7823b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java @@ -22,6 +22,7 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -122,7 +123,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase { waitForIdleSync(mPluginInstanceManager.mPluginHandler); waitForIdleSync(mPluginInstanceManager.mMainHandler); - verify(mMockListener, Mockito.never()).onPluginConnected(any(), any()); + verify(mMockListener, never()).onPluginConnected(any(), any()); } @Test @@ -162,7 +163,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase { waitForIdleSync(mPluginInstanceManager.mMainHandler); // Plugin shouldn't be connected because it is the wrong version. - verify(mMockListener, Mockito.never()).onPluginConnected(any(), any()); + verify(mMockListener, never()).onPluginConnected(any(), any()); verify(nm).notifyAsUser(eq(TestPlugin.class.getName()), eq(SystemMessage.NOTE_PLUGIN), any(), eq(UserHandle.ALL)); } @@ -200,7 +201,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase { waitForIdleSync(mPluginInstanceManager.mMainHandler);; // Non-debuggable build should receive no plugins. - verify(mMockListener, Mockito.never()).onPluginConnected(any(), any()); + verify(mMockListener, never()).onPluginConnected(any(), any()); } @Test @@ -229,7 +230,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase { // Start with an unrelated class. boolean result = mPluginInstanceManager.checkAndDisable(Activity.class.getName()); assertFalse(result); - verify(mMockPm, Mockito.never()).setComponentEnabledSetting( + verify(mMockPm, never()).setComponentEnabledSetting( ArgumentCaptor.forClass(ComponentName.class).capture(), ArgumentCaptor.forClass(int.class).capture(), ArgumentCaptor.forClass(int.class).capture()); @@ -255,6 +256,21 @@ public class PluginInstanceManagerTest extends SysuiTestCase { ArgumentCaptor.forClass(int.class).capture()); } + @Test + public void testDisableWhitelisted() throws Exception { + mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction", + mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo, + mMockManager, false, new String[] {WHITELISTED_PACKAGE}); + createPlugin(); // Get into valid created state. + + mPluginInstanceManager.disableAll(); + + verify(mMockPm, never()).setComponentEnabledSetting( + ArgumentCaptor.forClass(ComponentName.class).capture(), + ArgumentCaptor.forClass(int.class).capture(), + ArgumentCaptor.forClass(int.class).capture()); + } + private void setupFakePmQuery() throws Exception { List<ResolveInfo> list = new ArrayList<>(); ResolveInfo info = new ResolveInfo(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java index b5f67c06b2d1..098fa62f4044 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java @@ -15,22 +15,13 @@ package com.android.systemui.statusbar.notification.stack; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockitoSession; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -38,49 +29,34 @@ import static org.mockito.Mockito.when; import android.animation.Animator; import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.content.Context; -import android.graphics.Rect; import android.os.Handler; -import android.os.IPowerManager; -import android.os.Looper; -import android.os.PowerManager; import android.service.notification.StatusBarNotification; -import android.support.test.annotation.UiThreadTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import android.testing.TestableLooper.RunWithLooper; +import android.testing.UiThreadTest; import android.view.MotionEvent; -import android.view.VelocityTracker; import android.view.View; -import android.view.MotionEvent; import com.android.systemui.SwipeHelper; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.NotificationMenuRow; -import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoSession; -import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.mockito.stubbing.Answer; -import java.util.ArrayList; - /** * Tests for {@link NotificationSwipeHelper}. */ @SmallTest @RunWith(AndroidJUnit4.class) +@UiThreadTest public class NotificationSwipeHelperTest extends SysuiTestCase { private NotificationSwipeHelper mSwipeHelper; @@ -96,7 +72,6 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); @Before - @UiThreadTest public void setUp() throws Exception { mCallback = mock(NotificationSwipeHelper.NotificationCallback.class); mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java new file mode 100644 index 000000000000..a8c1ac61e4cc --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import static com.google.common.truth.Truth.assertThat; + +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { + + private static final int SCREEN_HEIGHT = 2000; + private static final int EMPTY_MARGIN = 0; + private static final int EMPTY_HEIGHT = 0; + private static final boolean SECURE_LOCKED = false; + private static final boolean PULSING_NO = false; + private static final float ZERO_DRAG = 0.f; + private static final float OPAQUE = 1.f; + private static final float TRANSPARENT = 0.f; + + private KeyguardClockPositionAlgorithm mClockPositionAlgorithm; + private KeyguardClockPositionAlgorithm.Result mClockPosition; + private int mNotificationStackHeight; + private float mPanelExpansion; + private int mKeyguardStatusHeight; + private float mDark; + + @Before + public void setUp() { + mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm(); + mClockPosition = new KeyguardClockPositionAlgorithm.Result(); + } + + @Test + public void clockPositionMiddleOfScreenOnAOD() { + // GIVEN on AOD and both stack scroll and clock have 0 height + givenAOD(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = EMPTY_HEIGHT; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the clock Y position is the middle of the screen (SCREEN_HEIGHT / 2). + assertThat(mClockPosition.clockY).isEqualTo(1000); + // AND the clock is opaque and positioned on the left. + assertThat(mClockPosition.clockX).isEqualTo(0); + assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE); + } + + @Test + public void clockPositionAdjustsForKeyguardStatusOnAOD() { + // GIVEN on AOD with a clock of height 100 + givenAOD(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = 100; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the clock Y position adjusts for the clock height (SCREEN_HEIGHT / 2 - 100). + assertThat(mClockPosition.clockY).isEqualTo(900); + // AND the clock is opaque and positioned on the left. + assertThat(mClockPosition.clockX).isEqualTo(0); + assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE); + } + + @Test + public void clockPositionLargeClockOnAOD() { + // GIVEN on AOD with a full screen clock + givenAOD(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = SCREEN_HEIGHT; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the clock Y position overflows the parent. + assertThat(mClockPosition.clockY).isEqualTo(-1000); + // AND the clock is opaque and positioned on the left. + assertThat(mClockPosition.clockX).isEqualTo(0); + assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE); + } + + @Test + public void clockPositionMiddleOfScreenOnLockScreen() { + // GIVEN on lock screen with stack scroll and clock of 0 height + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = EMPTY_HEIGHT; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the clock Y position is the middle of the screen (SCREEN_HEIGHT / 2). + assertThat(mClockPosition.clockY).isEqualTo(1000); + // AND the clock is opaque and positioned on the left. + assertThat(mClockPosition.clockX).isEqualTo(0); + assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE); + } + + @Test + public void clockPositionWithStackScrollExpandOnLockScreen() { + // GIVEN on lock screen with stack scroll of height 500 + givenLockScreen(); + mNotificationStackHeight = 500; + mKeyguardStatusHeight = EMPTY_HEIGHT; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the clock Y position adjusts for stack scroll height ( (SCREEN_HEIGHT - 500 ) / 2). + assertThat(mClockPosition.clockY).isEqualTo(750); + // AND the clock is opaque and positioned on the left. + assertThat(mClockPosition.clockX).isEqualTo(0); + assertThat(mClockPosition.clockAlpha).isEqualTo(OPAQUE); + } + + @Test + public void clockPositionWithPartialDragOnLockScreen() { + // GIVEN dragging up on lock screen + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = EMPTY_HEIGHT; + mPanelExpansion = 0.5f; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the clock Y position adjusts with drag gesture. + assertThat(mClockPosition.clockY).isLessThan(1000); + // AND the clock is positioned on the left and not fully opaque. + assertThat(mClockPosition.clockX).isEqualTo(0); + assertThat(mClockPosition.clockAlpha).isLessThan(OPAQUE); + } + + @Test + public void clockPositionWithFullDragOnLockScreen() { + // GIVEN the lock screen is dragged up + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = EMPTY_HEIGHT; + mPanelExpansion = 0.f; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the clock is transparent. + assertThat(mClockPosition.clockAlpha).isEqualTo(TRANSPARENT); + } + + @Test + public void largeClockOnLockScreenIsTransparent() { + // GIVEN on lock screen with a full screen clock + givenLockScreen(); + mNotificationStackHeight = EMPTY_HEIGHT; + mKeyguardStatusHeight = SCREEN_HEIGHT; + // WHEN the clock position algorithm is run + positionClock(); + // THEN the clock is transparent + assertThat(mClockPosition.clockAlpha).isEqualTo(TRANSPARENT); + } + + private void givenAOD() { + mPanelExpansion = 1.f; + mDark = 1.f; + } + + private void givenLockScreen() { + mPanelExpansion = 1.f; + mDark = 0.f; + } + + private void positionClock() { + mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight, + mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mDark, SECURE_LOCKED, + PULSING_NO, ZERO_DRAG); + mClockPositionAlgorithm.run(mClockPosition); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java index 5f54bceb6b9b..6d1e6ce9ea33 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java @@ -62,6 +62,11 @@ public class FakePluginManager implements PluginManager { } @Override + public String[] getWhitelistedPlugins() { + return new String[0]; + } + + @Override public <T extends Plugin> T getOneShotPlugin(Class<T> cls) { return null; } diff --git a/services/art-profile b/services/art-profile index 742ca1c94a77..bdd49de3ef02 100644 --- a/services/art-profile +++ b/services/art-profile @@ -2271,6 +2271,7 @@ HPLcom/android/server/wm/DisplayContent;->lambda$new$8(Lcom/android/server/wm/Di HPLcom/android/server/wm/DisplayContent;->prepareSurfaces()V HPLcom/android/server/wm/DisplayContent;->resetAnimationBackgroundAnimator()V HPLcom/android/server/wm/DisplayContent;->skipTraverseChild(Lcom/android/server/wm/WindowContainer;)Z +HPLcom/android/server/wm/DisplayContent;->updateOrientationFromAppTokens(Z)Z HPLcom/android/server/wm/DisplayContent;->updateTouchExcludeRegion()V HPLcom/android/server/wm/DockedStackDividerController;->isResizing()Z HPLcom/android/server/wm/DragDropController;->dragDropActiveLocked()Z @@ -2451,7 +2452,6 @@ HPLcom/android/server/wm/WindowManagerService;->relayoutWindow(Lcom/android/serv HPLcom/android/server/wm/WindowManagerService;->resetPriorityAfterLockedSection()V HPLcom/android/server/wm/WindowManagerService;->scheduleAnimationLocked()V HPLcom/android/server/wm/WindowManagerService;->traceStateLocked(Ljava/lang/String;)V -HPLcom/android/server/wm/WindowManagerService;->updateOrientationFromAppTokensLocked(IZ)Z HPLcom/android/server/wm/WindowManagerService;->windowForClientLocked(Lcom/android/server/wm/Session;Landroid/os/IBinder;Z)Lcom/android/server/wm/WindowState; HPLcom/android/server/wm/WindowManagerThreadPriorityBooster;->boost()V HPLcom/android/server/wm/WindowManagerThreadPriorityBooster;->reset()V @@ -18137,6 +18137,7 @@ PLcom/android/server/wm/DisplayContent;->updateBaseDisplayMetricsIfNeeded()V PLcom/android/server/wm/DisplayContent;->updateBounds()V PLcom/android/server/wm/DisplayContent;->updateDisplayAndOrientation(I)Landroid/view/DisplayInfo; PLcom/android/server/wm/DisplayContent;->updateDisplayInfo()V +PLcom/android/server/wm/DisplayContent;->updateOrientationFromAppTokens()Z PLcom/android/server/wm/DisplayContent;->updateRotationUnchecked()Z PLcom/android/server/wm/DisplayContent;->updateRotationUnchecked(Z)Z PLcom/android/server/wm/DisplayContent;->updateStackBoundsAfterConfigChange(Ljava/util/List;)V @@ -18906,7 +18907,6 @@ PLcom/android/server/wm/WindowManagerService;->updateFocusedWindowLocked(IZ)Z PLcom/android/server/wm/WindowManagerService;->updateNonSystemOverlayWindowsVisibilityIfNeeded(Lcom/android/server/wm/WindowState;Z)V PLcom/android/server/wm/WindowManagerService;->updateOrientationFromAppTokens(Landroid/content/res/Configuration;Landroid/os/IBinder;I)Landroid/content/res/Configuration; PLcom/android/server/wm/WindowManagerService;->updateOrientationFromAppTokens(Landroid/content/res/Configuration;Landroid/os/IBinder;IZ)Landroid/content/res/Configuration; -PLcom/android/server/wm/WindowManagerService;->updateOrientationFromAppTokensLocked(I)Z PLcom/android/server/wm/WindowManagerService;->updateOrientationFromAppTokensLocked(Landroid/content/res/Configuration;Landroid/os/IBinder;IZ)Landroid/content/res/Configuration; PLcom/android/server/wm/WindowManagerService;->updatePointerIcon(Landroid/view/IWindow;)V PLcom/android/server/wm/WindowManagerService;->updateRotation(ZZ)V diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index d3842b74990c..4205ac7d9f86 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -21,14 +21,11 @@ import static android.content.Context.AUTOFILL_MANAGER_SERVICE; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sFullScreenMode; -import static com.android.server.autofill.Helper.sPartitionMaxCount; -import static com.android.server.autofill.Helper.sVisibleDatasetsMaxCount; import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityThread; import android.content.BroadcastReceiver; @@ -38,13 +35,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.Rect; -import android.net.Uri; import android.os.Binder; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteCallback; @@ -53,7 +47,6 @@ import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManager; -import android.os.UserManagerInternal; import android.provider.Settings; import android.service.autofill.FillEventHistory; import android.service.autofill.UserData; @@ -63,7 +56,6 @@ import android.util.ArrayMap; import android.util.LocalLog; import android.util.Slog; import android.util.SparseArray; -import android.util.SparseBooleanArray; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillManagerInternal; @@ -73,14 +65,12 @@ import android.view.autofill.IAutoFillManagerClient; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.content.PackageMonitor; -import com.android.internal.os.BackgroundThread; import com.android.internal.os.IResultReceiver; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; +import com.android.server.AbstractMasterSystemService; import com.android.server.FgThread; import com.android.server.LocalServices; -import com.android.server.SystemService; import com.android.server.autofill.ui.AutoFillUI; import java.io.FileDescriptor; @@ -98,10 +88,13 @@ import java.util.Objects; * {@link AutofillManagerServiceImpl} per user; the real work is done by * {@link AutofillManagerServiceImpl} itself. */ -public final class AutofillManagerService extends SystemService { +public final class AutofillManagerService + extends AbstractMasterSystemService<AutofillManagerServiceImpl> { private static final String TAG = "AutofillManagerService"; + private static final Object sLock = AutofillManagerService.class; + static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions"; private static final char COMPAT_PACKAGE_DELIMITER = ':'; @@ -109,26 +102,27 @@ public final class AutofillManagerService extends SystemService { private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '['; private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']'; - private final Context mContext; - private final AutoFillUI mUi; - - private final Object mLock = new Object(); /** - * Cache of {@link AutofillManagerServiceImpl} per user id. - * <p> - * It has to be mapped by user id because the same current user could have simultaneous sessions - * associated to different user profiles (for example, in a multi-window environment or when - * device has work profiles). + * Maximum number of partitions that can be allowed in a session. + * + * <p>Can be modified using {@code cmd autofill set max_partitions} or through + * {@link android.provider.Settings.Global#AUTOFILL_MAX_PARTITIONS_SIZE}. */ - @GuardedBy("mLock") - private SparseArray<AutofillManagerServiceImpl> mServicesCache = new SparseArray<>(); + @GuardedBy("sLock") + private static int sPartitionMaxCount = AutofillManager.DEFAULT_MAX_PARTITIONS_SIZE; /** - * Users disabled due to {@link UserManager} restrictions. + * Maximum number of visible datasets in the dataset picker UI, or {@code 0} to use default + * value from resources. + * + * <p>Can be modified using {@code cmd autofill set max_visible_datasets} or through + * {@link android.provider.Settings.Global#AUTOFILL_MAX_VISIBLE_DATASETS}. */ - @GuardedBy("mLock") - private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray(); + @GuardedBy("sLock") + private static int sVisibleDatasetsMaxCount = 0; + + private final AutoFillUI mUi; private final LocalLog mRequestsHistory = new LocalLog(20); private final LocalLog mUiLatencyHistory = new LocalLog(20); @@ -148,22 +142,19 @@ public final class AutofillManagerService extends SystemService { // beneath it is brought back to top. Ideally, we should just hide the UI and // bring it back when the activity resumes. synchronized (mLock) { - for (int i = 0; i < mServicesCache.size(); i++) { - mServicesCache.valueAt(i).destroyFinishedSessionsLocked(); - } + visitServicesLocked((s) -> s.destroyFinishedSessionsLocked()); } - mUi.hideAll(null); } } }; + // TODO(b/117779333): move to superclass / create super-class for ShellCommand @GuardedBy("mLock") private boolean mAllowInstantService; public AutofillManagerService(Context context) { - super(context); - mContext = context; + super(context, UserManager.DISALLOW_AUTOFILL); mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext()); setLogLevelFromSettings(); @@ -172,199 +163,91 @@ public final class AutofillManagerService extends SystemService { final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler()); - - // Hookup with UserManager to disable service when necessary. - final UserManager um = context.getSystemService(UserManager.class); - final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); - final List<UserInfo> users = um.getUsers(); - for (int i = 0; i < users.size(); i++) { - final int userId = users.get(i).id; - final boolean disabled = umi.getUserRestriction(userId, UserManager.DISALLOW_AUTOFILL); - if (disabled) { - Slog.i(TAG, "Disabling Autofill for user " + userId); - mDisabledUsers.put(userId, disabled); - } - } - umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> { - final boolean disabledNow = - newRestrictions.getBoolean(UserManager.DISALLOW_AUTOFILL, false); - synchronized (mLock) { - final boolean disabledBefore = mDisabledUsers.get(userId); - if (disabledBefore == disabledNow) { - // Nothing changed, do nothing. - if (sDebug) { - Slog.d(TAG, "Autofill restriction did not change for user " + userId); - return; - } - } - Slog.i(TAG, "Updating Autofill for user " + userId + ": disabled=" + disabledNow); - mDisabledUsers.put(userId, disabledNow); - updateCachedServiceLocked(userId, disabledNow); - } - }); - startTrackingPackageChanges(); + context.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler()); } - private void startTrackingPackageChanges() { - PackageMonitor monitor = new PackageMonitor() { - @Override - public void onSomePackagesChanged() { - synchronized (mLock) { - updateCachedServiceLocked(getChangingUserId()); - } - } - - @Override - public void onPackageUpdateFinished(String packageName, int uid) { - synchronized (mLock) { - final String activePackageName = getActiveAutofillServicePackageName(); - if (packageName.equals(activePackageName)) { - removeCachedServiceLocked(getChangingUserId()); - } else { - handlePackageUpdateLocked(packageName); - } - } - } + @Override // from MasterSystemService + protected String getServiceSettingsProperty() { + return Settings.Secure.AUTOFILL_SERVICE; + } - @Override - public void onPackageRemoved(String packageName, int uid) { - synchronized (mLock) { - final int userId = getChangingUserId(); - final AutofillManagerServiceImpl userState = peekServiceForUserLocked(userId); - if (userState != null) { - final ComponentName componentName = userState.getServiceComponentName(); - if (componentName != null) { - if (packageName.equals(componentName.getPackageName())) { - handleActiveAutofillServiceRemoved(userId); - } - } - } - } - } + @Override // from MasterSystemService + protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver, + @NonNull ContentObserver observer) { + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer, + UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.AUTOFILL_LOGGING_LEVEL), false, observer, + UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE), false, observer, + UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, observer, + UserHandle.USER_ALL); + } - @Override - public boolean onHandleForceStop(Intent intent, String[] packages, - int uid, boolean doit) { + @Override // from MasterSystemService + protected void onSettingsChanged(int userId, @NonNull String property) { + switch (property) { + case Settings.Global.AUTOFILL_LOGGING_LEVEL: + setLogLevelFromSettings(); + break; + case Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE: + setMaxPartitionsFromSettings(); + break; + case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS: + setMaxVisibleDatasetsFromSettings(); + break; + default: + Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead"); + // fall through + case Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES: synchronized (mLock) { - final String activePackageName = getActiveAutofillServicePackageName(); - for (String pkg : packages) { - if (pkg.equals(activePackageName)) { - if (!doit) { - return true; - } - removeCachedServiceLocked(getChangingUserId()); - } else { - handlePackageUpdateLocked(pkg); - } - } + updateCachedServiceLocked(userId); } - return false; - } - - private void handleActiveAutofillServiceRemoved(int userId) { - removeCachedServiceLocked(userId); - Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.AUTOFILL_SERVICE, null, userId); - } + } + } - private String getActiveAutofillServicePackageName() { - final int userId = getChangingUserId(); - final AutofillManagerServiceImpl userState = peekServiceForUserLocked(userId); - if (userState == null) { - return null; - } - final ComponentName serviceComponent = userState.getServiceComponentName(); - if (serviceComponent == null) { - return null; - } - return serviceComponent.getPackageName(); - } + @Override // from MasterSystemService + protected AutofillManagerServiceImpl newServiceLocked(int resolvedUserId, boolean disabled) { + return new AutofillManagerServiceImpl(this, mLock, mRequestsHistory, + mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, + disabled); + } - @GuardedBy("mLock") - private void handlePackageUpdateLocked(String packageName) { - final int size = mServicesCache.size(); - for (int i = 0; i < size; i++) { - mServicesCache.valueAt(i).handlePackageUpdateLocked(packageName); - } - } - }; + @Override // MasterSystemService + protected AutofillManagerServiceImpl removeCachedServiceLocked(int userId) { + final AutofillManagerServiceImpl service = super.removeCachedServiceLocked(userId); + if (service != null) { + service.destroyLocked(); + mAutofillCompatState.removeCompatibilityModeRequests(userId); + } + return service; + } - // package changes - monitor.register(mContext, null, UserHandle.ALL, true); + @Override // from MasterSystemService + protected void onServiceEnabledLocked(@NonNull AutofillManagerServiceImpl service, int userId) { + addCompatibilityModeRequestsLocked(service, userId); } - @Override + @Override // from SystemService public void onStart() { publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub()); publishLocalService(AutofillManagerInternal.class, mLocalService); } - @Override - public void onBootPhase(int phase) { - if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { - new SettingsObserver(BackgroundThread.getHandler()); - } - } - - @Override - public void onUnlockUser(int userId) { - synchronized (mLock) { - updateCachedServiceLocked(userId); - } - } - - @Override + @Override // from SystemService public void onSwitchUser(int userHandle) { if (sDebug) Slog.d(TAG, "Hiding UI when user switched"); mUi.hideAll(null); } - @Override - public void onCleanupUser(int userId) { - synchronized (mLock) { - removeCachedServiceLocked(userId); - } - } - - /** - * Gets the service instance for an user. - * - * @return service instance. - */ - @GuardedBy("mLock") - @NonNull - AutofillManagerServiceImpl getServiceForUserLocked(int userId) { - final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), - Binder.getCallingUid(), userId, false, false, null, null); - AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId); - if (service == null) { - service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory, - mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, - mAutofillCompatState, mDisabledUsers.get(resolvedUserId)); - mServicesCache.put(userId, service); - addCompatibilityModeRequestsLocked(service, userId); - } - return service; - } - - /** - * Peeks the service instance for a user. - * - * @return service instance or {@code null} if not already present - */ - @GuardedBy("mLock") - @Nullable - AutofillManagerServiceImpl peekServiceForUserLocked(int userId) { - final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), - Binder.getCallingUid(), userId, false, false, null, null); - return mServicesCache.get(resolvedUserId); - } - // Called by Shell command. void destroySessions(int userId, IResultReceiver receiver) { Slog.i(TAG, "destroySessions() for userId " + userId); - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); synchronized (mLock) { if (userId != UserHandle.USER_ALL) { @@ -373,10 +256,7 @@ public final class AutofillManagerService extends SystemService { service.destroySessionsLocked(); } } else { - final int size = mServicesCache.size(); - for (int i = 0; i < size; i++) { - mServicesCache.valueAt(i).destroySessionsLocked(); - } + visitServicesLocked((s) -> s.destroySessionsLocked()); } } @@ -390,7 +270,7 @@ public final class AutofillManagerService extends SystemService { // Called by Shell command. void listSessions(int userId, IResultReceiver receiver) { Slog.i(TAG, "listSessions() for userId " + userId); - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); final Bundle resultData = new Bundle(); final ArrayList<String> sessions = new ArrayList<>(); @@ -402,10 +282,7 @@ public final class AutofillManagerService extends SystemService { service.listSessionsLocked(sessions); } } else { - final int size = mServicesCache.size(); - for (int i = 0; i < size; i++) { - mServicesCache.valueAt(i).listSessionsLocked(sessions); - } + visitServicesLocked((s) -> s.listSessionsLocked(sessions)); } } @@ -420,25 +297,22 @@ public final class AutofillManagerService extends SystemService { // Called by Shell command. void reset() { Slog.i(TAG, "reset()"); - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); synchronized (mLock) { - final int size = mServicesCache.size(); - for (int i = 0; i < size; i++) { - mServicesCache.valueAt(i).destroyLocked(); - } - mServicesCache.clear(); + visitServicesLocked((s) -> s.destroyLocked()); + clearCacheLocked(); } } // Called by Shell command. void setLogLevel(int level) { Slog.i(TAG, "setLogLevel(): " + level); - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); final long token = Binder.clearCallingIdentity(); try { - Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.putInt(getContext().getContentResolver(), Settings.Global.AUTOFILL_LOGGING_LEVEL, level); } finally { Binder.restoreCallingIdentity(token); @@ -447,7 +321,7 @@ public final class AutofillManagerService extends SystemService { private void setLogLevelFromSettings() { final int level = Settings.Global.getInt( - mContext.getContentResolver(), + getContext().getContentResolver(), Settings.Global.AUTOFILL_LOGGING_LEVEL, AutofillManager.DEFAULT_LOGGING_LEVEL); boolean debug = false; boolean verbose = false; @@ -465,14 +339,13 @@ public final class AutofillManagerService extends SystemService { + ", verbose=" + verbose); } synchronized (mLock) { - setDebugLocked(debug); - setVerboseLocked(verbose); + setLoggingLevelsLocked(debug, verbose); } } // Called by Shell command. int getLogLevel() { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); synchronized (mLock) { if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE; @@ -483,7 +356,7 @@ public final class AutofillManagerService extends SystemService { // Called by Shell command. int getMaxPartitions() { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); synchronized (mLock) { return sPartitionMaxCount; @@ -492,12 +365,12 @@ public final class AutofillManagerService extends SystemService { // Called by Shell command. void setMaxPartitions(int max) { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); Slog.i(TAG, "setMaxPartitions(): " + max); final long token = Binder.clearCallingIdentity(); try { - Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.putInt(getContext().getContentResolver(), Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, max); } finally { Binder.restoreCallingIdentity(token); @@ -505,33 +378,33 @@ public final class AutofillManagerService extends SystemService { } private void setMaxPartitionsFromSettings() { - final int max = Settings.Global.getInt(mContext.getContentResolver(), + final int max = Settings.Global.getInt(getContext().getContentResolver(), Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, AutofillManager.DEFAULT_MAX_PARTITIONS_SIZE); if (sDebug) Slog.d(TAG, "setMaxPartitionsFromSettings(): " + max); - synchronized (mLock) { + synchronized (sLock) { sPartitionMaxCount = max; } } // Called by Shell command. int getMaxVisibleDatasets() { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); - synchronized (mLock) { + synchronized (sLock) { return sVisibleDatasetsMaxCount; } } // Called by Shell command. void setMaxVisibleDatasets(int max) { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); Slog.i(TAG, "setMaxVisibleDatasets(): " + max); final long token = Binder.clearCallingIdentity(); try { - Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.putInt(getContext().getContentResolver(), Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, max); } finally { Binder.restoreCallingIdentity(token); @@ -539,11 +412,11 @@ public final class AutofillManagerService extends SystemService { } private void setMaxVisibleDatasetsFromSettings() { - final int max = Settings.Global.getInt(mContext.getContentResolver(), + final int max = Settings.Global.getInt(getContext().getContentResolver(), Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, 0); if (sDebug) Slog.d(TAG, "setMaxVisibleDatasetsFromSettings(): " + max); - synchronized (mLock) { + synchronized (sLock) { sVisibleDatasetsMaxCount = max; } } @@ -551,10 +424,10 @@ public final class AutofillManagerService extends SystemService { // Called by Shell command. void getScore(@Nullable String algorithmName, @NonNull String value1, @NonNull String value2, @NonNull RemoteCallback callback) { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); final FieldClassificationStrategy strategy = - new FieldClassificationStrategy(mContext, UserHandle.USER_CURRENT); + new FieldClassificationStrategy(getContext(), UserHandle.USER_CURRENT); strategy.getScores(callback, algorithmName, null, Arrays.asList(AutofillValue.forText(value1)), new String[] { value2 }); @@ -562,19 +435,19 @@ public final class AutofillManagerService extends SystemService { // Called by Shell command. Boolean getFullScreenMode() { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); return sFullScreenMode; } // Called by Shell command. void setFullScreenMode(@Nullable Boolean mode) { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); sFullScreenMode = mode; } // Called by Shell command. boolean getAllowInstantService() { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); synchronized (mLock) { return mAllowInstantService; } @@ -582,59 +455,21 @@ public final class AutofillManagerService extends SystemService { // Called by Shell command. void setAllowInstantService(boolean mode) { - mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); Slog.i(TAG, "setAllowInstantService(): " + mode); synchronized (mLock) { mAllowInstantService = mode; } } - private void setDebugLocked(boolean debug) { + private void setLoggingLevelsLocked(boolean debug, boolean verbose) { com.android.server.autofill.Helper.sDebug = debug; android.view.autofill.Helper.sDebug = debug; - } + this.debug = debug; - private void setVerboseLocked(boolean verbose) { com.android.server.autofill.Helper.sVerbose = verbose; android.view.autofill.Helper.sVerbose = verbose; - } - - /** - * Removes a cached service for a given user. - */ - @GuardedBy("mLock") - private void removeCachedServiceLocked(int userId) { - final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); - if (service != null) { - mServicesCache.delete(userId); - service.destroyLocked(); - mAutofillCompatState.removeCompatibilityModeRequests(userId); - } - } - - /** - * Updates a cached service for a given user. - */ - @GuardedBy("mLock") - private void updateCachedServiceLocked(int userId) { - updateCachedServiceLocked(userId, mDisabledUsers.get(userId)); - } - - /** - * Updates a cached service for a given user. - */ - @GuardedBy("mLock") - private void updateCachedServiceLocked(int userId, boolean disabled) { - AutofillManagerServiceImpl service = getServiceForUserLocked(userId); - if (service != null) { - service.destroySessionsLocked(); - service.updateLocked(disabled); - if (!service.isEnabledLocked()) { - removeCachedServiceLocked(userId); - } else { - addCompatibilityModeRequestsLocked(service, userId); - } - } + this.verbose = verbose; } private void addCompatibilityModeRequestsLocked(@NonNull AutofillManagerServiceImpl service @@ -664,7 +499,7 @@ public final class AutofillManagerService extends SystemService { private String getWhitelistedCompatModePackagesFromSettings() { return Settings.Global.getString( - mContext.getContentResolver(), + getContext().getContentResolver(), Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES); } @@ -758,6 +593,24 @@ public final class AutofillManagerService extends SystemService { return compatPackages; } + /** + * Gets the maximum number of partitions / fill requests. + */ + public static int getPartitionMaxCount() { + synchronized (sLock) { + return sPartitionMaxCount; + } + } + + /** + * Gets the maxium number of datasets visible in the UI. + */ + public static int getVisibleDatasetsMaxCount() { + synchronized (sLock) { + return sVisibleDatasetsMaxCount; + } + } + private final class LocalService extends AutofillManagerInternal { @Override public void onBackKeyPressed() { @@ -889,20 +742,24 @@ public final class AutofillManagerService extends SystemService { } private void dump(String prefix, PrintWriter pw) { - if (mUserSpecs == null) { - pw.println("N/A"); - return; - } - pw.println(); - final String prefix2 = prefix + " "; - for (int i = 0; i < mUserSpecs.size(); i++) { - final int user = mUserSpecs.keyAt(i); - pw.print(prefix); pw.print("User: "); pw.println(user); - final ArrayMap<String, PackageCompatState> perUser = mUserSpecs.valueAt(i); - for (int j = 0; j < perUser.size(); j++) { - final String packageName = perUser.keyAt(j); - final PackageCompatState state = perUser.valueAt(j); - pw.print(prefix2); pw.print(packageName); pw.print(": "); pw.println(state); + synchronized (mLock) { + if (mUserSpecs == null) { + pw.println("N/A"); + return; + } + pw.println(); + final String prefix2 = prefix + " "; + for (int i = 0; i < mUserSpecs.size(); i++) { + final int user = mUserSpecs.keyAt(i); + pw.print(prefix); + pw.print("User: "); + pw.println(user); + final ArrayMap<String, PackageCompatState> perUser = mUserSpecs.valueAt(i); + for (int j = 0; j < perUser.size(); j++) { + final String packageName = perUser.keyAt(j); + final PackageCompatState state = perUser.valueAt(j); + pw.print(prefix2); pw.print(packageName); pw.print(": "); pw.println(state); + } } } } @@ -971,7 +828,7 @@ public final class AutofillManagerService extends SystemService { Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId"); try { - mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId); + getContext().getPackageManager().getPackageInfoAsUser(packageName, 0, userId); } catch (PackageManager.NameNotFoundException e) { throw new IllegalArgumentException(packageName + " is not a valid package", e); } @@ -1139,7 +996,7 @@ public final class AutofillManagerService extends SystemService { boolean restored = false; synchronized (mLock) { - final AutofillManagerServiceImpl service = mServicesCache.get(userId); + final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); if (service != null) { restored = service.restoreSession(sessionId, getCallingUid(), activityToken, appCallback); @@ -1216,7 +1073,7 @@ public final class AutofillManagerService extends SystemService { public void isServiceSupported(int userId, @NonNull IResultReceiver receiver) { boolean supported = false; synchronized (mLock) { - supported = !mDisabledUsers.get(userId); + supported = !isDisabledLocked(userId); } send(receiver, supported); } @@ -1253,7 +1110,7 @@ public final class AutofillManagerService extends SystemService { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; boolean showHistory = true; boolean uiOnly = false; @@ -1280,102 +1137,48 @@ public final class AutofillManagerService extends SystemService { return; } - boolean oldDebug = sDebug; final String prefix = " "; - final String prefix2 = " "; + boolean realDebug = sDebug; + boolean realVerbose = sVerbose; try { + sDebug = sVerbose = true; synchronized (mLock) { - oldDebug = sDebug; - setDebugLocked(true); - pw.print("Debug mode: "); pw.println(oldDebug); - pw.print("Verbose mode: "); pw.println(sVerbose); - pw.print("Disabled users: "); pw.println(mDisabledUsers); + pw.print("sDebug: "); pw.print(realDebug); + pw.print(" sVerbose: "); pw.println(realVerbose); + // Dump per-user services + dumpLocked("", pw); pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount); pw.print("Max visible datasets: "); pw.println(sVisibleDatasetsMaxCount); if (sFullScreenMode != null) { pw.print("Overridden full-screen mode: "); pw.println(sFullScreenMode); } pw.println("User data constraints: "); UserData.dumpConstraints(prefix, pw); - final int size = mServicesCache.size(); - pw.print("Cached services: "); - if (size == 0) { - pw.println("none"); - } else { - pw.println(size); - for (int i = 0; i < size; i++) { - pw.print("\nService at index "); pw.println(i); - final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i); - impl.dumpLocked(prefix, pw); - } - } mUi.dump(pw); pw.print("Autofill Compat State: "); - mAutofillCompatState.dump(prefix2, pw); - pw.print(prefix2); pw.print("from settings: "); + mAutofillCompatState.dump(prefix, pw); + pw.print("from settings: "); pw.println(getWhitelistedCompatModePackagesFromSettings()); pw.print("Allow instant service: "); pw.println(mAllowInstantService); - } - if (showHistory) { - pw.println(); pw.println("Requests history:"); pw.println(); - mRequestsHistory.reverseDump(fd, pw, args); - pw.println(); pw.println("UI latency history:"); pw.println(); - mUiLatencyHistory.reverseDump(fd, pw, args); - pw.println(); pw.println("WTF history:"); pw.println(); - mWtfHistory.reverseDump(fd, pw, args); + if (showHistory) { + pw.println(); pw.println("Requests history:"); pw.println(); + mRequestsHistory.reverseDump(fd, pw, args); + pw.println(); pw.println("UI latency history:"); pw.println(); + mUiLatencyHistory.reverseDump(fd, pw, args); + pw.println(); pw.println("WTF history:"); pw.println(); + mWtfHistory.reverseDump(fd, pw, args); + } } } finally { - setDebugLocked(oldDebug); + sDebug = realDebug; + sVerbose = realVerbose; } } @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { - (new AutofillManagerServiceShellCommand(AutofillManagerService.this)).exec( + new AutofillManagerServiceShellCommand(AutofillManagerService.this).exec( this, in, out, err, args, callback, resultReceiver); } } - - private final class SettingsObserver extends ContentObserver { - SettingsObserver(Handler handler) { - super(handler); - ContentResolver resolver = mContext.getContentResolver(); - resolver.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.AUTOFILL_SERVICE), false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, this, - UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.AUTOFILL_LOGGING_LEVEL), false, this, - UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE), false, this, - UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, this, - UserHandle.USER_ALL); - } - - @Override - public void onChange(boolean selfChange, Uri uri, int userId) { - if (sVerbose) Slog.v(TAG, "onChange(): uri=" + uri + ", userId=" + userId); - switch (uri.getLastPathSegment()) { - case Settings.Global.AUTOFILL_LOGGING_LEVEL: - setLogLevelFromSettings(); - break; - case Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE: - setMaxPartitionsFromSettings(); - break; - case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS: - setMaxVisibleDatasetsFromSettings(); - break; - default: - synchronized (mLock) { - updateCachedServiceLocked(userId); - } - } - } - } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 14d68cb853d6..48103559afb6 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -25,19 +25,14 @@ import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.ActivityTaskManager; import android.app.ActivityManagerInternal; -import android.app.AppGlobals; +import android.app.ActivityTaskManager; import android.app.IActivityTaskManager; import android.content.ComponentName; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ServiceInfo; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.metrics.LogMaker; import android.os.AsyncTask; import android.os.Binder; @@ -49,7 +44,6 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; -import android.os.UserManager; import android.provider.Settings; import android.service.autofill.AutofillService; import android.service.autofill.AutofillServiceInfo; @@ -60,7 +54,6 @@ import android.service.autofill.FillEventHistory.Event; import android.service.autofill.FillResponse; import android.service.autofill.IAutoFillService; import android.service.autofill.UserData; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; @@ -77,6 +70,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.server.AbstractPerUserSystemService; import com.android.server.LocalServices; import com.android.server.autofill.AutofillManagerService.AutofillCompatState; import com.android.server.autofill.ui.AutoFillUI; @@ -91,7 +85,8 @@ import java.util.Random; * app's {@link IAutoFillService} implementation. * */ -final class AutofillManagerServiceImpl { +final class AutofillManagerServiceImpl + extends AbstractPerUserSystemService<AutofillManagerServiceImpl> { private static final String TAG = "AutofillManagerServiceImpl"; private static final int MAX_SESSION_ID_CREATE_TRIES = 2048; @@ -99,9 +94,6 @@ final class AutofillManagerServiceImpl { /** Minimum interval to prune abandoned sessions */ private static final int MAX_ABANDONED_SESSION_MILLIS = 30000; - private final int mUserId; - private final Context mContext; - private final Object mLock; private final AutoFillUI mUi; private final MetricsLogger mMetricsLogger = new MetricsLogger(); @@ -132,23 +124,11 @@ final class AutofillManagerServiceImpl { private ArrayMap<ComponentName, Long> mDisabledActivities; /** - * Whether service was disabled for user due to {@link UserManager} restrictions. - */ - @GuardedBy("mLock") - private boolean mDisabled; - - /** * Data used for field classification. */ @GuardedBy("mLock") private UserData mUserData; - /** - * Caches whether the setup completed for the current user. - */ - @GuardedBy("mLock") - private boolean mSetupComplete; - private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); /** @@ -170,116 +150,27 @@ final class AutofillManagerServiceImpl { /** When was {@link PruneTask} last executed? */ private long mLastPrune = 0; - AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory, + AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog requestsHistory, LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, AutofillCompatState autofillCompatState, boolean disabled) { - mContext = context; - mLock = lock; + super(master, lock, userId); + mRequestsHistory = requestsHistory; mUiLatencyHistory = uiLatencyHistory; mWtfHistory = wtfHistory; - mUserId = userId; mUi = ui; - mFieldClassificationStrategy = new FieldClassificationStrategy(context, userId); + mFieldClassificationStrategy = new FieldClassificationStrategy(getContext(), userId); mAutofillCompatState = autofillCompatState; updateLocked(disabled); } @GuardedBy("mLock") - private int getServiceUidLocked() { - if (mInfo == null) { - Slog.w(TAG, "getServiceUidLocked(): no mInfo"); - return -1; - } - return mInfo.getServiceInfo().applicationInfo.uid; - } - - - @Nullable - String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) { - return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId); - } - - @Nullable - String getServicePackageName() { - final ComponentName serviceComponent = getServiceComponentName(); - if (serviceComponent != null) { - return serviceComponent.getPackageName(); - } - return null; - } - - @Nullable - ComponentName getServiceComponentName() { - synchronized (mLock) { - if (mInfo == null) { - return null; - } - return mInfo.getServiceInfo().getComponentName(); - } - } - - int getTargedSdkLocked() { - if (mInfo == null) { - return 0; - } - return mInfo.getServiceInfo().applicationInfo.targetSdkVersion; - } - - private boolean isSetupCompletedLocked() { - final String setupComplete = Settings.Secure.getStringForUser( - mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId); - return "1".equals(setupComplete); - } - - private String getComponentNameFromSettings() { - return Settings.Secure.getStringForUser( - mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId); - } - - @GuardedBy("mLock") - void updateLocked(boolean disabled) { - final boolean wasEnabled = isEnabledLocked(); - if (sVerbose) { - Slog.v(TAG, "updateLocked(u=" + mUserId + "): wasEnabled=" + wasEnabled - + ", mSetupComplete= " + mSetupComplete - + ", disabled=" + disabled + ", mDisabled=" + mDisabled); - } - mSetupComplete = isSetupCompletedLocked(); - mDisabled = disabled; - ComponentName serviceComponent = null; - ServiceInfo serviceInfo = null; - final String componentName = getComponentNameFromSettings(); - if (!TextUtils.isEmpty(componentName)) { - try { - serviceComponent = ComponentName.unflattenFromString(componentName); - serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, - 0, mUserId); - if (serviceInfo == null) { - Slog.e(TAG, "Bad AutofillService name: " + componentName); - } - } catch (RuntimeException | RemoteException e) { - Slog.e(TAG, "Error getting service info for '" + componentName + "': " + e); - serviceInfo = null; - } - } - try { - if (serviceInfo != null) { - mInfo = new AutofillServiceInfo(mContext, serviceComponent, mUserId); - if (sDebug) Slog.d(TAG, "Set component for user " + mUserId + " as " + mInfo); - } else { - mInfo = null; - if (sDebug) { - Slog.d(TAG, "Reset component for user " + mUserId + " (" + componentName + ")"); - } - } - } catch (Exception e) { - Slog.e(TAG, "Bad AutofillServiceInfo for '" + componentName + "': " + e); - mInfo = null; - } - final boolean isEnabled = isEnabledLocked(); - if (wasEnabled != isEnabled) { - if (!isEnabled) { + @Override // from PerUserSystemService + protected boolean updateLocked(boolean disabled) { + destroySessionsLocked(); + final boolean enabledChanged = super.updateLocked(disabled); + if (enabledChanged) { + if (!isEnabledLocked()) { final int sessionCount = mSessions.size(); for (int i = sessionCount - 1; i >= 0; i--) { final Session session = mSessions.valueAt(i); @@ -288,6 +179,19 @@ final class AutofillManagerServiceImpl { } sendStateToClients(false); } + return enabledChanged; + } + + @Override // from PerUserSystemService + protected ServiceInfo newServiceInfo(@NonNull ComponentName serviceComponent) + throws NameNotFoundException { + mInfo = new AutofillServiceInfo(getContext(), serviceComponent, mUserId); + return mInfo.getServiceInfo(); + } + + @Nullable + String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) { + return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId); } @GuardedBy("mLock") @@ -469,7 +373,7 @@ final class AutofillManagerServiceImpl { if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) { mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF, componentName.getPackageName()); - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(getContext().getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, null, mUserId); destroySessionsLocked(); } else { @@ -501,7 +405,7 @@ final class AutofillManagerServiceImpl { assertCallerLocked(componentName, compatMode); - final Session newSession = new Session(this, mUi, mContext, mHandler, mUserId, mLock, + final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock, sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory, mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, compatMode, bindInstantServiceAllowed, flags); @@ -515,7 +419,7 @@ final class AutofillManagerServiceImpl { */ private void assertCallerLocked(@NonNull ComponentName componentName, boolean compatMode) { final String packageName = componentName.getPackageName(); - final PackageManager pm = mContext.getPackageManager(); + final PackageManager pm = getContext().getPackageManager(); final int callingUid = Binder.getCallingUid(); final int packageUid; try { @@ -651,7 +555,8 @@ final class AutofillManagerServiceImpl { } @GuardedBy("mLock") - void handlePackageUpdateLocked(String packageName) { + @Override // from PerUserSystemService + protected void handlePackageUpdateLocked(@NonNull String packageName) { final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo(); if (serviceInfo != null && serviceInfo.packageName.equals(packageName)) { resetExtServiceLocked(); @@ -691,29 +596,6 @@ final class AutofillManagerServiceImpl { } /** - * Gets the user-visibile name of the service this service binds to, or {@code null} if the - * service is disabled. - */ - @Nullable - @GuardedBy("mLock") - public CharSequence getServiceLabelLocked() { - return mInfo == null ? null : mInfo.getServiceInfo().loadSafeLabel( - mContext.getPackageManager(), 0 /* do not ellipsize */, - PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM); - } - - /** - * Gets the icon of the service this service binds to, or {@code null} if the service is - * disabled. - */ - @NonNull - @Nullable - @GuardedBy("mLock") - Drawable getServiceIconLocked() { - return mInfo == null ? null : mInfo.getServiceInfo().loadIcon(mContext.getPackageManager()); - } - - /** * Initializes the last fill selection after an autofill service returned a new * {@link FillResponse}. */ @@ -941,11 +823,13 @@ final class AutofillManagerServiceImpl { return true; } + @Override @GuardedBy("mLock") - void dumpLocked(String prefix, PrintWriter pw) { + protected void dumpLocked(String prefix, PrintWriter pw) { + super.dumpLocked(prefix, pw); + final String prefix2 = prefix + " "; - pw.print(prefix); pw.print("User: "); pw.println(mUserId); pw.print(prefix); pw.print("UID: "); pw.println(getServiceUidLocked()); pw.print(prefix); pw.print("Autofill Service Info: "); if (mInfo == null) { @@ -958,9 +842,8 @@ final class AutofillManagerServiceImpl { } pw.print(prefix); pw.print("Component from settings: "); pw.println(getComponentNameFromSettings()); - pw.print(prefix); pw.print("Default component: "); - pw.println(mContext.getString(R.string.config_defaultAutofillService)); - pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled); + pw.print(prefix); pw.print("Default component: "); pw.println(getContext() + .getString(R.string.config_defaultAutofillService)); pw.print(prefix); pw.print("Field classification enabled: "); pw.println(isFieldClassificationEnabledLocked()); pw.print(prefix); pw.print("Compat pkgs: "); @@ -970,7 +853,6 @@ final class AutofillManagerServiceImpl { } else { pw.println(compatPkgs); } - pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete); pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune); pw.print(prefix); pw.print("Disabled apps: "); @@ -1158,11 +1040,6 @@ final class AutofillManagerServiceImpl { return true; } - @GuardedBy("mLock") - boolean isEnabledLocked() { - return mSetupComplete && mInfo != null && !mDisabled; - } - /** * Called by {@link Session} when service asked to disable autofill for an app. */ @@ -1270,7 +1147,7 @@ final class AutofillManagerServiceImpl { // Called by internally, no need to check UID. boolean isFieldClassificationEnabledLocked() { return Settings.Secure.getIntForUser( - mContext.getContentResolver(), + getContext().getContentResolver(), Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 1, mUserId) == 1; } diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java index 420c2be008cb..3c0da7d2d388 100644 --- a/services/autofill/java/com/android/server/autofill/Helper.java +++ b/services/autofill/java/com/android/server/autofill/Helper.java @@ -28,20 +28,21 @@ import android.util.ArraySet; import android.util.Slog; import android.view.WindowManager; import android.view.autofill.AutofillId; -import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; +import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.LinkedList; public final class Helper { private static final String TAG = "AutofillHelper"; + // TODO(b/117779333): get rid of sDebug / sVerbose and always use the service variables instead + /** * Defines a logging flag that can be dynamically changed at runtime using * {@code cmd autofill set log_level debug} or through @@ -57,23 +58,6 @@ public final class Helper { public static boolean sVerbose = false; /** - * Maximum number of partitions that can be allowed in a session. - * - * <p>Can be modified using {@code cmd autofill set max_partitions} or through - * {@link android.provider.Settings.Global#AUTOFILL_MAX_PARTITIONS_SIZE}. - */ - static int sPartitionMaxCount = AutofillManager.DEFAULT_MAX_PARTITIONS_SIZE; - - /** - * Maximum number of visible datasets in the dataset picker UI, or {@code 0} to use default - * value from resources. - * - * <p>Can be modified using {@code cmd autofill set max_visible_datasets} or through - * {@link android.provider.Settings.Global#AUTOFILL_MAX_VISIBLE_DATASETS}. - */ - public static int sVisibleDatasetsMaxCount = 0; - - /** * When non-null, overrides whether the UI should be shown on full-screen mode. * * <p>Note: access to this variable is not synchronized because it's "final" on real usage - @@ -162,7 +146,7 @@ public final class Helper { private static ViewNode findViewNode(@NonNull AssistStructure structure, @NonNull ViewNodeFilter filter) { - final LinkedList<ViewNode> nodesToProcess = new LinkedList<>(); + final ArrayDeque<ViewNode> nodesToProcess = new ArrayDeque<>(); final int numWindowNodes = structure.getWindowNodeCount(); for (int i = 0; i < numWindowNodes; i++) { nodesToProcess.add(structure.getWindowNodeAt(i).getRootViewNode()); diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index d1b09ca1aca8..9aa9d7c52818 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -18,7 +18,6 @@ package com.android.server.autofill; import static android.service.autofill.FillRequest.INVALID_REQUEST_ID; -import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sVerbose; @@ -26,17 +25,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.IntentSender; -import android.content.ServiceConnection; -import android.os.Build; -import android.os.Handler; import android.os.IBinder; -import android.os.IBinder.DeathRecipient; import android.os.ICancellationSignal; +import android.os.IInterface; import android.os.RemoteException; -import android.os.SystemClock; -import android.os.UserHandle; import android.service.autofill.AutofillService; import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; @@ -47,59 +40,17 @@ import android.service.autofill.SaveRequest; import android.text.format.DateUtils; import android.util.Slog; -import com.android.internal.annotations.GuardedBy; -import com.android.server.FgThread; +import com.android.server.AbstractRemoteService; -import java.io.PrintWriter; -import java.lang.ref.WeakReference; +final class RemoteFillService extends AbstractRemoteService { -/** - * This class represents a remote fill service. It abstracts away the binding - * and unbinding from the remote implementation. - * - * <p>Clients can call methods of this class without worrying about when and - * how to bind/unbind/timeout. All state of this class is modified on a handler - * thread. - */ -final class RemoteFillService implements DeathRecipient { - private static final String LOG_TAG = "RemoteFillService"; - // How long after the last interaction with the service we would unbind private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; - - // How long after we make a remote request to a fill service we timeout private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; - private static final int MSG_UNBIND = 3; - - private final Context mContext; - - private final ComponentName mComponentName; - - private final Intent mIntent; - private final FillServiceCallbacks mCallbacks; - - private final int mUserId; - - private final ServiceConnection mServiceConnection = new RemoteServiceConnection(); - - private final Handler mHandler; - - private final boolean mBindInstantServiceAllowed; - private IAutoFillService mAutoFillService; - private boolean mBinding; - - private boolean mDestroyed; - - private boolean mServiceDied; - - private boolean mCompleted; - - private PendingRequest mPendingRequest; - - public interface FillServiceCallbacks { + public interface FillServiceCallbacks extends VultureCallback { void onFillRequestSuccess(int requestId, @Nullable FillResponse response, @NonNull String servicePackageName, int requestFlags); void onFillRequestFailure(int requestId, @Nullable CharSequence message); @@ -109,48 +60,42 @@ final class RemoteFillService implements DeathRecipient { // TODO(b/80093094): add timeout here too? void onSaveRequestFailure(@Nullable CharSequence message, @NonNull String servicePackageName); - void onServiceDied(RemoteFillService service); } - public RemoteFillService(Context context, ComponentName componentName, - int userId, FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) { - mContext = context; + RemoteFillService(Context context, ComponentName componentName, int userId, + FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) { + super(context, AutofillService.SERVICE_INTERFACE, componentName, userId, callbacks, + bindInstantServiceAllowed, sVerbose); mCallbacks = callbacks; - mComponentName = componentName; - mIntent = new Intent(AutofillService.SERVICE_INTERFACE).setComponent(mComponentName); - mUserId = userId; - mHandler = new Handler(FgThread.getHandler().getLooper()); - mBindInstantServiceAllowed = bindInstantServiceAllowed; } - public void destroy() { - mHandler.sendMessage(obtainMessage(RemoteFillService::handleDestroy, this)); + @Override + protected void onConnectedStateChanged(boolean state) { + if (mAutoFillService == null) { + Slog.w(mTag, "onConnectedStateChanged(): null service"); + return; + } + try { + mAutoFillService.onConnectedStateChanged(state); + } catch (Exception e) { + Slog.w(mTag, "Exception calling onConnectedStateChanged(): " + e); + } } - private void handleDestroy() { - if (checkIfDestroyed()) return; - if (mPendingRequest != null) { - mPendingRequest.cancel(); - mPendingRequest = null; - } - ensureUnbound(); - mDestroyed = true; + @Override + protected IInterface getServiceInterface(IBinder service) { + mAutoFillService = IAutoFillService.Stub.asInterface(service); + return mAutoFillService; } @Override - public void binderDied() { - mHandler.sendMessage(obtainMessage( - RemoteFillService::handleBinderDied, this)); + protected long getTimeoutIdleBindMillis() { + return TIMEOUT_IDLE_BIND_MILLIS; } - private void handleBinderDied() { - if (checkIfDestroyed()) return; - if (mAutoFillService != null) { - mAutoFillService.asBinder().unlinkToDeath(this, 0); - } - mAutoFillService = null; - mServiceDied = true; - mCallbacks.onServiceDied(this); + @Override + protected long getRemoteRequestMillis() { + return TIMEOUT_REMOTE_REQUEST_MILLIS; } /** @@ -162,8 +107,9 @@ final class RemoteFillService implements DeathRecipient { * @return the id of the canceled request, or {@link FillRequest#INVALID_REQUEST_ID} if no * {@link PendingFillRequest} was canceled. */ + // TODO(b/117779333): move this logic to super class (and make mPendingRequest private) public int cancelCurrentRequest() { - if (mDestroyed) { + if (isDestroyed()) { return INVALID_REQUEST_ID; } @@ -190,118 +136,6 @@ final class RemoteFillService implements DeathRecipient { scheduleRequest(new PendingSaveRequest(request, this)); } - private void scheduleRequest(PendingRequest pendingRequest) { - mHandler.sendMessage(obtainMessage( - RemoteFillService::handlePendingRequest, this, pendingRequest)); - } - - // Note: we are dumping without a lock held so this is a bit racy but - // adding a lock to a class that offloads to a handler thread would - // mean adding a lock adding overhead to normal runtime operation. - public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { - String tab = " "; - pw.append(prefix).append("service:").println(); - pw.append(prefix).append(tab).append("userId=") - .append(String.valueOf(mUserId)).println(); - pw.append(prefix).append(tab).append("componentName=") - .append(mComponentName.flattenToString()).println(); - pw.append(prefix).append(tab).append("destroyed=") - .append(String.valueOf(mDestroyed)).println(); - pw.append(prefix).append(tab).append("bound=") - .append(String.valueOf(isBound())).println(); - pw.append(prefix).append(tab).append("hasPendingRequest=") - .append(String.valueOf(mPendingRequest != null)).println(); - pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed); - pw.println(); - } - - private void cancelScheduledUnbind() { - mHandler.removeMessages(MSG_UNBIND); - } - - private void scheduleUnbind() { - cancelScheduledUnbind(); - mHandler.sendMessageDelayed( - obtainMessage(RemoteFillService::handleUnbind, this) - .setWhat(MSG_UNBIND), - TIMEOUT_IDLE_BIND_MILLIS); - } - - private void handleUnbind() { - if (checkIfDestroyed()) return; - ensureUnbound(); - } - - private void handlePendingRequest(PendingRequest pendingRequest) { - if (checkIfDestroyed()) return; - if (mCompleted) { - return; - } - if (!isBound()) { - if (mPendingRequest != null) { - mPendingRequest.cancel(); - } - mPendingRequest = pendingRequest; - ensureBound(); - } else { - if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] handlePendingRequest()"); - pendingRequest.run(); - if (pendingRequest.isFinal()) { - mCompleted = true; - } - } - } - - private boolean isBound() { - return mAutoFillService != null; - } - - private void ensureBound() { - if (isBound() || mBinding) { - return; - } - if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureBound()"); - mBinding = true; - - int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE; - if (mBindInstantServiceAllowed) { - flags |= Context.BIND_ALLOW_INSTANT; - } - - final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags, - new UserHandle(mUserId)); - - if (!willBind) { - Slog.w(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent + " using flags " - + flags); - mBinding = false; - - if (!mServiceDied) { - handleBinderDied(); - } - } - } - - private void ensureUnbound() { - if (!isBound() && !mBinding) { - return; - } - if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()"); - mBinding = false; - if (isBound()) { - try { - mAutoFillService.onConnectedStateChanged(false); - } catch (Exception e) { - Slog.w(LOG_TAG, "Exception calling onDisconnected(): " + e); - } - if (mAutoFillService != null) { - mAutoFillService.asBinder().unlinkToDeath(this, 0); - mAutoFillService = null; - } - } - mContext.unbindService(mServiceConnection); - } - private void dispatchOnFillRequestSuccess(@NonNull PendingFillRequest pendingRequest, @Nullable FillResponse response, int requestFlags) { mHandler.post(() -> { @@ -334,12 +168,12 @@ final class RemoteFillService implements DeathRecipient { try { cancellationSignal.cancel(); } catch (RemoteException e) { - Slog.w(LOG_TAG, "Error calling cancellation signal: " + e); + Slog.w(mTag, "Error calling cancellation signal: " + e); } }); } - private void dispatchOnSaveRequestSuccess(PendingRequest pendingRequest, + private void dispatchOnSaveRequestSuccess(PendingSaveRequest pendingRequest, IntentSender intentSender) { mHandler.post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { @@ -348,7 +182,7 @@ final class RemoteFillService implements DeathRecipient { }); } - private void dispatchOnSaveRequestFailure(PendingRequest pendingRequest, + private void dispatchOnSaveRequestFailure(PendingSaveRequest pendingRequest, @Nullable CharSequence message) { mHandler.post(() -> { if (handleResponseCallbackCommon(pendingRequest)) { @@ -357,162 +191,7 @@ final class RemoteFillService implements DeathRecipient { }); } - private boolean handleResponseCallbackCommon(PendingRequest pendingRequest) { - if (mDestroyed) { - return false; - } - if (mPendingRequest == pendingRequest) { - mPendingRequest = null; - } - if (mPendingRequest == null) { - scheduleUnbind(); - } - return true; - } - - private class RemoteServiceConnection implements ServiceConnection { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - if (mDestroyed || !mBinding) { - // This is abnormal. Unbinding the connection has been requested already. - Slog.wtf(LOG_TAG, "onServiceConnected was dispatched after unbindService."); - return; - } - mBinding = false; - mAutoFillService = IAutoFillService.Stub.asInterface(service); - try { - service.linkToDeath(RemoteFillService.this, 0); - } catch (RemoteException re) { - handleBinderDied(); - return; - } - try { - mAutoFillService.onConnectedStateChanged(true); - } catch (RemoteException e) { - Slog.w(LOG_TAG, "Exception calling onConnected(): " + e); - } - - if (mPendingRequest != null) { - PendingRequest pendingRequest = mPendingRequest; - mPendingRequest = null; - handlePendingRequest(pendingRequest); - } - - mServiceDied = false; - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mBinding = true; - mAutoFillService = null; - } - } - - private boolean checkIfDestroyed() { - if (mDestroyed) { - if (sVerbose) { - Slog.v(LOG_TAG, "Not handling operation as service for " - + mComponentName + " is already destroyed"); - } - } - return mDestroyed; - } - - private static abstract class PendingRequest implements Runnable { - protected final Object mLock = new Object(); - private final WeakReference<RemoteFillService> mWeakService; - - private final Runnable mTimeoutTrigger; - private final Handler mServiceHandler; - - @GuardedBy("mLock") - private boolean mCancelled; - - @GuardedBy("mLock") - private boolean mCompleted; - - PendingRequest(RemoteFillService service) { - mWeakService = new WeakReference<>(service); - mServiceHandler = service.mHandler; - mTimeoutTrigger = () -> { - synchronized (mLock) { - if (mCancelled) { - return; - } - mCompleted = true; - } - - Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out"); - final RemoteFillService remoteService = mWeakService.get(); - if (remoteService != null) { - Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out after " - + TIMEOUT_REMOTE_REQUEST_MILLIS + " ms"); - onTimeout(remoteService); - } - }; - mServiceHandler.postAtTime(mTimeoutTrigger, - SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS); - } - - protected RemoteFillService getService() { - return mWeakService.get(); - } - - /** - * Sub-classes must call this method when the remote service finishes, i.e., when it - * called {@code onFill...} or {@code onSave...}. - * - * @return {@code false} in the service is already finished, {@code true} otherwise. - */ - protected final boolean finish() { - synchronized (mLock) { - if (mCompleted || mCancelled) { - return false; - } - mCompleted = true; - } - mServiceHandler.removeCallbacks(mTimeoutTrigger); - return true; - } - - @GuardedBy("mLock") - protected boolean isCancelledLocked() { - return mCancelled; - } - - /** - * Cancels the service. - * - * @return {@code false} if service is already canceled, {@code true} otherwise. - */ - boolean cancel() { - synchronized (mLock) { - if (mCancelled || mCompleted) { - return false; - } - mCancelled = true; - } - - mServiceHandler.removeCallbacks(mTimeoutTrigger); - return true; - } - - /** - * Called by the self-destructure timeout when the AutofilllService didn't reply to the - * request on time. - */ - abstract void onTimeout(RemoteFillService remoteService); - - /** - * @return whether this request leads to a final state where no - * other requests can be made. - */ - boolean isFinal() { - return false; - } - } - - private static final class PendingFillRequest extends PendingRequest { + private static final class PendingFillRequest extends PendingRequest<RemoteFillService> { private final FillRequest mRequest; private final IFillCallback mCallback; private ICancellationSignal mCancellation; @@ -534,7 +213,7 @@ final class RemoteFillService implements DeathRecipient { try { cancellation.cancel(); } catch (RemoteException e) { - Slog.e(LOG_TAG, "Error requesting a cancellation", e); + Slog.e(mTag, "Error requesting a cancellation", e); } } } @@ -565,7 +244,7 @@ final class RemoteFillService implements DeathRecipient { } @Override - void onTimeout(RemoteFillService remoteService) { + protected void onTimeout(RemoteFillService remoteService) { // NOTE: Must make these 2 calls asynchronously, because the cancellation signal is // handled by the service, which could block. final ICancellationSignal cancellation; @@ -582,17 +261,17 @@ final class RemoteFillService implements DeathRecipient { public void run() { synchronized (mLock) { if (isCancelledLocked()) { - if (sDebug) Slog.d(LOG_TAG, "run() called after canceled: " + mRequest); + if (sDebug) Slog.d(mTag, "run() called after canceled: " + mRequest); return; } } final RemoteFillService remoteService = getService(); if (remoteService != null) { - if (sVerbose) Slog.v(LOG_TAG, "calling onFillRequest() for id=" + mRequest.getId()); + if (sVerbose) Slog.v(mTag, "calling onFillRequest() for id=" + mRequest.getId()); try { remoteService.mAutoFillService.onFillRequest(mRequest, mCallback); } catch (RemoteException e) { - Slog.e(LOG_TAG, "Error calling on fill request", e); + Slog.e(mTag, "Error calling on fill request", e); remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null); } @@ -611,14 +290,14 @@ final class RemoteFillService implements DeathRecipient { try { cancellation.cancel(); } catch (RemoteException e) { - Slog.e(LOG_TAG, "Error cancelling a fill request", e); + Slog.e(mTag, "Error cancelling a fill request", e); } } return true; } } - private static final class PendingSaveRequest extends PendingRequest { + private static final class PendingSaveRequest extends PendingRequest<RemoteFillService> { private final SaveRequest mRequest; private final ISaveCallback mCallback; @@ -653,7 +332,7 @@ final class RemoteFillService implements DeathRecipient { } @Override - void onTimeout(RemoteFillService remoteService) { + protected void onTimeout(RemoteFillService remoteService) { remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null); } @@ -661,11 +340,11 @@ final class RemoteFillService implements DeathRecipient { public void run() { final RemoteFillService remoteService = getService(); if (remoteService != null) { - if (sVerbose) Slog.v(LOG_TAG, "calling onSaveRequest()"); + if (sVerbose) Slog.v(mTag, "calling onSaveRequest()"); try { remoteService.mAutoFillService.onSaveRequest(mRequest, mCallback); } catch (RemoteException e) { - Slog.e(LOG_TAG, "Error calling on save request", e); + Slog.e(mTag, "Error calling on save request", e); remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null); } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index f85749af54fd..09f915e252ee 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -27,7 +27,6 @@ import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.autofill.Helper.getNumericValue; import static com.android.server.autofill.Helper.sDebug; -import static com.android.server.autofill.Helper.sPartitionMaxCount; import static com.android.server.autofill.Helper.sVerbose; import static com.android.server.autofill.Helper.toArray; import static com.android.server.autofill.ViewState.STATE_RESTARTED_SESSION; @@ -65,7 +64,6 @@ import android.service.autofill.AutofillService; import android.service.autofill.Dataset; import android.service.autofill.FieldClassification; import android.service.autofill.FieldClassification.Match; -import android.text.TextUtils; import android.service.autofill.FillContext; import android.service.autofill.FillRequest; import android.service.autofill.FillResponse; @@ -75,10 +73,10 @@ import android.service.autofill.SaveInfo; import android.service.autofill.SaveRequest; import android.service.autofill.UserData; import android.service.autofill.ValueFinder; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LocalLog; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; @@ -94,6 +92,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; +import com.android.server.AbstractRemoteService; import com.android.server.autofill.ui.AutoFillUI; import com.android.server.autofill.ui.PendingUi; @@ -903,9 +902,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState this, authenticationId, intent, fillInIntent)); } - // FillServiceCallbacks + // VultureCallback @Override - public void onServiceDied(RemoteFillService service) { + public void onServiceDied(AbstractRemoteService service) { Slog.w(TAG, "removing session because service died"); forceRemoveSelfLocked(); } @@ -2095,9 +2094,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } final int numResponses = mResponses.size(); - if (numResponses >= sPartitionMaxCount) { + if (numResponses >= AutofillManagerService.getPartitionMaxCount()) { Slog.e(TAG, "Not starting a new partition on " + id + " because session " + this.id - + " reached maximum of " + sPartitionMaxCount); + + " reached maximum of " + AutofillManagerService.getPartitionMaxCount()); return false; } @@ -2289,7 +2288,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags); // Remove the UI if the ViewState has changed. - if (mCurrentViewId != viewState.id) { + if (!Objects.equals(mCurrentViewId, viewState.id)) { mUi.hideFillUi(this); mCurrentViewId = viewState.id; } @@ -2298,7 +2297,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState viewState.update(value, virtualBounds, flags); break; case ACTION_VIEW_EXITED: - if (mCurrentViewId == viewState.id) { + if (Objects.equals(mCurrentViewId, viewState.id)) { if (sVerbose) Slog.d(TAG, "Exiting view " + id); mUi.hideFillUi(this); mCurrentViewId = null; @@ -3077,7 +3076,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private void wtf(@Nullable Exception e, String fmt, Object...args) { final String message = String.format(fmt, args); - mWtfHistory.log(message); + synchronized (mLock) { + mWtfHistory.log(message); + } if (e != null) { Slog.wtf(TAG, message, e); diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java index f79f6ff73d29..d1fe970c0783 100644 --- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java @@ -19,25 +19,22 @@ import static com.android.server.autofill.Helper.paramsToString; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sFullScreenMode; import static com.android.server.autofill.Helper.sVerbose; -import static com.android.server.autofill.Helper.sVisibleDatasetsMaxCount; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.PendingIntent; import android.content.Context; -import android.graphics.drawable.Drawable; -import android.view.ContextThemeWrapper; -import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.service.autofill.Dataset; import android.service.autofill.Dataset.DatasetFieldFilter; import android.service.autofill.FillResponse; import android.text.TextUtils; import android.util.Slog; import android.util.TypedValue; +import android.view.ContextThemeWrapper; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -60,6 +57,7 @@ import android.widget.TextView; import com.android.internal.R; import com.android.server.UiThread; +import com.android.server.autofill.AutofillManagerService; import com.android.server.autofill.Helper; import java.io.PrintWriter; @@ -193,8 +191,8 @@ final class FillUi { } }); - if (sVisibleDatasetsMaxCount > 0) { - mVisibleDatasetsMaxCount = sVisibleDatasetsMaxCount; + if (AutofillManagerService.getVisibleDatasetsMaxCount() > 0) { + mVisibleDatasetsMaxCount = AutofillManagerService.getVisibleDatasetsMaxCount(); if (sVerbose) { Slog.v(TAG, "overriding maximum visible datasets to " + mVisibleDatasetsMaxCount); } diff --git a/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java b/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java new file mode 100644 index 000000000000..9cab1ed15b9e --- /dev/null +++ b/services/autofill/java/com/android/server/intelligence/ContentCaptureSession.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.intelligence; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.os.IBinder; +import android.service.intelligence.IntelligenceService; +import android.service.intelligence.InteractionContext; +import android.service.intelligence.InteractionSessionId; +import android.util.Slog; +import android.view.intelligence.ContentCaptureEvent; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.Preconditions; +import com.android.server.AbstractRemoteService; +import com.android.server.intelligence.RemoteIntelligenceService.RemoteIntelligenceServiceCallbacks; + +import java.io.PrintWriter; +import java.util.List; + +final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks { + + private static final String TAG = "ContentCaptureSession"; + + private final Object mLock; + private final IBinder mActivityToken; + + private final IntelligencePerUserService mService; + private final RemoteIntelligenceService mRemoteService; + private final InteractionContext mInterationContext; + private final InteractionSessionId mId; + + ContentCaptureSession(@NonNull Context context, int userId, @NonNull Object lock, + @NonNull IBinder activityToken, @NonNull IntelligencePerUserService service, + @NonNull ComponentName serviceComponentName, @NonNull ComponentName appComponentName, + int taskId, int displayId, @NonNull InteractionSessionId sessionId, int flags, + boolean bindInstantServiceAllowed, boolean verbose) { + mLock = lock; + mActivityToken = activityToken; + mService = service; + mId = Preconditions.checkNotNull(sessionId); + mRemoteService = new RemoteIntelligenceService(context, + IntelligenceService.SERVICE_INTERFACE, serviceComponentName, userId, this, + bindInstantServiceAllowed, verbose); + mInterationContext = new InteractionContext(appComponentName, taskId, displayId, flags); + } + + /** + * Notifies the {@link IntelligenceService} that the service started. + */ + @GuardedBy("mLock") + public void notifySessionStartedLocked() { + mRemoteService.onSessionLifecycleRequest(mInterationContext, mId); + } + + /** + * Notifies the {@link IntelligenceService} of a batch of events. + */ + public void sendEventsLocked(List<ContentCaptureEvent> events) { + mRemoteService.onContentCaptureEventsRequest(mId, events); + } + + /** + * Cleans up the session and remove itself from the service. + * + * @param notifyRemoteService whether it should trigger a {@link + * IntelligenceService#onDestroyInteractionSession(InteractionSessionId)} + * request. + */ + @GuardedBy("mLock") + public void removeSelfLocked(boolean notifyRemoteService) { + try { + if (notifyRemoteService) { + mRemoteService.onSessionLifecycleRequest(/* context= */ null, mId); + } + } finally { + mService.removeSessionLocked(mId); + } + } + + @Override // from RemoteScreenObservationServiceCallbacks + public void onServiceDied(AbstractRemoteService service) { + // TODO(b/111276913): implement (remove session from PerUserSession?) + if (mService.isDebug()) { + Slog.d(TAG, "onServiceDied() for " + mId); + } + synchronized (mLock) { + removeSelfLocked(/* notifyRemoteService= */ false); + } + } + + @Override // from RemoteScreenObservationServiceCallbacks + public void onFailureOrTimeout(boolean timedOut) { + // TODO(b/111276913): log metrics on whether timed out or not + if (mService.isDebug()) { + Slog.d(TAG, "onFailureOrTimeout(" + mId + "): timed out=" + timedOut); + } + synchronized (mLock) { + removeSelfLocked(/* notifyRemoteService= */ false); + } + } + + @GuardedBy("mLock") + public void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) { + pw.print(prefix); pw.print("id: "); mId.dump(pw); pw.println(); + pw.print(prefix); pw.print("context: "); mInterationContext.dump(pw); pw.println(); + pw.print(prefix); pw.print("activity token: "); pw.println(mActivityToken); + } + + @Override + public String toString() { + return "ContentCaptureSession[id=" + mId.getValue() + ", act=" + mActivityToken + "]"; + } +} diff --git a/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java b/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java new file mode 100644 index 000000000000..43d4a4476c11 --- /dev/null +++ b/services/autofill/java/com/android/server/intelligence/IntelligenceManagerService.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.intelligence; + +import static android.content.Context.INTELLIGENCE_MANAGER_SERVICE; + +import android.annotation.NonNull; +import android.app.ActivityManagerInternal; +import android.content.ComponentName; +import android.content.Context; +import android.os.IBinder; +import android.os.UserManager; +import android.service.intelligence.InteractionSessionId; +import android.view.intelligence.ContentCaptureEvent; +import android.view.intelligence.IIntelligenceManager; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.IResultReceiver; +import com.android.internal.util.DumpUtils; +import com.android.internal.util.Preconditions; +import com.android.server.AbstractMasterSystemService; +import com.android.server.LocalServices; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.List; + +/** + * A service used to observe the contents of the screen. + * + * <p>The data collected by this service can be analyzed and combined with other sources to provide + * contextual data in other areas of the system such as Autofill. + */ +public final class IntelligenceManagerService + extends AbstractMasterSystemService<IntelligencePerUserService> { + + private static final String TAG = "IntelligenceManagerService"; + + @GuardedBy("mLock") + private ActivityManagerInternal mAm; + + public IntelligenceManagerService(Context context) { + super(context, UserManager.DISALLOW_INTELLIGENCE_CAPTURE); + } + + @Override // from MasterSystemService + protected String getServiceSettingsProperty() { + // TODO(b/111276913): STOPSHIP temporary settings, until it's set by resourcs + cmd + return "intel_service"; + } + + @Override // from MasterSystemService + protected IntelligencePerUserService newServiceLocked(int resolvedUserId, + boolean disabled) { + return new IntelligencePerUserService(this, mLock, resolvedUserId); + } + + @Override // from SystemService + public void onStart() { + publishBinderService(INTELLIGENCE_MANAGER_SERVICE, + new IntelligenceManagerServiceStub()); + } + + private ActivityManagerInternal getAmInternal() { + synchronized (mLock) { + if (mAm == null) { + mAm = LocalServices.getService(ActivityManagerInternal.class); + } + } + return mAm; + } + + final class IntelligenceManagerServiceStub extends IIntelligenceManager.Stub { + + @Override + public void startSession(int userId, @NonNull IBinder activityToken, + @NonNull ComponentName componentName, @NonNull InteractionSessionId sessionId, + int flags, @NonNull IResultReceiver result) { + Preconditions.checkNotNull(activityToken); + Preconditions.checkNotNull(componentName); + Preconditions.checkNotNull(sessionId); + + // TODO(b/111276913): refactor getTaskIdForActivity() to also return ComponentName, + // so we don't pass it on startSession (same for Autofill) + final int taskId = getAmInternal().getTaskIdForActivity(activityToken, false); + + // TODO(b/111276913): get from AM as well + final int displayId = 0; + + synchronized (mLock) { + final IntelligencePerUserService service = getServiceForUserLocked(userId); + service.startSessionLocked(activityToken, componentName, taskId, displayId, + sessionId, flags, result); + } + } + + @Override + public void sendEvents(int userId, @NonNull InteractionSessionId sessionId, + @NonNull List<ContentCaptureEvent> events) { + Preconditions.checkNotNull(sessionId); + Preconditions.checkNotNull(events); + + synchronized (mLock) { + final IntelligencePerUserService service = getServiceForUserLocked(userId); + service.sendEventsLocked(sessionId, events); + } + } + + @Override + public void finishSession(int userId, @NonNull InteractionSessionId sessionId) { + Preconditions.checkNotNull(sessionId); + + synchronized (mLock) { + final IntelligencePerUserService service = getServiceForUserLocked(userId); + service.finishSessionLocked(sessionId); + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; + + synchronized (mLock) { + dumpLocked("", pw); + } + } + } +} diff --git a/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java b/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java new file mode 100644 index 000000000000..584b872c64d0 --- /dev/null +++ b/services/autofill/java/com/android/server/intelligence/IntelligencePerUserService.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.intelligence; + +import android.Manifest; +import android.annotation.NonNull; +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ServiceInfo; +import android.os.IBinder; +import android.os.RemoteException; +import android.service.intelligence.InteractionSessionId; +import android.util.ArrayMap; +import android.util.Slog; +import android.view.intelligence.ContentCaptureEvent; +import android.view.intelligence.IntelligenceManager; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.IResultReceiver; +import com.android.server.AbstractPerUserSystemService; + +import java.io.PrintWriter; +import java.util.List; + +/** + * Per-user instance of {@link IntelligenceManagerService}. + */ +final class IntelligencePerUserService + extends AbstractPerUserSystemService<IntelligencePerUserService> { + + private static final String TAG = "IntelligencePerUserService"; + + @GuardedBy("mLock") + private final ArrayMap<InteractionSessionId, ContentCaptureSession> mSessions = + new ArrayMap<>(); + + // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's + + protected IntelligencePerUserService( + IntelligenceManagerService master, Object lock, int userId) { + super(master, lock, userId); + } + + @Override // from PerUserSystemService + protected ServiceInfo newServiceInfo(@NonNull ComponentName serviceComponent) + throws NameNotFoundException { + + ServiceInfo si; + try { + // TODO(b/111276913): must check that either the service is from a system component, + // or it matches a service set by shell cmd (so it can be used on CTS tests and when + // OEMs are implementing the real service + si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, + PackageManager.GET_META_DATA, mUserId); + } catch (RemoteException e) { + Slog.w(TAG, "Could not get service for " + serviceComponent + ": " + e); + return null; + } + if (!Manifest.permission.BIND_INTELLIGENCE_SERVICE.equals(si.permission)) { + Slog.w(TAG, "IntelligenceService from '" + si.packageName + + "' does not require permission " + + Manifest.permission.BIND_INTELLIGENCE_SERVICE); + throw new SecurityException("Service does not require permission " + + Manifest.permission.BIND_INTELLIGENCE_SERVICE); + } + return si; + } + + // TODO(b/111276913): log metrics + @GuardedBy("mLock") + public void startSessionLocked(@NonNull IBinder activityToken, + @NonNull ComponentName componentName, int taskId, int displayId, + @NonNull InteractionSessionId sessionId, int flags, + @NonNull IResultReceiver resultReceiver) { + final ComponentName serviceComponentName = getServiceComponentName(); + if (serviceComponentName == null) { + // TODO(b/111276913): this happens when the system service is starting, we should + // probably handle it in a more elegant way (like waiting for boot_complete or + // something like that + Slog.w(TAG, "startSession(" + activityToken + "): hold your horses"); + return; + } + + ContentCaptureSession session = mSessions.get(sessionId); + if (session != null) { + if (mMaster.debug) { + Slog.d(TAG, "startSession(): reusing session " + sessionId + " for " + + componentName); + } + // TODO(b/111276913): check if local ids match and decide what to do if they don't + // TODO(b/111276913): should we call session.notifySessionStartedLocked() again?? + // if not, move notifySessionStartedLocked() into session constructor + sendToClient(resultReceiver, IntelligenceManager.STATE_ACTIVE); + return; + } + + // TODO(b/117779333): get from mMaster once it's moved to superclass + final boolean bindInstantServiceAllowed = false; + + session = new ContentCaptureSession(getContext(), mUserId, mLock, activityToken, + this, serviceComponentName, componentName, taskId, displayId, sessionId, flags, + bindInstantServiceAllowed, mMaster.verbose); + if (mMaster.verbose) { + Slog.v(TAG, "startSession(): new session for " + componentName + " and id " + + sessionId); + } + mSessions.put(sessionId, session); + session.notifySessionStartedLocked(); + sendToClient(resultReceiver, IntelligenceManager.STATE_ACTIVE); + } + + // TODO(b/111276913): log metrics + @GuardedBy("mLock") + public void finishSessionLocked(@NonNull InteractionSessionId sessionId) { + final ContentCaptureSession session = mSessions.get(sessionId); + if (session == null) { + Slog.w(TAG, "finishSession(): no session with id" + sessionId); + return; + } + if (mMaster.verbose) { + Slog.v(TAG, "finishSession(): " + session); + } + session.removeSelfLocked(true); + } + + @GuardedBy("mLock") + public void sendEventsLocked(@NonNull InteractionSessionId sessionId, + @NonNull List<ContentCaptureEvent> events) { + final ContentCaptureSession session = mSessions.get(sessionId); + if (session == null) { + Slog.w(TAG, "sendEvents(): no session for " + sessionId); + return; + } + if (mMaster.verbose) { + Slog.v(TAG, "sendEvents(): id=" + sessionId + "; events =" + events.size()); + } + session.sendEventsLocked(events); + } + + @GuardedBy("mLock") + public void removeSessionLocked(@NonNull InteractionSessionId sessionId) { + mSessions.remove(sessionId); + } + + @Override + protected void dumpLocked(String prefix, PrintWriter pw) { + super.dumpLocked(prefix, pw); + if (mSessions.isEmpty()) { + pw.print(prefix); pw.println("no sessions"); + } else { + final int size = mSessions.size(); + pw.print(prefix); pw.print("number sessions: "); pw.println(size); + final String prefix2 = prefix + " "; + for (int i = 0; i < size; i++) { + pw.print(prefix); pw.print("session@"); pw.println(i); + final ContentCaptureSession session = mSessions.valueAt(i); + session.dumpLocked(prefix2, pw); + } + } + } + + private static void sendToClient(@NonNull IResultReceiver resultReceiver, int value) { + try { + resultReceiver.send(value, null); + } catch (RemoteException e) { + Slog.w(TAG, "Error async reporting result to client: " + e); + } + } +} diff --git a/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java b/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java new file mode 100644 index 000000000000..9d241fbf820d --- /dev/null +++ b/services/autofill/java/com/android/server/intelligence/RemoteIntelligenceService.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.intelligence; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; +import android.os.IBinder; +import android.os.IInterface; +import android.os.RemoteException; +import android.service.intelligence.IIntelligenceService; +import android.service.intelligence.InteractionContext; +import android.service.intelligence.InteractionSessionId; +import android.text.format.DateUtils; +import android.util.Slog; +import android.view.intelligence.ContentCaptureEvent; + +import com.android.server.AbstractRemoteService; + +import java.util.List; + +final class RemoteIntelligenceService extends AbstractRemoteService { + + private static final String TAG = "RemoteIntelligenceService"; + + private static final long TIMEOUT_IDLE_BIND_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS; + private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS; + + private final RemoteIntelligenceServiceCallbacks mCallbacks; + private IIntelligenceService mService; + + RemoteIntelligenceService(Context context, String serviceInterface, + ComponentName componentName, int userId, + RemoteIntelligenceServiceCallbacks callbacks, boolean bindInstantServiceAllowed, + boolean verbose) { + super(context, serviceInterface, componentName, userId, callbacks, + bindInstantServiceAllowed, verbose); + mCallbacks = callbacks; + } + + @Override // from RemoteService + protected IInterface getServiceInterface(@NonNull IBinder service) { + mService = IIntelligenceService.Stub.asInterface(service); + return mService; + } + + // TODO(b/111276913): modify super class to allow permanent binding when value is 0 or negative + @Override // from RemoteService + protected long getTimeoutIdleBindMillis() { + // TODO(b/111276913): read from Settings so it can be changed in the field + return TIMEOUT_IDLE_BIND_MILLIS; + } + + @Override // from RemoteService + protected long getRemoteRequestMillis() { + // TODO(b/111276913): read from Settings so it can be changed in the field + return TIMEOUT_REMOTE_REQUEST_MILLIS; + } + + /** + * Called by {@link ContentCaptureSession} to generate a call to the + * {@link RemoteIntelligenceService} to indicate the session was created (when {@code context} + * is not {@code null} or destroyed (when {@code context} is {@code null}). + */ + public void onSessionLifecycleRequest(@Nullable InteractionContext context, + @NonNull InteractionSessionId sessionId) { + cancelScheduledUnbind(); + scheduleRequest(new PendingSessionLifecycleRequest(this, context, sessionId)); + } + + /** + * Called by {@link ContentCaptureSession} to send a batch of events to the service. + */ + public void onContentCaptureEventsRequest(@NonNull InteractionSessionId sessionId, + @NonNull List<ContentCaptureEvent> events) { + cancelScheduledUnbind(); + scheduleRequest(new PendingOnContentCaptureEventsRequest(this, sessionId, events)); + } + + + private abstract static class MyPendingRequest + extends PendingRequest<RemoteIntelligenceService> { + protected final InteractionSessionId mSessionId; + + private MyPendingRequest(@NonNull RemoteIntelligenceService service, + @NonNull InteractionSessionId sessionId) { + super(service); + mSessionId = sessionId; + } + + @Override // from PendingRequest + protected final void onTimeout(RemoteIntelligenceService remoteService) { + Slog.w(TAG, "timed out handling " + getClass().getSimpleName() + " for " + + mSessionId); + remoteService.mCallbacks.onFailureOrTimeout(/* timedOut= */ true); + } + + @Override // from PendingRequest + public final void run() { + final RemoteIntelligenceService remoteService = getService(); + if (remoteService != null) { + try { + myRun(remoteService); + // We don't expect the service to call us back, so we finish right away. + finish(); + } catch (RemoteException e) { + Slog.w(TAG, "exception handling " + getClass().getSimpleName() + " for " + + mSessionId + ": " + e); + remoteService.mCallbacks.onFailureOrTimeout(/* timedOut= */ false); + } + } + } + + protected abstract void myRun(@NonNull RemoteIntelligenceService service) + throws RemoteException; + + } + + private static final class PendingSessionLifecycleRequest extends MyPendingRequest { + + private final InteractionContext mContext; + + protected PendingSessionLifecycleRequest(@NonNull RemoteIntelligenceService service, + @Nullable InteractionContext context, @NonNull InteractionSessionId sessionId) { + super(service, sessionId); + mContext = context; + } + + @Override // from MyPendingRequest + public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException { + remoteService.mService.onSessionLifecycle(mContext, mSessionId); + } + } + + private static final class PendingOnContentCaptureEventsRequest extends MyPendingRequest { + + private final List<ContentCaptureEvent> mEvents; + + protected PendingOnContentCaptureEventsRequest(@NonNull RemoteIntelligenceService service, + @NonNull InteractionSessionId sessionId, + @NonNull List<ContentCaptureEvent> events) { + super(service, sessionId); + mEvents = events; + } + + @Override // from MyPendingRequest + public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException { + remoteService.mService.onContentCaptureEvents(mSessionId, mEvents); + } + } + + public interface RemoteIntelligenceServiceCallbacks extends VultureCallback { + // To keep it simple, we use the same callback for all failures / timeouts. + void onFailureOrTimeout(boolean timedOut); + } +} diff --git a/services/core/Android.bp b/services/core/Android.bp index 2fa2941efe7f..888ad1da3fcc 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -55,7 +55,7 @@ java_genrule { srcs: [":services.core.unboosted"], tools: ["lockedregioncodeinjection"], cmd: "$(location lockedregioncodeinjection) " + - " --targets \"Lcom/android/server/am/ActivityManagerService;,Lcom/android/server/wm/WindowHashMap;\" " + + " --targets \"Lcom/android/server/am/ActivityManagerService;,Lcom/android/server/wm/WindowManagerGlobalLock;\" " + " --pre \"com/android/server/am/ActivityManagerService.boostPriorityForLockedSection,com/android/server/wm/WindowManagerService.boostPriorityForLockedSection\" " + " --post \"com/android/server/am/ActivityManagerService.resetPriorityAfterLockedSection,com/android/server/wm/WindowManagerService.resetPriorityAfterLockedSection\" " + " -o $(out) " + diff --git a/services/core/java/com/android/server/AbstractMasterSystemService.java b/services/core/java/com/android/server/AbstractMasterSystemService.java new file mode 100644 index 000000000000..c955daf2fae4 --- /dev/null +++ b/services/core/java/com/android/server/AbstractMasterSystemService.java @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.UserInfo; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Binder; +import android.os.Handler; +import android.os.UserHandle; +import android.os.UserManager; +import android.os.UserManagerInternal; +import android.provider.Settings; +import android.util.Slog; +import android.util.SparseArray; +import android.util.SparseBooleanArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.content.PackageMonitor; +import com.android.internal.os.BackgroundThread; + +import java.io.PrintWriter; +import java.util.List; + +/** + * Base class for {@link SystemService SystemServices} that support multi user. + * + * <p>Subclasses of this service are just a facade for the service binder calls - the "real" work + * is done by the {@link AbstractPerUserSystemService} subclasses, which are automatically managed + * through an user -> service cache. + * + * <p>It also takes care of other plumbing tasks such as: + * + * <ul> + * <li>Disabling the service when {@link UserManager} restrictions change. + * <li>Refreshing the service when its underlying + * {@link #getServiceSettingsProperty() Settings property} changed. + * <li>Calling the service when other Settings properties changed. + * </ul> + * + * <p>See {@code com.android.server.autofill.AutofillManagerService} for a concrete + * (no pun intended) example of how to use it. + * + * @param <S> "real" service class. + * + * @hide + */ +// TODO(b/117779333): improve javadoc above instead of using Autofill as an example +public abstract class AbstractMasterSystemService<S extends AbstractPerUserSystemService<S>> + extends SystemService { + + /** + * Log tag + */ + protected final String mTag = getClass().getSimpleName(); + + /** + * Lock used to synchronize access to internal state; should be acquired before calling a + * method whose name ends with {@code locked}. + */ + protected final Object mLock = new Object(); + + /** + * Whether the service should log debug statements. + */ + public boolean verbose = false; + + /** + * Whether the service should log verbose statements. + */ + public boolean debug = false; + + /** + * Users disabled due to {@link UserManager} restrictions, or {@code null} if the service cannot + * be disabled through {@link UserManager}. + */ + @GuardedBy("mLock") + @Nullable + private final SparseBooleanArray mDisabledUsers; + + /** + * Cache of services per user id. + */ + @GuardedBy("mLock") + private final SparseArray<S> mServicesCache = new SparseArray<>(); + + /** + * Default constructor. + * + * @param context system context. + * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that + * disables the service. + */ + protected AbstractMasterSystemService(@NonNull Context context, + @Nullable String disallowProperty) { + super(context); + + if (disallowProperty == null) { + mDisabledUsers = null; + } else { + mDisabledUsers = new SparseBooleanArray(); + // Hookup with UserManager to disable service when necessary. + final UserManager um = context.getSystemService(UserManager.class); + final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); + final List<UserInfo> users = um.getUsers(); + for (int i = 0; i < users.size(); i++) { + final int userId = users.get(i).id; + final boolean disabled = umi.getUserRestriction(userId, disallowProperty); + if (disabled) { + Slog.i(mTag, "Disabling for user " + userId); + mDisabledUsers.put(userId, disabled); + } + } + umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> { + final boolean disabledNow = + newRestrictions.getBoolean(disallowProperty, false); + synchronized (mLock) { + final boolean disabledBefore = mDisabledUsers.get(userId); + if (disabledBefore == disabledNow) { + // Nothing changed, do nothing. + if (debug) { + Slog.d(mTag, "Restriction did not change for user " + userId); + return; + } + } + Slog.i(mTag, "Updating for user " + userId + ": disabled=" + disabledNow); + mDisabledUsers.put(userId, disabledNow); + updateCachedServiceLocked(userId, disabledNow); + } + }); + } + startTrackingPackageChanges(); + } + + @Override // from SystemService + public void onBootPhase(int phase) { + if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + new SettingsObserver(BackgroundThread.getHandler()); + } + } + + @Override // from SystemService + public void onUnlockUser(int userId) { + synchronized (mLock) { + updateCachedServiceLocked(userId); + } + } + + @Override // from SystemService + public void onCleanupUser(int userId) { + synchronized (mLock) { + removeCachedServiceLocked(userId); + } + } + + /** + * Creates a new service that will be added to the cache. + * + * @param resolvedUserId the resolved user id for the service. + * @param disabled whether the service is currently disabled (due to {@link UserManager} + * restrictions). + * + * @return a new instance. + */ + protected abstract S newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled); + + /** + * Register the service for extra Settings changes (i.e., other than + * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or + * {@link #getServiceSettingsProperty()}, which are automatically handled). + * + * <p> Example: + * + * <pre><code> + * resolver.registerContentObserver(Settings.Global.getUriFor( + * Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer, + * UserHandle.USER_ALL); + * </code></pre> + * + * <p><b>NOTE: </p>it doesn't need to register for + * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE} or + * {@link #getServiceSettingsProperty()}. + * + */ + @SuppressWarnings("unused") + protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver, + @NonNull ContentObserver observer) { + } + + /** + * Callback for Settings changes that were registered though + * {@link #registerForExtraSettingsChanges(ContentResolver, ContentObserver)}. + * + * @param userId user associated with the change + * @param property Settings property changed. + */ + protected void onSettingsChanged(@UserIdInt int userId, @NonNull String property) { + } + + /** + * Gets the service instance for an user, creating an instance if not present in the cache. + */ + @GuardedBy("mLock") + @NonNull + protected S getServiceForUserLocked(@UserIdInt int userId) { + final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, false, null, null); + S service = mServicesCache.get(resolvedUserId); + if (service == null) { + final boolean disabled = isDisabledLocked(userId); + service = newServiceLocked(resolvedUserId, disabled); + if (!disabled) { + onServiceEnabledLocked(service, resolvedUserId); + } + mServicesCache.put(userId, service); + } + return service; + } + + /** + * Gets the <b>existing</b> service instance for a user, returning {@code null} if not already + * present in the cache. + */ + @GuardedBy("mLock") + @Nullable + protected S peekServiceForUserLocked(int userId) { + final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, false, null, null); + return mServicesCache.get(resolvedUserId); + } + + /** + * Updates a cached service for a given user. + */ + @GuardedBy("mLock") + protected void updateCachedServiceLocked(int userId) { + updateCachedServiceLocked(userId, isDisabledLocked(userId)); + } + + /** + * Checks whether the service is disabled (through {@link UserManager} restrictions) for the + * given user. + */ + protected boolean isDisabledLocked(int userId) { + return mDisabledUsers == null ? false : mDisabledUsers.get(userId); + } + + /** + * Updates a cached service for a given user. + * + * @param userId user handle. + * @param disabled whether the user is disabled. + * @return service for the user. + */ + @GuardedBy("mLock") + protected S updateCachedServiceLocked(int userId, boolean disabled) { + final S service = getServiceForUserLocked(userId); + if (service != null) { + service.updateLocked(disabled); + if (!service.isEnabledLocked()) { + removeCachedServiceLocked(userId); + } else { + onServiceEnabledLocked(service, userId); + } + } + return service; + } + + /** + * Gets the Settings property that defines the name of the component name used to bind this + * service to an external service, or {@code null} when the service is not defined by such + * property (for example, if it's a system service defined by framework resources). + */ + @Nullable + protected String getServiceSettingsProperty() { + return null; + } + + /** + * Callback called after a new service was added to the cache, or an existing service that was + * previously disabled gets enabled. + * + * <p>By default doesn't do anything, but can be overridden by subclasses. + */ + @SuppressWarnings("unused") + protected void onServiceEnabledLocked(S service, @UserIdInt int userId) { + } + + /** + * Removes a cached service for a given user. + * + * @return the removed service; + */ + @GuardedBy("mLock") + @NonNull + protected S removeCachedServiceLocked(@UserIdInt int userId) { + final S service = peekServiceForUserLocked(userId); + if (service != null) { + mServicesCache.delete(userId); + } + return service; + } + + /** + * Visits all services in the cache. + */ + @GuardedBy("mLock") + protected void visitServicesLocked(@NonNull Visitor<S> visitor) { + final int size = mServicesCache.size(); + for (int i = 0; i < size; i++) { + visitor.visit(mServicesCache.valueAt(i)); + } + } + + /** + * Clear the cache by removing all services. + */ + @GuardedBy("mLock") + protected void clearCacheLocked() { + mServicesCache.clear(); + } + + // TODO(b/117779333): support proto + protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) { + boolean realDebug = debug; + boolean realVerbose = verbose; + + try { + // Temporarily turn on full logging; + debug = verbose = true; + final int size = mServicesCache.size(); + pw.print(prefix); pw.print("Debug: "); pw.print(realDebug); + pw.print(" Verbose: "); pw.println(realVerbose); + pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers); + pw.print(prefix); pw.print("Settings property: "); pw.println( + getServiceSettingsProperty()); + pw.print(prefix); pw.print("Cached services: "); + if (size == 0) { + pw.println("none"); + } else { + pw.println(size); + final String prefix2 = " "; + for (int i = 0; i < size; i++) { + pw.print(prefix); pw.print("Service at "); pw.print(i); pw.println(": "); + final S service = mServicesCache.valueAt(i); + service.dumpLocked(prefix2, pw); + pw.println(); + } + } + } finally { + debug = realDebug; + verbose = realVerbose; + } + } + + private void startTrackingPackageChanges() { + PackageMonitor monitor = new PackageMonitor() { + @Override + public void onSomePackagesChanged() { + synchronized (mLock) { + updateCachedServiceLocked(getChangingUserId()); + } + } + + @Override + public void onPackageUpdateFinished(String packageName, int uid) { + synchronized (mLock) { + final String activePackageName = getActiveServicePackageName(); + if (packageName.equals(activePackageName)) { + removeCachedServiceLocked(getChangingUserId()); + } else { + handlePackageUpdateLocked(packageName); + } + } + } + + @Override + public void onPackageRemoved(String packageName, int uid) { + synchronized (mLock) { + final int userId = getChangingUserId(); + final S service = peekServiceForUserLocked(userId); + if (service != null) { + final ComponentName componentName = service.getServiceComponentName(); + if (componentName != null) { + if (packageName.equals(componentName.getPackageName())) { + handleActiveServiceRemoved(userId); + } + } + } + } + } + + @Override + public boolean onHandleForceStop(Intent intent, String[] packages, + int uid, boolean doit) { + synchronized (mLock) { + final String activePackageName = getActiveServicePackageName(); + for (String pkg : packages) { + if (pkg.equals(activePackageName)) { + if (!doit) { + return true; + } + removeCachedServiceLocked(getChangingUserId()); + } else { + handlePackageUpdateLocked(pkg); + } + } + } + return false; + } + + private void handleActiveServiceRemoved(@UserIdInt int userId) { + removeCachedServiceLocked(userId); + final String serviceSettingsProperty = getServiceSettingsProperty(); + if (serviceSettingsProperty != null) { + Settings.Secure.putStringForUser(getContext().getContentResolver(), + serviceSettingsProperty, null, userId); + } + } + + private String getActiveServicePackageName() { + final int userId = getChangingUserId(); + final S service = peekServiceForUserLocked(userId); + if (service == null) { + return null; + } + final ComponentName serviceComponent = service.getServiceComponentName(); + if (serviceComponent == null) { + return null; + } + return serviceComponent.getPackageName(); + } + + @GuardedBy("mLock") + private void handlePackageUpdateLocked(String packageName) { + visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName)); + } + }; + + // package changes + monitor.register(getContext(), null, UserHandle.ALL, true); + } + + /** + * Visitor pattern. + * + * @param <S> visited class. + */ + public interface Visitor<S> { + /** + * Visits a service. + * + * @param service the service to be visited. + */ + void visit(@NonNull S service); + } + + private final class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + ContentResolver resolver = getContext().getContentResolver(); + final String serviceProperty = getServiceSettingsProperty(); + if (serviceProperty != null) { + resolver.registerContentObserver(Settings.Secure.getUriFor( + serviceProperty), false, this, UserHandle.USER_ALL); + } + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL); + registerForExtraSettingsChanges(resolver, this); + } + + @Override + public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) { + if (verbose) Slog.v(mTag, "onChange(): uri=" + uri + ", userId=" + userId); + final String property = uri.getLastPathSegment(); + if (property.equals(getServiceSettingsProperty()) + || property.equals(Settings.Secure.USER_SETUP_COMPLETE)) { + synchronized (mLock) { + updateCachedServiceLocked(userId); + } + } else { + onSettingsChanged(userId, property); + } + } + } +} diff --git a/services/core/java/com/android/server/AbstractPerUserSystemService.java b/services/core/java/com/android/server/AbstractPerUserSystemService.java new file mode 100644 index 000000000000..201abe689283 --- /dev/null +++ b/services/core/java/com/android/server/AbstractPerUserSystemService.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server; + +import android.annotation.CallSuper; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ServiceInfo; +import android.graphics.drawable.Drawable; +import android.os.Process; +import android.os.RemoteException; +import android.os.UserManager; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; + +/** + * Companion for {@link AbstractMasterSystemService}, it's the base class for the "real" service + * implementation. + * + * @param <S> itself + * + * @hide + */ +public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSystemService<S>> { + + protected final @UserIdInt int mUserId; + protected final Object mLock; + protected final String mTag = getClass().getSimpleName(); + + protected final AbstractMasterSystemService<S> mMaster; + + /** + * Whether service was disabled for user due to {@link UserManager} restrictions. + */ + @GuardedBy("mLock") + private boolean mDisabled; + + /** + * Caches whether the setup completed for the current user. + */ + @GuardedBy("mLock") + private boolean mSetupComplete; + + @GuardedBy("mLock") + private ServiceInfo mServiceInfo; + + protected AbstractPerUserSystemService(@NonNull AbstractMasterSystemService<S> master, + @NonNull Object lock, @UserIdInt int userId) { + mMaster = master; + mLock = lock; + mUserId = userId; + } + + /** + * Creates a new {@link ServiceInfo} for the given service name. + * + * @throws NameNotFoundException if the service does not exist. + * @throws SecurityException if the service does not have the proper permissions to be bound to. + */ + protected abstract ServiceInfo newServiceInfo(@NonNull ComponentName serviceComponent) + throws NameNotFoundException; + + /** + * Callback called when an app has been updated. + * + * @param packageName package of the app being updated. + */ + protected void handlePackageUpdateLocked(@NonNull String packageName) { + } + + /** + * Gets whether the service is enabled and ready. + */ + @GuardedBy("mLock") + protected boolean isEnabledLocked() { + return mSetupComplete && mServiceInfo != null && !mDisabled; + } + + /** + * Updates the state of this service. + * + * <p>Typically called when the service {@link Settings} property or {@link UserManager} + * restriction changed, which includes the initial creation of the service. + * + * <p>Subclasses can extend this method to provide extra initialization. + * + * @param disabled whether the service is disabled (due to {@link UserManager} restrictions). + * + * @return whether the disabled state changed. + */ + @GuardedBy("mLock") + @CallSuper + protected boolean updateLocked(boolean disabled) { + + final boolean wasEnabled = isEnabledLocked(); + if (mMaster.verbose) { + Slog.v(mTag, "updateLocked(u=" + mUserId + "): wasEnabled=" + wasEnabled + + ", mSetupComplete=" + mSetupComplete + + ", disabled=" + disabled + ", mDisabled=" + mDisabled); + } + + mSetupComplete = isSetupCompletedLocked(); + mDisabled = disabled; + ComponentName serviceComponent = null; + ServiceInfo serviceInfo = null; + final String componentName = getComponentNameFromSettings(); + if (!TextUtils.isEmpty(componentName)) { + try { + serviceComponent = ComponentName.unflattenFromString(componentName); + serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, + 0, mUserId); + if (serviceInfo == null) { + Slog.e(mTag, "Bad service name: " + componentName); + } + } catch (RuntimeException | RemoteException e) { + Slog.e(mTag, "Error getting service info for '" + componentName + "': " + e); + serviceInfo = null; + } + } + try { + if (serviceInfo != null) { + mServiceInfo = newServiceInfo(serviceComponent); + if (mMaster.debug) { + Slog.d(mTag, "Set component for user " + mUserId + " as " + mServiceInfo); + } + } else { + mServiceInfo = null; + if (mMaster.debug) { + Slog.d(mTag, "Reset component for user " + mUserId + ":" + componentName); + } + } + } catch (Exception e) { + Slog.e(mTag, "Bad ServiceInfo for '" + componentName + "': " + e); + mServiceInfo = null; + } + return wasEnabled != isEnabledLocked(); + } + + /** + * Gets this UID of the remote service this service binds to, or {@code -1} if the service is + * disabled. + */ + @GuardedBy("mLock") + protected final int getServiceUidLocked() { + if (mServiceInfo == null) { + Slog.w(mTag, "getServiceUidLocked(): no mServiceInfo"); + return Process.INVALID_UID; + } + return mServiceInfo.applicationInfo.uid; + } + + /** + * Gets this name of the remote service this service binds to as defined by {@link Settings}. + */ + @Nullable + protected final String getComponentNameFromSettings() { + final String property = mMaster.getServiceSettingsProperty(); + return property == null ? null : Settings.Secure + .getStringForUser(getContext().getContentResolver(), property, mUserId); + } + + /** + * Gets the {@link ComponentName} of the remote service this service binds to, or {@code null} + * if the service is disabled. + */ + @Nullable + public final ComponentName getServiceComponentName() { + synchronized (mLock) { + return mServiceInfo == null ? null : mServiceInfo.getComponentName(); + } + } + /** + * Gets the name of the of the app this service binds to, or {@code null} if the service is + * disabled. + */ + @Nullable + public final String getServicePackageName() { + final ComponentName serviceComponent = getServiceComponentName(); + return serviceComponent == null ? null : serviceComponent.getPackageName(); + } + + /** + * Gets the user-visibile name of the service this service binds to, or {@code null} if the + * service is disabled. + */ + @Nullable + @GuardedBy("mLock") + public final CharSequence getServiceLabelLocked() { + return mServiceInfo == null ? null : mServiceInfo.loadSafeLabel( + getContext().getPackageManager(), 0 /* do not ellipsize */, + PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM); + } + + /** + * Gets the icon the service this service binds to, or {@code null} if the service is disabled. + */ + @Nullable + @GuardedBy("mLock") + public final Drawable getServiceIconLocked() { + return mServiceInfo == null ? null + : mServiceInfo.loadIcon(getContext().getPackageManager()); + } + + /** + * Whether the service should log debug statements. + */ + public final boolean isDebug() { + return mMaster.debug; + } + + /** + * Whether the service should log verbose statements. + */ + public final boolean isVerbose() { + return mMaster.verbose; + } + + /** + * Gets the target SDK level of the service this service binds to, + * or {@code 0} if the service is disabled. + */ + public final int getTargedSdkLocked() { + return mServiceInfo == null ? 0 : mServiceInfo.applicationInfo.targetSdkVersion; + } + + /** + * Gets whether the device already finished setup. + */ + protected final boolean isSetupCompletedLocked() { + final String setupComplete = Settings.Secure.getStringForUser( + getContext().getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId); + return "1".equals(setupComplete); + } + + /** + * Gets the context associated with this service. + */ + protected final Context getContext() { + return mMaster.getContext(); + } + + // TODO(b/117779333): support proto + @GuardedBy("mLock") + protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) { + pw.print(prefix); pw.print("User: "); pw.println(mUserId); + pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled); + pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete); + pw.print(prefix); pw.print("Service name: "); pw.println(getComponentNameFromSettings()); + } +} diff --git a/services/core/java/com/android/server/AbstractRemoteService.java b/services/core/java/com/android/server/AbstractRemoteService.java new file mode 100644 index 000000000000..181d7fde1fb8 --- /dev/null +++ b/services/core/java/com/android/server/AbstractRemoteService.java @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.IBinder; +import android.os.IBinder.DeathRecipient; +import android.os.IInterface; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.UserHandle; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; + +/** + * Base class representing a remote service. + * + * <p>It abstracts away the binding and unbinding from the remote implementation, so clients can + * call its methods without worrying about when and how to bind/unbind/timeout. + * + * <p>All state of this class is modified on a handler thread. + * + * <p>See {@code com.android.server.autofill.RemoteFillService} for a concrete + * (no pun intended) example of how to use it. + * + * @hide + */ +//TODO(b/117779333): improve javadoc above instead of using Autofill as an example +public abstract class AbstractRemoteService implements DeathRecipient { + + private static final int MSG_UNBIND = 1; + + protected static final int LAST_PRIVATE_MSG = MSG_UNBIND; + + // TODO(b/117779333): convert all booleans into an integer / flags + public final boolean mVerbose; + + protected final String mTag = getClass().getSimpleName(); + protected final Handler mHandler; + protected final ComponentName mComponentName; + + protected PendingRequest<? extends AbstractRemoteService> mPendingRequest; + + private final Context mContext; + private final Intent mIntent; + private final VultureCallback mVultureCallback; + private final int mUserId; + private final ServiceConnection mServiceConnection = new RemoteServiceConnection(); + private final boolean mBindInstantServiceAllowed; + private IInterface mServiceInterface; + + private boolean mBinding; + private boolean mDestroyed; + private boolean mServiceDied; + private boolean mCompleted; + + /** + * Callback called when the service dies. + */ + public interface VultureCallback { + /** + * Called when the service dies. + * + * @param service service that died! + */ + void onServiceDied(AbstractRemoteService service); + } + + public AbstractRemoteService(@NonNull Context context, @NonNull String serviceInterface, + @NonNull ComponentName componentName, int userId, @NonNull VultureCallback callback, + boolean bindInstantServiceAllowed, boolean verbose) { + mContext = context; + mVultureCallback = callback; + mVerbose = verbose; + mComponentName = componentName; + mIntent = new Intent(serviceInterface).setComponent(mComponentName); + mUserId = userId; + mHandler = new Handler(FgThread.getHandler().getLooper()); + mBindInstantServiceAllowed = bindInstantServiceAllowed; + } + + /** + * Destroys this service. + */ + public final void destroy() { + mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleDestroy, this)); + } + + /** + * Checks whether this service is destroyed. + */ + public final boolean isDestroyed() { + return mDestroyed; + } + + /** + * Callback called when the system connected / disconnected to the service. + * + * @param state {@code true} when connected, {@code false} when disconnected. + */ + protected void onConnectedStateChanged(boolean state) { + } + + /** + * Gets the base Binder interface from the service. + */ + @NonNull + protected abstract IInterface getServiceInterface(@NonNull IBinder service); + + /** + * Defines How long after the last interaction with the service we would unbind. + */ + protected abstract long getTimeoutIdleBindMillis(); + + /** + * Defines how long after we make a remote request to a fill service we timeout. + */ + protected abstract long getRemoteRequestMillis(); + + private void handleDestroy() { + if (checkIfDestroyed()) return; + if (mPendingRequest != null) { + mPendingRequest.cancel(); + mPendingRequest = null; + } + ensureUnbound(); + mDestroyed = true; + } + + @Override // from DeathRecipient + public void binderDied() { + mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleBinderDied, this)); + } + + private void handleBinderDied() { + if (checkIfDestroyed()) return; + if (mServiceInterface != null) { + mServiceInterface.asBinder().unlinkToDeath(this, 0); + } + mServiceInterface = null; + mServiceDied = true; + mVultureCallback.onServiceDied(this); + } + + // Note: we are dumping without a lock held so this is a bit racy but + // adding a lock to a class that offloads to a handler thread would + // mean adding a lock adding overhead to normal runtime operation. + /** + * Dump it! + */ + public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + String tab = " "; + pw.append(prefix).append("service:").println(); + pw.append(prefix).append(tab).append("userId=") + .append(String.valueOf(mUserId)).println(); + pw.append(prefix).append(tab).append("componentName=") + .append(mComponentName.flattenToString()).println(); + pw.append(prefix).append(tab).append("destroyed=") + .append(String.valueOf(mDestroyed)).println(); + pw.append(prefix).append(tab).append("bound=") + .append(String.valueOf(isBound())).println(); + pw.append(prefix).append(tab).append("hasPendingRequest=") + .append(String.valueOf(mPendingRequest != null)).println(); + pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed); + pw.append(prefix).append("idleTimeout=") + .append(Long.toString(getTimeoutIdleBindMillis() / 1000)).append("s").println(); + pw.append(prefix).append("requestTimeout=") + .append(Long.toString(getRemoteRequestMillis() / 1000)).append("s").println(); + pw.println(); + } + + protected void scheduleRequest(PendingRequest<? extends AbstractRemoteService> pendingRequest) { + mHandler.sendMessage(obtainMessage( + AbstractRemoteService::handlePendingRequest, this, pendingRequest)); + } + + protected void cancelScheduledUnbind() { + mHandler.removeMessages(MSG_UNBIND); + } + + protected void scheduleUnbind() { + cancelScheduledUnbind(); + mHandler.sendMessageDelayed(obtainMessage(AbstractRemoteService::handleUnbind, this) + .setWhat(MSG_UNBIND), getTimeoutIdleBindMillis()); + } + + private void handleUnbind() { + if (checkIfDestroyed()) return; + + ensureUnbound(); + } + + private void handlePendingRequest( + PendingRequest<? extends AbstractRemoteService> pendingRequest) { + if (checkIfDestroyed() || mCompleted) return; + + if (!isBound()) { + if (mPendingRequest != null) { + mPendingRequest.cancel(); + } + mPendingRequest = pendingRequest; + ensureBound(); + } else { + if (mVerbose) Slog.v(mTag, "handlePendingRequest(): " + pendingRequest); + pendingRequest.run(); + if (pendingRequest.isFinal()) { + mCompleted = true; + } + } + } + + private boolean isBound() { + return mServiceInterface != null; + } + + private void ensureBound() { + if (isBound() || mBinding) return; + + if (mVerbose) Slog.v(mTag, "ensureBound()"); + mBinding = true; + + int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE; + if (mBindInstantServiceAllowed) { + flags |= Context.BIND_ALLOW_INSTANT; + } + + final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags, + new UserHandle(mUserId)); + + if (!willBind) { + Slog.w(mTag, "could not bind to " + mIntent + " using flags " + flags); + mBinding = false; + + if (!mServiceDied) { + handleBinderDied(); + } + } + } + + private void ensureUnbound() { + if (!isBound() && !mBinding) return; + + if (mVerbose) Slog.v(mTag, "ensureUnbound()"); + mBinding = false; + if (isBound()) { + onConnectedStateChanged(false); + if (mServiceInterface != null) { + mServiceInterface.asBinder().unlinkToDeath(this, 0); + mServiceInterface = null; + } + } + mContext.unbindService(mServiceConnection); + } + + private class RemoteServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (mDestroyed || !mBinding) { + // This is abnormal. Unbinding the connection has been requested already. + Slog.wtf(mTag, "onServiceConnected() was dispatched after unbindService."); + return; + } + mBinding = false; + mServiceInterface = getServiceInterface(service); + try { + service.linkToDeath(AbstractRemoteService.this, 0); + } catch (RemoteException re) { + handleBinderDied(); + return; + } + onConnectedStateChanged(true); + + if (mPendingRequest != null) { + final PendingRequest<? extends AbstractRemoteService> pendingRequest = + mPendingRequest; + mPendingRequest = null; + handlePendingRequest(pendingRequest); + } + + mServiceDied = false; + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mBinding = true; + mServiceInterface = null; + } + } + + private boolean checkIfDestroyed() { + if (mDestroyed) { + if (mVerbose) { + Slog.v(mTag, "Not handling operation as service for " + mComponentName + + " is already destroyed"); + } + } + return mDestroyed; + } + + protected boolean handleResponseCallbackCommon( + PendingRequest<? extends AbstractRemoteService> pendingRequest) { + if (isDestroyed()) return false; + + if (mPendingRequest == pendingRequest) { + mPendingRequest = null; + } + if (mPendingRequest == null) { + scheduleUnbind(); + } + return true; + } + + /** + * Base class for the requests serviced by the remote service. + * + * @param <S> the remote service class + */ + public abstract static class PendingRequest<S extends AbstractRemoteService> + implements Runnable { + protected final String mTag = getClass().getSimpleName(); + protected final Object mLock = new Object(); + + private final WeakReference<S> mWeakService; + private final Runnable mTimeoutTrigger; + private final Handler mServiceHandler; + + @GuardedBy("mLock") + private boolean mCancelled; + + @GuardedBy("mLock") + private boolean mCompleted; + + protected PendingRequest(S service) { + mWeakService = new WeakReference<>(service); + mServiceHandler = service.mHandler; + mTimeoutTrigger = () -> { + synchronized (mLock) { + if (mCancelled) { + return; + } + mCompleted = true; + } + + final S remoteService = mWeakService.get(); + if (remoteService != null) { + Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms"); + onTimeout(remoteService); + } else { + Slog.w(mTag, "timed out (no service)"); + } + }; + mServiceHandler.postAtTime(mTimeoutTrigger, + SystemClock.uptimeMillis() + service.getRemoteRequestMillis()); + } + + /** + * Gets a reference to the remote service. + */ + protected final S getService() { + return mWeakService.get(); + } + + /** + * Subclasses must call this method when the remote service finishes, i.e., when the service + * finishes processing a request. + * + * @return {@code false} in the service is already finished, {@code true} otherwise. + */ + protected final boolean finish() { + synchronized (mLock) { + if (mCompleted || mCancelled) { + return false; + } + mCompleted = true; + } + mServiceHandler.removeCallbacks(mTimeoutTrigger); + return true; + } + + /** + * Checks whether this request was cancelled. + */ + @GuardedBy("mLock") + protected final boolean isCancelledLocked() { + return mCancelled; + } + + /** + * Cancels the service. + * + * @return {@code false} if service is already canceled, {@code true} otherwise. + */ + public boolean cancel() { + synchronized (mLock) { + if (mCancelled || mCompleted) { + return false; + } + mCancelled = true; + } + + mServiceHandler.removeCallbacks(mTimeoutTrigger); + return true; + } + + /** + * Called by the self-destruct timeout when the remote service didn't reply to the + * request on time. + */ + protected abstract void onTimeout(S remoteService); + + /** + * Checks whether this request leads to a final state where no other requests can be made. + */ + protected boolean isFinal() { + return false; + } + } +} diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 38b9647c15b4..854c03f128dd 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -1462,6 +1462,10 @@ class AlarmManagerService extends SystemService { TimeZone.setDefault(null); if (timeZoneWasChanged) { + // Don't wait for broadcasts to update our midnight alarm + mClockReceiver.scheduleDateChangedEvent(); + + // And now let everyone else know Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index c2aec29e688a..cd98263e417e 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -26,10 +26,14 @@ import static android.app.AppOpsManager.UID_STATE_TOP; import static android.app.AppOpsManager._NUM_UID_STATE; import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.AppOpsManager.HistoricalOpEntry; +import android.app.AppOpsManager.HistoricalPackageOps; import android.app.AppOpsManagerInternal; import android.app.AppOpsManagerInternal.CheckOpsDelegate; import android.content.ContentResolver; @@ -38,6 +42,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.media.AudioAttributes; @@ -929,6 +934,116 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override + public @Nullable ParceledListSlice getAllHistoricalPackagesOps(@Nullable String[] opNames, + long beginTimeMillis, long endTimeMillis) { + Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis, + "beginTimeMillis must be non negative and lesser than endTimeMillis"); + + mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, + Binder.getCallingPid(), Binder.getCallingUid(), "getAllHistoricalPackagesOps"); + + ArrayList<HistoricalPackageOps> historicalPackageOpsList = null; + + final int uidStateCount = mUidStates.size(); + for (int i = 0; i < uidStateCount; i++) { + final UidState uidState = mUidStates.valueAt(i); + if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) { + continue; + } + final ArrayMap<String, Ops> packages = uidState.pkgOps; + final int packageCount = packages.size(); + for (int j = 0; j < packageCount; j++) { + final Ops pkgOps = packages.valueAt(j); + final AppOpsManager.HistoricalPackageOps historicalPackageOps = + createHistoricalPackageOps(uidState.uid, pkgOps, opNames, + beginTimeMillis, endTimeMillis); + if (historicalPackageOps != null) { + if (historicalPackageOpsList == null) { + historicalPackageOpsList = new ArrayList<>(); + } + historicalPackageOpsList.add(historicalPackageOps); + } + } + } + + if (historicalPackageOpsList == null) { + return null; + } + + return new ParceledListSlice<>(historicalPackageOpsList); + } + + private static @Nullable HistoricalPackageOps createHistoricalPackageOps(int uid, + @Nullable Ops pkgOps, @Nullable String[] opNames, long beginTimeMillis, + long endTimeMillis) { + // TODO: Implement historical data collection + if (pkgOps == null) { + return null; + } + + final HistoricalPackageOps historicalPackageOps = new HistoricalPackageOps(uid, + pkgOps.packageName); + + if (opNames == null) { + opNames = AppOpsManager.getOpStrs(); + } + for (String opName : opNames) { + addHistoricOpEntry(AppOpsManager.strOpToOp(opName), pkgOps, historicalPackageOps); + } + + return historicalPackageOps; + } + + @Override + public @Nullable HistoricalPackageOps getHistoricalPackagesOps(int uid, + @NonNull String packageName, @Nullable String[] opNames, + long beginTimeMillis, long endTimeMillis) { + Preconditions.checkNotNull(packageName, + "packageName cannot be null"); + Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis, + "beginTimeMillis must be non negative and lesser than endTimeMillis"); + + mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, + Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalPackagesOps"); + + final String resolvedPackageName = resolvePackageName(uid, packageName); + if (resolvedPackageName == null) { + return null; + } + + // TODO: Implement historical data collection + final Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */, + false /* uidMismatchExpected */); + return createHistoricalPackageOps(uid, pkgOps, opNames, beginTimeMillis, endTimeMillis); + } + + private static void addHistoricOpEntry(int opCode, @NonNull Ops ops, + @NonNull HistoricalPackageOps outHistoricalPackageOps) { + final Op op = ops.get(opCode); + if (op == null) { + return; + } + + final HistoricalOpEntry historicalOpEntry = new HistoricalOpEntry(opCode); + + // TODO: Keep per UID state duration + for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) { + final int acceptCount; + final int rejectCount; + if (op.rejectTime[uidState] == 0) { + acceptCount = 1; + rejectCount = 0; + } else { + acceptCount = 0; + rejectCount = 1; + } + historicalOpEntry.addEntry(uidState, acceptCount, rejectCount, 0); + } + + outHistoricalPackageOps.addEntry(historicalOpEntry); + } + + @Override public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) { mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS, Binder.getCallingPid(), Binder.getCallingUid(), null); @@ -2020,7 +2135,8 @@ public class AppOpsService extends IAppOpsService.Stub { try { ApplicationInfo appInfo = ActivityThread.getPackageManager() .getApplicationInfo(packageName, - PackageManager.MATCH_DEBUG_TRIAGED_MISSING, + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, UserHandle.getUserId(uid)); if (appInfo != null) { pkgUid = appInfo.uid; diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 93bdcbbb718e..90ad09eed5d7 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -541,7 +541,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } - private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) { + private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) { PackageManager pm = mContext.getPackageManager(); String systemPackageName = mContext.getPackageName(); ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs); @@ -646,16 +646,14 @@ public class LocationManagerService extends ILocationManager.Stub { that matches the signature of at least one package on this list. */ Resources resources = mContext.getResources(); - ArrayList<String> providerPackageNames = new ArrayList<>(); String[] pkgs = resources.getStringArray( com.android.internal.R.array.config_locationProviderPackageNames); if (D) { Log.d(TAG, "certificates for location providers pulled from: " + Arrays.toString(pkgs)); } - if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs)); - ensureFallbackFusedProviderPresentLocked(providerPackageNames); + ensureFallbackFusedProviderPresentLocked(pkgs); // bind to network provider LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( @@ -664,8 +662,7 @@ public class LocationManagerService extends ILocationManager.Stub { NETWORK_LOCATION_SERVICE_ACTION, com.android.internal.R.bool.config_enableNetworkLocationOverlay, com.android.internal.R.string.config_networkLocationProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames, - mLocationHandler); + com.android.internal.R.array.config_locationProviderPackageNames); if (networkProvider != null) { mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider); mProxyProviders.add(networkProvider); @@ -681,8 +678,7 @@ public class LocationManagerService extends ILocationManager.Stub { FUSED_LOCATION_SERVICE_ACTION, com.android.internal.R.bool.config_enableFusedLocationOverlay, com.android.internal.R.string.config_fusedLocationProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames, - mLocationHandler); + com.android.internal.R.array.config_locationProviderPackageNames); if (fusedLocationProvider != null) { addProviderLocked(fusedLocationProvider); mProxyProviders.add(fusedLocationProvider); @@ -697,8 +693,7 @@ public class LocationManagerService extends ILocationManager.Stub { mGeocodeProvider = GeocoderProxy.createAndBind(mContext, com.android.internal.R.bool.config_enableGeocoderOverlay, com.android.internal.R.string.config_geocoderProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames, - mLocationHandler); + com.android.internal.R.array.config_locationProviderPackageNames); if (mGeocodeProvider == null) { Slog.e(TAG, "no geocoder provider found"); } @@ -708,7 +703,6 @@ public class LocationManagerService extends ILocationManager.Stub { mContext, com.android.internal.R.bool.config_enableGeofenceOverlay, com.android.internal.R.string.config_geofenceProviderPackageName, com.android.internal.R.array.config_locationProviderPackageNames, - mLocationHandler, mGpsGeofenceProxy, null); if (provider == null) { @@ -725,7 +719,6 @@ public class LocationManagerService extends ILocationManager.Stub { } ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind( mContext, - mLocationHandler, activityRecognitionHardwareIsSupported, activityRecognitionHardware, com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay, diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java index 42c836eab7d7..574f54a51eb1 100644 --- a/services/core/java/com/android/server/ServiceWatcher.java +++ b/services/core/java/com/android/server/ServiceWatcher.java @@ -16,8 +16,10 @@ package com.android.server; -import android.annotation.NonNull; +import android.annotation.MainThread; import android.annotation.Nullable; +import android.annotation.WorkerThread; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -30,17 +32,21 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; import android.content.res.Resources; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.UserHandle; import android.util.Log; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; +import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -50,90 +56,125 @@ import java.util.Objects; * Handles run-time package changes. */ public class ServiceWatcher implements ServiceConnection { + + private static final String TAG = "ServiceWatcher"; private static final boolean D = false; + public static final String EXTRA_SERVICE_VERSION = "serviceVersion"; public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser"; - private final String mTag; - private final Context mContext; - private final PackageManager mPm; - private final List<HashSet<Signature>> mSignatureSets; - private final String mAction; - /** - * If mServicePackageName is not null, only this package will be searched for the service that - * implements mAction. When null, all packages in the system that matches one of the signature - * in mSignatureSets are searched. + * The runner that runs on the binder retrieved from {@link ServiceWatcher}. */ - private final String mServicePackageName; - private final Runnable mNewServiceWork; - private final Handler mHandler; - - private final Object mLock = new Object(); - - @GuardedBy("mLock") - private int mCurrentUserId = UserHandle.USER_SYSTEM; - - @GuardedBy("mLock") - private IBinder mBoundService; - @GuardedBy("mLock") - private ComponentName mBoundComponent; - @GuardedBy("mLock") - private String mBoundPackageName; - @GuardedBy("mLock") - private int mBoundVersion = Integer.MIN_VALUE; - @GuardedBy("mLock") - private int mBoundUserId = UserHandle.USER_NULL; + public interface BinderRunner { + /** + * Runs on the retrieved binder. + * + * @param binder the binder retrieved from the {@link ServiceWatcher}. + */ + void run(IBinder binder); + } public static ArrayList<HashSet<Signature>> getSignatureSets(Context context, - List<String> initialPackageNames) { + String... packageNames) { PackageManager pm = context.getPackageManager(); - ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>(); - for (int i = 0, size = initialPackageNames.size(); i < size; i++) { - String pkg = initialPackageNames.get(i); + + ArrayList<HashSet<Signature>> signatureSets = new ArrayList<>(packageNames.length); + for (String packageName : packageNames) { try { - HashSet<Signature> set = new HashSet<Signature>(); - Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY - | PackageManager.GET_SIGNATURES).signatures; - set.addAll(Arrays.asList(sigs)); - sigSets.add(set); + Signature[] signatures = pm.getPackageInfo(packageName, + PackageManager.MATCH_SYSTEM_ONLY + | PackageManager.GET_SIGNATURES).signatures; + + HashSet<Signature> set = new HashSet<>(); + Collections.addAll(set, signatures); + signatureSets.add(set); } catch (NameNotFoundException e) { - Log.w("ServiceWatcher", pkg + " not found"); + Log.w(TAG, packageName + " not found"); } } - return sigSets; + return signatureSets; } + /** Checks if signatures match. */ + public static boolean isSignatureMatch(Signature[] signatures, + List<HashSet<Signature>> sigSets) { + if (signatures == null) return false; + + // build hashset of input to test against + HashSet<Signature> inputSet = new HashSet<>(); + Collections.addAll(inputSet, signatures); + + // test input against each of the signature sets + for (HashSet<Signature> referenceSet : sigSets) { + if (referenceSet.equals(inputSet)) { + return true; + } + } + return false; + } + + private final Context mContext; + private final String mTag; + private final String mAction; + private final String mServicePackageName; + private final List<HashSet<Signature>> mSignatureSets; + + private final Handler mHandler; + + // this lock is held to ensure the service binder is not exposed (via runOnBinder) until after + // the new service initialization work has completed + private final Object mBindLock = new Object(); + + // read/write from handler thread + private int mCurrentUserId; + + // read from any thread, write from handler thread + private volatile ComponentName mBestComponent; + private volatile int mBestVersion; + private volatile int mBestUserId; + private volatile IBinder mBestService; + public ServiceWatcher(Context context, String logTag, String action, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Runnable newServiceWork, - Handler handler) { + int initialPackageNamesResId, Handler handler) { + Resources resources = context.getResources(); + mContext = context; mTag = logTag; mAction = action; - mPm = mContext.getPackageManager(); - mNewServiceWork = newServiceWork; - mHandler = handler; - Resources resources = context.getResources(); - // Whether to enable service overlay. boolean enableOverlay = resources.getBoolean(overlaySwitchResId); - ArrayList<String> initialPackageNames = new ArrayList<String>(); if (enableOverlay) { - // A list of package names used to create the signatures. String[] pkgs = resources.getStringArray(initialPackageNamesResId); - if (pkgs != null) initialPackageNames.addAll(Arrays.asList(pkgs)); mServicePackageName = null; + mSignatureSets = getSignatureSets(context, pkgs); if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs)); } else { - // The default package name that is searched for service implementation when overlay is - // disabled. - String servicePackageName = resources.getString(defaultServicePackageNameResId); - if (servicePackageName != null) initialPackageNames.add(servicePackageName); - mServicePackageName = servicePackageName; - if (D) Log.d(mTag, "Overlay disabled, default package=" + servicePackageName); + mServicePackageName = resources.getString(defaultServicePackageNameResId); + mSignatureSets = getSignatureSets(context, mServicePackageName); + if (D) Log.d(mTag, "Overlay disabled, default package=" + mServicePackageName); } - mSignatureSets = getSignatureSets(context, initialPackageNames); + + mHandler = handler; + + mBestComponent = null; + mBestVersion = Integer.MIN_VALUE; + mBestUserId = UserHandle.USER_NULL; + + mBestService = null; + } + + // called on handler thread + @GuardedBy("mBindLock") + protected void onBind() { + + } + + // called on handler thread + @GuardedBy("mBindLock") + protected void onUnbind() { + } /** @@ -143,16 +184,39 @@ public class ServiceWatcher implements ServiceConnection { * Note that if there are no matching encryption-aware services, we may not * bind to a real service until after the current user is unlocked. * - * @returns {@code true} if a potential service implementation was found. + * @return {@code true} if a potential service implementation was found. */ - public boolean start() { + public final boolean start() { + // if we have to return false, do it before registering anything if (isServiceMissing()) return false; - synchronized (mLock) { - bindBestPackageLocked(mServicePackageName, false); + // listen for relevant package changes if service overlay is enabled on handler + if (mServicePackageName == null) { + new PackageMonitor() { + @Override + public void onPackageUpdateFinished(String packageName, int uid) { + bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); + } + + @Override + public void onPackageAdded(String packageName, int uid) { + bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); + } + + @Override + public void onPackageRemoved(String packageName, int uid) { + bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); + } + + @Override + public boolean onPackageChanged(String packageName, int uid, String[] components) { + bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); + return super.onPackageChanged(packageName, uid, components); + } + }.register(mContext, UserHandle.ALL, true, mHandler); } - // listen for user change + // listen for user change on handler IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_SWITCHED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); @@ -163,283 +227,205 @@ public class ServiceWatcher implements ServiceConnection { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (Intent.ACTION_USER_SWITCHED.equals(action)) { - switchUser(userId); + mCurrentUserId = userId; + bindBestPackage(false); } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) { - unlockUser(userId); + if (userId == mCurrentUserId) { + bindBestPackage(false); + } } } }, UserHandle.ALL, intentFilter, null, mHandler); - // listen for relevant package changes if service overlay is enabled. - if (mServicePackageName == null) { - mPackageMonitor.register(mContext, null, UserHandle.ALL, true); - } + mCurrentUserId = ActivityManager.getCurrentUser(); + mHandler.post(() -> bindBestPackage(false)); return true; } + /** Returns thje name of the currently connected package or null. */ + @Nullable + public String getCurrentPackageName() { + ComponentName bestComponent = mBestComponent; + return bestComponent == null ? null : bestComponent.getPackageName(); + } + + public int getCurrentPackageVersion() { + return mBestVersion; + } + /** - * Check if any instance of this service is present on the device, - * regardless of it being encryption-aware or not. + * Runs the given BinderRunner if currently connected. Returns true if it was run, and false + * otherwise. All invocations to runOnBinder are run serially. */ + public final void runOnBinder(BinderRunner runner) { + synchronized (mBindLock) { + IBinder service = mBestService; + if (service != null) { + try { + runner.run(service); + } catch (Exception e) { + // remote exceptions cannot be allowed to crash system server + Log.e(TAG, "exception while while running " + runner + " on " + service + + " from " + mBestComponent.toShortString(), e); + } + } + } + } + private boolean isServiceMissing() { - final Intent intent = new Intent(mAction); - final int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; - return mPm.queryIntentServicesAsUser(intent, flags, mCurrentUserId).isEmpty(); + return mContext.getPackageManager().queryIntentServicesAsUser(new Intent(mAction), + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, + UserHandle.USER_SYSTEM).isEmpty(); } /** * Searches and binds to the best package, or do nothing if the best package * is already bound, unless force rebinding is requested. * - * @param justCheckThisPackage Only consider this package, or consider all - * packages if it is {@code null}. - * @param forceRebind Force a rebinding to the best package if it's already - * bound. - * @returns {@code true} if a valid package was found to bind to. + * @param forceRebind Force a rebinding to the best package if it's already + * bound. */ - @GuardedBy("mLock") - private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) { + @WorkerThread + private void bindBestPackage(boolean forceRebind) { + Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); + Intent intent = new Intent(mAction); - if (justCheckThisPackage != null) { - intent.setPackage(justCheckThisPackage); + if (mServicePackageName != null) { + intent.setPackage(mServicePackageName); } - final List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent, - PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING, + + List<ResolveInfo> rInfos = mContext.getPackageManager().queryIntentServicesAsUser(intent, + PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AUTO, mCurrentUserId); - int bestVersion = Integer.MIN_VALUE; + if (rInfos == null) { + rInfos = Collections.emptyList(); + } + ComponentName bestComponent = null; + int bestVersion = Integer.MIN_VALUE; boolean bestIsMultiuser = false; - if (rInfos != null) { - for (ResolveInfo rInfo : rInfos) { - final ComponentName component = rInfo.serviceInfo.getComponentName(); - final String packageName = component.getPackageName(); - // check signature - try { - PackageInfo pInfo; - pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES - | PackageManager.MATCH_DEBUG_TRIAGED_MISSING); - if (!isSignatureMatch(pInfo.signatures)) { - Log.w(mTag, packageName + " resolves service " + mAction - + ", but has wrong signature, ignoring"); - continue; - } - } catch (NameNotFoundException e) { - Log.wtf(mTag, e); - continue; - } + for (ResolveInfo rInfo : rInfos) { + ComponentName component = rInfo.serviceInfo.getComponentName(); + String packageName = component.getPackageName(); - // check metadata - int version = Integer.MIN_VALUE; - boolean isMultiuser = false; - if (rInfo.serviceInfo.metaData != null) { - version = rInfo.serviceInfo.metaData.getInt( - EXTRA_SERVICE_VERSION, Integer.MIN_VALUE); - isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER); + // check signature + try { + PackageInfo pInfo = mContext.getPackageManager().getPackageInfo(packageName, + PackageManager.GET_SIGNATURES + | PackageManager.MATCH_DIRECT_BOOT_AUTO); + if (!isSignatureMatch(pInfo.signatures, mSignatureSets)) { + Log.w(mTag, packageName + " resolves service " + mAction + + ", but has wrong signature, ignoring"); + continue; } + } catch (NameNotFoundException e) { + Log.wtf(mTag, e); + continue; + } - if (version > bestVersion) { - bestVersion = version; - bestComponent = component; - bestIsMultiuser = isMultiuser; - } + // check metadata + Bundle metadata = rInfo.serviceInfo.metaData; + int version = Integer.MIN_VALUE; + boolean isMultiuser = false; + if (metadata != null) { + version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE); + isMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false); } - if (D) { - Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction, - (justCheckThisPackage == null ? "" - : "(" + justCheckThisPackage + ") "), rInfos.size(), - (bestComponent == null ? "no new best component" - : "new best component: " + bestComponent))); + if (version > bestVersion) { + bestComponent = component; + bestVersion = version; + bestIsMultiuser = isMultiuser; } - } else { - if (D) Log.d(mTag, "Unable to query intent services for action: " + mAction); + } + + if (D) { + Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction, + (mServicePackageName == null ? "" + : "(" + mServicePackageName + ") "), rInfos.size(), + (bestComponent == null ? "no new best component" + : "new best component: " + bestComponent))); } if (bestComponent == null) { Slog.w(mTag, "Odd, no component found for service " + mAction); - unbindLocked(); - return false; + unbind(); + return; } - final int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId; - final boolean alreadyBound = Objects.equals(bestComponent, mBoundComponent) - && bestVersion == mBoundVersion && userId == mBoundUserId; + int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId; + boolean alreadyBound = Objects.equals(bestComponent, mBestComponent) + && bestVersion == mBestVersion && userId == mBestUserId; if (forceRebind || !alreadyBound) { - unbindLocked(); - bindToPackageLocked(bestComponent, bestVersion, userId); + unbind(); + bind(bestComponent, bestVersion, userId); } - return true; } - @GuardedBy("mLock") - private void unbindLocked() { - ComponentName component; - component = mBoundComponent; - mBoundComponent = null; - mBoundPackageName = null; - mBoundVersion = Integer.MIN_VALUE; - mBoundUserId = UserHandle.USER_NULL; - if (component != null) { - if (D) Log.d(mTag, "unbinding " + component); - mBoundService = null; - mContext.unbindService(this); - } - } + @WorkerThread + private void bind(ComponentName component, int version, int userId) { + Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); - @GuardedBy("mLock") - private void bindToPackageLocked(ComponentName component, int version, int userId) { Intent intent = new Intent(mAction); intent.setComponent(component); - mBoundComponent = component; - mBoundPackageName = component.getPackageName(); - mBoundVersion = version; - mBoundUserId = userId; + + mBestComponent = component; + mBestVersion = version; + mBestUserId = userId; + if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")"); mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE, - new UserHandle(userId)); + UserHandle.of(userId)); } - public static boolean isSignatureMatch(Signature[] signatures, - List<HashSet<Signature>> sigSets) { - if (signatures == null) return false; + @WorkerThread + private void unbind() { + Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); - // build hashset of input to test against - HashSet<Signature> inputSet = new HashSet<Signature>(); - for (Signature s : signatures) { - inputSet.add(s); - } - - // test input against each of the signature sets - for (HashSet<Signature> referenceSet : sigSets) { - if (referenceSet.equals(inputSet)) { - return true; - } + if (mBestComponent != null) { + if (D) Log.d(mTag, "unbinding " + mBestComponent); + mContext.unbindService(this); } - return false; - } - private boolean isSignatureMatch(Signature[] signatures) { - return isSignatureMatch(signatures, mSignatureSets); + mBestComponent = null; + mBestVersion = Integer.MIN_VALUE; + mBestUserId = UserHandle.USER_NULL; } - private final PackageMonitor mPackageMonitor = new PackageMonitor() { - /** - * Called when package has been reinstalled - */ - @Override - public void onPackageUpdateFinished(String packageName, int uid) { - synchronized (mLock) { - final boolean forceRebind = Objects.equals(packageName, mBoundPackageName); - bindBestPackageLocked(null, forceRebind); - } - } - - @Override - public void onPackageAdded(String packageName, int uid) { - synchronized (mLock) { - final boolean forceRebind = Objects.equals(packageName, mBoundPackageName); - bindBestPackageLocked(null, forceRebind); - } - } - - @Override - public void onPackageRemoved(String packageName, int uid) { - synchronized (mLock) { - final boolean forceRebind = Objects.equals(packageName, mBoundPackageName); - bindBestPackageLocked(null, forceRebind); - } - } - - @Override - public boolean onPackageChanged(String packageName, int uid, String[] components) { - synchronized (mLock) { - final boolean forceRebind = Objects.equals(packageName, mBoundPackageName); - bindBestPackageLocked(null, forceRebind); - } - return super.onPackageChanged(packageName, uid, components); - } - }; - + @MainThread @Override - public void onServiceConnected(ComponentName component, IBinder binder) { - synchronized (mLock) { - if (component.equals(mBoundComponent)) { - if (D) Log.d(mTag, component + " connected"); - mBoundService = binder; - if (mHandler !=null && mNewServiceWork != null) { - mHandler.post(mNewServiceWork); - } - } else { - Log.w(mTag, "unexpected onServiceConnected: " + component); + public final void onServiceConnected(ComponentName component, IBinder binder) { + mHandler.post(() -> { + if (D) Log.d(mTag, component + " connected"); + + // hold the lock so that mBestService cannot be used by runOnBinder until complete + synchronized (mBindLock) { + mBestService = binder; + onBind(); } - } + }); } + @MainThread @Override - public void onServiceDisconnected(ComponentName component) { - synchronized (mLock) { + public final void onServiceDisconnected(ComponentName component) { + mHandler.post(() -> { if (D) Log.d(mTag, component + " disconnected"); - if (component.equals(mBoundComponent)) { - mBoundService = null; + mBestService = null; + synchronized (mBindLock) { + onUnbind(); } - } - } - - public @Nullable String getBestPackageName() { - synchronized (mLock) { - return mBoundPackageName; - } - } - - public int getBestVersion() { - synchronized (mLock) { - return mBoundVersion; - } + }); } - /** - * The runner that runs on the binder retrieved from {@link ServiceWatcher}. - */ - public interface BinderRunner { - /** - * Runs on the retrieved binder. - * @param binder the binder retrieved from the {@link ServiceWatcher}. - */ - public void run(@NonNull IBinder binder); - } - - /** - * Retrieves the binder from {@link ServiceWatcher} and runs it. - * @return whether a valid service exists. - */ - public boolean runOnBinder(@NonNull BinderRunner runner) { - synchronized (mLock) { - if (mBoundService == null) { - return false; - } else { - runner.run(mBoundService); - return true; - } - } - } - - public void switchUser(int userId) { - synchronized (mLock) { - mCurrentUserId = userId; - bindBestPackageLocked(mServicePackageName, false); - } - } - - public void unlockUser(int userId) { - synchronized (mLock) { - if (userId == mCurrentUserId) { - bindBestPackageLocked(mServicePackageName, false); - } - } + @Override + public String toString() { + ComponentName bestComponent = mBestComponent; + return bestComponent == null ? "null" : bestComponent.toShortString() + "@" + mBestVersion; } } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 5643a6a66251..54c7d17d70a7 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -878,6 +878,7 @@ class StorageManagerService extends IStorageManager.Stub mStoraged.onUserStarted(userId); } mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing); + mStorageManagerInternal.onReset(mVold); } catch (Exception e) { Slog.wtf(TAG, e); } @@ -3635,6 +3636,10 @@ class StorageManagerService extends IStorageManager.Stub private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies = new CopyOnWriteArrayList<>(); + @GuardedBy("mResetListeners") + private final List<StorageManagerInternal.ResetListener> mResetListeners = + new ArrayList<>(); + @Override public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) { // No locking - CopyOnWriteArrayList @@ -3666,6 +3671,21 @@ class StorageManagerService extends IStorageManager.Stub return mountMode; } + @Override + public void addResetListener(StorageManagerInternal.ResetListener listener) { + synchronized (mResetListeners) { + mResetListeners.add(listener); + } + } + + public void onReset(IVold vold) { + synchronized (mResetListeners) { + for (StorageManagerInternal.ResetListener listener : mResetListeners) { + listener.onReset(vold); + } + } + } + public boolean hasExternalStorage(int uid, String packageName) { // No need to check for system uid. This avoids a deadlock between // PackageManagerService and AppOpsService. diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 793a1778f900..26e22bf6f8a2 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -1258,8 +1258,6 @@ public class VibratorService extends IVibratorService.Stub private final class VibratorShellCommand extends ShellCommand { - private static final long MAX_VIBRATION_MS = 200; - private final IBinder mToken; private VibratorShellCommand(IBinder token) { @@ -1303,9 +1301,6 @@ public class VibratorService extends IVibratorService.Stub } final long duration = Long.parseLong(getNextArgRequired()); - if (duration > MAX_VIBRATION_MS) { - throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS); - } String description = getNextArg(); if (description == null) { description = "Shell command"; diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 405a2d0ca478..2d3912bda9cc 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -95,6 +95,7 @@ import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.webkit.WebViewZygote; import com.android.server.uri.NeededUriGrants; +import com.android.server.wm.ActivityServiceConnectionsHolder; public final class ActiveServices { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActiveServices" : TAG_AM; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b06320a9c4a1..9a1c12bfa00b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -127,28 +127,28 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; -import static com.android.server.am.ActivityTaskManagerService.DUMP_ACTIVITIES_CMD; -import static com.android.server.am.ActivityTaskManagerService.DUMP_ACTIVITIES_SHORT_CMD; -import static com.android.server.am.ActivityTaskManagerService.DUMP_CONTAINERS_CMD; -import static com.android.server.am.ActivityTaskManagerService.DUMP_LASTANR_CMD; -import static com.android.server.am.ActivityTaskManagerService.DUMP_LASTANR_TRACES_CMD; -import static com.android.server.am.ActivityTaskManagerService.DUMP_RECENTS_CMD; -import static com.android.server.am.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD; -import static com.android.server.am.ActivityTaskManagerService.DUMP_STARTER_CMD; -import static com.android.server.am.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE; -import static com.android.server.am.ActivityTaskManagerService.relaunchReasonToString; import static com.android.server.am.MemoryStatUtil.MEMORY_STAT_INTERESTING_NATIVE_PROCESSES; import static com.android.server.am.MemoryStatUtil.hasMemcg; import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; +import static com.android.server.wm.ActivityTaskManagerService.DUMP_ACTIVITIES_CMD; +import static com.android.server.wm.ActivityTaskManagerService.DUMP_ACTIVITIES_SHORT_CMD; +import static com.android.server.wm.ActivityTaskManagerService.DUMP_CONTAINERS_CMD; +import static com.android.server.wm.ActivityTaskManagerService.DUMP_LASTANR_CMD; +import static com.android.server.wm.ActivityTaskManagerService.DUMP_LASTANR_TRACES_CMD; +import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_CMD; +import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD; +import static com.android.server.wm.ActivityTaskManagerService.DUMP_STARTER_CMD; +import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; +import static com.android.server.wm.ActivityTaskManagerService.relaunchReasonToString; import android.Manifest; import android.Manifest.permission; @@ -352,8 +352,11 @@ import com.android.server.uri.GrantUri; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.utils.PriorityDump; import com.android.server.vr.VrManagerInternal; +import com.android.server.wm.ActivityServiceConnectionsHolder; import com.android.server.wm.ActivityTaskManagerInternal; +import com.android.server.wm.ActivityTaskManagerService; import com.android.server.wm.WindowManagerService; +import com.android.server.wm.WindowProcessController; import dalvik.system.VMRuntime; @@ -567,7 +570,8 @@ public class ActivityManagerService extends IActivityManager.Stub String mDeviceOwnerName; final UserController mUserController; - final PendingIntentController mPendingIntentController; + @VisibleForTesting + public final PendingIntentController mPendingIntentController; final AppErrors mAppErrors; @@ -1276,10 +1280,14 @@ public class ActivityManagerService extends IActivityManager.Stub */ int mBootPhase; - WindowManagerService mWindowManager; - ActivityTaskManagerService mActivityTaskManager; - ActivityTaskManagerInternal mAtmInternal; - UriGrantsManagerInternal mUgmInternal; + @VisibleForTesting + public WindowManagerService mWindowManager; + @VisibleForTesting + public ActivityTaskManagerService mActivityTaskManager; + @VisibleForTesting + public ActivityTaskManagerInternal mAtmInternal; + @VisibleForTesting + public UriGrantsManagerInternal mUgmInternal; final ActivityThread mSystemThread; private final class AppDeathRecipient implements IBinder.DeathRecipient { @@ -1349,7 +1357,8 @@ public class ActivityManagerService extends IActivityManager.Stub */ private boolean mUserIsMonkey; - final ServiceThread mHandlerThread; + @VisibleForTesting + public final ServiceThread mHandlerThread; final MainHandler mHandler; final Handler mUiHandler; final ServiceThread mProcStartHandlerThread; @@ -2111,7 +2120,7 @@ public class ActivityManagerService extends IActivityManager.Stub * given to initialize the dependency members. */ @VisibleForTesting - ActivityManagerService(Injector injector, ServiceThread handlerThread) { + public ActivityManagerService(Injector injector, ServiceThread handlerThread) { final boolean hasHandlerThread = handlerThread != null; mInjector = injector; mContext = mInjector.getContext(); @@ -3843,7 +3852,7 @@ public class ActivityManagerService extends IActivityManager.Stub final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); - final int userId = UserHandle.getUserId(callingUid); + final int callingUserId = UserHandle.getUserId(callingUid); final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, callingUid) == PackageManager.PERMISSION_GRANTED; // Check REAL_GET_TASKS to see if they are allowed to access other uids @@ -3861,11 +3870,17 @@ public class ActivityManagerService extends IActivityManager.Stub oomAdj = proc != null ? proc.setAdj : 0; } } - if (!allUids || (!allUsers && (proc == null - || UserHandle.getUserId(proc.uid) != userId))) { - // The caller is not allow to get information about this other process... - // just leave it empty. - continue; + final int targetUid = (proc != null) ? proc.uid : -1; + final int targetUserId = (proc != null) ? UserHandle.getUserId(targetUid) : -1; + + if (callingUid != targetUid) { + if (!allUids) { + continue; // Not allowed to see other UIDs. + } + + if (!allUsers && (targetUserId != callingUserId)) { + continue; // Not allowed to see other users. + } } if (proc != null && proc.lastMemInfoTime >= lastNow && proc.lastMemInfo != null) { // It hasn't been long enough that we want to take another sample; return @@ -5556,7 +5571,8 @@ public class ActivityManagerService extends IActivityManager.Stub return pi; } - void grantEphemeralAccessLocked(int userId, Intent intent, + @VisibleForTesting + public void grantEphemeralAccessLocked(int userId, Intent intent, int targetAppId, int ephemeralAppId) { getPackageManagerInternalLocked(). grantEphemeralAccess(userId, intent, targetAppId, ephemeralAppId); @@ -6509,6 +6525,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Wait for the provider to be published... final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT; + boolean timedOut = false; synchronized (cpr) { while (cpr.provider == null) { if (cpr.launchingApp == null) { @@ -6532,12 +6549,8 @@ public class ActivityManagerService extends IActivityManager.Stub } cpr.wait(wait); if (cpr.provider == null) { - Slog.wtf(TAG, "Timeout waiting for provider " - + cpi.applicationInfo.packageName + "/" - + cpi.applicationInfo.uid + " for provider " - + name - + " providerRunning=" + providerRunning); - return null; + timedOut = true; + break; } } catch (InterruptedException ex) { } finally { @@ -6547,7 +6560,26 @@ public class ActivityManagerService extends IActivityManager.Stub } } } - return cpr != null ? cpr.newHolder(conn) : null; + if (timedOut) { + // Note we do it afer releasing the lock. + String callerName = "unknown"; + synchronized (this) { + final ProcessRecord record = mProcessList.getLRURecordForAppLocked(caller); + if (record != null) { + callerName = record.processName; + } + } + + Slog.wtf(TAG, "Timeout waiting for provider " + + cpi.applicationInfo.packageName + "/" + + cpi.applicationInfo.uid + " for provider " + + name + + " providerRunning=" + providerRunning + + " caller=" + callerName + "/" + Binder.getCallingUid()); + return null; + } + + return cpr.newHolder(conn); } private static final class StartActivityRunnable implements Runnable { @@ -6606,11 +6638,13 @@ public class ActivityManagerService extends IActivityManager.Stub * PackageManager could be unavailable at construction time and therefore needs to be accessed * on demand. */ - IPackageManager getPackageManager() { + @VisibleForTesting + public IPackageManager getPackageManager() { return AppGlobals.getPackageManager(); } - PackageManagerInternal getPackageManagerInternalLocked() { + @VisibleForTesting + public PackageManagerInternal getPackageManagerInternalLocked() { if (mPackageManagerInt == null) { mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class); } @@ -7292,13 +7326,6 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing, - int secondaryDisplayShowing) { - mActivityTaskManager.setLockScreenShown( - keyguardShowing, aodShowing, secondaryDisplayShowing); - } - - @Override public void notifyLockedProfile(@UserIdInt int userId) { mAtmInternal.notifyLockedProfile(userId, mUserController.getCurrentUserId()); } @@ -7682,7 +7709,7 @@ public class ActivityManagerService extends IActivityManager.Stub * * @return {@code true} if this succeeded. */ - static boolean scheduleAsRegularPriority(int tid, boolean suppressLogs) { + public static boolean scheduleAsRegularPriority(int tid, boolean suppressLogs) { try { Process.setThreadScheduler(tid, Process.SCHED_OTHER, 0); return true; @@ -7706,7 +7733,7 @@ public class ActivityManagerService extends IActivityManager.Stub * * @return {@code true} if this succeeded. */ - static boolean scheduleAsFifoPriority(int tid, boolean suppressLogs) { + public static boolean scheduleAsFifoPriority(int tid, boolean suppressLogs) { try { Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); return true; @@ -10458,11 +10485,11 @@ public class ActivityManagerService extends IActivityManager.Stub ArrayList<Integer> objects; boolean all; - ItemMatcher() { + public ItemMatcher() { all = true; } - void build(String name) { + public void build(String name) { ComponentName componentName = ComponentName.unflattenFromString(name); if (componentName != null) { if (components == null) { @@ -10491,7 +10518,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - int build(String[] args, int opti) { + public int build(String[] args, int opti) { for (; opti<args.length; opti++) { String name = args[opti]; if ("--".equals(name)) { @@ -10502,7 +10529,7 @@ public class ActivityManagerService extends IActivityManager.Stub return opti; } - boolean match(Object object, ComponentName comp) { + public boolean match(Object object, ComponentName comp) { if (all) { return true; } @@ -17327,8 +17354,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now); - incrementProcStateSeqAndNotifyAppsLocked(); mNumServiceProcs = mNewNumServiceProcs; @@ -17590,6 +17615,9 @@ public class ActivityManagerService extends IActivityManager.Stub mHandler.post(new ProcStatsRunnable(ActivityManagerService.this, mProcessStats)); } + // Run this after making sure all procstates are updated. + mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now); + if (DEBUG_OOM_ADJ) { final long duration = SystemClock.uptimeMillis() - now; if (false) { @@ -18464,7 +18492,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @VisibleForTesting - final class LocalService extends ActivityManagerInternal { + public final class LocalService extends ActivityManagerInternal { @Override public String checkContentProviderAccess(String authority, int userId) { return ActivityManagerService.this.checkContentProviderAccess(authority, userId); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 44f69b1693e9..dd3f3b51d2fd 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -17,12 +17,13 @@ package com.android.server.am; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityManagerService.MY_PID; import static com.android.server.am.ActivityManagerService.SYSTEM_DEBUGGABLE; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -37,7 +38,6 @@ import android.net.Uri; import android.os.Binder; import android.os.Message; import android.os.Process; -import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; @@ -54,12 +54,11 @@ import com.android.internal.app.ProcessMap; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.server.RescueParty; -import com.android.server.Watchdog; +import com.android.server.wm.WindowProcessController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collections; -import java.util.Set; /** * Controls error conditions in applications. @@ -619,7 +618,7 @@ class AppErrors { report.installerPackageName = r.errorReportReceiver.getPackageName(); report.processName = r.processName; report.time = timeMillis; - report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + report.systemApp = (r.info.flags & FLAG_SYSTEM) != 0; if (r.isCrashing() || r.forceCrashReport) { report.type = ApplicationErrorReport.TYPE_CRASH; @@ -732,7 +731,7 @@ class AppErrors { final WindowProcessController proc = app.getWindowProcessController(); final WindowProcessController homeProc = mService.mAtmInternal.getHomeProcess(); if (proc == homeProc && proc.hasActivities() - && (homeProc.mInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + && (((ProcessRecord) homeProc.mOwner).info.flags & FLAG_SYSTEM) == 0) { proc.clearPackagePreferredForHomeActivities(); } diff --git a/services/core/java/com/android/server/am/AppTimeTracker.java b/services/core/java/com/android/server/am/AppTimeTracker.java index 772865d89d3b..debe0a94b1b0 100644 --- a/services/core/java/com/android/server/am/AppTimeTracker.java +++ b/services/core/java/com/android/server/am/AppTimeTracker.java @@ -122,7 +122,7 @@ public class AppTimeTracker { } } - void writeToProto(ProtoOutputStream proto, long fieldId, boolean details) { + public void writeToProto(ProtoOutputStream proto, long fieldId, boolean details) { final long token = proto.start(fieldId); proto.write(AppTimeTrackerProto.RECEIVER, mReceiver.toString()); proto.write(AppTimeTrackerProto.TOTAL_DURATION_MS, mTotalTime); diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java index cd4d6a3e14c5..aabb5877764e 100644 --- a/services/core/java/com/android/server/am/BaseErrorDialog.java +++ b/services/core/java/com/android/server/am/BaseErrorDialog.java @@ -26,7 +26,7 @@ import android.view.KeyEvent; import android.view.WindowManager; import android.widget.Button; -class BaseErrorDialog extends AlertDialog { +public class BaseErrorDialog extends AlertDialog { private static final int ENABLE_BUTTONS = 0; private static final int DISABLE_BUTTONS = 1; diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java index 1242ed626a18..37d07bbda760 100644 --- a/services/core/java/com/android/server/am/ConnectionRecord.java +++ b/services/core/java/com/android/server/am/ConnectionRecord.java @@ -27,6 +27,7 @@ import android.util.proto.ProtoUtils; import com.android.internal.app.procstats.AssociationState; import com.android.internal.app.procstats.ProcessStats; +import com.android.server.wm.ActivityServiceConnectionsHolder; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java index 48e26ed3d863..968c17f8df0b 100644 --- a/services/core/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java @@ -59,6 +59,7 @@ final class CoreSettingsObserver extends ContentObserver { sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class); sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class); sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class); + sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS_GLES, String.class); sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class); // add other global settings here... } diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java index f77be5b0799c..c978c134530c 100644 --- a/services/core/java/com/android/server/am/MemoryStatUtil.java +++ b/services/core/java/com/android/server/am/MemoryStatUtil.java @@ -16,7 +16,7 @@ package com.android.server.am; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_METRICS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -273,18 +273,18 @@ public final class MemoryStatUtil { public static final class MemoryStat { /** Number of page faults */ - long pgfault; + public long pgfault; /** Number of major page faults */ - long pgmajfault; + public long pgmajfault; /** Number of bytes of anonymous and swap cache memory */ - long rssInBytes; + public long rssInBytes; /** Number of bytes of page cache memory */ - long cacheInBytes; + public long cacheInBytes; /** Number of bytes of swap usage */ - long swapInBytes; + public long swapInBytes; /** Number of bytes of peak anonymous and swap cache memory */ - long rssHighWatermarkInBytes; + public long rssHighWatermarkInBytes; /** Device time when the processes started. */ - long startTimeNanos; + public long startTimeNanos; } } diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java index a9c00a70650c..a5d47386afb5 100644 --- a/services/core/java/com/android/server/am/PendingIntentController.java +++ b/services/core/java/com/android/server/am/PendingIntentController.java @@ -43,6 +43,7 @@ import com.android.internal.os.IResultReceiver; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.wm.ActivityTaskManagerInternal; +import com.android.server.wm.SafeActivityOptions; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -84,8 +85,8 @@ public class PendingIntentController { } } - PendingIntentRecord getIntentSender(int type, String packageName, int callingUid, int userId, - IBinder token, String resultWho, int requestCode, Intent[] intents, + public PendingIntentRecord getIntentSender(int type, String packageName, int callingUid, + int userId, IBinder token, String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions) { synchronized (mLock) { if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid); diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 2dcddff2f442..447243b542ea 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -39,6 +39,7 @@ import android.util.TimeUtils; import com.android.internal.os.IResultReceiver; import com.android.internal.util.function.pooled.PooledLambda; +import com.android.server.wm.SafeActivityOptions; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -50,7 +51,7 @@ public final class PendingIntentRecord extends IIntentSender.Stub { final PendingIntentController controller; final Key key; final int uid; - final WeakReference<PendingIntentRecord> ref; + public final WeakReference<PendingIntentRecord> ref; boolean sent = false; boolean canceled = false; private ArrayMap<IBinder, Long> whitelistDuration; @@ -248,7 +249,7 @@ public final class PendingIntentRecord extends IIntentSender.Stub { requiredPermission, null, null, 0, 0, 0, options); } - int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken, + public int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) { if (intent != null) intent.setDefusable(true); @@ -450,7 +451,7 @@ public final class PendingIntentRecord extends IIntentSender.Stub { } } - void dump(PrintWriter pw, String prefix) { + public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("uid="); pw.print(uid); pw.print(" packageName="); pw.print(key.packageName); pw.print(" type="); pw.print(key.typeName()); diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 6741dc07fcdf..93c8391ea8d7 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -92,6 +92,7 @@ import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.Watchdog; import com.android.server.pm.dex.DexManager; +import com.android.server.wm.ActivityServiceConnectionsHolder; import com.android.server.wm.WindowManagerService; import dalvik.system.VMRuntime; @@ -212,7 +213,7 @@ public final class ProcessList { // Activity manager's version of Process.THREAD_GROUP_DEFAULT static final int SCHED_GROUP_DEFAULT = 2; // Activity manager's version of Process.THREAD_GROUP_TOP_APP - static final int SCHED_GROUP_TOP_APP = 3; + public static final int SCHED_GROUP_TOP_APP = 3; // Activity manager's version of Process.THREAD_GROUP_TOP_APP // Disambiguate between actual top app and processes bound to the top app static final int SCHED_GROUP_TOP_APP_BOUND = 4; @@ -2523,9 +2524,13 @@ public final class ProcessList { currApp.importanceReasonImportance = ActivityManager.RunningAppProcessInfo.procStateToImportance( app.adjSourceProcState); - } else if (app.adjSource instanceof ActivityRecord) { - ActivityRecord r = (ActivityRecord)app.adjSource; - if (r.app != null) currApp.importanceReasonPid = r.app.getPid(); + } else if (app.adjSource instanceof ActivityServiceConnectionsHolder) { + final ActivityServiceConnectionsHolder r = + (ActivityServiceConnectionsHolder) app.adjSource; + final int pid = r.getActivityPid(); + if (pid != -1) { + currApp.importanceReasonPid = pid; + } } if (app.adjTarget instanceof ComponentName) { currApp.importanceReasonComponent = (ComponentName)app.adjTarget; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 683754cd9a35..bb87ad031ad5 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -33,7 +33,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; -import android.content.res.Configuration; import android.os.Binder; import android.os.Debug; import android.os.IBinder; @@ -58,7 +57,8 @@ import com.android.internal.app.procstats.ProcessState; import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.BatteryStatsImpl; import com.android.internal.os.ProcessCpuTracker; -import com.android.server.Watchdog; +import com.android.server.wm.WindowProcessController; +import com.android.server.wm.WindowProcessListener; import java.io.File; import java.io.IOException; diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java index 5d4263b13903..bc3cc3bd383c 100644 --- a/services/core/java/com/android/server/biometrics/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/face/FaceService.java @@ -70,7 +70,7 @@ import java.util.List; /** * A service to manage multiple clients that want to access the face HAL API. * The service is responsible for maintaining a list of clients and dispatching all - * face -related events. + * face-related events. * * @hide */ diff --git a/services/core/java/com/android/server/biometrics/iris/IrisService.java b/services/core/java/com/android/server/biometrics/iris/IrisService.java new file mode 100644 index 000000000000..37cdc2a4f07a --- /dev/null +++ b/services/core/java/com/android/server/biometrics/iris/IrisService.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.biometrics.iris; + +import android.content.Context; + +import com.android.server.biometrics.BiometricServiceBase; +import com.android.server.biometrics.BiometricUtils; +import com.android.server.biometrics.Metrics; + +/** + * A service to manage multiple clients that want to access the Iris HAL API. + * The service is responsible for maintaining a list of clients and dispatching all + * iris-related events. + * + * TODO: The vendor is expected to fill in the service. See + * {@link com.android.server.biometrics.fingerprint.FingerprintService} + * + * @hide + */ +public class IrisService extends BiometricServiceBase { + + private static final String TAG = "IrisService"; + + /** + * Initializes the system service. + * <p> + * Subclasses must define a single argument constructor that accepts the context + * and passes it to super. + * </p> + * + * @param context The system server context. + */ + public IrisService(Context context) { + super(context); + } + + @Override + public void onStart() { + super.onStart(); + } + + @Override + protected String getTag() { + return TAG; + } + + @Override + protected BiometricUtils getBiometricUtils() { + return null; + } + + @Override + protected int getFailedAttemptsLockoutTimed() { + return 0; + } + + @Override + protected int getFailedAttemptsLockoutPermanent() { + return 0; + } + + @Override + protected Metrics getMetrics() { + return null; + } + + @Override + protected boolean hasReachedEnrollmentLimit(int userId) { + return false; + } + + @Override + protected void updateActiveGroup(int userId, String clientPackage) { + + } + + @Override + protected String getLockoutResetIntent() { + return null; + } + + @Override + protected String getLockoutBroadcastPermission() { + return null; + } + + @Override + protected long getHalDeviceId() { + return 0; + } + + @Override + protected void handleUserSwitching(int userId) { + + } + + @Override + protected boolean hasEnrolledBiometrics(int userId) { + return false; + } + + @Override + protected String getManageBiometricPermission() { + return null; + } + + @Override + protected void checkUseBiometricPermission() { + + } + + @Override + protected boolean checkAppOps(int uid, String opPackageName) { + return false; + } +} diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java index 4f31e533f8f9..422f5566eee1 100644 --- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java +++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java @@ -208,7 +208,8 @@ public class NetdEventListenerService extends INetdEventListener.Stub { for (INetdEventCallback callback : mNetdEventCallbackList) { if (callback != null) { - callback.onDnsEvent(hostname, ipAddresses, ipAddressesCount, timestamp, uid); + callback.onDnsEvent(netId, eventType, returnCode, hostname, ipAddresses, + ipAddressesCount, timestamp, uid); } } } diff --git a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java index f82b9761f569..22fabb2cdd3e 100644 --- a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java +++ b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java @@ -16,58 +16,25 @@ package com.android.server.location; -import com.android.server.ServiceWatcher; - import android.content.Context; import android.hardware.location.ActivityRecognitionHardware; import android.hardware.location.IActivityRecognitionHardwareClient; import android.hardware.location.IActivityRecognitionHardwareWatcher; -import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.internal.os.BackgroundThread; +import com.android.server.ServiceWatcher; + /** * Proxy class to bind GmsCore to the ActivityRecognitionHardware. * * @hide */ public class ActivityRecognitionProxy { - private static final String TAG = "ActivityRecognitionProxy"; - - private final ServiceWatcher mServiceWatcher; - private final boolean mIsSupported; - private final ActivityRecognitionHardware mInstance; - - private ActivityRecognitionProxy( - Context context, - Handler handler, - boolean activityRecognitionHardwareIsSupported, - ActivityRecognitionHardware activityRecognitionHardware, - int overlaySwitchResId, - int defaultServicePackageNameResId, - int initialPackageNameResId) { - mIsSupported = activityRecognitionHardwareIsSupported; - mInstance = activityRecognitionHardware; - - Runnable newServiceWork = new Runnable() { - @Override - public void run() { - bindProvider(); - } - }; - // prepare the connection to the provider - mServiceWatcher = new ServiceWatcher( - context, - TAG, - "com.android.location.service.ActivityRecognitionProvider", - overlaySwitchResId, - defaultServicePackageNameResId, - initialPackageNameResId, - newServiceWork, - handler); - } + private static final String TAG = "ActivityRecognitionProxy"; /** * Creates an instance of the proxy and binds it to the appropriate FusedProvider. @@ -76,7 +43,6 @@ public class ActivityRecognitionProxy { */ public static ActivityRecognitionProxy createAndBind( Context context, - Handler handler, boolean activityRecognitionHardwareIsSupported, ActivityRecognitionHardware activityRecognitionHardware, int overlaySwitchResId, @@ -84,74 +50,69 @@ public class ActivityRecognitionProxy { int initialPackageNameResId) { ActivityRecognitionProxy activityRecognitionProxy = new ActivityRecognitionProxy( context, - handler, activityRecognitionHardwareIsSupported, activityRecognitionHardware, overlaySwitchResId, defaultServicePackageNameResId, initialPackageNameResId); - // try to bind the provider - if (!activityRecognitionProxy.mServiceWatcher.start()) { - Log.e(TAG, "ServiceWatcher could not start."); + if (activityRecognitionProxy.mServiceWatcher.start()) { + return activityRecognitionProxy; + } else { return null; } - return activityRecognitionProxy; } - /** - * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance. - */ - private void bindProvider() { - if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { + private final ServiceWatcher mServiceWatcher; + private final boolean mIsSupported; + private final ActivityRecognitionHardware mInstance; + + private ActivityRecognitionProxy( + Context context, + boolean activityRecognitionHardwareIsSupported, + ActivityRecognitionHardware activityRecognitionHardware, + int overlaySwitchResId, + int defaultServicePackageNameResId, + int initialPackageNameResId) { + mIsSupported = activityRecognitionHardwareIsSupported; + mInstance = activityRecognitionHardware; + + mServiceWatcher = new ServiceWatcher( + context, + TAG, + "com.android.location.service.ActivityRecognitionProvider", + overlaySwitchResId, + defaultServicePackageNameResId, + initialPackageNameResId, + BackgroundThread.getHandler()) { @Override - public void run(IBinder binder) { - String descriptor; - try { - descriptor = binder.getInterfaceDescriptor(); - } catch (RemoteException e) { - Log.e(TAG, "Unable to get interface descriptor.", e); - return; - } + protected void onBind() { + runOnBinder(ActivityRecognitionProxy.this::initializeService); + } + }; + } + + private void initializeService(IBinder binder) { + try { + String descriptor = binder.getInterfaceDescriptor(); - if (IActivityRecognitionHardwareWatcher.class.getCanonicalName() - .equals(descriptor)) { - IActivityRecognitionHardwareWatcher watcher = - IActivityRecognitionHardwareWatcher.Stub.asInterface(binder); - if (watcher == null) { - Log.e(TAG, "No watcher found on connection."); - return; - } - if (mInstance == null) { - // to keep backwards compatibility do not update the watcher when there is - // no instance available, or it will cause an NPE - Log.d(TAG, "AR HW instance not available, binding will be a no-op."); - return; - } - try { - watcher.onInstanceChanged(mInstance); - } catch (RemoteException e) { - Log.e(TAG, "Error delivering hardware interface to watcher.", e); - } - } else if (IActivityRecognitionHardwareClient.class.getCanonicalName() - .equals(descriptor)) { - IActivityRecognitionHardwareClient client = - IActivityRecognitionHardwareClient.Stub.asInterface(binder); - if (client == null) { - Log.e(TAG, "No client found on connection."); - return; - } - try { - client.onAvailabilityChanged(mIsSupported, mInstance); - } catch (RemoteException e) { - Log.e(TAG, "Error delivering hardware interface to client.", e); - } - } else { - Log.e(TAG, "Invalid descriptor found on connection: " + descriptor); + if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals( + descriptor)) { + IActivityRecognitionHardwareWatcher watcher = + IActivityRecognitionHardwareWatcher.Stub.asInterface(binder); + if (mInstance != null) { + watcher.onInstanceChanged(mInstance); } + } else if (IActivityRecognitionHardwareClient.class.getCanonicalName() + .equals(descriptor)) { + IActivityRecognitionHardwareClient client = + IActivityRecognitionHardwareClient.Stub.asInterface(binder); + client.onAvailabilityChanged(mIsSupported, mInstance); + } else { + Log.e(TAG, "Invalid descriptor found on connection: " + descriptor); } - })) { - Log.e(TAG, "Null binder found on connection."); + } catch (RemoteException e) { + Log.w(TAG, e); } } } diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java index 60f70c70b8e0..642347021201 100644 --- a/services/core/java/com/android/server/location/ContextHubClientBroker.java +++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java @@ -159,25 +159,12 @@ public class ContextHubClientBroker extends IContextHubClient.Stub /* package */ ContextHubClientBroker( Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager, - ContextHubInfo contextHubInfo, short hostEndPointId, - IContextHubClientCallback callback) { + ContextHubInfo contextHubInfo, short hostEndPointId) { mContext = context; mContextHubProxy = contextHubProxy; mClientManager = clientManager; mAttachedContextHubInfo = contextHubInfo; mHostEndPointId = hostEndPointId; - mCallbackInterface = callback; - } - - /** - * Attaches a death recipient for this client - * - * @throws RemoteException if the client has already died - */ - /* package */ synchronized void attachDeathRecipient() throws RemoteException { - if (mCallbackInterface != null) { - mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */); - } } /** @@ -245,9 +232,15 @@ public class ContextHubClientBroker extends IContextHubClient.Stub public boolean unregisterIntent(PendingIntent pendingIntent) { ContextHubServiceUtil.checkPermissions(mContext); + boolean success = false; synchronized (this) { - return mPendingIntentRequest.unregister(pendingIntent); + success = mPendingIntentRequest.unregister(pendingIntent); + if (mCallbackInterface == null) { + close(); + } } + + return success; } /** @@ -276,6 +269,37 @@ public class ContextHubClientBroker extends IContextHubClient.Stub } /** + * Sets the callback interface for this client, only if the callback is currently unregistered. + * + * Also attaches a death recipient to a ContextHubClientBroker object. If unsuccessful, the + * connection is closed. + * + * @param callback the callback interface + * @return true if the callback was successfully set, false otherwise + * + * @throws IllegalStateException if the client has already been registered to a callback + */ + /* package */ + synchronized boolean setCallback(IContextHubClientCallback callback) { + boolean success = false; + if (mCallbackInterface != null) { + throw new IllegalStateException("Client is already registered with a callback"); + } else { + mCallbackInterface = callback; + try { + mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */); + success = true; + } catch (RemoteException e) { + // The client process has died, so we close the connection. + Log.e(TAG, "Failed to attach death recipient to client"); + close(); + } + } + + return success; + } + + /** * @return the ID of the context hub this client is attached to */ /* package */ int getAttachedContextHubId() { @@ -347,6 +371,18 @@ public class ContextHubClientBroker extends IContextHubClient.Stub } /** + * @param intent the PendingIntent to compare to + * @return true if the given PendingIntent is currently registered, false otherwise + */ + /* package */ boolean hasPendingIntent(PendingIntent intent) { + PendingIntent pendingIntent = null; + synchronized (this) { + pendingIntent = mPendingIntentRequest.getPendingIntent(); + } + return (pendingIntent != null) && pendingIntent.equals(intent); + } + + /** * Helper function to invoke a specified client callback, if the connection is open. * * @param consumer the consumer specifying the callback to invoke @@ -407,6 +443,9 @@ public class ContextHubClientBroker extends IContextHubClient.Stub Log.w(TAG, "PendingIntent has been canceled, unregistering from client" + " (host endpoint ID " + mHostEndPointId + ")"); mPendingIntentRequest.clear(); + if (mCallbackInterface == null) { + close(); + } } } } diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java index eda8c6f8b418..72879ddc2018 100644 --- a/services/core/java/com/android/server/location/ContextHubClientManager.java +++ b/services/core/java/com/android/server/location/ContextHubClientManager.java @@ -16,6 +16,7 @@ package com.android.server.location; +import android.app.PendingIntent; import android.content.Context; import android.hardware.contexthub.V1_0.ContextHubMsg; import android.hardware.contexthub.V1_0.IContexthub; @@ -88,15 +89,9 @@ import java.util.function.Consumer; */ /* package */ IContextHubClient registerClient( IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) { - ContextHubClientBroker broker = createNewClientBroker(clientCallback, contextHubInfo); - - try { - broker.attachDeathRecipient(); - } catch (RemoteException e) { - // The client process has died, so we close the connection and return null. - Log.e(TAG, "Failed to attach death recipient to client"); - broker.close(); - return null; + ContextHubClientBroker broker = createNewClientBroker(contextHubInfo); + if (!broker.setCallback(clientCallback)) { + return null; // Client process has died, so we return null } Log.d(TAG, "Registered client with host endpoint ID " + broker.getHostEndPointId()); @@ -104,6 +99,36 @@ import java.util.function.Consumer; } /** + * Binds a existing and registered client with a new callback interface, provided a previously + * registered PendingIntent. + * + * @param pendingIntent a previously registered PendingIntent for a registered client + * @param clientCallback the callback interface of the client to bind to + * @param contextHubId the ID of the hub this client is attached to + * + * @return the client interface + * + * @throws IllegalArgumentException if no matching client is found + * @throws IllegalStateException if the client has already been registered to a callback + */ + /* package */ IContextHubClient bindClient( + PendingIntent pendingIntent, IContextHubClientCallback clientCallback, + int contextHubId) { + ContextHubClientBroker broker = getClientBroker(pendingIntent, contextHubId); + if (broker == null) { + throw new IllegalArgumentException("Could not find client of Context Hub (ID = " + + contextHubId + ") with PendingIntent"); + } + + if (!broker.setCallback(clientCallback)) { + return null; // Client process has died, so we return null + } + + Log.d(TAG, "Re-registered client with host endpoint ID " + broker.getHostEndPointId()); + return IContextHubClient.Stub.asInterface(broker); + } + + /** * Handles a message sent from a nanoapp. * * @param contextHubId the ID of the hub where the nanoapp sent the message from @@ -182,7 +207,6 @@ import java.util.function.Consumer; * Creates a new ContextHubClientBroker object for a client and registers it with the client * manager. * - * @param clientCallback the callback interface of the client to register * @param contextHubInfo the object describing the hub this client is attached to * * @return the ContextHubClientBroker object @@ -190,7 +214,7 @@ import java.util.function.Consumer; * @throws IllegalStateException if max number of clients have already registered */ private synchronized ContextHubClientBroker createNewClientBroker( - IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) { + ContextHubInfo contextHubInfo) { if (mHostEndPointIdToClientMap.size() == MAX_CLIENT_ID + 1) { throw new IllegalStateException("Could not register client - max limit exceeded"); } @@ -200,8 +224,7 @@ import java.util.function.Consumer; for (int i = 0; i <= MAX_CLIENT_ID; i++) { if (!mHostEndPointIdToClientMap.containsKey((short) id)) { broker = new ContextHubClientBroker( - mContext, mContextHubProxy, this, contextHubInfo, (short) id, - clientCallback); + mContext, mContextHubProxy, this, contextHubInfo, (short) id); mHostEndPointIdToClientMap.put((short) id, broker); mNextHostEndpointId = (id == MAX_CLIENT_ID) ? 0 : id + 1; break; @@ -236,4 +259,22 @@ import java.util.function.Consumer; } } } + + /** + * Retrieves a ContextHubClientBroker object with a matching PendingIntent and Context Hub ID. + * + * @param pendingIntent the PendingIntent to match + * @param contextHubId the ID of the Context Hub the client is attached to + * @return the matching ContextHubClientBroker, null if not found + */ + private ContextHubClientBroker getClientBroker(PendingIntent pendingIntent, int contextHubId) { + for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) { + if (broker.hasPendingIntent(pendingIntent) + && broker.getAttachedContextHubId() == contextHubId) { + return broker; + } + } + + return null; + } } diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java index e3c2863e7c72..215e67c0884f 100644 --- a/services/core/java/com/android/server/location/ContextHubService.java +++ b/services/core/java/com/android/server/location/ContextHubService.java @@ -16,6 +16,7 @@ package com.android.server.location; +import android.app.PendingIntent; import android.content.Context; import android.hardware.contexthub.V1_0.AsyncEventType; import android.hardware.contexthub.V1_0.ContextHub; @@ -631,6 +632,37 @@ public class ContextHubService extends IContextHubService.Stub { } /** + * Recreates and binds a IContextHubClientCallback interface to an existing and registered + * client at the service for the specified Context Hub, provided a previously registered + * PendingIntent. + * + * @param pendingIntent the PendingIntent previously registered for the client + * @param clientCallback the client interface to register with the service + * @param contextHubId the ID of the hub this client is attached to + * @return the generated client interface, null if registration was unsuccessful + * + * @throws IllegalArgumentException if contextHubId is not a valid ID + * @throws NullPointerException if clientCallback or pendingIntent is null + */ + @Override + public IContextHubClient bindClient( + PendingIntent pendingIntent, IContextHubClientCallback clientCallback, + int contextHubId) throws RemoteException { + checkPermissions(); + if (!isValidContextHubId(contextHubId)) { + throw new IllegalArgumentException("Invalid context hub ID " + contextHubId); + } + if (pendingIntent == null) { + throw new NullPointerException("Cannot create client with null pending intent"); + } + if (clientCallback == null) { + throw new NullPointerException("Cannot create client with null callback"); + } + + return mClientManager.bindClient(pendingIntent, clientCallback, contextHubId); + } + + /** * Loads a nanoapp binary at the specified Context hub. * * @param contextHubId the ID of the hub to load the binary diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java index 9ad4aa190d16..f1de37188510 100644 --- a/services/core/java/com/android/server/location/GeocoderProxy.java +++ b/services/core/java/com/android/server/location/GeocoderProxy.java @@ -20,12 +20,12 @@ import android.content.Context; import android.location.Address; import android.location.GeocoderParams; import android.location.IGeocodeProvider; -import android.os.Handler; -import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.internal.os.BackgroundThread; import com.android.server.ServiceWatcher; + import java.util.List; /** @@ -36,14 +36,13 @@ public class GeocoderProxy { private static final String SERVICE_ACTION = "com.android.location.service.GeocodeProvider"; - private final Context mContext; private final ServiceWatcher mServiceWatcher; public static GeocoderProxy createAndBind(Context context, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler) { + int initialPackageNamesResId) { GeocoderProxy proxy = new GeocoderProxy(context, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, handler); + defaultServicePackageNameResId, initialPackageNamesResId); if (proxy.bind()) { return proxy; } else { @@ -53,34 +52,30 @@ public class GeocoderProxy { private GeocoderProxy(Context context, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler) { - mContext = context; - - mServiceWatcher = new ServiceWatcher(mContext, TAG, SERVICE_ACTION, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, null, handler); + int initialPackageNamesResId) { + mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId, + defaultServicePackageNameResId, initialPackageNamesResId, + BackgroundThread.getHandler()); } - private boolean bind () { + private boolean bind() { return mServiceWatcher.start(); } public String getConnectedPackageName() { - return mServiceWatcher.getBestPackageName(); + return mServiceWatcher.getCurrentPackageName(); } public String getFromLocation(double latitude, double longitude, int maxResults, GeocoderParams params, List<Address> addrs) { - final String[] result = new String[] {"Service not Available"}; - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder); - try { - result[0] = provider.getFromLocation( - latitude, longitude, maxResults, params, addrs); - } catch (RemoteException e) { - Log.w(TAG, e); - } + final String[] result = new String[]{"Service not Available"}; + mServiceWatcher.runOnBinder(binder -> { + IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder); + try { + result[0] = provider.getFromLocation( + latitude, longitude, maxResults, params, addrs); + } catch (RemoteException e) { + Log.w(TAG, e); } }); return result[0]; @@ -90,18 +85,15 @@ public class GeocoderProxy { double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude, double upperRightLongitude, int maxResults, GeocoderParams params, List<Address> addrs) { - final String[] result = new String[] {"Service not Available"}; - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder); - try { - result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude, - lowerLeftLongitude, upperRightLatitude, upperRightLongitude, - maxResults, params, addrs); - } catch (RemoteException e) { - Log.w(TAG, e); - } + final String[] result = new String[]{"Service not Available"}; + mServiceWatcher.runOnBinder(binder -> { + IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder); + try { + result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude, + lowerLeftLongitude, upperRightLatitude, upperRightLongitude, + maxResults, params, addrs); + } catch (RemoteException e) { + Log.w(TAG, e); } }); return result[0]; diff --git a/services/core/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java index eb47b2f8798c..ca4f7fee494a 100644 --- a/services/core/java/com/android/server/location/GeofenceProxy.java +++ b/services/core/java/com/android/server/location/GeofenceProxy.java @@ -15,61 +15,60 @@ */ package com.android.server.location; +import android.annotation.Nullable; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.hardware.location.GeofenceHardwareService; import android.hardware.location.IGeofenceHardware; +import android.location.IFusedGeofenceHardware; import android.location.IGeofenceProvider; import android.location.IGpsGeofenceHardware; -import android.location.IFusedGeofenceHardware; -import android.content.Context; -import android.os.Handler; import android.os.IBinder; -import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; + +import com.android.internal.os.BackgroundThread; import com.android.server.ServiceWatcher; /** * @hide */ public final class GeofenceProxy { + private static final String TAG = "GeofenceProxy"; - private static final String SERVICE_ACTION = - "com.android.location.service.GeofenceProvider"; - private final ServiceWatcher mServiceWatcher; + private static final String SERVICE_ACTION = "com.android.location.service.GeofenceProvider"; + private final Context mContext; + private final ServiceWatcher mServiceWatcher; + + @Nullable private final IGpsGeofenceHardware mGpsGeofenceHardware; + @Nullable private final IFusedGeofenceHardware mFusedGeofenceHardware; - private final Object mLock = new Object(); - - // Access to mGeofenceHardware needs to be synchronized by mLock. - private IGeofenceHardware mGeofenceHardware; - - private static final int GEOFENCE_PROVIDER_CONNECTED = 1; - private static final int GEOFENCE_HARDWARE_CONNECTED = 2; - private static final int GEOFENCE_HARDWARE_DISCONNECTED = 3; - private static final int GEOFENCE_GPS_HARDWARE_CONNECTED = 4; - private static final int GEOFENCE_GPS_HARDWARE_DISCONNECTED = 5; + private volatile IGeofenceHardware mGeofenceHardware; - private Runnable mRunnable = new Runnable() { - @Override - public void run() { - mHandler.sendEmptyMessage(GEOFENCE_PROVIDER_CONNECTED); + private final ServiceWatcher.BinderRunner mUpdateGeofenceHardware = (binder) -> { + IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder); + try { + provider.setGeofenceHardware(mGeofenceHardware); + } catch (RemoteException e) { + Log.w(TAG, e); } }; public static GeofenceProxy createAndBind(Context context, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence, - IFusedGeofenceHardware fusedGeofenceHardware) { + int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence, + @Nullable IFusedGeofenceHardware fusedGeofenceHardware) { GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence, - fusedGeofenceHardware); - if (proxy.bindGeofenceProvider()) { + defaultServicePackageNameResId, initialPackageNamesResId, gpsGeofence, + fusedGeofenceHardware); + + if (proxy.bind()) { return proxy; } else { return null; @@ -78,111 +77,56 @@ public final class GeofenceProxy { private GeofenceProxy(Context context, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence, - IFusedGeofenceHardware fusedGeofenceHardware) { + int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence, + @Nullable IFusedGeofenceHardware fusedGeofenceHardware) { mContext = context; mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler); + defaultServicePackageNameResId, initialPackageNamesResId, + BackgroundThread.getHandler()) { + @Override + protected void onBind() { + runOnBinder(mUpdateGeofenceHardware); + } + }; + mGpsGeofenceHardware = gpsGeofence; mFusedGeofenceHardware = fusedGeofenceHardware; - bindHardwareGeofence(); - } - private boolean bindGeofenceProvider() { - return mServiceWatcher.start(); + mGeofenceHardware = null; } - private void bindHardwareGeofence() { - mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class), - mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); + private boolean bind() { + if (mServiceWatcher.start()) { + mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class), + new GeofenceProxyServiceConnection(), Context.BIND_AUTO_CREATE, + UserHandle.SYSTEM); + return true; + } + + return false; } - private ServiceConnection mServiceConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - synchronized (mLock) { - mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service); - mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED); - } - } + private class GeofenceProxyServiceConnection implements ServiceConnection { @Override - public void onServiceDisconnected(ComponentName name) { - synchronized (mLock) { - mGeofenceHardware = null; - mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED); - } - } - }; + public void onServiceConnected(ComponentName name, IBinder service) { + IGeofenceHardware geofenceHardware = IGeofenceHardware.Stub.asInterface(service); - private void setGeofenceHardwareInProviderLocked() { - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - final IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder); - try { - provider.setGeofenceHardware(mGeofenceHardware); - } catch (RemoteException e) { - Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e); - } - } - }); - } + try { + geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware); + geofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware); - private void setGpsGeofenceLocked() { - try { - if (mGpsGeofenceHardware != null) { - mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware); + mGeofenceHardware = geofenceHardware; + mServiceWatcher.runOnBinder(mUpdateGeofenceHardware); + } catch (Exception e) { + Log.w(TAG, e); } - } catch (RemoteException e) { - Log.e(TAG, "Error while connecting to GeofenceHardwareService"); - } - } - - private void setFusedGeofenceLocked() { - try { - mGeofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware); - } catch(RemoteException e) { - Log.e(TAG, "Error while connecting to GeofenceHardwareService"); } - } - - // This needs to be reworked, when more services get added, - // Might need a state machine or add a framework utility class, - private Handler mHandler = new Handler() { @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case GEOFENCE_PROVIDER_CONNECTED: - synchronized (mLock) { - if (mGeofenceHardware != null) { - setGeofenceHardwareInProviderLocked(); - } - // else: the geofence provider will be notified when the connection to - // GeofenceHardwareService is established. - } - break; - case GEOFENCE_HARDWARE_CONNECTED: - synchronized (mLock) { - // Theoretically this won't happen because once the GeofenceHardwareService - // is connected to, we won't lose connection to it because it's a system - // service. But this check does make the code more robust. - if (mGeofenceHardware != null) { - setGpsGeofenceLocked(); - setFusedGeofenceLocked(); - setGeofenceHardwareInProviderLocked(); - } - } - break; - case GEOFENCE_HARDWARE_DISCONNECTED: - synchronized (mLock) { - if (mGeofenceHardware == null) { - setGeofenceHardwareInProviderLocked(); - } - } - break; - } + public void onServiceDisconnected(ComponentName name) { + mGeofenceHardware = null; + mServiceWatcher.runOnBinder(mUpdateGeofenceHardware); } - }; + } } diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index 16eae6206d2d..bb86b4852fd5 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -16,26 +16,28 @@ package com.android.server.location; -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.PrintWriter; - +import android.annotation.Nullable; import android.content.Context; import android.location.LocationProvider; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.WorkSource; import android.util.Log; -import com.android.internal.location.ProviderProperties; +import com.android.internal.annotations.GuardedBy; import com.android.internal.location.ILocationProvider; +import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; +import com.android.internal.os.BackgroundThread; import com.android.internal.os.TransferPipe; import com.android.server.LocationManagerService; import com.android.server.ServiceWatcher; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; + /** * Proxy for ILocationProvider implementations. */ @@ -43,25 +45,36 @@ public class LocationProviderProxy implements LocationProviderInterface { private static final String TAG = "LocationProviderProxy"; private static final boolean D = LocationManagerService.D; - private final Context mContext; - private final String mName; private final ServiceWatcher mServiceWatcher; - private Object mLock = new Object(); + private final String mName; + + // used to ensure that updates to mRequest and mWorkSource are atomic + private final Object mRequestLock = new Object(); + + + private volatile boolean mEnabled = false; + @Nullable + private volatile ProviderProperties mProperties; - // cached values set by the location manager, synchronized on mLock - private ProviderProperties mProperties; - private boolean mEnabled = false; - private ProviderRequest mRequest = null; - private WorkSource mWorksource = new WorkSource(); + @GuardedBy("mRequestLock") + @Nullable + private ProviderRequest mRequest; + @GuardedBy("mRequestLock") + private WorkSource mWorkSource; + /** + * Creates a new LocationProviderProxy and immediately begins binding to the best applicable + * service. + */ + @Nullable public static LocationProviderProxy createAndBind( Context context, String name, String action, int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler) { - LocationProviderProxy proxy = new LocationProviderProxy(context, name, action, - overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId, - handler); + int initialPackageNamesResId) { + LocationProviderProxy proxy = new LocationProviderProxy(context, name, + action, overlaySwitchResId, defaultServicePackageNameResId, + initialPackageNamesResId); if (proxy.bind()) { return proxy; } else { @@ -69,78 +82,66 @@ public class LocationProviderProxy implements LocationProviderInterface { } } - private LocationProviderProxy(Context context, String name, String action, - int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler) { - mContext = context; - mName = name; - mServiceWatcher = new ServiceWatcher(mContext, TAG + "-" + name, action, overlaySwitchResId, + private LocationProviderProxy(Context context, String name, + String action, int overlaySwitchResId, int defaultServicePackageNameResId, + int initialPackageNamesResId) { + + mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId, - mNewServiceWork, handler); + BackgroundThread.getHandler()) { + @Override + protected void onBind() { + runOnBinder(LocationProviderProxy.this::initializeService); + } + }; + mName = name; + + mProperties = null; + mRequest = null; + mWorkSource = new WorkSource(); } - private boolean bind () { + private boolean bind() { return mServiceWatcher.start(); } - public String getConnectedPackageName() { - return mServiceWatcher.getBestPackageName(); - } + private void initializeService(IBinder binder) { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + if (D) Log.d(TAG, "applying state to connected service"); - /** - * Work to apply current state to a newly connected provider. - * Remember we can switch the service that implements a providers - * at run-time, so need to apply current state. - */ - private Runnable mNewServiceWork = new Runnable() { - @Override - public void run() { - if (D) Log.d(TAG, "applying state to connected service"); - - boolean enabled; - final ProviderProperties[] properties = new ProviderProperties[1]; - ProviderRequest request; - WorkSource source; - synchronized (mLock) { - enabled = mEnabled; - request = mRequest; - source = mWorksource; - } + ProviderProperties[] properties = new ProviderProperties[1]; + ProviderRequest request; + WorkSource source; + synchronized (mRequestLock) { + request = mRequest; + source = mWorkSource; + } + try { + // load properties from provider + properties[0] = service.getProperties(); + if (properties[0] == null) { + Log.e(TAG, mServiceWatcher.getCurrentPackageName() + + " has invalid location provider properties"); + } - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - // load properties from provider - properties[0] = service.getProperties(); - if (properties[0] == null) { - Log.e(TAG, mServiceWatcher.getBestPackageName() + - " has invalid location provider properties"); - } - - // apply current state to new service - if (enabled) { - service.enable(); - if (request != null) { - service.setRequest(request, source); - } - } - } catch (RemoteException e) { - Log.w(TAG, e); - } catch (Exception e) { - // never let remote service crash system server - Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); - } + // apply current state to new service + if (mEnabled) { + service.enable(); + if (request != null) { + service.setRequest(request, source); } - }); - - synchronized (mLock) { - mProperties = properties[0]; } + } catch (RemoteException e) { + Log.w(TAG, e); } - }; + + mProperties = properties[0]; + } + + public String getConnectedPackageName() { + return mServiceWatcher.getCurrentPackageName(); + } @Override public String getName() { @@ -149,78 +150,52 @@ public class LocationProviderProxy implements LocationProviderInterface { @Override public ProviderProperties getProperties() { - synchronized (mLock) { - return mProperties; - } + return mProperties; } @Override public void enable() { - synchronized (mLock) { - mEnabled = true; - } - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - service.enable(); - } catch (RemoteException e) { - Log.w(TAG, e); - } catch (Exception e) { - // never let remote service crash system server - Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); - } + mEnabled = true; + mServiceWatcher.runOnBinder(binder -> { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + try { + service.enable(); + } catch (RemoteException e) { + Log.w(TAG, e); } }); } @Override public void disable() { - synchronized (mLock) { - mEnabled = false; - } - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - service.disable(); - } catch (RemoteException e) { - Log.w(TAG, e); - } catch (Exception e) { - // never let remote service crash system server - Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); - } + mEnabled = false; + mServiceWatcher.runOnBinder(binder -> { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + try { + service.disable(); + } catch (RemoteException e) { + Log.w(TAG, e); } }); } @Override public boolean isEnabled() { - synchronized (mLock) { - return mEnabled; - } + return mEnabled; } @Override public void setRequest(ProviderRequest request, WorkSource source) { - synchronized (mLock) { + synchronized (mRequestLock) { mRequest = request; - mWorksource = source; + mWorkSource = source; } - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - service.setRequest(request, source); - } catch (RemoteException e) { - Log.w(TAG, e); - } catch (Exception e) { - // never let remote service crash system server - Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); - } + mServiceWatcher.runOnBinder(binder -> { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + try { + service.setRequest(request, source); + } catch (RemoteException e) { + Log.w(TAG, e); } }); } @@ -229,39 +204,28 @@ public class LocationProviderProxy implements LocationProviderInterface { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.append("REMOTE SERVICE"); pw.append(" name=").append(mName); - pw.append(" pkg=").append(mServiceWatcher.getBestPackageName()); - pw.append(" version=").append("" + mServiceWatcher.getBestVersion()); + pw.append(" pkg=").append(mServiceWatcher.getCurrentPackageName()); + pw.append(" version=").append(Integer.toString(mServiceWatcher.getCurrentPackageVersion())); pw.append('\n'); - if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - TransferPipe.dumpAsync(service.asBinder(), fd, args); - } catch (IOException | RemoteException e) { - pw.println("Failed to dump location provider: " + e); - } + mServiceWatcher.runOnBinder(binder -> { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + try { + TransferPipe.dumpAsync(service.asBinder(), fd, args); + } catch (IOException | RemoteException e) { + pw.println("Failed to dump location provider: " + e); } - })) { - pw.println("service down (null)"); - } + }); } @Override public int getStatus(Bundle extras) { - final int[] result = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE}; - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - result[0] = service.getStatus(extras); - } catch (RemoteException e) { - Log.w(TAG, e); - } catch (Exception e) { - // never let remote service crash system server - Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); - } + int[] result = new int[]{LocationProvider.TEMPORARILY_UNAVAILABLE}; + mServiceWatcher.runOnBinder(binder -> { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + try { + result[0] = service.getStatus(extras); + } catch (RemoteException e) { + Log.w(TAG, e); } }); return result[0]; @@ -269,19 +233,13 @@ public class LocationProviderProxy implements LocationProviderInterface { @Override public long getStatusUpdateTime() { - final long[] result = new long[] {0L}; - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - result[0] = service.getStatusUpdateTime(); - } catch (RemoteException e) { - Log.w(TAG, e); - } catch (Exception e) { - // never let remote service crash system server - Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); - } + long[] result = new long[]{0L}; + mServiceWatcher.runOnBinder(binder -> { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + try { + result[0] = service.getStatusUpdateTime(); + } catch (RemoteException e) { + Log.w(TAG, e); } }); return result[0]; @@ -289,21 +247,15 @@ public class LocationProviderProxy implements LocationProviderInterface { @Override public boolean sendExtraCommand(String command, Bundle extras) { - final boolean[] result = new boolean[] {false}; - mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() { - @Override - public void run(IBinder binder) { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - result[0] = service.sendExtraCommand(command, extras); - } catch (RemoteException e) { - Log.w(TAG, e); - } catch (Exception e) { - // never let remote service crash system server - Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e); - } + boolean[] result = new boolean[]{false}; + mServiceWatcher.runOnBinder(binder -> { + ILocationProvider service = ILocationProvider.Stub.asInterface(binder); + try { + result[0] = service.sendExtraCommand(command, extras); + } catch (RemoteException e) { + Log.w(TAG, e); } }); return result[0]; } - } +} diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java index 29b1339e8022..fa90e9055f04 100644 --- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java +++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java @@ -142,8 +142,8 @@ public class NetworkWatchlistService extends INetworkWatchlistManager.Stub { private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() { @Override - public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount, - long timestamp, int uid) { + public void onDnsEvent(int netId, int eventType, int returnCode, String hostname, + String[] ipAddresses, int ipAddressesCount, long timestamp, int uid) { if (!mIsLoggingEnabled) { return; } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index fc9bd37a0f80..f279af03753e 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -96,7 +96,7 @@ public class ZenModeHelper { private final SettingsObserver mSettingsObserver; @VisibleForTesting protected final AppOpsManager mAppOps; @VisibleForTesting protected final NotificationManager mNotificationManager; - protected ZenModeConfig mDefaultConfig; + @VisibleForTesting protected ZenModeConfig mDefaultConfig; private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); private final ZenModeFiltering mFiltering; protected final RingerModeDelegate mRingerModeDelegate = new @@ -309,9 +309,6 @@ public class ZenModeHelper { newConfig = mConfig.copy(); ZenRule rule = new ZenRule(); populateZenRule(automaticZenRule, rule, true); - if (newConfig.automaticRules.put(rule.id, rule) != null) { - rule.modified = true; - } if (setConfigLocked(newConfig, reason, rule.component, true)) { return rule.id; } else { @@ -341,9 +338,6 @@ public class ZenModeHelper { } } populateZenRule(automaticZenRule, rule, false); - if (newConfig.automaticRules.put(ruleId, rule) != null) { - rule.modified = true; - } return setConfigLocked(newConfig, reason, rule.component, true); } } @@ -431,13 +425,16 @@ public class ZenModeHelper { updateDefaultAutomaticRuleNames(); for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) { ZenRule currRule = mConfig.automaticRules.get(defaultRule.id); - // if default rule wasn't modified, use localized name instead of previous - if (currRule != null && !currRule.modified && !defaultRule.name.equals(currRule.name)) { - if (canManageAutomaticZenRule(defaultRule)) { + // if default rule wasn't user-modified nor enabled, use localized name + // instead of previous system name + if (currRule != null && !currRule.modified && !currRule.enabled + && !defaultRule.name.equals(currRule.name)) { + if (canManageAutomaticZenRule(currRule)) { if (DEBUG) Slog.d(TAG, "Locale change - updating default zen rule name " + "from " + currRule.name + " to " + defaultRule.name); // update default rule (if locale changed, name of rule will change) - updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(defaultRule), + currRule.name = defaultRule.name; + updateAutomaticZenRule(defaultRule.id, createAutomaticZenRule(currRule), "locale changed"); } } @@ -481,6 +478,7 @@ public class ZenModeHelper { rule.condition = null; rule.conditionId = automaticZenRule.getConditionId(); rule.enabled = automaticZenRule.isEnabled(); + rule.modified = automaticZenRule.isModified(); if (automaticZenRule.getZenPolicy() != null) { rule.zenPolicy = automaticZenRule.getZenPolicy(); } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 404f152bb8d1..275f3dcdb6d2 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -77,7 +77,6 @@ import java.util.List; */ public class LauncherAppsService extends SystemService { - private static final boolean SHOW_HIDDEN_APP_ENABLED = false; private final LauncherAppsImpl mLauncherAppsImpl; public LauncherAppsService(Context context) { @@ -310,22 +309,28 @@ public class LauncherAppsService extends SystemService { .addCategory(Intent.CATEGORY_LAUNCHER) .setPackage(packageName), user); - if (!SHOW_HIDDEN_APP_ENABLED) { + if (Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 0) == 0) { return launcherActivities; } final int callingUid = injectBinderCallingUid(); final ArrayList<ResolveInfo> result = new ArrayList<>(launcherActivities.getList()); + final PackageManagerInternal pmInt = + LocalServices.getService(PackageManagerInternal.class); if (packageName != null) { - // If target package has launcher activities, then return those launcher - // activities. Otherwise, return hidden activity that forwards user to app - // details page. + // If this hidden app should not be shown, return the original list. + // Otherwise, inject hidden activity that forwards user to app details page. if (result.size() > 0) { return launcherActivities; } - ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user); - if (info != null) { - result.add(info); + ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName, /*flags*/ 0, + callingUid, user.getIdentifier()); + if (shouldShowHiddenApp(appInfo)) { + ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user); + if (info != null) { + result.add(info); + } } return new ParceledListSlice<>(result); } @@ -336,8 +341,6 @@ public class LauncherAppsService extends SystemService { for (ResolveInfo info : result) { visiblePackages.add(info.activityInfo.packageName); } - final PackageManagerInternal pmInt = - LocalServices.getService(PackageManagerInternal.class); List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(0, user.getIdentifier(), callingUid); for (ApplicationInfo applicationInfo : installedPackages) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 0b32d1a5d69b..6ccd0406bfcc 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -58,7 +58,6 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SELinux; -import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; @@ -646,8 +645,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } try { - Os.mkdir(stageDir.getAbsolutePath(), 0755); - Os.chmod(stageDir.getAbsolutePath(), 0755); + Os.mkdir(stageDir.getAbsolutePath(), 0775); + Os.chmod(stageDir.getAbsolutePath(), 0775); } catch (ErrnoException e) { // This purposefully throws if directory already exists throw new IOException("Failed to prepare session dir: " + stageDir, e); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 51225a77b005..249edab2be94 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -43,6 +43,7 @@ import static com.android.server.pm.PackageInstallerService.prepareStageDir; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.apex.IApexService; import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; @@ -75,6 +76,7 @@ import android.os.ParcelableException; import android.os.Process; import android.os.RemoteException; import android.os.RevocableFileDescriptor; +import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.storage.StorageManager; @@ -838,12 +840,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { resolveStageDirLocked(); mSealed = true; - - // Verify that stage looks sane with respect to existing application. - // This currently only ensures packageName, versionCode, and certificate - // consistency. try { - validateInstallLocked(pkgInfo); + if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { + validateApexInstallLocked(pkgInfo); + } else { + // Verify that stage looks sane with respect to existing application. + // This currently only ensures packageName, versionCode, and certificate + // consistency. + validateApkInstallLocked(pkgInfo); + } } catch (PackageManagerException e) { throw e; } catch (Throwable e) { @@ -926,6 +931,31 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Preconditions.checkNotNull(mSigningDetails); Preconditions.checkNotNull(mResolvedBaseFile); + if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { + commitApexLocked(); + } else { + commitApkLocked(); + } + } + + @GuardedBy("mLock") + private void commitApexLocked() throws PackageManagerException { + try { + IApexService apex = IApexService.Stub.asInterface( + ServiceManager.getService("apexservice")); + apex.stagePackage(mResolvedBaseFile.toString()); + } catch (Throwable e) { + // Convert all exceptions into package manager exceptions as only those are handled + // in the code above + throw new PackageManagerException(e); + } finally { + destroyInternal(); + dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "APEX installed", null); + } + } + + @GuardedBy("mLock") + private void commitApkLocked() throws PackageManagerException { if (needToAskForPermissionsLocked()) { // User needs to confirm installation; give installer an intent they can use to involve // user. @@ -1047,6 +1077,57 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { (params.installFlags & PackageManager.DONT_KILL_APP) != 0; } + @GuardedBy("mLock") + private void validateApexInstallLocked(@Nullable PackageInfo pkgInfo) + throws PackageManagerException { + mResolvedStagedFiles.clear(); + mResolvedInheritedFiles.clear(); + + try { + resolveStageDirLocked(); + } catch (IOException e) { + throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR, + "Failed to resolve stage location", e); + } + + final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter); + if (ArrayUtils.isEmpty(addedFiles)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); + } + + if (addedFiles.length > 1) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Only one APEX file at a time might be installed"); + } + File addedFile = addedFiles[0]; + final ApkLite apk; + try { + apk = PackageParser.parseApkLite( + addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES); + } catch (PackageParserException e) { + throw PackageManagerException.from(e); + } + + mPackageName = apk.packageName; + mVersionCode = apk.getLongVersionCode(); + mSigningDetails = apk.signingDetails; + mResolvedBaseFile = addedFile; + + assertApkConsistentLocked(String.valueOf(addedFile), apk); + + if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) { + try { + // STOPSHIP: For APEX we should also implement proper APK Signature verification. + mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts( + pkgInfo.applicationInfo.sourceDir, + PackageParser.SigningDetails.SignatureSchemeVersion.JAR); + } catch (PackageParserException e) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Couldn't obtain signatures from base APK"); + } + } + } + /** * Validate install by confirming that all application packages are have * consistent package name, version code, and signing certificates. @@ -1060,7 +1141,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * {@link PackageManagerService}. */ @GuardedBy("mLock") - private void validateInstallLocked(@Nullable PackageInfo pkgInfo) + private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo) throws PackageManagerException { ApkLite baseApk = null; mPackageName = null; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9210d46c1476..ed3e8577a5b4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -85,6 +85,11 @@ import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageParser.isApkFile; +import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE; +import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER; +import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; +import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK; +import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.os.storage.StorageManager.FLAG_STORAGE_CE; import static android.os.storage.StorageManager.FLAG_STORAGE_DE; @@ -366,6 +371,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; import java.util.function.Predicate; /** @@ -2090,6 +2096,28 @@ public class PackageManagerService extends IPackageManager.Stub } } + @GuardedBy("mPackages") + private void setupBuiltinSharedLibraryDependenciesLocked() { + // Builtin libraries don't have versions. + long version = SharedLibraryInfo.VERSION_UNDEFINED; + + SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ANDROID_HIDL_MANAGER, version); + if (libraryInfo != null) { + libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_HIDL_BASE, version)); + } + + libraryInfo = getSharedLibraryInfoLPr(ANDROID_TEST_RUNNER, version); + if (libraryInfo != null) { + libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_MOCK, version)); + libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_BASE, version)); + } + + libraryInfo = getSharedLibraryInfoLPr(ANDROID_TEST_MOCK, version); + if (libraryInfo != null) { + libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_BASE, version)); + } + } + public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES); @@ -2205,6 +2233,9 @@ public class PackageManagerService extends IPackageManager.Stub addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED, SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0); } + // Builtin libraries cannot encode their dependency where they are + // defined, so fix that now. + setupBuiltinSharedLibraryDependenciesLocked(); SELinuxMMAC.readInstallPolicy(); @@ -4867,7 +4898,10 @@ public class PackageManagerService extends IPackageManager.Stub SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(), libInfo.getPackageName(), libInfo.getName(), libInfo.getLongVersion(), libInfo.getType(), libInfo.getDeclaringPackage(), - getPackagesUsingSharedLibraryLPr(libInfo, flags, userId)); + getPackagesUsingSharedLibraryLPr(libInfo, flags, userId), + (libInfo.getDependencies() == null + ? null + : new ArrayList(libInfo.getDependencies()))); if (result == null) { result = new ArrayList<>(); @@ -9598,16 +9632,34 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mPackages") - private void addSharedLibraryLPr(Set<String> usesLibraryFiles, - SharedLibraryInfo file, - PackageParser.Package changingLib) { + private void applyDefiningSharedLibraryUpdateLocked( + PackageParser.Package pkg, SharedLibraryInfo libInfo, + BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) { + if (pkg.isLibrary()) { + if (pkg.staticSharedLibName != null) { + SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( + pkg.staticSharedLibName, pkg.staticSharedLibVersion); + action.accept(definedLibrary, libInfo); + } else { + for (String libraryName : pkg.libraryNames) { + SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( + libraryName, SharedLibraryInfo.VERSION_UNDEFINED); + action.accept(definedLibrary, libInfo); + } + } + } + } + + @GuardedBy("mPackages") + private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles, + SharedLibraryInfo libInfo, PackageParser.Package changingLib) { - if (file.getPath() != null) { - usesLibraryFiles.add(file.getPath()); + if (libInfo.getPath() != null) { + usesLibraryFiles.add(libInfo.getPath()); return; } - PackageParser.Package p = mPackages.get(file.getPackageName()); - if (changingLib != null && changingLib.packageName.equals(file.getPackageName())) { + PackageParser.Package p = mPackages.get(libInfo.getPackageName()); + if (changingLib != null && changingLib.packageName.equals(libInfo.getPackageName())) { // If we are doing this while in the middle of updating a library apk, // then we need to make sure to use that new apk for determining the // dependencies here. (We haven't yet finished committing the new apk @@ -9618,6 +9670,10 @@ public class PackageManagerService extends IPackageManager.Stub } if (p != null) { usesLibraryFiles.addAll(p.getAllCodePaths()); + // If the package provides libraries, add the dependency to them. + applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> { + definingLibrary.addDependency(dependency); + }); if (p.usesLibraryFiles != null) { Collections.addAll(usesLibraryFiles, p.usesLibraryFiles); } @@ -9630,6 +9686,12 @@ public class PackageManagerService extends IPackageManager.Stub if (pkg == null) { return; } + + // If the package provides libraries, clear their old dependencies. + // This method will set them up again. + applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> { + definingLibrary.clearDependencies(); + }); // The collection used here must maintain the order of addition (so // that libraries are searched in the correct order) and must have no // duplicates. @@ -9656,7 +9718,7 @@ public class PackageManagerService extends IPackageManager.Stub // usesLibraryFiles while eliminating duplicates. Set<String> usesLibraryFiles = new LinkedHashSet<>(); for (SharedLibraryInfo libInfo : usesLibraryInfos) { - addSharedLibraryLPr(usesLibraryFiles, libInfo, changingLib); + addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib); } pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]); } else { @@ -11201,7 +11263,7 @@ public class PackageManagerService extends IPackageManager.Stub } SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, apk, name, version, type, new VersionedPackage(declaringPackageName, declaringVersionCode), - null); + null, null); versionedLib.put(version, libraryInfo); return true; } @@ -12067,8 +12129,7 @@ public class PackageManagerService extends IPackageManager.Stub void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) { mComponentResolver.removeAllComponents(pkg, chatty); - final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet()); - mPermissionManager.removeAllPermissions(pkg, allPackageNames, mPermissionCallback, chatty); + mPermissionManager.removeAllPermissions(pkg, chatty); final int instrumentationSize = pkg.instrumentation.size(); StringBuilder r = null; @@ -15153,14 +15214,8 @@ public class PackageManagerService extends IPackageManager.Stub pkgList.add(oldPackage.applicationInfo.packageName); sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null); } - - clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE - | StorageManager.FLAG_STORAGE_CE - | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); } - - // Update the in-memory copy of the previous code paths. PackageSetting ps1 = mSettings.mPackages.get( reconciledPkg.prepareResult.existingPackage.packageName); @@ -15364,7 +15419,8 @@ public class PackageManagerService extends IPackageManager.Stub /** * On successful install, executes remaining steps after commit completes and the package lock - * is released. + * is released. These are typically more expensive or require calls to installd, which often + * locks on {@link #mPackages}. */ private void executePostCommitSteps(CommitRequest commitRequest) { for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) { @@ -16093,7 +16149,6 @@ public class PackageManagerService extends IPackageManager.Stub try { final PackageParser.Package existingPackage; String renamedPackage = null; - boolean clearCodeCache = false; boolean sysPkg = false; String targetVolumeUuid = volumeUuid; int targetScanFlags = scanFlags; @@ -16314,7 +16369,6 @@ public class PackageManagerService extends IPackageManager.Stub Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg + ", old=" + oldPackage); } - clearCodeCache = true; res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, ApplicationInfo.FLAG_UPDATED_SYSTEM_APP); @@ -16370,7 +16424,7 @@ public class PackageManagerService extends IPackageManager.Stub shouldCloseFreezerBeforeReturn = false; return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName, args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg, - clearCodeCache, sysPkg, renamedPackage, freezer); + replace /* clearCodeCache */, sysPkg, renamedPackage, freezer); } finally { if (shouldCloseFreezerBeforeReturn) { freezer.close(); diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index e25cca43e8da..38bd1722e61f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -920,7 +920,10 @@ class PackageManagerShellCommand extends ShellCommand { pw.println("Error: must either specify a package size or an APK file"); return 1; } - if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk", + final boolean isApex = + (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0; + String splitName = "base." + (isApex ? "apex" : "apk"); + if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { return 1; } @@ -2262,6 +2265,9 @@ class PackageManagerShellCommand extends ShellCommand { case "--force-sdk": sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK; break; + case "--apex": + sessionParams.installFlags |= PackageManager.INSTALL_APEX; + break; default: throw new IllegalArgumentException("Unknown option " + opt); } diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 392d4d839c45..753c2833b056 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -30,6 +30,7 @@ import android.os.storage.StorageManager; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings.Global; +import android.util.Log; import android.util.Slog; import android.util.jar.StrictJarFile; @@ -74,7 +75,7 @@ public class DexManager { private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST = "pm.dexopt.priv-apps-oob-list"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final Context mContext; @@ -192,6 +193,16 @@ public class DexManager { String[] classLoaderContexts = DexoptUtils.processContextForDexLoad( classLoaderNames, classPaths); + // A null classLoaderContexts means that there are unsupported class loaders in the + // chain. + if (classLoaderContexts == null) { + if (DEBUG) { + Slog.i(TAG, loadingAppInfo.packageName + + " uses unsupported class loader in " + classLoaderNames); + } + return; + } + int dexPathIndex = 0; for (String dexPath : dexPathsToRegister) { // Find the owning package name. @@ -219,14 +230,10 @@ public class DexManager { } // Record dex file usage. If the current usage is a new pattern (e.g. new secondary, - // or UsedBytOtherApps), record will return true and we trigger an async write + // or UsedByOtherApps), record will return true and we trigger an async write // to disk to make sure we don't loose the data in case of a reboot. - // A null classLoaderContexts means that there are unsupported class loaders in the - // chain. - String classLoaderContext = classLoaderContexts == null - ? PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT - : classLoaderContexts[dexPathIndex]; + String classLoaderContext = classLoaderContexts[dexPathIndex]; if (mPackageDexUsage.record(searchResult.mOwningPackageName, dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit, loadingAppInfo.packageName, classLoaderContext)) { diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java index 602ce3b2a0c1..86f7380e331b 100644 --- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java +++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java @@ -21,6 +21,7 @@ import android.util.Slog; import android.os.Build; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FastPrintWriter; import com.android.server.pm.AbstractStatsBase; import com.android.server.pm.PackageManagerServiceUtils; @@ -78,14 +79,16 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { // skip optimizations on that dex files. /*package*/ static final String VARIABLE_CLASS_LOADER_CONTEXT = "=VariableClassLoaderContext="; - // The marker used for unsupported class loader contexts. - /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT = - "=UnsupportedClassLoaderContext="; // The markers used for unknown class loader contexts. This can happen if the dex file was // recorded in a previous version and we didn't have a chance to update its usage. /*package*/ static final String UNKNOWN_CLASS_LOADER_CONTEXT = "=UnknownClassLoaderContext="; + // The marker used for unsupported class loader contexts (no longer written, may occur in old + // files so discarded on read). + private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT = + "=UnsupportedClassLoaderContext="; + // Map which structures the information we have on a package. // Maps package name to package data (which stores info about UsedByOtherApps and // secondary dex files.). @@ -365,6 +368,12 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { Set<String> loadingPackages = maybeReadLoadingPackages(in, version); String classLoaderContext = maybeReadClassLoaderContext(in, version); + if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(classLoaderContext)) { + // We used to record use of unsupported class loaders, but we no longer do. + // Discard such entries; they will be deleted when we next write the file. + continue; + } + int ownerUserId = Integer.parseInt(elems[0]); boolean isUsedByOtherApps = readBoolean(elems[1]); DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId, @@ -709,13 +718,13 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { // the compiled code will be private. private boolean mUsedByOtherAppsBeforeUpgrade; - public PackageUseInfo() { + /*package*/ PackageUseInfo() { mCodePathsUsedByOtherApps = new HashMap<>(); mDexUseInfoMap = new HashMap<>(); } // Creates a deep copy of the `other`. - public PackageUseInfo(PackageUseInfo other) { + private PackageUseInfo(PackageUseInfo other) { mCodePathsUsedByOtherApps = new HashMap<>(); for (Map.Entry<String, Set<String>> e : other.mCodePathsUsedByOtherApps.entrySet()) { mCodePathsUsedByOtherApps.put(e.getKey(), new HashSet<>(e.getValue())); @@ -796,8 +805,9 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { // Packages who load this dex file. private final Set<String> mLoadingPackages; - public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String classLoaderContext, - String loaderIsa) { + @VisibleForTesting + /* package */ DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, + String classLoaderContext, String loaderIsa) { mIsUsedByOtherApps = isUsedByOtherApps; mOwnerUserId = ownerUserId; mClassLoaderContext = classLoaderContext; @@ -809,7 +819,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } // Creates a deep copy of the `other`. - public DexUseInfo(DexUseInfo other) { + private DexUseInfo(DexUseInfo other) { mIsUsedByOtherApps = other.mIsUsedByOtherApps; mOwnerUserId = other.mOwnerUserId; mClassLoaderContext = other.mClassLoaderContext; @@ -827,11 +837,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) { // Can happen if we read a previous version. mClassLoaderContext = dexUseInfo.mClassLoaderContext; - } else if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(dexUseInfo.mClassLoaderContext)) { - // We detected an unsupported context. - mClassLoaderContext = UNSUPPORTED_CLASS_LOADER_CONTEXT; - } else if (!UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext) && - !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) { + } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) { // We detected a context change. mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT; } @@ -846,7 +852,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { return mIsUsedByOtherApps; } - public int getOwnerUserId() { + /* package */ int getOwnerUserId() { return mOwnerUserId; } @@ -860,17 +866,15 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { public String getClassLoaderContext() { return mClassLoaderContext; } - public boolean isUnsupportedClassLoaderContext() { - return UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext); - } - - public boolean isUnknownClassLoaderContext() { + @VisibleForTesting + /* package */ boolean isUnknownClassLoaderContext() { // The class loader context may be unknown if we loaded the data from a previous version // which didn't save the context. return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext); } - public boolean isVariableClassLoaderContext() { + @VisibleForTesting + /* package */ boolean isVariableClassLoaderContext() { return VARIABLE_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext); } } diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 45cb477cb4f3..9d1a30107d35 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -40,7 +40,6 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.media.RingtoneManager; import android.net.Uri; -import android.os.Binder; import android.os.Build; import android.os.Environment; import android.os.Handler; @@ -344,40 +343,43 @@ public final class DefaultPermissionGrantPolicy { @SafeVarargs private final void grantIgnoringSystemPackage(String packageName, int userId, Set<String>... permissionGroups) { - grantPermissionsToSystemPackage(packageName, userId, false, true, permissionGroups); + grantPermissionsToPackage( + packageName, userId, true /* ignoreSystemPackage */, permissionGroups); } @SafeVarargs private final void grantSystemFixedPermissionsToSystemPackage(String packageName, int userId, Set<String>... permissionGroups) { - grantPermissionsToSystemPackage(packageName, userId, true, false, permissionGroups); + grantPermissionsToSystemPackage( + packageName, userId, true /* systemFixed */, permissionGroups); } @SafeVarargs private final void grantPermissionsToSystemPackage( String packageName, int userId, Set<String>... permissionGroups) { - grantPermissionsToSystemPackage(packageName, userId, false, false, permissionGroups); + grantPermissionsToSystemPackage( + packageName, userId, false /* systemFixed */, permissionGroups); } @SafeVarargs private final void grantPermissionsToSystemPackage(String packageName, int userId, - boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) { - if (!ignoreSystemPackage && !isSystemPackage(packageName)) { + boolean systemFixed, Set<String>... permissionGroups) { + if (!isSystemPackage(packageName)) { return; } - grantRuntimePermissionsToPackage(getSystemPackageInfo(packageName), - userId, systemFixed, ignoreSystemPackage, permissionGroups); + grantPermissionsToPackage(getSystemPackageInfo(packageName), + userId, systemFixed, false /* ignoreSystemPackage */, permissionGroups); } @SafeVarargs - private final void grantRuntimePermissionsToPackage(String packageName, int userId, - boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) { - grantRuntimePermissionsToPackage(getPackageInfo(packageName), - userId, systemFixed, ignoreSystemPackage, permissionGroups); + private final void grantPermissionsToPackage(String packageName, int userId, + boolean ignoreSystemPackage, Set<String>... permissionGroups) { + grantPermissionsToPackage(getPackageInfo(packageName), + userId, false /* systemFixed */, ignoreSystemPackage, permissionGroups); } @SafeVarargs - private final void grantRuntimePermissionsToPackage(PackageInfo packageName, int userId, + private final void grantPermissionsToPackage(PackageInfo packageName, int userId, boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) { if (packageName == null) return; if (doesPackageSupportRuntimePermissions(packageName)) { @@ -589,9 +591,8 @@ public final class DefaultPermissionGrantPolicy { browserPackage = null; } } - grantRuntimePermissionsToPackage(browserPackage, userId, - false /* systemFixed */, false /* ignoreSystemPackage */, - LOCATION_PERMISSIONS); + grantPermissionsToPackage(browserPackage, userId, + false /* ignoreSystemPackage */, LOCATION_PERMISSIONS); // Voice interaction if (voiceInteractPackageNames != null) { @@ -786,7 +787,7 @@ public final class DefaultPermissionGrantPolicy { return; } Log.i(TAG, "Granting permissions to sim call manager for user:" + userId); - grantRuntimePermissionsToPackage(packageName, userId, false, false, + grantPermissionsToPackage(packageName, userId, false /* ignoreSystemPackage */, PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS); } @@ -878,9 +879,8 @@ public final class DefaultPermissionGrantPolicy { } private String getDefaultSystemHandlerActivityPackage(Intent intent, int userId) { - ResolveInfo handler = mServiceInternal.resolveIntent(intent, - intent.resolveType(mContext.getContentResolver()), DEFAULT_INTENT_QUERY_FLAGS, - userId, false, Binder.getCallingUid()); + ResolveInfo handler = mContext.getPackageManager().resolveActivityAsUser( + intent, DEFAULT_INTENT_QUERY_FLAGS, userId); if (handler == null || handler.activityInfo == null) { return null; } @@ -897,8 +897,8 @@ public final class DefaultPermissionGrantPolicy { private String getDefaultSystemHandlerServicePackage( Intent intent, int userId) { - List<ResolveInfo> handlers = mServiceInternal.queryIntentServices( - intent, DEFAULT_INTENT_QUERY_FLAGS, Binder.getCallingUid(), userId); + List<ResolveInfo> handlers = mContext.getPackageManager().queryIntentServicesAsUser( + intent, DEFAULT_INTENT_QUERY_FLAGS, userId); if (handlers == null) { return null; } @@ -922,10 +922,8 @@ public final class DefaultPermissionGrantPolicy { for (String syncAdapterPackageName : syncAdapterPackageNames) { homeIntent.setPackage(syncAdapterPackageName); - ResolveInfo homeActivity = mServiceInternal.resolveIntent(homeIntent, - homeIntent.resolveType(mContext.getContentResolver()), - DEFAULT_INTENT_QUERY_FLAGS, - userId, false, Binder.getCallingUid()); + ResolveInfo homeActivity = mContext.getPackageManager().resolveActivityAsUser( + homeIntent, DEFAULT_INTENT_QUERY_FLAGS, userId); if (homeActivity != null) { continue; } @@ -939,7 +937,7 @@ public final class DefaultPermissionGrantPolicy { } private String getDefaultProviderAuthorityPackage(String authority, int userId) { - ProviderInfo provider = mServiceInternal.resolveContentProvider( + ProviderInfo provider = mContext.getPackageManager().resolveContentProviderAsUser( authority, DEFAULT_INTENT_QUERY_FLAGS, userId); if (provider != null) { return provider.packageName; @@ -978,8 +976,9 @@ public final class DefaultPermissionGrantPolicy { continue; } - final int flags = mServiceInternal.getPermissionFlagsTEMP( - permission, packageName, userId); + UserHandle user = UserHandle.of(userId); + final int flags = mContext.getPackageManager() + .getPermissionFlags(permission, packageName, user); // We didn't get this through the default grant policy. Move along. if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) == 0) { @@ -995,7 +994,7 @@ public final class DefaultPermissionGrantPolicy { if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0 && !systemFixed) { continue; } - mServiceInternal.revokeRuntimePermission(packageName, permission, userId, false); + mContext.getPackageManager().revokeRuntimePermission(packageName, permission, user); if (DEBUG) { Log.i(TAG, "revoked " + (systemFixed ? "fixed " : "not fixed ") @@ -1005,8 +1004,8 @@ public final class DefaultPermissionGrantPolicy { // Remove the GRANTED_BY_DEFAULT flag without touching the others. // Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains // sticky once set. - mServiceInternal.updatePermissionFlagsTEMP(permission, packageName, - PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, userId); + mContext.getPackageManager().updatePermissionFlags(permission, packageName, + PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, 0, user); } } @@ -1075,8 +1074,9 @@ public final class DefaultPermissionGrantPolicy { } if (permissions.contains(permission)) { - final int flags = mServiceInternal.getPermissionFlagsTEMP( - permission, pkg.packageName, userId); + UserHandle user = UserHandle.of(userId); + final int flags = mContext.getPackageManager().getPermissionFlags( + permission, pkg.packageName, user); // If any flags are set to the permission, then it is either set in // its current state by the system or device/profile owner or the user. @@ -1092,8 +1092,8 @@ public final class DefaultPermissionGrantPolicy { continue; } - mServiceInternal.grantRuntimePermission( - pkg.packageName, permission, userId, false); + mContext.getPackageManager() + .grantRuntimePermission(pkg.packageName, permission, user); if (DEBUG) { Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ") + permission + " to default handler " + pkg); @@ -1104,8 +1104,8 @@ public final class DefaultPermissionGrantPolicy { newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; } - mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName, - newFlags, newFlags, userId); + mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName, + newFlags, newFlags, user); } // If a component gets a permission for being the default handler A @@ -1117,8 +1117,8 @@ public final class DefaultPermissionGrantPolicy { Log.i(TAG, "Granted not fixed " + permission + " to default handler " + pkg); } - mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName, - PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId); + mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName, + PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, user); } } } @@ -1135,10 +1135,12 @@ public final class DefaultPermissionGrantPolicy { private PackageInfo getPackageInfo(String pkg, @PackageManager.PackageInfoFlags int extraFlags) { - return mServiceInternal.getPackageInfo(pkg, - DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags, - //TODO is this the right filterCallingUid? - UserHandle.USER_SYSTEM, UserHandle.USER_SYSTEM); + try { + return mContext.getPackageManager().getPackageInfo(pkg, + DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags); + } catch (NameNotFoundException e) { + return null; + } } private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageInfo pkg) { diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS index ffc4731feadd..88b97ea2cb49 100644 --- a/services/core/java/com/android/server/pm/permission/OWNERS +++ b/services/core/java/com/android/server/pm/permission/OWNERS @@ -1,8 +1,9 @@ per-file DefaultPermissionGrantPolicy.java = bpoiesz@google.com -per-file DefaultPermissionGrantPolicy.java = fkupolov@google.com per-file DefaultPermissionGrantPolicy.java = hackbod@android.com per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com per-file DefaultPermissionGrantPolicy.java = toddke@google.com per-file DefaultPermissionGrantPolicy.java = yamasani@google.com per-file DefaultPermissionGrantPolicy.java = patb@google.com +per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com +per-file DefaultPermissionGrantPolicy.java = moltmann@google.com diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java index 80a5fbb6366e..ec15c16981a8 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java @@ -107,11 +107,7 @@ public abstract class PermissionManagerInternal { */ public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty); - public abstract void removeAllPermissions( - @NonNull PackageParser.Package pkg, - @NonNull List<String> allPackageNames, - @Nullable PermissionCallback permissionCallback, - boolean chatty); + public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); public abstract boolean addDynamicPermission(@NonNull PermissionInfo info, boolean async, int callingUid, @Nullable PermissionCallback callback); public abstract void removeDynamicPermission(@NonNull String permName, int callingUid, @@ -185,4 +181,4 @@ public abstract class PermissionManagerInternal { /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */ public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName); -} +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 4b6760c6405a..18c6a3d0b361 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -31,7 +31,6 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; @@ -39,7 +38,6 @@ import android.content.pm.PackageParser.Package; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.metrics.LogMaker; -import android.os.AsyncTask; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -478,9 +476,8 @@ public class PermissionManagerService { " to " + newPermissionGroupName); try { - revokeRuntimePermission(permissionName, packageName, - mSettings.getPermission(permissionName), false, - Process.SYSTEM_UID, userId, permissionCallback, false); + revokeRuntimePermission(permissionName, packageName, false, + Process.SYSTEM_UID, userId, permissionCallback); } catch (IllegalArgumentException e) { Slog.e(TAG, "Could not revoke " + permissionName + " from " + packageName, e); @@ -573,59 +570,9 @@ public class PermissionManagerService { } - private void revokeAllPermissions( - @NonNull List<BasePermission> bps, - @NonNull List<String> allPackageNames, - @Nullable PermissionCallback permissionCallback) { - AsyncTask.execute(() -> { - final int numRemovedPermissions = bps.size(); - for (int permissionNum = 0; permissionNum < numRemovedPermissions; permissionNum++) { - final int[] userIds = mUserManagerInt.getUserIds(); - final int numUserIds = userIds.length; - - final int numPackages = allPackageNames.size(); - for (int packageNum = 0; packageNum < numPackages; packageNum++) { - final String packageName = allPackageNames.get(packageNum); - final ApplicationInfo applicationInfo = mPackageManagerInt.getApplicationInfo( - packageName, 0, Process.SYSTEM_UID, UserHandle.USER_SYSTEM); - if (applicationInfo != null - && applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { - continue; - } - for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { - final int userId = userIds[userIdNum]; - final String permissionName = bps.get(permissionNum).getName(); - if (checkPermission(permissionName, packageName, UserHandle.USER_SYSTEM, - userId) == PackageManager.PERMISSION_GRANTED) { - try { - revokeRuntimePermission( - permissionName, - packageName, - bps.get(permissionNum), - false, - Process.SYSTEM_UID, - userId, - permissionCallback, - true); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Could not revoke " + permissionName + " from " - + packageName, e); - } - } - } - } - } - }); - } - - private void removeAllPermissions( - @NonNull PackageParser.Package pkg, - @NonNull List<String> allPackageNames, - @Nullable PermissionCallback permissionCallback, - boolean chatty) { + private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) { synchronized (mLock) { int N = pkg.permissions.size(); - List<BasePermission> bps = new ArrayList<BasePermission>(N); StringBuilder r = null; for (int i=0; i<N; i++) { PackageParser.Permission p = pkg.permissions.get(i); @@ -634,9 +581,6 @@ public class PermissionManagerService { bp = mSettings.mPermissionTrees.get(p.info.name); } if (bp != null && bp.isPermission(p)) { - if ((p.info.getProtection() & PermissionInfo.PROTECTION_DANGEROUS) != 0) { - bps.add(bp); - } bp.setPermission(null); if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -655,7 +599,6 @@ public class PermissionManagerService { } } } - revokeAllPermissions(bps, allPackageNames, permissionCallback); if (r != null) { if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); } @@ -1571,10 +1514,9 @@ public class PermissionManagerService { } } - - private void revokeRuntimePermission(String permName, String packageName, BasePermission bp, - boolean overridePolicy, int callingUid, int userId, PermissionCallback callback, - boolean permissionRemoved) { + + private void revokeRuntimePermission(String permName, String packageName, + boolean overridePolicy, int callingUid, int userId, PermissionCallback callback) { if (!mUserManagerInt.exists(userId)) { Log.e(TAG, "No such user:" + userId); return; @@ -1599,7 +1541,7 @@ public class PermissionManagerService { if (mPackageManagerInt.filterAppAccess(pkg, Binder.getCallingUid(), userId)) { throw new IllegalArgumentException("Unknown package: " + packageName); } - + final BasePermission bp = mSettings.getPermissionLocked(permName); if (bp == null) { throw new IllegalArgumentException("Unknown permission: " + permName); } @@ -2156,10 +2098,8 @@ public class PermissionManagerService { PermissionManagerService.this.addAllPermissionGroups(pkg, chatty); } @Override - public void removeAllPermissions(Package pkg, List<String> allPackageNames, - PermissionCallback permissionCallback, boolean chatty) { - PermissionManagerService.this.removeAllPermissions( - pkg, allPackageNames, permissionCallback, chatty); + public void removeAllPermissions(Package pkg, boolean chatty) { + PermissionManagerService.this.removeAllPermissions(pkg, chatty); } @Override public boolean addDynamicPermission(PermissionInfo info, boolean async, int callingUid, @@ -2195,8 +2135,7 @@ public class PermissionManagerService { boolean overridePolicy, int callingUid, int userId, PermissionCallback callback) { PermissionManagerService.this.revokeRuntimePermission(permName, packageName, - mSettings.getPermission(permName), overridePolicy, callingUid, userId, - callback, false); + overridePolicy, callingUid, userId, callback); } @Override public void updatePermissions(String packageName, Package pkg, boolean replaceGrant, diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index 1e0b52adb2f4..ae1090cfb045 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -1,13 +1,11 @@ package com.android.server.policy.keyguard; -import static android.view.Display.INVALID_DISPLAY; import static com.android.server.wm.KeyguardServiceDelegateProto.INTERACTIVE_STATE; import static com.android.server.wm.KeyguardServiceDelegateProto.OCCLUDED; import static com.android.server.wm.KeyguardServiceDelegateProto.SCREEN_STATE; import static com.android.server.wm.KeyguardServiceDelegateProto.SECURE; import static com.android.server.wm.KeyguardServiceDelegateProto.SHOWING; -import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.content.ComponentName; import android.content.Context; @@ -212,10 +210,10 @@ public class KeyguardServiceDelegate { mHandler.post(() -> { try { // There are no longer any keyguard windows on secondary displays, so pass - // INVALID_DISPLAY. All that means is that showWhenLocked activities on - // secondary displays now get to show. + // {@code null}. All that means is that showWhenLocked activities on + // external displays now get to show. ActivityTaskManager.getService().setLockScreenShown(true /* keyguardShowing */, - false /* aodShowing */, INVALID_DISPLAY); + false /* aodShowing */, null /* secondaryDisplaysShowing */); } catch (RemoteException e) { // Local call. } diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java index 4f8e6b650e24..5323b1f34d26 100644 --- a/services/core/java/com/android/server/power/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java @@ -64,9 +64,28 @@ public class BatterySaverPolicy extends ContentObserver { private static final String KEY_VIBRATION_DISABLED = "vibration_disabled"; private static final String KEY_ANIMATION_DISABLED = "animation_disabled"; private static final String KEY_SOUNDTRIGGER_DISABLED = "soundtrigger_disabled"; - private static final String KEY_FIREWALL_DISABLED = "firewall_disabled"; + + /** + * Disable turning on the network firewall when Battery Saver is turned on. + * If set to false, the firewall WILL be turned on when Battery Saver is turned on. + * If set to true, the firewall WILL NOT be turned on when Battery Saver is turned on. + */ + private static final String KEY_ACTIVATE_FIREWALL_DISABLED = "firewall_disabled"; + + /** + * Disable turning on the special low power screen brightness dimming when Battery Saver is + * turned on. + * If set to false, the screen brightness dimming WILL be turned on by Battery Saver. + * If set to true, the screen brightness WILL NOT be turned on by Battery Saver. + */ private static final String KEY_ADJUST_BRIGHTNESS_DISABLED = "adjust_brightness_disabled"; - private static final String KEY_DATASAVER_DISABLED = "datasaver_disabled"; + + /** + * Disable turning on Data Saver when Battery Saver is turned on. + * If set to false, Data Saver WILL be turned on when Battery Saver is turned on. + * If set to true, Data Saver WILL NOT be turned on when Battery Saver is turned on. + */ + private static final String KEY_ACTIVATE_DATASAVER_DISABLED = "datasaver_disabled"; private static final String KEY_LAUNCH_BOOST_DISABLED = "launch_boost_disabled"; private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor"; private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred"; @@ -154,31 +173,32 @@ public class BatterySaverPolicy extends ContentObserver { private boolean mKeyValueBackupDeferred; /** - * {@code true} if network policy firewall is disabled in battery saver mode. + * {@code true} if network policy firewall should be turned on in battery saver mode. * * @see Settings.Global#BATTERY_SAVER_CONSTANTS - * @see #KEY_FIREWALL_DISABLED + * @see #KEY_ACTIVATE_FIREWALL_DISABLED */ @GuardedBy("mLock") - private boolean mFireWallDisabled; + private boolean mEnableFirewall; /** - * {@code true} if adjust brightness is disabled in battery saver mode. + * {@code true} if low power mode brightness adjustment should be turned on in battery saver + * mode. * * @see Settings.Global#BATTERY_SAVER_CONSTANTS * @see #KEY_ADJUST_BRIGHTNESS_DISABLED */ @GuardedBy("mLock") - private boolean mAdjustBrightnessDisabled; + private boolean mEnableAdjustBrightness; /** - * {@code true} if data saver is disabled in battery saver mode. + * {@code true} if data saver should be turned on in battery saver mode. * * @see Settings.Global#BATTERY_SAVER_CONSTANTS - * @see #KEY_DATASAVER_DISABLED + * @see #KEY_ACTIVATE_DATASAVER_DISABLED */ @GuardedBy("mLock") - private boolean mDataSaverDisabled; + private boolean mEnableDataSaver; /** * {@code true} if launch boost should be disabled on battery saver. @@ -391,10 +411,10 @@ public class BatterySaverPolicy extends ContentObserver { mSoundTriggerDisabled = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true); mFullBackupDeferred = parser.getBoolean(KEY_FULLBACKUP_DEFERRED, true); mKeyValueBackupDeferred = parser.getBoolean(KEY_KEYVALUE_DEFERRED, true); - mFireWallDisabled = parser.getBoolean(KEY_FIREWALL_DISABLED, false); - mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true); + mEnableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED, false); + mEnableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true); mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f); - mDataSaverDisabled = parser.getBoolean(KEY_DATASAVER_DISABLED, true); + mEnableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED, true); mLaunchBoostDisabled = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED, true); mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true); mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true); @@ -436,9 +456,9 @@ public class BatterySaverPolicy extends ContentObserver { if (mSoundTriggerDisabled) sb.append("s"); if (mFullBackupDeferred) sb.append("F"); if (mKeyValueBackupDeferred) sb.append("K"); - if (!mFireWallDisabled) sb.append("f"); - if (!mDataSaverDisabled) sb.append("d"); - if (!mAdjustBrightnessDisabled) sb.append("b"); + if (mEnableFirewall) sb.append("f"); + if (mEnableDataSaver) sb.append("d"); + if (mEnableAdjustBrightness) sb.append("b"); if (mLaunchBoostDisabled) sb.append("l"); if (mOptionalSensorsDisabled) sb.append("S"); @@ -485,14 +505,14 @@ public class BatterySaverPolicy extends ContentObserver { return builder.setBatterySaverEnabled(mKeyValueBackupDeferred) .build(); case ServiceType.NETWORK_FIREWALL: - return builder.setBatterySaverEnabled(!mFireWallDisabled) + return builder.setBatterySaverEnabled(mEnableFirewall) .build(); case ServiceType.SCREEN_BRIGHTNESS: - return builder.setBatterySaverEnabled(!mAdjustBrightnessDisabled) + return builder.setBatterySaverEnabled(mEnableAdjustBrightness) .setBrightnessFactor(mAdjustBrightnessFactor) .build(); case ServiceType.DATA_SAVER: - return builder.setBatterySaverEnabled(!mDataSaverDisabled) + return builder.setBatterySaverEnabled(mEnableDataSaver) .build(); case ServiceType.SOUND: return builder.setBatterySaverEnabled(mSoundTriggerDisabled) @@ -565,10 +585,10 @@ public class BatterySaverPolicy extends ContentObserver { pw.println(" " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled); pw.println(" " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred); pw.println(" " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred); - pw.println(" " + KEY_FIREWALL_DISABLED + "=" + mFireWallDisabled); - pw.println(" " + KEY_DATASAVER_DISABLED + "=" + mDataSaverDisabled); + pw.println(" " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !mEnableFirewall); + pw.println(" " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !mEnableDataSaver); pw.println(" " + KEY_LAUNCH_BOOST_DISABLED + "=" + mLaunchBoostDisabled); - pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled); + pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + !mEnableAdjustBrightness); pw.println(" " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor); pw.println(" " + KEY_GPS_MODE + "=" + mGpsMode); pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby); diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS index d118c4e58a20..20e4985ddd19 100644 --- a/services/core/java/com/android/server/power/OWNERS +++ b/services/core/java/com/android/server/power/OWNERS @@ -2,3 +2,4 @@ michaelwr@google.com per-file BatterySaverPolicy.java=omakoto@google.com per-file ShutdownThread.java=fkupolov@google.com +per-file ThermalManagerService.java=wvw@google.com
\ No newline at end of file diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java new file mode 100644 index 000000000000..812fd82a35f9 --- /dev/null +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.power; + +import android.content.Context; +import android.hardware.thermal.V1_0.ThermalStatus; +import android.hardware.thermal.V1_0.ThermalStatusCode; +import android.hardware.thermal.V1_1.IThermalCallback; +import android.hardware.thermal.V2_0.IThermalChangedCallback; +import android.hardware.thermal.V2_0.ThrottlingSeverity; +import android.os.Binder; +import android.os.HwBinder; +import android.os.IThermalEventListener; +import android.os.IThermalService; +import android.os.PowerManager; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.DumpUtils; +import com.android.server.FgThread; +import com.android.server.SystemService; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * This is a system service that listens to HAL thermal events and dispatch those to listeners. + * <p>The service will also trigger actions based on severity of the throttling status.</p> + * + * @hide + */ +public class ThermalManagerService extends SystemService { + private static final String TAG = ThermalManagerService.class.getSimpleName(); + + /** Registered observers of the thermal changed events. Cookie is used to store type */ + @GuardedBy("mLock") + private final RemoteCallbackList<IThermalEventListener> mThermalEventListeners = + new RemoteCallbackList<>(); + + /** Lock to protect HAL handles and listen list. */ + private final Object mLock = new Object(); + + /** Newly registered callback. */ + @GuardedBy("mLock") + private IThermalEventListener mNewListenerCallback = null; + + /** Newly registered callback type, null means not filter type. */ + @GuardedBy("mLock") + private Integer mNewListenerType = null; + + /** Local PMS handle. */ + private final PowerManager mPowerManager; + + /** Proxy object for the Thermal HAL 2.0 service. */ + @GuardedBy("mLock") + private android.hardware.thermal.V2_0.IThermal mThermalHal20 = null; + + /** Proxy object for the Thermal HAL 1.1 service. */ + @GuardedBy("mLock") + private android.hardware.thermal.V1_1.IThermal mThermalHal11 = null; + + /** Cookie for matching the right end point. */ + private static final int THERMAL_HAL_DEATH_COOKIE = 5612; + + /** HWbinder callback for Thermal HAL 2.0. */ + private final IThermalChangedCallback.Stub mThermalCallback20 = + new IThermalChangedCallback.Stub() { + @Override + public void notifyThrottling( + android.hardware.thermal.V2_0.Temperature temperature) { + android.os.Temperature thermalSvcTemp = new android.os.Temperature( + temperature.value, temperature.type, temperature.name, + temperature.throttlingStatus); + final long token = Binder.clearCallingIdentity(); + try { + notifyThrottlingImpl(thermalSvcTemp); + } finally { + Binder.restoreCallingIdentity(token); + } + } + }; + + /** HWbinder callback for Thermal HAL 1.1. */ + private final IThermalCallback.Stub mThermalCallback11 = + new IThermalCallback.Stub() { + @Override + public void notifyThrottling(boolean isThrottling, + android.hardware.thermal.V1_0.Temperature temperature) { + android.os.Temperature thermalSvcTemp = new android.os.Temperature( + temperature.currentValue, temperature.type, temperature.name, + isThrottling ? ThrottlingSeverity.SEVERE : ThrottlingSeverity.NONE); + final long token = Binder.clearCallingIdentity(); + try { + notifyThrottlingImpl(thermalSvcTemp); + } finally { + Binder.restoreCallingIdentity(token); + } + } + }; + + public ThermalManagerService(Context context) { + super(context); + mPowerManager = context.getSystemService(PowerManager.class); + } + + private void setNewListener(IThermalEventListener listener, Integer type) { + synchronized (mLock) { + mNewListenerCallback = listener; + mNewListenerType = type; + } + } + + private void clearNewListener() { + synchronized (mLock) { + mNewListenerCallback = null; + mNewListenerType = null; + } + } + + private final IThermalService.Stub mService = new IThermalService.Stub() { + @Override + public void registerThermalEventListener(IThermalEventListener listener) { + synchronized (mLock) { + mThermalEventListeners.register(listener, null); + // Notify its callback after new client registered. + setNewListener(listener, null); + long token = Binder.clearCallingIdentity(); + try { + notifyCurrentTemperaturesLocked(); + } finally { + Binder.restoreCallingIdentity(token); + clearNewListener(); + } + } + } + + @Override + public void registerThermalEventListenerWithType(IThermalEventListener listener, int type) { + synchronized (mLock) { + mThermalEventListeners.register(listener, new Integer(type)); + setNewListener(listener, new Integer(type)); + // Notify its callback after new client registered. + long token = Binder.clearCallingIdentity(); + try { + notifyCurrentTemperaturesLocked(); + } finally { + Binder.restoreCallingIdentity(token); + clearNewListener(); + } + } + } + + @Override + public void unregisterThermalEventListener(IThermalEventListener listener) { + synchronized (mLock) { + long token = Binder.clearCallingIdentity(); + try { + mThermalEventListeners.unregister(listener); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + + @Override + public List<android.os.Temperature> getCurrentTemperatures() { + List<android.os.Temperature> ret; + long token = Binder.clearCallingIdentity(); + try { + ret = getCurrentTemperaturesInternal(false, 0 /* not used */); + } finally { + Binder.restoreCallingIdentity(token); + } + return ret; + } + + @Override + public List<android.os.Temperature> getCurrentTemperaturesWithType(int type) { + List<android.os.Temperature> ret; + long token = Binder.clearCallingIdentity(); + try { + ret = getCurrentTemperaturesInternal(true, type); + } finally { + Binder.restoreCallingIdentity(token); + } + return ret; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; + pw.println("ThermalEventListeners dump:"); + synchronized (mLock) { + mThermalEventListeners.dump(pw, "\t"); + pw.println("ThermalHAL 1.1 connected: " + (mThermalHal11 != null ? "yes" : "no")); + pw.println("ThermalHAL 2.0 connected: " + (mThermalHal20 != null ? "yes" : "no")); + } + } + }; + + private List<android.os.Temperature> getCurrentTemperaturesInternal(boolean shouldFilter, + int type) { + List<android.os.Temperature> ret = new ArrayList<>(); + synchronized (mLock) { + if (mThermalHal20 == null) { + return ret; + } + try { + mThermalHal20.getCurrentTemperatures(shouldFilter, type, + (ThermalStatus status, + ArrayList<android.hardware.thermal.V2_0.Temperature> + temperatures) -> { + if (ThermalStatusCode.SUCCESS == status.code) { + for (android.hardware.thermal.V2_0.Temperature + temperature : temperatures) { + ret.add(new android.os.Temperature( + temperature.value, temperature.type, temperature.name, + temperature.throttlingStatus)); + } + } else { + Slog.e(TAG, + "Couldn't get temperatures because of HAL error: " + + status.debugMessage); + } + + }); + } catch (RemoteException e) { + Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e); + connectToHalLocked(); + // Post to listeners after reconnect to HAL. + notifyCurrentTemperaturesLocked(); + } + } + return ret; + } + + private void notifyListener(android.os.Temperature temperature, IThermalEventListener listener, + Integer type) { + // Skip if listener registered with a different type + if (type != null && type != temperature.getType()) { + return; + } + final boolean thermalCallbackQueued = FgThread.getHandler().post(() -> { + try { + listener.notifyThrottling(temperature); + } catch (RemoteException | RuntimeException e) { + Slog.e(TAG, "Thermal callback failed to call", e); + } + }); + if (!thermalCallbackQueued) { + Slog.e(TAG, "Thermal callback failed to queue"); + } + } + + private void notifyThrottlingImpl(android.os.Temperature temperature) { + synchronized (mLock) { + // Thermal Shutdown for Skin temperature + if (temperature.getStatus() == android.os.Temperature.THROTTLING_SHUTDOWN + && temperature.getType() == android.os.Temperature.TYPE_SKIN) { + final long token = Binder.clearCallingIdentity(); + try { + mPowerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + if (mNewListenerCallback != null) { + // Only notify current newly added callback. + notifyListener(temperature, mNewListenerCallback, mNewListenerType); + } else { + final int length = mThermalEventListeners.beginBroadcast(); + try { + for (int i = 0; i < length; i++) { + final IThermalEventListener listener = + mThermalEventListeners.getBroadcastItem(i); + final Integer type = (Integer) mThermalEventListeners.getBroadcastCookie(i); + notifyListener(temperature, listener, type); + } + } finally { + mThermalEventListeners.finishBroadcast(); + } + } + } + } + + @Override + public void onStart() { + publishBinderService(Context.THERMAL_SERVICE, mService); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { + onActivityManagerReady(); + } + } + + private void notifyCurrentTemperaturesCallbackLocked(ThermalStatus status, + ArrayList<android.hardware.thermal.V2_0.Temperature> temperatures) { + if (ThermalStatusCode.SUCCESS != status.code) { + Slog.e(TAG, "Couldn't get temperatures because of HAL error: " + + status.debugMessage); + return; + } + for (android.hardware.thermal.V2_0.Temperature temperature : temperatures) { + android.os.Temperature thermal_svc_temp = + new android.os.Temperature( + temperature.value, temperature.type, + temperature.name, + temperature.throttlingStatus); + notifyThrottlingImpl(thermal_svc_temp); + } + } + + private void notifyCurrentTemperaturesLocked() { + if (mThermalHal20 == null) { + return; + } + try { + mThermalHal20.getCurrentTemperatures(false, 0, + this::notifyCurrentTemperaturesCallbackLocked); + } catch (RemoteException e) { + Slog.e(TAG, "Couldn't get temperatures, reconnecting...", e); + connectToHalLocked(); + } + } + + private void onActivityManagerReady() { + synchronized (mLock) { + connectToHalLocked(); + // Post to listeners after connect to HAL. + notifyCurrentTemperaturesLocked(); + } + } + + final class DeathRecipient implements HwBinder.DeathRecipient { + @Override + public void serviceDied(long cookie) { + if (cookie == THERMAL_HAL_DEATH_COOKIE) { + Slog.e(TAG, "Thermal HAL service died cookie: " + cookie); + synchronized (mLock) { + connectToHalLocked(); + // Post to listeners after reconnect to HAL. + notifyCurrentTemperaturesLocked(); + } + } + } + } + + private void connectToHalLocked() { + try { + mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService(); + mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE); + mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false, + 0 /* not used */); + } catch (NoSuchElementException | RemoteException e) { + Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1."); + mThermalHal20 = null; + try { + mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService(); + mThermalHal11.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE); + mThermalHal11.registerThermalCallback(mThermalCallback11); + } catch (NoSuchElementException | RemoteException e2) { + Slog.e(TAG, + "Thermal HAL 1.1 service not connected, no thermal call back " + + "will be called."); + mThermalHal11 = null; + } + } + } + +} diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 4d3fc1a8a51d..2be55c02638d 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -253,8 +253,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { if (b != null) { sThermalService = IThermalService.Stub.asInterface(b); try { - sThermalService.registerThermalEventListener( - new ThermalEventListener()); + sThermalService.registerThermalEventListenerWithType( + new ThermalEventListener(), Temperature.TYPE_SKIN); Slog.i(TAG, "register thermal listener successfully"); } catch (RemoteException e) { // Should never happen. @@ -1853,7 +1853,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // Thermal event received from vendor thermal management subsystem private static final class ThermalEventListener extends IThermalEventListener.Stub { @Override - public void notifyThrottling(boolean isThrottling, Temperature temp) { + public void notifyThrottling(Temperature temp) { + boolean isThrottling = temp.getStatus() >= Temperature.THROTTLING_SEVERE; StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(), isThrottling ? 1 : 0, temp.getValue()); } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 9edb3d07ca32..e4d1cfe943a8 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -735,7 +735,7 @@ final class AccessibilityController { } public void setShown(boolean shown, boolean animate) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mShown == shown) { return; } @@ -750,13 +750,13 @@ final class AccessibilityController { @SuppressWarnings("unused") // Called reflectively from an animator. public int getAlpha() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { return mAlpha; } } public void setAlpha(int alpha) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mAlpha == alpha) { return; } @@ -769,7 +769,7 @@ final class AccessibilityController { } public void setBounds(Region bounds) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mBounds.equals(bounds)) { return; } @@ -782,7 +782,7 @@ final class AccessibilityController { } public void updateSize() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mWindowManager.getDefaultDisplay().getRealSize(mTempPoint); mSurfaceControl.setSize(mTempPoint.x, mTempPoint.y); invalidate(mDirtyRect); @@ -801,7 +801,7 @@ final class AccessibilityController { /** NOTE: This has to be called within a surface transaction. */ public void drawIfNeeded() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (!mInvalidated) { return; } @@ -948,7 +948,7 @@ final class AccessibilityController { } break; case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mMagnifedViewport.isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked()) { mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true); @@ -1039,7 +1039,7 @@ final class AccessibilityController { boolean windowsChanged = false; List<WindowInfo> windows = new ArrayList<WindowInfo>(); - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { // Do not send the windows if there is no current focus as // the window manager is still looking for where to put it. // We will do the work when we get a focus change callback. diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index 05293b5138a0..678d233237fe 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -14,13 +14,14 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; @@ -37,20 +38,21 @@ import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID; import static com.android.server.am.ActivityDisplayProto.ID; import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY; import static com.android.server.am.ActivityDisplayProto.STACKS; -import static com.android.server.am.ActivityStack.ActivityState.RESUMED; -import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; -import static com.android.server.am.ActivityStackSupervisor.TAG_STATES; -import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STACK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STATES; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STACK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStackSupervisor.FindTaskResult; +import static com.android.server.wm.ActivityStackSupervisor.TAG_STATES; +import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.WindowConfiguration; +import android.content.res.Configuration; import android.graphics.Point; import android.os.UserHandle; import android.util.IntArray; @@ -59,10 +61,7 @@ import android.util.proto.ProtoOutputStream; import android.view.Display; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.wm.ActivityTaskManagerInternal; -import com.android.server.wm.ConfigurationContainer; -import com.android.server.wm.DisplayWindowController; -import com.android.server.wm.WindowContainerListener; +import com.android.server.am.EventLogTags; import java.io.PrintWriter; import java.util.ArrayList; @@ -159,7 +158,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> } void updateBounds() { - mDisplay.getSize(mTmpDisplaySize); + mDisplay.getRealSize(mTmpDisplaySize); setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y); } @@ -941,6 +940,25 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> return mStacks.indexOf(stack); } + @Override + public void onOverrideConfigurationChanged(Configuration overrideConfiguration) { + final int currRotation = getOverrideConfiguration().windowConfiguration.getRotation(); + if (currRotation != ROTATION_UNDEFINED + && currRotation != overrideConfiguration.windowConfiguration.getRotation() + && getWindowContainerController() != null) { + getWindowContainerController().applyRotation(currRotation, + overrideConfiguration.windowConfiguration.getRotation()); + } + super.onOverrideConfigurationChanged(overrideConfiguration); + } + + @Override + public void onConfigurationChanged(Configuration newParentConfig) { + // update resources before cascade so that docked/pinned stacks use the correct info + getWindowContainerController().preOnConfigurationChanged(); + super.onConfigurationChanged(newParentConfig); + } + void onLockTaskPackagesUpdated() { for (int i = mStacks.size() - 1; i >= 0; --i) { mStacks.get(i).onLockTaskPackagesUpdated(); @@ -1038,8 +1056,6 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> releaseSelfIfNeeded(); - mSupervisor.getKeyguardController().onDisplayRemoved(mDisplayId); - if (!mAllSleepTokens.isEmpty()) { mSupervisor.mSleepTokens.removeAll(mAllSleepTokens); mAllSleepTokens.clear(); @@ -1052,6 +1068,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> mWindowContainerController.removeContainer(); mWindowContainerController = null; mSupervisor.removeChild(this); + mSupervisor.getKeyguardController().onDisplayRemoved(mDisplayId); } } diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java new file mode 100644 index 000000000000..e3133efb890c --- /dev/null +++ b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Observe activity manager launch sequences. + * + * The activity manager can have at most 1 concurrent launch sequences. Calls to this interface + * are ordered by a happens-before relation for each defined state transition (see below). + * + * When a new launch sequence is made, that sequence is in the {@code INTENT_STARTED} state which + * is communicated by the {@link #onIntentStarted} callback. This is a transient state. + * + * The intent can fail to launch the activity, in which case the sequence's state transitions to + * {@code INTENT_FAILED} via {@link #onIntentFailed}. This is a terminal state. + * + * If an activity is successfully started, the launch sequence's state will transition into + * {@code STARTED} via {@link #onActivityLaunched}. This is a transient state. + * + * It must then transition to either {@code CANCELLED} with {@link #onActivityLaunchCancelled} + * or into {@code FINISHED} with {@link #onActivityLaunchFinished}. These are terminal states. + * + * Note that the {@link ActivityRecord} provided as a parameter to some state transitions isn't + * necessarily the same within a single launch sequence: it is only the top-most activity at the + * time (if any). Trampoline activities coalesce several activity starts into a single launch + * sequence. + * + * Upon reaching a terminal state, it is considered that there are no active launch sequences + * until a subsequent transition into {@code INTENT_STARTED} initiates a new launch sequence. + * + * <pre> + * ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ╔══════════════════════════╗ + * ╴╴▶ ⋮ INTENT_STARTED ⋮ ──▶ ⋮ ACTIVITY_LAUNCHED ⋮ ──▶ ║ ACTIVITY_LAUNCH_FINISHED ║ + * └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ ╚══════════════════════════╝ + * : : + * : : + * ▼ ▼ + * ╔════════════════╗ ╔═══════════════════════════╗ + * ║ INTENT_FAILED ║ ║ ACTIVITY_LAUNCH_CANCELLED ║ + * ╚════════════════╝ ╚═══════════════════════════╝ + * </pre> + */ +public interface ActivityMetricsLaunchObserver { + /** + * The 'temperature' at which a launch sequence had started. + * + * The lower the temperature the more work has to be done during start-up. + * A 'cold' temperature means that a new process has been started and likely + * nothing is cached. + * + * A hot temperature means the existing activity is brought to the foreground. + * It may need to regenerate some objects as a result of {@code onTrimMemory}. + * + * A warm temperature is in the middle; an existing process is used, but the activity + * has to be created from scratch with {@code #onCreate}. + * + * @see https://developer.android.com/topic/performance/vitals/launch-time + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + TEMPERATURE_COLD, + TEMPERATURE_WARM, + TEMPERATURE_HOT + }) + @interface Temperature {} + + /** Cold launch sequence: a new process has started. */ + public static final int TEMPERATURE_COLD = 1; + /** Warm launch sequence: process reused, but activity has to be created. */ + public static final int TEMPERATURE_WARM = 2; + /** Hot launch sequence: process reused, activity brought-to-top. */ + public static final int TEMPERATURE_HOT = 3; + + /** + * Notifies the observer that a new launch sequence has begun as a result of a new intent. + * + * Once a launch sequence begins, the resolved activity will either subsequently start with + * {@link #onActivityLaunched} or abort early (for example due to a resolution error or due to + * a security error) with {@link #onIntentFailed}. + * + * Multiple calls to this method cannot occur without first terminating the current + * launch sequence. + */ + public void onIntentStarted(@NonNull Intent intent); + + /** + * Notifies the observer that the current launch sequence has failed to launch an activity. + * + * This function call terminates the current launch sequence. The next method call, if any, + * must be {@link #onIntentStarted}. + * + * Examples of this happening: + * - Failure to resolve to an activity + * - Calling package did not have the security permissions to call the requested activity + * - Resolved activity was already running and only needed to be brought to the top + * + * Multiple calls to this method cannot occur without first terminating the current + * launch sequence. + */ + public void onIntentFailed(); + + /** + * Notifies the observer that the current launch sequence had begun starting an activity. + * + * This is an intermediate state: once an activity begins starting, the entire launch sequence + * will later terminate by either finishing or cancelling. + * + * The initial activity is the first activity to be started as part of a launch sequence: + * it is represented by {@param activity} However, it isn't + * necessarily the activity which will be considered as displayed when the activity + * finishes launching (e.g. {@code activity} in {@link #onActivityLaunchFinished}). + * + * Multiple calls to this method cannot occur without first terminating the current + * launch sequence. + */ + public void onActivityLaunched(@NonNull ActivityRecord activity, + @Temperature int temperature); + + /** + * Notifies the observer that the current launch sequence has been aborted. + * + * This function call terminates the current launch sequence. The next method call, if any, + * must be {@link #onIntentStarted}. + * + * This can happen for many reasons, for example the user switches away to another app + * prior to the launch sequence completing, or the application being killed. + * + * Multiple calls to this method cannot occur without first terminating the current + * launch sequence. + * + * @param abortingActivity the last activity that had the top-most window during abort + * (this can be {@code null} in rare situations its unknown). + * + * @apiNote The aborting activity isn't necessarily the same as the starting activity; + * in the case of a trampoline, multiple activities could've been started + * and only the latest activity is reported here. + */ + public void onActivityLaunchCancelled(@Nullable ActivityRecord abortingActivity); + + /** + * Notifies the observer that the current launch sequence has been successfully finished. + * + * This function call terminates the current launch sequence. The next method call, if any, + * must be {@link #onIntentStarted}. + * + * A launch sequence is considered to be successfully finished when a frame is fully + * drawn for the first time: the top-most activity at the time is what's reported here. + * + * @param finalActivity the top-most activity whose windows were first to fully draw + * + * Multiple calls to this method cannot occur without first terminating the current + * launch sequence. + * + * @apiNote The finishing activity isn't necessarily the same as the starting activity; + * in the case of a trampoline, multiple activities could've been started + * and only the latest activity that was top-most during first-frame drawn + * is reported here. + */ + public void onActivityLaunchFinished(@NonNull ActivityRecord finalActivity); +} diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index a0dd87811dae..9b01dfd8852c 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -1,4 +1,4 @@ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; @@ -72,14 +72,15 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_T import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_METRICS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME; import static com.android.server.am.MemoryStatUtil.MemoryStat; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT; +import android.app.WindowConfiguration.WindowingMode; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -141,15 +142,21 @@ class ActivityMetricsLogger { private final Context mContext; private final MetricsLogger mMetricsLogger = new MetricsLogger(); + // set to INVALID_START_TIME in reset. + // set to valid value in notifyActivityLaunching private long mCurrentTransitionStartTime = INVALID_START_TIME; private long mLastTransitionStartTime = INVALID_START_TIME; private int mCurrentTransitionDeviceUptime; private int mCurrentTransitionDelayMs; + + /** If the any app transitions have been logged as starting, after the latest reset. */ private boolean mLoggedTransitionStarting; + /** Map : @WindowingMode int => WindowingModeTransitionInfo */ private final SparseArray<WindowingModeTransitionInfo> mWindowingModeTransitionInfo = new SparseArray<>(); + /** Map : @WindowingMode int => WindowingModeTransitionInfo */ private final SparseArray<WindowingModeTransitionInfo> mLastWindowingModeTransitionInfo = new SparseArray<>(); private final H mHandler; @@ -157,6 +164,12 @@ class ActivityMetricsLogger { private ArtManagerInternal mArtManagerInternal; private final StringBuilder mStringBuilder = new StringBuilder(); + /** + * Due to the global single concurrent launch sequence, all calls to this observer must be made + * in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver. + */ + private final ActivityMetricsLaunchObserver mLaunchObserver = null; + private final class H extends Handler { public H(Looper looper) { @@ -175,6 +188,7 @@ class ActivityMetricsLogger { } private final class WindowingModeTransitionInfo { + /** The latest activity to have been launched. */ private ActivityRecord launchedActivity; private int startResult; private boolean currentTransitionProcessRunning; @@ -273,7 +287,7 @@ class ActivityMetricsLogger { return; } - int windowingMode = stack.getWindowingMode(); + @WindowingMode int windowingMode = stack.getWindowingMode(); if (windowingMode == WINDOWING_MODE_PINNED) { stack = mSupervisor.findStackBehind(stack); windowingMode = stack.getWindowingMode(); @@ -301,11 +315,19 @@ class ActivityMetricsLogger { * Notifies the tracker at the earliest possible point when we are starting to launch an * activity. */ - void notifyActivityLaunching() { + void notifyActivityLaunching(Intent intent) { + if (DEBUG_METRICS) { + Slog.i(TAG, String.format("notifyActivityLaunching: active:%b, intent:%s", + isAnyTransitionActive(), + intent)); + } + if (!isAnyTransitionActive()) { - if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunching"); + mCurrentTransitionStartTime = SystemClock.uptimeMillis(); mLastTransitionStartTime = mCurrentTransitionStartTime; + + launchObserverNotifyIntentStarted(intent); } } @@ -350,7 +372,9 @@ class ActivityMetricsLogger { + " processRunning=" + processRunning + " processSwitch=" + processSwitch); - final int windowingMode = launchedActivity != null + // If we are already in an existing transition, only update the activity name, but not the + // other attributes. + final @WindowingMode int windowingMode = launchedActivity != null ? launchedActivity.getWindowingMode() : WINDOWING_MODE_UNDEFINED; final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode); @@ -361,13 +385,15 @@ class ActivityMetricsLogger { if (launchedActivity != null && launchedActivity.nowVisible) { // Launched activity is already visible. We cannot measure windows drawn delay. - reset(true /* abort */, info); + reset(true /* abort */, info, "launched activity already visible"); return; } if (launchedActivity != null && info != null) { // If we are already in an existing transition, only update the activity name, but not // the other attributes. + + // Coalesce multiple (trampoline) activities from a single sequence together. info.launchedActivity = launchedActivity; return; } @@ -377,7 +403,7 @@ class ActivityMetricsLogger { if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) { // Failed to launch or it was not a process switch, so we don't care about the timing. - reset(true /* abort */, info); + reset(true /* abort */, info, "failed to launch or not a process switch"); return; } else if (otherWindowModesLaunching) { // Don't log this windowing mode but continue with the other windowing modes. @@ -386,6 +412,8 @@ class ActivityMetricsLogger { if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful"); + // A new launch sequence [with the windowingMode] has begun. + // Start tracking it. final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo(); newInfo.launchedActivity = launchedActivity; newInfo.currentTransitionProcessRunning = processRunning; @@ -394,6 +422,7 @@ class ActivityMetricsLogger { mLastWindowingModeTransitionInfo.put(windowingMode, newInfo); mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000); startTraces(newInfo); + launchObserverNotifyActivityLaunched(newInfo); } /** @@ -407,7 +436,8 @@ class ActivityMetricsLogger { /** * Notifies the tracker that all windows of the app have been drawn. */ - WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(int windowingMode, long timestamp) { + WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(@WindowingMode int windowingMode, + long timestamp) { if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode); final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode); @@ -419,7 +449,7 @@ class ActivityMetricsLogger { final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info); if (allWindowsDrawn() && mLoggedTransitionStarting) { - reset(false /* abort */, info); + reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn"); } return infoSnapshot; } @@ -427,7 +457,7 @@ class ActivityMetricsLogger { /** * Notifies the tracker that the starting window was drawn. */ - void notifyStartingWindowDrawn(int windowingMode, long timestamp) { + void notifyStartingWindowDrawn(@WindowingMode int windowingMode, long timestamp) { final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode); if (info == null || info.loggedStartingWindowDrawn) { return; @@ -444,22 +474,28 @@ class ActivityMetricsLogger { */ void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestamp) { if (!isAnyTransitionActive() || mLoggedTransitionStarting) { + // Ignore calls to this made after a reset and prior to notifyActivityLaunching. + + // Ignore any subsequent notifyTransitionStarting until the next reset. return; } if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting"); mCurrentTransitionDelayMs = calculateDelay(timestamp); mLoggedTransitionStarting = true; + + WindowingModeTransitionInfo foundInfo = null; for (int index = windowingModeToReason.size() - 1; index >= 0; index--) { - final int windowingMode = windowingModeToReason.keyAt(index); + final @WindowingMode int windowingMode = windowingModeToReason.keyAt(index); final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get( windowingMode); if (info == null) { continue; } info.reason = windowingModeToReason.valueAt(index); + foundInfo = info; } if (allWindowsDrawn()) { - reset(false /* abort */, null /* WindowingModeTransitionInfo */); + reset(false /* abort */, foundInfo, "notifyTransitionStarting - all windows drawn"); } } @@ -498,7 +534,7 @@ class ActivityMetricsLogger { logAppTransitionCancel(info); mWindowingModeTransitionInfo.remove(r.getWindowingMode()); if (mWindowingModeTransitionInfo.size() == 0) { - reset(true /* abort */, info); + reset(true /* abort */, info, "notifyVisibilityChanged to invisible"); } } } @@ -534,12 +570,25 @@ class ActivityMetricsLogger { && mWindowingModeTransitionInfo.size() > 0; } - private void reset(boolean abort, WindowingModeTransitionInfo info) { - if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort); + private void reset(boolean abort, WindowingModeTransitionInfo info, String cause) { + if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort + ",cause=" + cause); if (!abort && isAnyTransitionActive()) { logAppTransitionMultiEvents(); } stopLaunchTrace(info); + + // Ignore reset-after reset. + if (isAnyTransitionActive()) { + // LaunchObserver callbacks. + if (abort) { + launchObserverNotifyActivityLaunchCancelled(info); + } else { + launchObserverNotifyActivityLaunchFinished(info); + } + } else { + launchObserverNotifyIntentFailed(); + } + mCurrentTransitionStartTime = INVALID_START_TIME; mCurrentTransitionDelayMs = INVALID_DELAY; mLoggedTransitionStarting = false; @@ -572,6 +621,13 @@ class ActivityMetricsLogger { info.launchedActivity.packageName, convertAppStartTransitionType(type), info.launchedActivity.info.name); + if (DEBUG_METRICS) { + Slog.i(TAG, String.format("APP_START_CANCELED(%s, %s, %s, %s)", + info.launchedActivity.appInfo.uid, + info.launchedActivity.packageName, + convertAppStartTransitionType(type), + info.launchedActivity.info.name)); + } } private void logAppTransitionMultiEvents() { @@ -656,6 +712,17 @@ class ActivityMetricsLogger { launchToken, packageOptimizationInfo.getCompilationReason(), packageOptimizationInfo.getCompilationFilter()); + + if (DEBUG_METRICS) { + Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)", + info.applicationInfo.uid, + info.packageName, + convertAppStartTransitionType(info.type), + info.launchedActivityName, + info.launchedActivityLaunchedFromPackage)); + } + + logAppStartMemoryStateCapture(info); } @@ -923,4 +990,76 @@ class ActivityMetricsLogger { info.launchTraceActive = false; } } + + /** Notify the {@link ActivityMetricsLaunchObserver} that a new launch sequence has begun. */ + private void launchObserverNotifyIntentStarted(Intent intent) { + if (mLaunchObserver != null) { + // Beginning a launch is timing sensitive and so should be observed as soon as possible. + mLaunchObserver.onIntentStarted(intent); + } + } + + /** + * Notify the {@link ActivityMetricsLaunchObserver} that the previous launch sequence has + * aborted due to intent failure (e.g. intent resolve failed or security error, etc) or + * intent being delivered to the top running activity. + */ + private void launchObserverNotifyIntentFailed() { + if (mLaunchObserver != null) { + mLaunchObserver.onIntentFailed(); + } + } + + /** + * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity + * has started. + */ + private void launchObserverNotifyActivityLaunched(WindowingModeTransitionInfo info) { + @ActivityMetricsLaunchObserver.Temperature int temperature = + convertTransitionTypeToLaunchObserverTemperature(getTransitionType(info)); + + if (mLaunchObserver != null) { + // Beginning a launch is timing sensitive and so should be observed as soon as possible. + mLaunchObserver.onActivityLaunched(info.launchedActivity, + temperature); + } + } + + /** + * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence is + * cancelled. + */ + private void launchObserverNotifyActivityLaunchCancelled(WindowingModeTransitionInfo info) { + final ActivityRecord launchedActivity = info != null ? info.launchedActivity : null; + + if (mLaunchObserver != null) { + mLaunchObserver.onActivityLaunchCancelled(launchedActivity); + } + } + + /** + * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity + * has fully finished (successfully). + */ + private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info) { + final ActivityRecord launchedActivity = info.launchedActivity; + + if (mLaunchObserver != null) { + mLaunchObserver.onActivityLaunchFinished(launchedActivity); + } + } + + private static @ActivityMetricsLaunchObserver.Temperature int + convertTransitionTypeToLaunchObserverTemperature(int transitionType) { + switch (transitionType) { + case TYPE_TRANSITION_WARM_LAUNCH: + return ActivityMetricsLaunchObserver.TEMPERATURE_WARM; + case TYPE_TRANSITION_HOT_LAUNCH: + return ActivityMetricsLaunchObserver.TEMPERATURE_HOT; + case TYPE_TRANSITION_COLD_LAUNCH: + return ActivityMetricsLaunchObserver.TEMPERATURE_COLD; + default: + return -1; + } + } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 47b4f4700049..8223693f6834 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX; @@ -75,20 +75,20 @@ import static android.os.Process.SYSTEM_UID; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STATES; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STATES; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER; import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK; import static com.android.server.am.ActivityRecordProto.IDENTIFIER; @@ -96,23 +96,23 @@ import static com.android.server.am.ActivityRecordProto.PROC_ID; import static com.android.server.am.ActivityRecordProto.STATE; import static com.android.server.am.ActivityRecordProto.TRANSLUCENT; import static com.android.server.am.ActivityRecordProto.VISIBLE; -import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING; -import static com.android.server.am.ActivityStack.ActivityState.PAUSED; -import static com.android.server.am.ActivityStack.ActivityState.PAUSING; -import static com.android.server.am.ActivityStack.ActivityState.RESUMED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPING; -import static com.android.server.am.ActivityStack.LAUNCH_TICK; -import static com.android.server.am.ActivityStack.LAUNCH_TICK_MSG; -import static com.android.server.am.ActivityStack.PAUSE_TIMEOUT_MSG; -import static com.android.server.am.ActivityStack.STOP_TIMEOUT_MSG; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; +import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; +import static com.android.server.wm.ActivityStack.LAUNCH_TICK; +import static com.android.server.wm.ActivityStack.LAUNCH_TICK_MSG; +import static com.android.server.wm.ActivityStack.PAUSE_TIMEOUT_MSG; +import static com.android.server.wm.ActivityStack.STOP_TIMEOUT_MSG; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY; import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY; -import static com.android.server.am.TaskPersister.DEBUG; -import static com.android.server.am.TaskPersister.IMAGE_EXTENSION; +import static com.android.server.wm.TaskPersister.DEBUG; +import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; @@ -177,13 +177,11 @@ import com.android.internal.content.ReferrerIntent; import com.android.internal.util.XmlUtils; import com.android.server.AttributeCache; import com.android.server.AttributeCache.Entry; -import com.android.server.am.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot; -import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.AppTimeTracker; +import com.android.server.am.PendingIntentRecord; +import com.android.server.wm.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot; +import com.android.server.wm.ActivityStack.ActivityState; import com.android.server.uri.UriPermissionOwner; -import com.android.server.wm.AppWindowContainerController; -import com.android.server.wm.AppWindowContainerListener; -import com.android.server.wm.ConfigurationContainer; -import com.android.server.wm.TaskWindowContainerController; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/services/core/java/com/android/server/am/ActivityResult.java b/services/core/java/com/android/server/wm/ActivityResult.java index 395918e0863b..f2510de6dfb2 100644 --- a/services/core/java/com/android/server/am/ActivityResult.java +++ b/services/core/java/com/android/server/wm/ActivityResult.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import android.app.ResultInfo; import android.content.Intent; diff --git a/services/core/java/com/android/server/am/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java index b1ced29da4c2..ad4624875d06 100644 --- a/services/core/java/com/android/server/am/ActivityServiceConnectionsHolder.java +++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java @@ -14,10 +14,10 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; -import static com.android.server.am.ActivityStack.ActivityState.PAUSING; -import static com.android.server.am.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import java.io.PrintWriter; import java.util.HashSet; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index d646e9ae9458..c269f79470ed 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; @@ -46,17 +46,6 @@ import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_TASK_TO_BACK; import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; -import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM; -import static com.android.server.am.ActivityDisplay.POSITION_TOP; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP; -import static com.android.server.am.ActivityStack.ActivityState.DESTROYED; -import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.am.ActivityStack.ActivityState.FINISHING; -import static com.android.server.am.ActivityStack.ActivityState.PAUSED; -import static com.android.server.am.ActivityStack.ActivityState.PAUSING; -import static com.android.server.am.ActivityStack.ActivityState.RESUMED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPING; import static com.android.server.am.ActivityStackProto.BOUNDS; import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER; import static com.android.server.am.ActivityStackProto.DISPLAY_ID; @@ -64,45 +53,56 @@ import static com.android.server.am.ActivityStackProto.FULLSCREEN; import static com.android.server.am.ActivityStackProto.ID; import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY; import static com.android.server.am.ActivityStackProto.TASKS; -import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; -import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ALL; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_APP; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STACK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STATES; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_APP; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONTAINERS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STACK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STATES; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; +import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM; +import static com.android.server.wm.ActivityDisplay.POSITION_TOP; +import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; +import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; +import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; +import static com.android.server.wm.ActivityStackSupervisor.FindTaskResult; +import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_APP; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CLEANUP; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONTAINERS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static java.lang.Integer.MAX_VALUE; @@ -154,12 +154,11 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.Watchdog; +import com.android.server.am.ActivityManagerService; import com.android.server.am.ActivityManagerService.ItemMatcher; -import com.android.server.wm.ConfigurationContainer; -import com.android.server.wm.DisplayWindowController; -import com.android.server.wm.StackWindowController; -import com.android.server.wm.StackWindowListener; -import com.android.server.wm.WindowManagerService; +import com.android.server.am.AppTimeTracker; +import com.android.server.am.EventLogTags; +import com.android.server.am.PendingIntentRecord; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -514,14 +513,23 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai public void onConfigurationChanged(Configuration newParentConfig) { final int prevWindowingMode = getWindowingMode(); final boolean prevIsAlwaysOnTop = isAlwaysOnTop(); - super.onConfigurationChanged(newParentConfig); final ActivityDisplay display = getDisplay(); + + getBounds(mTmpRect2); + final boolean hasNewBounds = display != null && getWindowContainerController() != null + && getWindowContainerController().updateBoundsForConfigChange( + newParentConfig, getConfiguration(), mTmpRect2); + + super.onConfigurationChanged(newParentConfig); if (display == null) { return; } if (prevWindowingMode != getWindowingMode()) { display.onStackWindowingModeChanged(this); } + if (hasNewBounds) { + resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */); + } if (prevIsAlwaysOnTop != isAlwaysOnTop()) { // Since always on top is only on when the stack is freeform or pinned, the state // can be toggled when the windowing mode changes. We must make sure the stack is @@ -753,6 +761,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai * @param bounds Updated bounds. */ private void postAddToDisplay(ActivityDisplay activityDisplay, Rect bounds, boolean onTop) { + if (mDisplayId != activityDisplay.mDisplayId) { + // rotations are relative to the display, so pretend like our current rotation is + // the same as the new display so we don't try to rotate bounds. + getConfiguration().windowConfiguration.setRotation( + activityDisplay.getWindowConfiguration().getRotation()); + } mDisplayId = activityDisplay.mDisplayId; setBounds(bounds); onParentChanged(); @@ -811,10 +825,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai outBounds.setEmpty(); } - void getBoundsForNewConfiguration(Rect outBounds) { - mWindowContainerController.getBoundsForNewConfiguration(outBounds); - } - void positionChildWindowContainerAtTop(TaskRecord child) { mWindowContainerController.positionChildAtTop(child.getWindowContainerController(), true /* includingParents */); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 695fac274c95..9bcee8a3ab23 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.Manifest.permission.ACTIVITY_EMBEDDING; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; @@ -59,14 +59,6 @@ import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; -import static com.android.server.am.ActivityStack.ActivityState.DESTROYED; -import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING; -import static com.android.server.am.ActivityStack.ActivityState.PAUSED; -import static com.android.server.am.ActivityStack.ActivityState.PAUSING; -import static com.android.server.am.ActivityStack.ActivityState.RESUMED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPING; -import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; import static com.android.server.am.ActivityStackSupervisorProto.DISPLAYS; import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID; @@ -74,34 +66,42 @@ import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES; import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ALL; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_IDLE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STACK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STATES; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_IDLE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STACK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STATES; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityTaskManagerService.ANIMATE; -import static com.android.server.am.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; -import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; -import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; -import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; +import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; +import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IDLE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; +import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; +import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; +import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; +import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; +import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; +import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; +import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import static java.lang.Integer.MAX_VALUE; @@ -183,14 +183,12 @@ import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.internal.util.ArrayUtils; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; -import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.ActivityManagerService; +import com.android.server.am.AppTimeTracker; +import com.android.server.am.EventLogTags; +import com.android.server.am.UserState; +import com.android.server.wm.ActivityStack.ActivityState; import com.android.server.wm.ActivityTaskManagerInternal.SleepToken; -import com.android.server.wm.ConfigurationContainer; -import com.android.server.wm.DisplayWindowController; -import com.android.server.wm.PinnedStackWindowController; -import com.android.server.wm.RootWindowContainerController; -import com.android.server.wm.RootWindowContainerListener; -import com.android.server.wm.WindowManagerService; import java.io.FileDescriptor; import java.io.IOException; @@ -1978,8 +1976,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout); - // Make sure we can finish booting when all resumed activities are idle. - if ((!mService.isBooted() && allResumedActivitiesIdle()) || fromTimeout) { + // Check if able to finish booting when device is booting and all resumed activities + // are idle. + if ((mService.isBooting() && allResumedActivitiesIdle()) || fromTimeout) { booting = checkFinishBootingLocked(); } @@ -4138,7 +4137,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId); synchronized (mService.mGlobalLock) { getActivityDisplayOrCreateLocked(displayId); - startHomeOnDisplay(mCurrentUser, "displayAdded", displayId); + // Do not start home before booting, or it may accidentally finish booting before it + // starts. Instead, we expect home activities to be launched when the system is ready + // (ActivityManagerService#systemReady). + if (mService.isBooted() || mService.isBooting()) { + startHomeOnDisplay(mCurrentUser, "displayAdded", displayId); + } } } @@ -4747,7 +4751,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ActivityRecord targetActivity = task.getTopActivity(); sendPowerHintForLaunchStartIfNeeded(true /* forceSend */, targetActivity); - mActivityMetricsLogger.notifyActivityLaunching(); + mActivityMetricsLogger.notifyActivityLaunching(task.intent); try { mService.moveTaskToFrontLocked(task.taskId, 0, options, true /* fromRecents */); diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 3151ec9c1b83..904d9dd059c4 100644 --- a/services/core/java/com/android/server/am/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.START_SUCCESS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; @@ -22,8 +22,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.app.ActivityOptions; import android.app.IApplicationThread; @@ -46,9 +46,11 @@ import android.util.proto.ProtoOutputStream; import android.view.RemoteAnimationAdapter; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; -import com.android.server.am.ActivityStarter.DefaultFactory; -import com.android.server.am.ActivityStarter.Factory; +import com.android.server.am.ActivityManagerService; +import com.android.server.am.PendingIntentRecord; +import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch; +import com.android.server.wm.ActivityStarter.DefaultFactory; +import com.android.server.wm.ActivityStarter.Factory; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java index e51824f6f790..ee5a43ce0edb 100644 --- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY; import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS; @@ -57,6 +57,7 @@ import com.android.internal.app.HarmfulAppWarningActivity; import com.android.internal.app.SuspendedAppActivity; import com.android.internal.app.UnlaunchableAppActivity; import com.android.server.LocalServices; +import com.android.server.am.ActivityManagerService; /** * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked} diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 37ddaf94c0a0..afc946b5deb0 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.app.Activity.RESULT_CANCELED; import static android.app.ActivityManager.START_ABORTED; @@ -53,28 +53,28 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static com.android.server.am.ActivityStack.ActivityState.RESUMED; -import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME; -import static com.android.server.am.ActivityStackSupervisor.ON_TOP; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STACK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityTaskManagerService.ANIMATE; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; +import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; import static com.android.server.am.EventLogTags.AM_NEW_INTENT; -import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; -import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; +import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; +import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import android.annotation.NonNull; import android.annotation.Nullable; @@ -112,8 +112,10 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.app.IVoiceInteractor; -import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; -import com.android.server.am.LaunchParamsController.LaunchParams; +import com.android.server.am.EventLogTags; +import com.android.server.am.PendingIntentRecord; +import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch; +import com.android.server.wm.LaunchParamsController.LaunchParams; import com.android.server.pm.InstantAppResolver; import java.io.PrintWriter; @@ -994,7 +996,7 @@ class ActivityStarter { if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); } - mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(); + mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent); boolean componentSpecified = intent.getComponent() != null; final int realCallingPid = Binder.getCallingPid(); diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java index 4f2a254f080f..7f09a071308a 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; /** * Common class for the various debug {@link android.util.Log} output configuration relating to @@ -44,7 +44,7 @@ public class ActivityTaskManagerDebugConfig { private static final boolean DEBUG_ALL_ACTIVITIES = DEBUG_ALL || false; static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false; - static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false; + public static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false; static final boolean DEBUG_CONTAINERS = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_FOCUS = false; static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false; @@ -55,7 +55,7 @@ public class ActivityTaskManagerDebugConfig { static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_STACK = DEBUG_ALL || false; static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false; - static final boolean DEBUG_SWITCH = DEBUG_ALL || false; + public static final boolean DEBUG_SWITCH = DEBUG_ALL || false; static final boolean DEBUG_TASKS = DEBUG_ALL || false; static final boolean DEBUG_TRANSITION = DEBUG_ALL || false; static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false; @@ -65,8 +65,8 @@ public class ActivityTaskManagerDebugConfig { static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false; static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false; static final boolean DEBUG_RESULTS = DEBUG_ALL || false; - static final boolean DEBUG_CLEANUP = DEBUG_ALL || false; - static final boolean DEBUG_METRICS = DEBUG_ALL || false; + public static final boolean DEBUG_CLEANUP = DEBUG_ALL || false; + public static final boolean DEBUG_METRICS = DEBUG_ALL || false; static final String POSTFIX_APP = APPEND_CATEGORY_NAME ? "_App" : ""; static final String POSTFIX_CLEANUP = (APPEND_CATEGORY_NAME) ? "_Cleanup" : ""; @@ -74,17 +74,17 @@ public class ActivityTaskManagerDebugConfig { static final String POSTFIX_RELEASE = APPEND_CATEGORY_NAME ? "_Release" : ""; static final String POSTFIX_USER_LEAVING = APPEND_CATEGORY_NAME ? "_UserLeaving" : ""; static final String POSTFIX_ADD_REMOVE = APPEND_CATEGORY_NAME ? "_AddRemove" : ""; - static final String POSTFIX_CONFIGURATION = APPEND_CATEGORY_NAME ? "_Configuration" : ""; + public static final String POSTFIX_CONFIGURATION = APPEND_CATEGORY_NAME ? "_Configuration" : ""; static final String POSTFIX_CONTAINERS = APPEND_CATEGORY_NAME ? "_Containers" : ""; static final String POSTFIX_FOCUS = APPEND_CATEGORY_NAME ? "_Focus" : ""; static final String POSTFIX_IMMERSIVE = APPEND_CATEGORY_NAME ? "_Immersive" : ""; - static final String POSTFIX_LOCKTASK = APPEND_CATEGORY_NAME ? "_LockTask" : ""; + public static final String POSTFIX_LOCKTASK = APPEND_CATEGORY_NAME ? "_LockTask" : ""; static final String POSTFIX_PAUSE = APPEND_CATEGORY_NAME ? "_Pause" : ""; static final String POSTFIX_RECENTS = APPEND_CATEGORY_NAME ? "_Recents" : ""; static final String POSTFIX_SAVED_STATE = APPEND_CATEGORY_NAME ? "_SavedState" : ""; static final String POSTFIX_STACK = APPEND_CATEGORY_NAME ? "_Stack" : ""; static final String POSTFIX_STATES = APPEND_CATEGORY_NAME ? "_States" : ""; - static final String POSTFIX_SWITCH = APPEND_CATEGORY_NAME ? "_Switch" : ""; + public static final String POSTFIX_SWITCH = APPEND_CATEGORY_NAME ? "_Switch" : ""; static final String POSTFIX_TASKS = APPEND_CATEGORY_NAME ? "_Tasks" : ""; static final String POSTFIX_TRANSITION = APPEND_CATEGORY_NAME ? "_Transition" : ""; static final String POSTFIX_VISIBILITY = APPEND_CATEGORY_NAME ? "_Visibility" : ""; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 9a38f6899fd2..dcc7bc577396 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -36,12 +36,8 @@ import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; import com.android.internal.app.IVoiceInteractor; -import com.android.server.am.ActivityServiceConnectionsHolder; import com.android.server.am.PendingIntentRecord; -import com.android.server.am.SafeActivityOptions; -import com.android.server.am.TaskRecord; import com.android.server.am.UserState; -import com.android.server.am.WindowProcessController; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 9ddd58b6d051..3da950dfaf38 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.Manifest.permission.BIND_VOICE_INTERACTION; import static android.Manifest.permission.CHANGE_CONFIGURATION; @@ -82,46 +82,49 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HEA import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HOME_PROC; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC; -import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS; +import static com.android.server.am.ActivityManagerServiceDumpProcessesProto + .PREVIOUS_PROC_VISIBLE_TIME_MS; import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES; -import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE; -import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE; -import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; -import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME; -import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY; -import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; -import static com.android.server.am.ActivityStackSupervisor.ON_TOP; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ALL; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_IMMERSIVE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STACK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_IMMERSIVE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STACK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG; -import static com.android.server.am.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; -import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; -import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; +import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage + .MODE; +import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage + .PACKAGE; +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; +import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; +import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_ONLY; +import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; +import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IMMERSIVE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IMMERSIVE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE; +import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG; +import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; +import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; +import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT; +import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE; import android.Manifest; import android.annotation.NonNull; @@ -248,14 +251,19 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemServiceManager; import com.android.server.Watchdog; +import com.android.server.am.ActivityManagerService; +import com.android.server.am.ActivityManagerServiceDumpActivitiesProto; +import com.android.server.am.ActivityManagerServiceDumpProcessesProto; +import com.android.server.am.AppTimeTracker; +import com.android.server.am.BaseErrorDialog; +import com.android.server.am.EventLogTags; +import com.android.server.am.PendingIntentController; +import com.android.server.am.PendingIntentRecord; +import com.android.server.am.UserState; import com.android.server.firewall.IntentFirewall; import com.android.server.pm.UserManagerService; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.vr.VrManagerInternal; -import com.android.server.wm.ActivityTaskManagerInternal; -import com.android.server.wm.DisplayWindowController; -import com.android.server.wm.PinnedStackWindowController; -import com.android.server.wm.WindowManagerService; import java.io.BufferedReader; import java.io.File; @@ -631,7 +639,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mFontScaleSettingObserver = new FontScaleSettingObserver(); } - void retrieveSettings(ContentResolver resolver) { + public void retrieveSettings(ContentResolver resolver) { final boolean freeformWindowManagement = mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT) || Settings.Global.getInt( @@ -709,7 +717,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } // TODO: Will be converted to WM lock once transition is complete. - void setActivityManagerService(Object globalLock, Looper looper, + public void setActivityManagerService(Object globalLock, Looper looper, IntentFirewall intentFirewall, PendingIntentController intentController) { mGlobalLock = globalLock; mH = new H(looper); @@ -2877,7 +2885,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing, - int secondaryDisplayShowing) { + int[] secondaryDisplaysShowing) { if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires permission " @@ -2895,7 +2903,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } try { mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing, - secondaryDisplayShowing); + secondaryDisplaysShowing); } finally { Binder.restoreCallingIdentity(ident); } @@ -3874,7 +3882,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * Check that we have the features required for VR-related API calls, and throw an exception if * not. */ - void enforceSystemHasVrFeature() { + public void enforceSystemHasVrFeature() { if (!mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) { throw new UnsupportedOperationException("VR mode not supported on this device!"); @@ -4628,7 +4636,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { UserHandle.USER_NULL, deferResume); } - void updatePersistentConfiguration(Configuration values, @UserIdInt int userId) { + public void updatePersistentConfiguration(Configuration values, @UserIdInt int userId) { final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -4865,21 +4873,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mH.sendMessage(msg); } } - - // Update the configuration with WM first and check if any of the stacks need to be resized - // due to the configuration change. If so, resize the stacks now and do any relaunches if - // necessary. This way we don't need to relaunch again afterwards in - // ensureActivityConfiguration(). - if (mWindowManager != null) { - final int[] resizedStacks = - mWindowManager.setNewDisplayOverrideConfiguration(mTempConfig, displayId); - if (resizedStacks != null) { - for (int stackId : resizedStacks) { - resizeStackWithBoundsFromWindowManager(stackId, deferResume); - } - } - } - return changes; } @@ -5269,28 +5262,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return "focused app: " + packageName; } - /** Helper method that requests bounds from WM and applies them to stack. */ - private void resizeStackWithBoundsFromWindowManager(int stackId, boolean deferResume) { - final Rect newStackBounds = new Rect(); - final ActivityStack stack = mStackSupervisor.getStack(stackId); - - // TODO(b/71548119): Revert CL introducing below once cause of mismatch is found. - if (stack == null) { - final StringWriter writer = new StringWriter(); - final PrintWriter printWriter = new PrintWriter(writer); - mStackSupervisor.dumpDisplays(printWriter); - printWriter.flush(); - - Log.wtf(TAG, "stack not found:" + stackId + " displays:" + writer); - } - - stack.getBoundsForNewConfiguration(newStackBounds); - mStackSupervisor.resizeStackLocked( - stack, !newStackBounds.isEmpty() ? newStackBounds : null /* bounds */, - null /* tempTaskBounds */, null /* tempTaskInsetBounds */, - false /* preserveWindows */, false /* allowResizeInDockedMode */, deferResume); - } - /** Applies latest configuration and/or visibility updates if needed. */ private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) { boolean kept = true; diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java index a1f1ff9cc3ec..04fef02cd3b4 100644 --- a/services/core/java/com/android/server/am/AppTaskImpl.java +++ b/services/core/java/com/android/server/wm/AppTaskImpl.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; -import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; -import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; +import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; +import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; import android.app.ActivityManager; import android.app.IAppTask; diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 10a1be52b71e..089640b32dd3 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1924,7 +1924,7 @@ public class AppTransition implements Dump { } catch (RemoteException e) { Slog.w(TAG, "Failed to fetch app transition specs: " + e); } - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mNextAppTransitionAnimationsSpecsPending = false; overridePendingAppTransitionMultiThumb(specs, mNextAppTransitionFutureCallback, null /* finishedCallback */, @@ -2220,7 +2220,7 @@ public class AppTransition implements Dump { } private void handleAppTransitionTimeout() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final DisplayContent dc = mDisplayContent; if (dc == null) { return; diff --git a/services/core/java/com/android/server/am/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java index a705180e48ee..04368570e02e 100644 --- a/services/core/java/com/android/server/am/AppWarnings.java +++ b/services/core/java/com/android/server/wm/AppWarnings.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import android.annotation.UiThread; import android.content.ComponentName; diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java index 7435ea5e532f..584c1e4e3bae 100644 --- a/services/core/java/com/android/server/wm/AppWindowContainerController.java +++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java @@ -135,7 +135,7 @@ public class AppWindowContainerController final StartingData startingData; final AppWindowToken container; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to" + " add starting window"); @@ -169,7 +169,7 @@ public class AppWindowContainerController } if (surface != null) { boolean abort = false; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { // If the window was successfully added, then // we need to remove it. if (container.removed || container.startingData == null) { @@ -219,7 +219,7 @@ public class AppWindowContainerController super(listener, service); mHandler = new H(service.mH.getLooper()); mToken = token; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder()); if (atoken != null) { // TODO: Should this throw an exception instead? @@ -256,7 +256,7 @@ public class AppWindowContainerController } public void removeContainer(int displayId) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: " @@ -274,7 +274,7 @@ public class AppWindowContainerController } public void reparent(TaskWindowContainerController taskController, int position) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken + " to task=" + taskController + " at " + position); if (mContainer == null) { @@ -294,7 +294,7 @@ public class AppWindowContainerController public Configuration setOrientation(int requestedOrientation, int displayId, Configuration displayConfig, boolean freezeScreenIfNeeded) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "Attempted to set orientation of non-existing app token: " + mToken); @@ -310,7 +310,7 @@ public class AppWindowContainerController } public int getOrientation() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { return SCREEN_ORIENTATION_UNSPECIFIED; } @@ -320,7 +320,7 @@ public class AppWindowContainerController } public void setDisablePreviewScreenshots(boolean disable) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app" + " token: " + mToken); @@ -331,7 +331,7 @@ public class AppWindowContainerController } public void setVisibility(boolean visible, boolean deferHidingClient) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + mToken); @@ -449,7 +449,7 @@ public class AppWindowContainerController * of Keyguard flags it's going to set on its windows. */ public void notifyUnknownVisibilityLaunched() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer != null) { mContainer.getDisplayContent().mUnknownAppVisibilityController.notifyLaunched( mContainer); @@ -461,7 +461,7 @@ public class AppWindowContainerController CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning @@ -611,7 +611,7 @@ public class AppWindowContainerController } public void removeStartingWindow() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer.startingWindow == null) { if (mContainer.startingData != null) { // Starting window has not been added yet, but it is scheduled to be added. @@ -664,7 +664,7 @@ public class AppWindowContainerController } public void pauseKeyDispatching() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer != null) { mContainer.getDisplayContent().getInputMonitor().pauseDispatchingLw(mContainer); } @@ -672,7 +672,7 @@ public class AppWindowContainerController } public void resumeKeyDispatching() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer != null) { mContainer.getDisplayContent().getInputMonitor().resumeDispatchingLw(mContainer); } @@ -680,7 +680,7 @@ public class AppWindowContainerController } public void notifyAppResumed(boolean wasStopped) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken); return; @@ -690,7 +690,7 @@ public class AppWindowContainerController } public void notifyAppStopping() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: " + mToken); @@ -701,7 +701,7 @@ public class AppWindowContainerController } public void notifyAppStopped() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: " + mToken); @@ -712,7 +712,7 @@ public class AppWindowContainerController } public void startFreezingScreen(int configChanges) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "Attempted to freeze screen with non-existing app token: " + mContainer); @@ -729,7 +729,7 @@ public class AppWindowContainerController } public void stopFreezingScreen(boolean force) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { return; } @@ -740,7 +740,7 @@ public class AppWindowContainerController } public void registerRemoteAnimations(RemoteAnimationDefinition definition) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "Attempted to register remote animations with non-existing app" + " token: " + mToken); @@ -775,7 +775,7 @@ public class AppWindowContainerController * Apply override app transition base on options & animation type. */ public void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final int animationType = pendingOptions.getAnimationType(); final DisplayContent displayContent = mContainer.getDisplayContent(); switch (animationType) { @@ -875,7 +875,7 @@ public class AppWindowContainerController * signal on the WM side. */ public void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { return; } diff --git a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java b/services/core/java/com/android/server/wm/AssistDataReceiverProxy.java index 9991ce174e07..675627395e98 100644 --- a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java +++ b/services/core/java/com/android/server/wm/AssistDataReceiverProxy.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; -import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; -import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.app.IAssistDataReceiver; import android.graphics.Bitmap; @@ -34,7 +34,7 @@ import com.android.server.am.AssistDataRequester.AssistDataRequesterCallbacks; class AssistDataReceiverProxy implements AssistDataRequesterCallbacks, Binder.DeathRecipient { - private static final String TAG = TAG_WITH_CLASS_NAME ? "AssistDataReceiverProxy" : TAG_AM; + private static final String TAG = TAG_WITH_CLASS_NAME ? "AssistDataReceiverProxy" : TAG_ATM; private String mCallerPackage; private IAssistDataReceiver mReceiver; diff --git a/services/core/java/com/android/server/am/ClientLifecycleManager.java b/services/core/java/com/android/server/wm/ClientLifecycleManager.java index ae8d9fc104bb..7430f0f1dc47 100644 --- a/services/core/java/com/android/server/am/ClientLifecycleManager.java +++ b/services/core/java/com/android/server/wm/ClientLifecycleManager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import android.annotation.NonNull; import android.app.IApplicationThread; diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index 3c4ab006a4b6..c8f8e82bdb18 100644 --- a/services/core/java/com/android/server/am/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -14,13 +14,13 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import java.io.File; import java.io.FileInputStream; diff --git a/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java b/services/core/java/com/android/server/wm/DeprecatedTargetSdkVersionDialog.java index b39873fe4335..37244bd5bd06 100644 --- a/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java +++ b/services/core/java/com/android/server/wm/DeprecatedTargetSdkVersionDialog.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.app.AlertDialog; import android.content.Context; @@ -25,7 +25,6 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; -import android.os.SystemPropertiesProto; import android.util.Log; import android.view.Window; import android.view.WindowManager; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ba030340ef36..fece980065b0 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -157,8 +157,8 @@ import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.SurfaceSession; -import android.view.WindowManagerPolicyConstants.PointerEventListener; import android.view.WindowManager; +import android.view.WindowManagerPolicyConstants.PointerEventListener; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; @@ -314,7 +314,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * Last applied orientation of the display. * Constants as per {@link android.content.pm.ActivityInfo.ScreenOrientation}. * - * @see WindowManagerService#updateOrientationFromAppTokensLocked(boolean, int) + * @see #updateOrientationFromAppTokens() */ private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED; @@ -1045,18 +1045,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mLastOrientation; } - void setLastOrientation(int orientation) { - mLastOrientation = orientation; - } - boolean getAltOrientation() { return mAltOrientation; } - void setAltOrientation(boolean altOrientation) { - mAltOrientation = altOrientation; - } - int getLastWindowForcedOrientation() { return mLastWindowForcedOrientation; } @@ -1109,6 +1101,34 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return true; } + /** Notify the configuration change of this display. */ + void sendNewConfiguration() { + mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, this).sendToTarget(); + } + + /** + * Determine the new desired orientation of this display. + * + * The orientation is computed from non-application windows first. If none of the + * non-application windows specify orientation, the orientation is computed from application + * tokens. + * + * @return {@code true} if the orientation is changed. + */ + boolean updateOrientationFromAppTokens() { + return updateOrientationFromAppTokens(false /* forceUpdate */); + } + + boolean updateOrientationFromAppTokens(boolean forceUpdate) { + final int req = getOrientation(); + if (req != mLastOrientation || forceUpdate) { + mLastOrientation = req; + mDisplayRotation.setCurrentOrientation(req); + return updateRotationUnchecked(forceUpdate); + } + return false; + } + /** * Update rotation of the display and send configuration if the rotation is changed. * @@ -1117,7 +1137,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo boolean updateRotationAndSendNewConfigIfNeeded() { final boolean changed = updateRotationUnchecked(false /* forceUpdate */); if (changed) { - mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mDisplayId).sendToTarget(); + sendNewConfiguration(); } return changed; } @@ -1133,14 +1153,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } /** - * Update rotation of the display with an option to force the update. + * Update rotation of the DisplayContent with an option to force the update. This updates + * the container's perception of rotation and, depending on the top activities, will freeze + * the screen or start seamless rotation. The display itself gets rotated in + * {@link #applyRotationLocked} during {@link WindowManagerService#sendNewConfiguration}. + * * @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating * orientation because we're waiting for some rotation to finish or display * to unfreeze, which results in configuration of the previously visible * activity being applied to a newly visible one. Forcing the rotation * update allows to workaround this issue. * @return {@code true} if the rotation has been changed. In this case YOU MUST CALL - * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN. + * {@link WindowManagerService#sendNewConfiguration(int)} TO COMPLETE THE ROTATION AND + * UNFREEZE THE SCREEN. */ boolean updateRotationUnchecked(boolean forceUpdate) { ScreenRotationAnimation screenRotationAnimation; @@ -1238,7 +1263,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mService.mWaitingForConfig = true; } - setRotation(rotation); + mRotation = rotation; mAltOrientation = altOrientation; mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE; @@ -1252,18 +1277,29 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (!rotateSeamlessly) { mService.startFreezingDisplayLocked(anim[0], anim[1], this); // startFreezingDisplayLocked can reset the ScreenRotationAnimation. - screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked( - mDisplayId); } else { // The screen rotation animation uses a screenshot to freeze the screen // while windows resize underneath. // When we are rotating seamlessly, we allow the elements to transition // to their rotated state independently and without a freeze required. - screenRotationAnimation = null; - mService.startSeamlessRotation(); } + return true; + } + + /** + * Applies the rotation transaction. This must be called after {@link #updateRotationUnchecked} + * (if it returned {@code true}) to actually finish the rotation. + * + * @param oldRotation the rotation we are coming from. + * @param rotation the rotation to apply. + */ + void applyRotationLocked(final int oldRotation, final int rotation) { + mDisplayRotation.setRotation(rotation); + final boolean rotateSeamlessly = mService.isRotatingSeamlessly(); + ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly + ? null : mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId); // We need to update our screen size information to match the new rotation. If the rotation // has actually changed then this method will return true and, according to the comment at // the top of the method, the caller is obligated to call computeNewConfigurationLocked(). @@ -1324,8 +1360,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo && isDefaultDisplay) { mService.mAccessibilityController.onRotationChangedLocked(this); } - - return true; } void configureDisplayPolicy() { @@ -1435,7 +1469,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mCompatDisplayMetrics); } - updateBounds(); return mDisplayInfo; } @@ -1469,11 +1502,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ void computeScreenConfiguration(Configuration config) { final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode); + calculateBounds(displayInfo, mTmpBounds); + config.windowConfiguration.setBounds(mTmpBounds); final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; config.windowConfiguration.setWindowingMode(getWindowingMode()); + config.windowConfiguration.setRotation(displayInfo.rotation); final float density = mDisplayMetrics.density; config.screenWidthDp = @@ -1505,7 +1541,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale); config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale); config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, dw, - dh, mDisplayId); + dh, displayInfo.displayCutout, mDisplayId); config.densityDpi = displayInfo.logicalDensityDpi; config.colorMode = @@ -1582,7 +1618,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private int computeCompatSmallestWidth(boolean rotated, int uiMode, int dw, int dh, - int displayId) { + DisplayCutout displayCutout, int displayId) { mTmpDisplayMetrics.setTo(mDisplayMetrics); final DisplayMetrics tmpDm = mTmpDisplayMetrics; final int unrotDw, unrotDh; @@ -1594,22 +1630,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo unrotDh = dh; } int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh, - displayId); + displayCutout, displayId); sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw, - displayId); + displayCutout, displayId); sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh, - displayId); + displayCutout, displayId); sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw, - displayId); + displayCutout, displayId); return sw; } private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode, - DisplayMetrics dm, int dw, int dh, int displayId) { + DisplayMetrics dm, int dw, int dh, DisplayCutout displayCutout, int displayId) { dm.noncompatWidthPixels = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, - displayId, mDisplayInfo.displayCutout); + displayId, displayCutout); dm.noncompatHeightPixels = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, - uiMode, displayId, mDisplayInfo.displayCutout); + uiMode, displayId, displayCutout); float scale = CompatibilityInfo.computeCompatibleScaling(dm, null); int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f); if (curSize == 0 || size < curSize) { @@ -1647,24 +1683,24 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo unrotDw); int sl = Configuration.resetScreenLayout(outConfig.screenLayout); sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode, - displayId); + displayInfo.displayCutout, displayId); sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode, - displayId); + displayInfo.displayCutout, displayId); sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode, - displayId); + displayInfo.displayCutout, displayId); sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode, - displayId); + displayInfo.displayCutout, displayId); outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density); outConfig.screenLayout = sl; } private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh, - int uiMode, int displayId) { + int uiMode, DisplayCutout displayCutout, int displayId) { // Get the app screen size at this rotation. int w = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId, - mDisplayInfo.displayCutout); + displayCutout); int h = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId, - mDisplayInfo.displayCutout); + displayCutout); // Compute the screen layout size class for this rotation. int longSize = w; @@ -1838,11 +1874,26 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo public void onConfigurationChanged(Configuration newParentConfig) { super.onConfigurationChanged(newParentConfig); + // If there was no pinned stack, we still need to notify the controller of the display info + // update as a result of the config change. + if (mPinnedStackControllerLocked != null && !hasPinnedStack()) { + mPinnedStackControllerLocked.onDisplayInfoChanged(getDisplayInfo()); + } + // The display size information is heavily dependent on the resources in the current // configuration, so we need to reconfigure it every time the configuration changes. // See {@link #configureDisplayPolicy}...sigh... mService.reconfigureDisplayLocked(this); + } + + /** + * Updates the resources used by docked/pinned controllers. This needs to be called at the + * beginning of a configuration update cascade since the metrics from these resources are used + * for bounds calculations. Since ActivityDisplay initiates the configuration update, this + * should be called from there instead of DisplayContent's onConfigurationChanged. + */ + void preOnConfigurationChanged() { final DockedStackDividerController dividerController = getDockedDividerController(); if (dividerController != null) { @@ -1856,26 +1907,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } - /** - * Callback used to trigger bounds update after configuration change and get ids of stacks whose - * bounds were updated. - */ - void updateStackBoundsAfterConfigChange(@NonNull List<TaskStack> changedStackList) { - for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) { - final TaskStack stack = mTaskStackContainers.getChildAt(i); - if (stack.updateBoundsAfterConfigChange()) { - changedStackList.add(stack); - } - } - - // If there was no pinned stack, we still need to notify the controller of the display info - // update as a result of the config change. We do this here to consolidate the flow between - // changes when there is and is not a stack. - if (!hasPinnedStack()) { - mPinnedStackControllerLocked.onDisplayInfoChanged(); - } - } - @Override boolean fillsParent() { return true; @@ -2343,6 +2374,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mWindowingLayer.release(); mOverlayLayer.release(); } finally { + mDisplayReady = false; mRemovingDisplay = false; } @@ -2473,11 +2505,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo void rotateBounds(int oldRotation, int newRotation, Rect bounds) { getBounds(mTmpRect, newRotation); + rotateBounds(mTmpRect, oldRotation, newRotation, bounds); + } + void rotateBounds(Rect parentBounds, int oldRotation, int newRotation, Rect bounds) { // Compute a transform matrix to undo the coordinate space transformation, // and present the window at the same physical position it previously occupied. final int deltaRotation = deltaRotation(newRotation, oldRotation); - createRotationMatrix(deltaRotation, mTmpRect.width(), mTmpRect.height(), mTmpMatrix); + createRotationMatrix( + deltaRotation, parentBounds.width(), parentBounds.height(), mTmpMatrix); mTmpRectF.set(bounds); mTmpMatrix.mapRect(mTmpRectF); @@ -3348,9 +3384,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) { if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout"); - if (mService.updateOrientationFromAppTokensLocked(mDisplayId)) { + if (updateOrientationFromAppTokens()) { setLayoutNeeded(); - mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mDisplayId).sendToTarget(); + sendNewConfiguration(); } } @@ -3405,27 +3441,27 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private void updateBounds() { - calculateBounds(mTmpBounds); + calculateBounds(mDisplayInfo, mTmpBounds); setBounds(mTmpBounds); } // Determines the current display bounds based on the current state - private void calculateBounds(Rect out) { + private void calculateBounds(DisplayInfo displayInfo, Rect out) { // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. - final int orientation = mDisplayInfo.rotation; - boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270); + final int rotation = displayInfo.rotation; + boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; - int width = mDisplayInfo.logicalWidth; + int width = displayInfo.logicalWidth; int left = (physWidth - width) / 2; - int height = mDisplayInfo.logicalHeight; + int height = displayInfo.logicalHeight; int top = (physHeight - height) / 2; out.set(left, top, left + width, top + height); } @Override public void getBounds(Rect out) { - calculateBounds(out); + calculateBounds(mDisplayInfo, out); } private void getBounds(Rect out, int orientation) { diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java index 01d556a699e8..632494b92dc1 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowController.java +++ b/services/core/java/com/android/server/wm/DisplayWindowController.java @@ -52,7 +52,7 @@ public class DisplayWindowController super(listener, WindowManagerService.getInstance()); mDisplayId = display.getDisplayId(); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final long callingIdentity = Binder.clearCallingIdentity(); try { mRoot.createDisplayContent(display, this /* controller */); @@ -75,7 +75,7 @@ public class DisplayWindowController @Override public void removeContainer() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if(mContainer == null) { if (DEBUG_DISPLAY) Slog.i(TAG_WM, "removeDisplay: could not find displayId=" + mDisplayId); @@ -88,9 +88,34 @@ public class DisplayWindowController @Override public void onOverrideConfigurationChanged(Configuration overrideConfiguration) { - // TODO: The container receives override configuration changes through other means. enabling - // callbacks through the controller causes layout issues. Investigate consolidating - // override configuration propagation to just here. + synchronized (mGlobalLock) { + if (mContainer != null) { + mContainer.mService.setNewDisplayOverrideConfiguration(overrideConfiguration, + mContainer); + } + } + } + + /** + * Updates the docked/pinned controller resources to the current system context. + */ + public void preOnConfigurationChanged() { + synchronized (mGlobalLock) { + if (mContainer != null) { + mContainer.preOnConfigurationChanged(); + } + } + } + + /** + * @see DisplayContent#applyRotationLocked(int, int) + */ + public void applyRotation(int oldRotation, int newRotation) { + synchronized (mGlobalLock) { + if (mContainer != null) { + mContainer.applyRotationLocked(oldRotation, newRotation); + } + } } public int getDisplayId() { @@ -102,7 +127,7 @@ public class DisplayWindowController * {@link android.hardware.display.DisplayManager.DisplayListener#onDisplayChanged(int)}. */ public void onDisplayChanged() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { if (DEBUG_DISPLAY) Slog.i(TAG_WM, "onDisplayChanged: could not find display=" + mDisplayId); @@ -118,7 +143,7 @@ public class DisplayWindowController */ public void positionChildAt(StackWindowController child, int position, boolean includingParents) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_STACK) Slog.i(TAG_WM, "positionTaskStackAt: positioning stack=" + child + " at " + position); if (mContainer == null) { @@ -140,7 +165,7 @@ public class DisplayWindowController * attempt to update the IME target before all information about the Windows have been updated. */ public void deferUpdateImeTarget() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(mDisplayId); if (dc != null) { dc.deferUpdateImeTarget(); @@ -152,7 +177,7 @@ public class DisplayWindowController * Resumes updating the IME target after deferring. See {@link #deferUpdateImeTarget()} */ public void continueUpdateImeTarget() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(mDisplayId); if (dc != null) { dc.continueUpdateImeTarget(); @@ -167,7 +192,7 @@ public class DisplayWindowController * @param moveFocusNow Specifies if we should update the focused window immediately. */ public void setFocusedApp(IBinder token, boolean moveFocusNow) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "setFocusedApp: could not find displayId=" + mDisplayId); @@ -213,21 +238,21 @@ public class DisplayWindowController public void prepareAppTransition(@WindowManager.TransitionType int transit, boolean alwaysKeepCurrent, @WindowManager.TransitionFlags int flags, boolean forceOverride) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId).prepareAppTransition(transit, alwaysKeepCurrent, flags, forceOverride); } } public void executeAppTransition() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId).executeAppTransition(); } } public void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, IRemoteCallback startedCallback) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransition( packageName, enterAnim, exitAnim, startedCallback); } @@ -235,7 +260,7 @@ public class DisplayWindowController public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, int startHeight) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransitionScaleUp( startX, startY, startWidth, startHeight); } @@ -243,7 +268,7 @@ public class DisplayWindowController public void overridePendingAppTransitionClipReveal(int startX, int startY, int startWidth, int startHeight) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId) .mAppTransition.overridePendingAppTransitionClipReveal(startX, startY, startWidth, startHeight); @@ -252,7 +277,7 @@ public class DisplayWindowController public void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX, int startY, IRemoteCallback startedCallback, boolean scaleUp) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId) .mAppTransition.overridePendingAppTransitionThumb(srcThumb, startX, startY, startedCallback, scaleUp); @@ -262,7 +287,7 @@ public class DisplayWindowController public void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX, int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback, boolean scaleUp) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId) .mAppTransition.overridePendingAppTransitionAspectScaledThumb(srcThumb, startX, startY, targetWidth, targetHeight, startedCallback, scaleUp); @@ -272,7 +297,7 @@ public class DisplayWindowController public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs, IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback, boolean scaleUp) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId) .mAppTransition.overridePendingAppTransitionMultiThumb(specs, onAnimationStartedCallback, onAnimationFinishedCallback, scaleUp); @@ -280,14 +305,14 @@ public class DisplayWindowController } public void overridePendingAppTransitionStartCrossProfileApps() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId) .mAppTransition.overridePendingAppTransitionStartCrossProfileApps(); } } public void overridePendingAppTransitionInPlace(String packageName, int anim) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.getDisplayContent(mDisplayId) .mAppTransition.overrideInPlaceAppTransition(packageName, anim); } @@ -299,7 +324,7 @@ public class DisplayWindowController * @return The pending app transition of the display. */ public @TransitionType int getPendingAppTransition() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mRoot.getDisplayContent(mDisplayId).mAppTransition.getAppTransition(); } } diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 8ed29a9b27d4..6daf2f5ab59d 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -27,14 +27,15 @@ import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_LEFT; import static android.view.WindowManager.DOCKED_RIGHT; import static android.view.WindowManager.DOCKED_TOP; +import static android.view.WindowManager.TRANSIT_NONE; + import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION; import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR; -import static android.view.WindowManager.TRANSIT_NONE; +import static com.android.server.wm.DockedStackDividerControllerProto.MINIMIZED_DOCK; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED; import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM; -import static com.android.server.wm.DockedStackDividerControllerProto.MINIMIZED_DOCK; import android.content.Context; import android.content.res.Configuration; @@ -170,7 +171,7 @@ public class DockedStackDividerController { final int orientation = mTmpRect2.width() <= mTmpRect2.height() ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; - final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation); + final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation, rotation); final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide, getContentWidth()); @@ -201,7 +202,7 @@ public class DockedStackDividerController { * @param orientation the origination of device * @return current docked side */ - int getDockSide(Rect bounds, Rect displayRect, int orientation) { + int getDockSide(Rect bounds, Rect displayRect, int orientation, int rotation) { if (orientation == Configuration.ORIENTATION_PORTRAIT) { // Portrait mode, docked either at the top or the bottom. final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top); @@ -210,7 +211,8 @@ public class DockedStackDividerController { } else if (diff < 0) { return DOCKED_BOTTOM; } - return canPrimaryStackDockTo(DOCKED_TOP) ? DOCKED_TOP : DOCKED_BOTTOM; + return canPrimaryStackDockTo(DOCKED_TOP, displayRect, rotation) + ? DOCKED_TOP : DOCKED_BOTTOM; } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { // Landscape mode, docked either on the left or on the right. final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left); @@ -219,7 +221,8 @@ public class DockedStackDividerController { } else if (diff < 0) { return DOCKED_RIGHT; } - return canPrimaryStackDockTo(DOCKED_LEFT) ? DOCKED_LEFT : DOCKED_RIGHT; + return canPrimaryStackDockTo(DOCKED_LEFT, displayRect, rotation) + ? DOCKED_LEFT : DOCKED_RIGHT; } return DOCKED_INVALID; } @@ -462,10 +465,9 @@ public class DockedStackDividerController { * @param dockSide the side to see if it is valid * @return true if the side provided is valid */ - boolean canPrimaryStackDockTo(int dockSide) { - final DisplayInfo di = mDisplayContent.getDisplayInfo(); - return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide, di.logicalWidth, - di.logicalHeight, di.rotation); + boolean canPrimaryStackDockTo(int dockSide, Rect parentRect, int rotation) { + return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide, + parentRect.width(), parentRect.height(), rotation); } void notifyDockedStackExistsChanged(boolean exists) { @@ -820,7 +822,7 @@ public class DockedStackDividerController { mService.mWaitingForDrawnCallback.run(); } mService.mWaitingForDrawnCallback = () -> { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mAnimationStartDelayed = false; if (mDelayedImeWin != null) { mDelayedImeWin.endDelayingAnimationStart(); diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index f42e97908724..ce8c979d3f87 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -104,7 +104,7 @@ class DragDropController { final boolean callbackResult = mCallback.get().prePerformDrag(window, dragToken, touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data); try { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { try { if (!callbackResult) { Slog.w(TAG_WM, "IDragDropCallback rejects the performDrag request"); @@ -209,7 +209,7 @@ class DragDropController { mCallback.get().preReportDropResult(window, consumed); try { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mDragState == null) { // Most likely the drop recipient ANRed and we ended the drag // out from under it. Log the issue and move on. @@ -248,7 +248,7 @@ class DragDropController { mCallback.get().preCancelDragAndDrop(dragToken); try { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mDragState == null) { Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()"); throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()"); @@ -277,7 +277,7 @@ class DragDropController { * @param newY Y coordinate value in dp in the screen coordinate */ void handleMotionEvent(boolean keepHandling, float newX, float newY) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (!dragDropActiveLocked()) { // The drag has ended but the clean-up message has not been processed by // window manager. Drop events that occur after this until window manager @@ -352,7 +352,7 @@ class DragDropController { Slog.w(TAG_WM, "Timeout ending drag to win " + win); } - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { // !!! TODO: ANR the drag-receiving app if (mDragState != null) { mDragState.mDragResult = false; @@ -368,14 +368,14 @@ class DragDropController { final DragState.InputInterceptor interceptor = (DragState.InputInterceptor) msg.obj; if (interceptor == null) return; - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { interceptor.tearDown(); } break; } case MSG_ANIMATION_END: { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mDragState == null) { Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " + "plyaing animation"); diff --git a/services/core/java/com/android/server/am/FactoryErrorDialog.java b/services/core/java/com/android/server/wm/FactoryErrorDialog.java index f4632c135dfc..88b5475cc3a2 100644 --- a/services/core/java/com/android/server/am/FactoryErrorDialog.java +++ b/services/core/java/com/android/server/wm/FactoryErrorDialog.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import android.content.Context; import android.content.DialogInterface; @@ -22,6 +22,8 @@ import android.os.Handler; import android.os.Message; import android.view.WindowManager; +import com.android.server.am.BaseErrorDialog; + final class FactoryErrorDialog extends BaseErrorDialog { public FactoryErrorDialog(Context context, CharSequence msg) { super(context); diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 10d77e59b0b3..f823caadad79 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -53,7 +53,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal return; } - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { WindowState windowState = (WindowState) inputWindowHandle.windowState; if (windowState != null) { Slog.i(TAG_WM, "WINDOW DIED " + windowState); @@ -74,7 +74,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal AppWindowToken appWindowToken = null; WindowState windowState = null; boolean aboveSystem = false; - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (inputWindowHandle != null) { windowState = (WindowState) inputWindowHandle.windowState; if (windowState != null) { diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index ed3e6c6ad810..0e4ab53e5c56 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -96,7 +96,7 @@ final class InputMonitor { @Override public void dismiss() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mInputMonitor.destroyInputConsumer(mWindowHandle.name)) { mInputEventReceiver.dispose(); } diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 9c41c77342e5..c91af73dc6dd 100644 --- a/services/core/java/com/android/server/am/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -14,11 +14,10 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; @@ -30,13 +29,13 @@ import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES; import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING; import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID; import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.os.IBinder; import android.os.RemoteException; @@ -48,10 +47,9 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.ActivityTaskManagerInternal.SleepToken; -import com.android.server.wm.DisplayWindowController; -import com.android.server.wm.WindowManagerService; import java.io.PrintWriter; +import java.util.Arrays; /** * Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are @@ -69,10 +67,9 @@ class KeyguardController { private boolean mAodShowing; private boolean mKeyguardGoingAway; private boolean mDismissalRequested; + private int[] mSecondaryDisplayIdsShowing; private int mBeforeUnoccludeTransit; private int mVisibilityTransactionDepth; - // TODO(b/111955725): Support multiple external displays - private int mSecondaryDisplayShowing = INVALID_DISPLAY; private final SparseArray<KeyguardDisplayState> mDisplayStates = new SparseArray<>(); private final ActivityTaskManagerService mService; @@ -92,7 +89,9 @@ class KeyguardController { */ boolean isKeyguardOrAodShowing(int displayId) { return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway - && !isDisplayOccluded(displayId); + && (displayId == DEFAULT_DISPLAY + ? !isDisplayOccluded(DEFAULT_DISPLAY) + : isShowingOnSecondaryDisplay(displayId)); } /** @@ -100,7 +99,10 @@ class KeyguardController { * display, false otherwise */ boolean isKeyguardShowing(int displayId) { - return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId); + return mKeyguardShowing && !mKeyguardGoingAway + && (displayId == DEFAULT_DISPLAY + ? !isDisplayOccluded(DEFAULT_DISPLAY) + : isShowingOnSecondaryDisplay(displayId)); } /** @@ -122,16 +124,17 @@ class KeyguardController { * Update the Keyguard showing state. */ void setKeyguardShown(boolean keyguardShowing, boolean aodShowing, - int secondaryDisplayShowing) { + int[] secondaryDisplaysShowing) { boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing; // If keyguard is going away, but SystemUI aborted the transition, need to reset state. showingChanged |= mKeyguardGoingAway && keyguardShowing; - if (!showingChanged && secondaryDisplayShowing == mSecondaryDisplayShowing) { + if (!showingChanged && Arrays.equals(secondaryDisplaysShowing, + mSecondaryDisplayIdsShowing)) { return; } mKeyguardShowing = keyguardShowing; mAodShowing = aodShowing; - mSecondaryDisplayShowing = secondaryDisplayShowing; + mSecondaryDisplayIdsShowing = secondaryDisplaysShowing; mWindowManager.setAodShowing(aodShowing); if (showingChanged) { dismissDockedStackIfNeeded(); @@ -147,6 +150,14 @@ class KeyguardController { updateKeyguardSleepToken(); } + private boolean isShowingOnSecondaryDisplay(int displayId) { + if (mSecondaryDisplayIdsShowing == null) return false; + for (int showingId : mSecondaryDisplayIdsShowing) { + if (displayId == showingId) return true; + } + return false; + } + /** * Called when Keyguard is going away. * @@ -388,16 +399,18 @@ class KeyguardController { } private KeyguardDisplayState getDisplay(int displayId) { - if (mDisplayStates.get(displayId) == null) { - mDisplayStates.append(displayId, - new KeyguardDisplayState(mService, displayId)); + KeyguardDisplayState state = mDisplayStates.get(displayId); + if (state == null) { + state = new KeyguardDisplayState(mService, displayId); + mDisplayStates.append(displayId, state); } - return mDisplayStates.get(displayId); + return state; } void onDisplayRemoved(int displayId) { - if (mDisplayStates.get(displayId) != null) { - mDisplayStates.get(displayId).onRemoved(); + final KeyguardDisplayState state = mDisplayStates.get(displayId); + if (state != null) { + state.onRemoved(); mDisplayStates.remove(displayId); } } @@ -458,7 +471,8 @@ class KeyguardController { mOccluded |= controller.mWindowManager.isShowingDream(); } - // TODO(b/113840485): Handle app transition for individual display. + // TODO(b/113840485): Handle app transition for individual display, and apply occluded + // state change to secondary displays. // For now, only default display can change occluded. if (lastOccluded != mOccluded && mDisplayId == DEFAULT_DISPLAY) { controller.handleOccludedChanged(); diff --git a/services/core/java/com/android/server/am/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java index 68e897fdbd3e..252f47ca16e8 100644 --- a/services/core/java/com/android/server/am/LaunchParamsController.java +++ b/services/core/java/com/android/server/wm/LaunchParamsController.java @@ -14,15 +14,15 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; -import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; -import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; import android.annotation.IntDef; import android.app.ActivityOptions; diff --git a/services/core/java/com/android/server/am/LaunchWarningWindow.java b/services/core/java/com/android/server/wm/LaunchWarningWindow.java index 30c306655af0..1c0093eeccd5 100644 --- a/services/core/java/com/android/server/am/LaunchWarningWindow.java +++ b/services/core/java/com/android/server/wm/LaunchWarningWindow.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import com.android.internal.R; diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index bcebaaab6aa9..41d0777d1c78 100644 --- a/services/core/java/com/android/server/am/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; @@ -28,15 +28,15 @@ import static android.os.UserHandle.USER_CURRENT; import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; +import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; +import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; +import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_PINNABLE; +import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_WHITELISTED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -66,8 +66,8 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; +import com.android.server.am.ActivityManagerService; import com.android.server.statusbar.StatusBarManagerInternal; -import com.android.server.wm.WindowManagerService; import java.io.PrintWriter; import java.util.ArrayList; @@ -412,7 +412,7 @@ public class LockTaskController { /** * Clear all locked tasks and request the end of LockTask mode. * - * This method is called by {@link UserController} when starting a new foreground user, and, + * This method is called by UserController when starting a new foreground user, and, * unlike {@link #stopLockTaskMode(TaskRecord, boolean, int)}, it doesn't perform the checks. */ void clearLockedTasks(String reason) { diff --git a/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java b/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java index 877d896d433d..dcb9a6a3e1f3 100644 --- a/services/core/java/com/android/server/am/PendingRemoteAnimationRegistry.java +++ b/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import android.annotation.Nullable; import android.app.ActivityOptions; @@ -22,6 +22,8 @@ import android.os.Handler; import android.util.ArrayMap; import android.view.RemoteAnimationAdapter; +import com.android.server.am.ActivityManagerService; + /** * Registry to keep track of remote animations to be run for activity starts from a certain package. * diff --git a/services/core/java/com/android/server/am/PersisterQueue.java b/services/core/java/com/android/server/wm/PersisterQueue.java index 60ea0faaffee..1cfc7acbb3df 100644 --- a/services/core/java/com/android/server/am/PersisterQueue.java +++ b/services/core/java/com/android/server/wm/PersisterQueue.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import android.os.Process; import android.os.SystemClock; @@ -171,6 +171,11 @@ class PersisterQueue { mListeners.add(listener); } + @VisibleForTesting + boolean removeListener(Listener listener) { + return mListeners.remove(listener); + } + private void processNextItem() throws InterruptedException { // This part is extracted into a method so that the GC can clearly see the end of the // scope of the variable 'item'. If this part was in the loop in LazyTaskWriterThread, the diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/wm/PinnedActivityStack.java index edc6e5362c8e..af1807785b20 100644 --- a/services/core/java/com/android/server/am/PinnedActivityStack.java +++ b/services/core/java/com/android/server/wm/PinnedActivityStack.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; @@ -23,9 +23,6 @@ import android.app.RemoteAction; import android.content.res.Configuration; import android.graphics.Rect; -import com.android.server.wm.PinnedStackWindowController; -import com.android.server.wm.PinnedStackWindowListener; - import java.util.ArrayList; import java.util.List; diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index b64d4f867faf..d21f67d908d5 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -20,10 +20,10 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.util.TypedValue.COMPLEX_UNIT_DIP; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.PinnedStackControllerProto.DEFAULT_BOUNDS; import static com.android.server.wm.PinnedStackControllerProto.MOVEMENT_BOUNDS; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.app.RemoteAction; import android.content.pm.ParceledListSlice; @@ -142,7 +142,7 @@ class PinnedStackController { @Override public int getDisplayRotation() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { return mDisplayInfo.rotation; } } @@ -288,7 +288,7 @@ class PinnedStackController { * will apply the default bounds to the provided snap fraction. */ Rect getDefaultBounds(float snapFraction) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final Rect insetBounds = new Rect(); getInsetBounds(insetBounds); @@ -314,8 +314,8 @@ class PinnedStackController { * onTaskStackBoundsChanged() to be called. But we still should update our known display info * with the new state so that we can update SystemUI. */ - synchronized void onDisplayInfoChanged() { - mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo()); + synchronized void onDisplayInfoChanged(DisplayInfo displayInfo) { + mDisplayInfo.copyFrom(displayInfo); notifyMovementBoundsChanged(false /* fromImeAdjustment */, false /* fromShelfAdjustment */); } @@ -324,7 +324,7 @@ class PinnedStackController { * new orientation of the device if necessary. */ boolean onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); if (mDisplayInfo.equals(displayInfo)) { // We are already in the right orientation, ignore @@ -481,7 +481,7 @@ class PinnedStackController { */ private void notifyMovementBoundsChanged(boolean fromImeAdjustment, boolean fromShelfAdjustment) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mPinnedStackListener == null) { return; } @@ -513,7 +513,7 @@ class PinnedStackController { * @return the bounds on the screen that the PIP can be visible in. */ private void getInsetBounds(Rect outRect) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mService.mPolicy.getStableInsetsLw(mDisplayInfo.rotation, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight, mDisplayInfo.displayCutout, mTmpInsets); outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y, @@ -527,7 +527,7 @@ class PinnedStackController { * controller. */ private Rect getMovementBounds(Rect stackBounds) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { return getMovementBounds(stackBounds, true /* adjustForIme */, true /* adjustForShelf */); } @@ -538,7 +538,7 @@ class PinnedStackController { * controller. */ private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme, boolean adjustForShelf) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final Rect movementBounds = new Rect(); getInsetBounds(movementBounds); @@ -554,7 +554,7 @@ class PinnedStackController { * Applies the minimized offsets to the given stack bounds. */ private void applyMinimizedOffset(Rect stackBounds, Rect movementBounds) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets); mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize, diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java index 1807eeb0ed52..bbdcc62ddbc0 100644 --- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java +++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java @@ -47,7 +47,7 @@ public class PinnedStackWindowController extends StackWindowController { * default bounds. */ public Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (!mService.mSupportsPictureInPicture || mContainer == null) { return null; } @@ -78,7 +78,7 @@ public class PinnedStackWindowController extends StackWindowController { */ public void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds, int animationDuration, boolean fromFullscreen) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { throw new IllegalArgumentException("Pinned stack container not found :("); } @@ -133,7 +133,7 @@ public class PinnedStackWindowController extends StackWindowController { * Sets the current picture-in-picture aspect ratio. */ public void setPictureInPictureAspectRatio(float aspectRatio) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (!mService.mSupportsPictureInPicture || mContainer == null) { return; } @@ -160,7 +160,7 @@ public class PinnedStackWindowController extends StackWindowController { * Sets the current picture-in-picture actions. */ public void setPictureInPictureActions(List<RemoteAction> actions) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (!mService.mSupportsPictureInPicture || mContainer == null) { return; } @@ -174,7 +174,7 @@ public class PinnedStackWindowController extends StackWindowController { * from fullscreen to non-fullscreen bounds. */ public boolean deferScheduleMultiWindowModeChanged() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mContainer.deferScheduleMultiWindowModeChanged(); } } @@ -183,7 +183,7 @@ public class PinnedStackWindowController extends StackWindowController { * @return whether the bounds are currently animating to fullscreen. */ public boolean isAnimatingBoundsToFullscreen() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mContainer.isAnimatingBoundsToFullscreen(); } } @@ -192,7 +192,7 @@ public class PinnedStackWindowController extends StackWindowController { * @return whether the stack can be resized from the bounds animation. */ public boolean pinnedStackResizeDisallowed() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mContainer.pinnedStackResizeDisallowed(); } } diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 57f939f4438b..c995d3fcbcc4 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.FLAG_AND_UNLOCKED; import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; @@ -33,14 +33,14 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.Process.SYSTEM_UID; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import android.app.ActivityManager; @@ -69,7 +69,8 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.am.TaskRecord.TaskActivitiesReport; +import com.android.server.am.ActivityManagerService; +import com.android.server.wm.TaskRecord.TaskActivitiesReport; import com.google.android.collect.Sets; diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 41d488babd92..9aeb0253250a 100644 --- a/services/core/java/com/android/server/am/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE; @@ -26,7 +26,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.WindowManager.TRANSIT_NONE; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; @@ -42,10 +42,9 @@ import android.os.Trace; import android.util.Slog; import android.view.IRecentsAnimationRunner; -import com.android.server.wm.DisplayWindowController; -import com.android.server.wm.RecentsAnimationController; +import com.android.server.wm.AssistDataReceiverProxy; +import com.android.server.am.AssistDataRequester; import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; -import com.android.server.wm.WindowManagerService; /** * Manages the recents animation, including the reordering of the stacks for the transition and @@ -123,7 +122,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, targetActivity); } - mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(); + mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent); mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true); diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 0ec4baf06099..f5acdccf07f4 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -182,7 +182,7 @@ class RemoteAnimationController implements DeathRecipient { if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "onAnimationFinished(): mPendingAnimations=" + mPendingAnimations.size()); mHandler.removeCallbacks(mTimeoutRunnable); - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { unlinkToDeathOfRunner(); releaseFinishedCallback(); mService.openSurfaceTransaction(); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 62078f722434..8c0c073ce11a 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -42,7 +42,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION; import static com.android.server.wm.WindowManagerService.H.WINDOW_FREEZE_TIMEOUT; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; @@ -55,6 +54,7 @@ import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PEN import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE; import android.annotation.CallSuper; +import android.annotation.NonNull; import android.content.res.Configuration; import android.hardware.power.V1_0.PowerHint; import android.os.Binder; @@ -76,12 +76,10 @@ import android.view.DisplayInfo; import android.view.SurfaceControl; import android.view.WindowManager; -import com.android.internal.util.ArrayUtils; import com.android.server.EventLogTags; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.List; import java.util.function.Consumer; /** Root {@link WindowContainer} for the device. */ @@ -116,9 +114,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { boolean mOrientationChangeComplete = true; boolean mWallpaperActionPending = false; - private final ArrayList<TaskStack> mTmpStackList = new ArrayList(); - private final ArrayList<Integer> mTmpStackIds = new ArrayList<>(); - final WallpaperController mWallpaperController; private final Handler mHandler; @@ -314,57 +309,33 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { } /** - * Set new display override config and return array of ids of stacks that were changed during - * update. If called for the default display, global configuration will also be updated. Stacks - * that are marked for deferred removal are excluded from the returned array. + * Set new display override config. If called for the default display, global configuration + * will also be updated. */ - int[] setDisplayOverrideConfigurationIfNeeded(Configuration newConfiguration, int displayId) { - final DisplayContent displayContent = getDisplayContent(displayId); - if (displayContent == null) { - throw new IllegalArgumentException("Display not found for id: " + displayId); - } + void setDisplayOverrideConfigurationIfNeeded(Configuration newConfiguration, + @NonNull DisplayContent displayContent) { final Configuration currentConfig = displayContent.getOverrideConfiguration(); final boolean configChanged = currentConfig.diff(newConfiguration) != 0; if (!configChanged) { - return null; + return; } displayContent.onOverrideConfigurationChanged(newConfiguration); - mTmpStackList.clear(); - if (displayId == DEFAULT_DISPLAY) { + if (displayContent.getDisplayId() == DEFAULT_DISPLAY) { // Override configuration of the default display duplicates global config. In this case // we also want to update the global config. - setGlobalConfigurationIfNeeded(newConfiguration, mTmpStackList); - } else { - updateStackBoundsAfterConfigChange(displayId, mTmpStackList); - } - - mTmpStackIds.clear(); - final int stackCount = mTmpStackList.size(); - - for (int i = 0; i < stackCount; ++i) { - final TaskStack stack = mTmpStackList.get(i); - - // We only include stacks that are not marked for removal as they do not exist outside - // of WindowManager at this point. - if (!stack.mDeferRemoval) { - mTmpStackIds.add(stack.mStackId); - } + setGlobalConfigurationIfNeeded(newConfiguration); } - - return mTmpStackIds.isEmpty() ? null : ArrayUtils.convertToIntArray(mTmpStackIds); } - private void setGlobalConfigurationIfNeeded(Configuration newConfiguration, - List<TaskStack> changedStacks) { + private void setGlobalConfigurationIfNeeded(Configuration newConfiguration) { final boolean configChanged = getConfiguration().diff(newConfiguration) != 0; if (!configChanged) { return; } onConfigurationChanged(newConfiguration); - updateStackBoundsAfterConfigChange(changedStacks); } @Override @@ -375,24 +346,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { forAllDisplays(mDisplayContentConfigChangesConsumer); } - /** - * Callback used to trigger bounds update after configuration change and get ids of stacks whose - * bounds were updated. - */ - private void updateStackBoundsAfterConfigChange(List<TaskStack> changedStacks) { - final int numDisplays = mChildren.size(); - for (int i = 0; i < numDisplays; ++i) { - final DisplayContent dc = mChildren.get(i); - dc.updateStackBoundsAfterConfigChange(changedStacks); - } - } - - /** Same as {@link #updateStackBoundsAfterConfigChange()} but only for a specific display. */ - private void updateStackBoundsAfterConfigChange(int displayId, List<TaskStack> changedStacks) { - final DisplayContent dc = getDisplayContent(displayId); - dc.updateStackBoundsAfterConfigChange(changedStacks); - } - private void prepareFreezingTaskBounds() { for (int i = mChildren.size() - 1; i >= 0; i--) { mChildren.get(i).prepareFreezingTaskBounds(); @@ -911,10 +864,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { boolean changed = false; for (int i = mChildren.size() - 1; i >= 0; i--) { final DisplayContent displayContent = mChildren.get(i); - if (displayContent.updateRotationUnchecked()) { + if (displayContent.updateRotationAndSendNewConfigIfNeeded()) { changed = true; - mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayContent.getDisplayId()) - .sendToTarget(); } } return changed; diff --git a/services/core/java/com/android/server/wm/RootWindowContainerController.java b/services/core/java/com/android/server/wm/RootWindowContainerController.java index 93be6e9b68e3..11762201852b 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainerController.java +++ b/services/core/java/com/android/server/wm/RootWindowContainerController.java @@ -25,7 +25,7 @@ public class RootWindowContainerController public RootWindowContainerController(RootWindowContainerListener listener) { super(listener, WindowManagerService.getInstance()); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.setController(this); } } @@ -39,7 +39,7 @@ public class RootWindowContainerController /** Move the display to the given position. */ public void positionChildAt(DisplayWindowController child, int position) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mContainer.positionChildAt(position, child.mContainer); } } diff --git a/services/core/java/com/android/server/am/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java index d878f5124f43..34282cdb7ed9 100644 --- a/services/core/java/com/android/server/am/RunningTasks.java +++ b/services/core/java/com/android/server/wm/RunningTasks.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import android.app.ActivityManager.RunningTaskInfo; import android.app.WindowConfiguration.ActivityType; diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java index 115216592e71..ac9028329023 100644 --- a/services/core/java/com/android/server/am/SafeActivityOptions.java +++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; @@ -22,8 +22,8 @@ import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.view.Display.INVALID_DISPLAY; import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.Nullable; import android.app.ActivityOptions; @@ -62,7 +62,7 @@ public class SafeActivityOptions { * * @param bOptions The {@link ActivityOptions} as {@link Bundle}. */ - static SafeActivityOptions fromBundle(Bundle bOptions) { + public static SafeActivityOptions fromBundle(Bundle bOptions) { return bOptions != null ? new SafeActivityOptions(ActivityOptions.fromBundle(bOptions)) : null; @@ -75,7 +75,7 @@ public class SafeActivityOptions { * * @param options The options to wrap. */ - SafeActivityOptions(@Nullable ActivityOptions options) { + public SafeActivityOptions(@Nullable ActivityOptions options) { mOriginalCallingPid = Binder.getCallingPid(); mOriginalCallingUid = Binder.getCallingUid(); mOriginalOptions = options; @@ -86,7 +86,7 @@ public class SafeActivityOptions { * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this * method. */ - void setCallerOptions(@Nullable ActivityOptions options) { + public void setCallerOptions(@Nullable ActivityOptions options) { mRealCallingPid = Binder.getCallingPid(); mRealCallingUid = Binder.getCallingUid(); mCallerOptions = options; diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index acc9c038bd9c..b411fad814c5 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -143,7 +143,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void binderDied() { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mCallback.asBinder().unlinkToDeath(this, 0); mClientDead = true; killSessionLocked(); @@ -229,14 +229,14 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void setInTouchMode(boolean mode) { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mService.mInTouchMode = mode; } } @Override public boolean getInTouchMode() { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { return mService.mInTouchMode; } } @@ -244,7 +244,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public boolean performHapticFeedback(IWindow window, int effectId, boolean always) { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { long ident = Binder.clearCallingIdentity(); try { return mService.mPolicy.performHapticFeedbackLw( @@ -317,7 +317,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { long ident = Binder.clearCallingIdentity(); try { mService.mRoot.mWallpaperController.setWindowWallpaperPosition( @@ -331,14 +331,14 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void wallpaperOffsetsComplete(IBinder window) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mService.mRoot.mWallpaperController.wallpaperOffsetsComplete(window); } } @Override public void setWallpaperDisplayOffset(IBinder window, int x, int y) { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { long ident = Binder.clearCallingIdentity(); try { mService.mRoot.mWallpaperController.setWindowWallpaperDisplayOffset( @@ -352,7 +352,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y, int z, Bundle extras, boolean sync) { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { long ident = Binder.clearCallingIdentity(); try { return mService.mRoot.mWallpaperController.sendWindowWallpaperCommand( @@ -366,14 +366,14 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void wallpaperCommandComplete(IBinder window, Bundle result) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mService.mRoot.mWallpaperController.wallpaperCommandComplete(window); } } @Override public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final long identity = Binder.clearCallingIdentity(); try { mService.onRectangleOnScreenRequested(token, rectangle); diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java index 6ac63a1dd14a..d8e1ebfbb1b1 100644 --- a/services/core/java/com/android/server/wm/StackWindowController.java +++ b/services/core/java/com/android/server/wm/StackWindowController.java @@ -16,6 +16,11 @@ package com.android.server.wm; +import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; +import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + import android.app.WindowConfiguration; import android.content.res.Configuration; import android.graphics.Rect; @@ -31,11 +36,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.lang.ref.WeakReference; -import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; -import static com.android.server.wm.WindowContainer.POSITION_TOP; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - /** * Controller for the stack container. This is created by activity manager to link activity stacks * to the stack container they use in window manager. @@ -67,7 +67,7 @@ public class StackWindowController mStackId = stackId; mHandler = new H(new WeakReference<>(this), service.mH.getLooper()); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { throw new IllegalArgumentException("Trying to add stackId=" + stackId @@ -81,7 +81,7 @@ public class StackWindowController @Override public void removeContainer() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer != null) { mContainer.removeIfPossible(); super.removeContainer(); @@ -90,7 +90,7 @@ public class StackWindowController } public void reparent(int displayId, Rect outStackBounds, boolean onTop) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { throw new IllegalArgumentException("Trying to move unknown stackId=" + mStackId + " to displayId=" + displayId); @@ -108,7 +108,7 @@ public class StackWindowController } public void positionChildAt(TaskWindowContainerController child, int position) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_STACK) Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position); if (child.mContainer == null) { @@ -132,7 +132,7 @@ public class StackWindowController return; } - synchronized(mWindowMap) { + synchronized (mGlobalLock) { final Task childTask = child.mContainer; if (childTask == null) { Slog.e(TAG_WM, "positionChildAtTop: task=" + child + " not found"); @@ -155,7 +155,7 @@ public class StackWindowController return; } - synchronized(mWindowMap) { + synchronized (mGlobalLock) { final Task childTask = child.mContainer; if (childTask == null) { Slog.e(TAG_WM, "positionChildAtBottom: task=" + child + " not found"); @@ -179,7 +179,7 @@ public class StackWindowController */ public void resize(Rect bounds, SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { throw new IllegalArgumentException("resizeStack: stack " + this + " not found."); } @@ -194,7 +194,7 @@ public class StackWindowController } public void onPipAnimationEndResize() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mContainer.onPipAnimationEndResize(); } } @@ -204,7 +204,7 @@ public class StackWindowController */ public void getStackDockedModeBounds(Rect currentTempTaskBounds, Rect outStackBounds, Rect outTempTaskBounds, boolean ignoreVisibility) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer != null) { mContainer.getStackDockedModeBoundsLocked(currentTempTaskBounds, outStackBounds, outTempTaskBounds, ignoreVisibility); @@ -216,7 +216,7 @@ public class StackWindowController } public void prepareFreezingTaskBounds() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { throw new IllegalArgumentException("prepareFreezingTaskBounds: stack " + this + " not found."); @@ -226,7 +226,7 @@ public class StackWindowController } public void getRawBounds(Rect outBounds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer.matchParentBounds()) { outBounds.setEmpty(); } else { @@ -236,7 +236,7 @@ public class StackWindowController } public void getBounds(Rect outBounds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer != null) { mContainer.getBounds(outBounds); return; @@ -245,12 +245,6 @@ public class StackWindowController } } - public void getBoundsForNewConfiguration(Rect outBounds) { - synchronized(mWindowMap) { - mContainer.getBoundsForNewConfiguration(outBounds); - } - } - /** * Adjusts the screen size in dp's for the {@param config} for the given params. The provided * params represent the desired state of a configuration change. Since this utility is used @@ -261,7 +255,7 @@ public class StackWindowController Rect nonDecorBounds, Rect stableBounds, boolean overrideWidth, boolean overrideHeight, float density, Configuration config, Configuration parentConfig, int windowingMode) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final TaskStack stack = mContainer; final DisplayContent displayContent = stack.getDisplayContent(); final DisplayInfo di = displayContent.getDisplayInfo(); @@ -378,6 +372,14 @@ public class StackWindowController mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget(); } + /** @see TaskStack.updateBoundsForConfigChange(Configuration, Configuration, Rect) */ + public boolean updateBoundsForConfigChange( + Configuration parentConfig, Configuration prevConfig, Rect outBounds) { + synchronized (mGlobalLock) { + return mContainer.updateBoundsForConfigChange(parentConfig, prevConfig, outBounds); + } + } + @Override public String toString() { return "{StackWindowController stackId=" + mStackId + "}"; diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index ba3d091f4a08..3ea615a3b58a 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -71,7 +71,7 @@ class SurfaceAnimator { private OnAnimationFinishedCallback getFinishedCallback( @Nullable Runnable animationFinishedCallback) { return anim -> { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim); if (target != null) { target.mInnerAnimationFinishedCallback.onAnimationFinished(anim); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 2a529d95fcff..30eca89a88ec 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -227,7 +227,7 @@ class Task extends WindowContainer<AppWindowToken> { } } - /** @see com.android.server.am.ActivityTaskManagerService#positionTaskInStack(int, int, int). */ + /** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */ void positionAt(int position) { mStack.positionChildAt(position, this, false /* includingParents */); } @@ -290,12 +290,7 @@ class Task extends WindowContainer<AppWindowToken> { if (displayContent != null) { rotation = displayContent.getDisplayInfo().rotation; } else if (bounds == null) { - // Can't set to fullscreen if we don't have a display to get bounds from... - return BOUNDS_CHANGE_NONE; - } - - if (equivalentOverrideBounds(bounds)) { - return BOUNDS_CHANGE_NONE; + return super.setBounds(bounds); } final int boundsChange = super.setBounds(bounds); diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java index efb80bee5d6f..3b3feacc5cda 100644 --- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import android.app.ActivityManager.TaskSnapshot; import android.app.ITaskStackListener; diff --git a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index c15b4acd971d..b7804e8d13a8 100644 --- a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -35,8 +35,8 @@ import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import android.annotation.NonNull; import android.annotation.Nullable; @@ -49,8 +49,8 @@ import android.os.Build; import android.util.Slog; import android.view.Gravity; -import com.android.server.am.LaunchParamsController.LaunchParams; -import com.android.server.am.LaunchParamsController.LaunchParamsModifier; +import com.android.server.wm.LaunchParamsController.LaunchParams; +import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; import java.util.ArrayList; import java.util.List; diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java index fc5dfb4db1fc..9705d42464d5 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/wm/TaskPersister.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; -import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; +import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; import android.annotation.NonNull; import android.graphics.Bitmap; diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index d2696c0479af..66ebc9b27358 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -159,7 +159,7 @@ class TaskPositioner { if (DEBUG_TASK_POSITIONING){ Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}"); } - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mDragEnded = notifyMoveLocked(newX, newY); mTask.getDimBounds(mTmpRect); } @@ -192,7 +192,7 @@ class TaskPositioner { if (mDragEnded) { final boolean wasResizing = mResizing; - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { endDragLocked(); mTask.getDimBounds(mTmpRect); } @@ -397,7 +397,7 @@ class TaskPositioner { // bounds yet. This will guarantee that the app starts the backdrop renderer before // configuration changes which could cause an activity restart. if (mResizing) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { notifyMoveLocked(startX, startY); } diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 25148d15343a..f2d3dca27cf9 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -61,7 +61,7 @@ class TaskPositioningController { boolean startMovingTask(IWindow window, float startX, float startY) { WindowState win = null; - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { win = mService.windowForClientLocked(null, window, false); // win shouldn't be null here, pass it down to startPositioningLocked // to get warning if it's null. @@ -79,7 +79,7 @@ class TaskPositioningController { void handleTapOutsideTask(DisplayContent displayContent, int x, int y) { mHandler.post(() -> { int taskId = -1; - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final Task task = displayContent.findTaskForResizePoint(x, y); if (task != null) { if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/, @@ -152,7 +152,7 @@ class TaskPositioningController { mHandler.post(() -> { if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning"); - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mTaskPositioner != null) { mTaskPositioner.unregister(); mTaskPositioner = null; diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index 5f5916331e67..d697f28a66eb 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.ActivityTaskManager.INVALID_TASK_ID; @@ -46,22 +46,22 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VER import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN; -import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; -import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP; -import static com.android.server.am.ActivityStackSupervisor.ON_TOP; -import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY; -import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP; +import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; +import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.am.TaskRecordProto.ACTIVITIES; import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE; import static com.android.server.am.TaskRecordProto.BOUNDS; @@ -109,13 +109,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.util.XmlUtils; -import com.android.server.am.ActivityStack.ActivityState; -import com.android.server.wm.AppWindowContainerController; -import com.android.server.wm.ConfigurationContainer; -import com.android.server.wm.StackWindowController; -import com.android.server.wm.TaskWindowContainerController; -import com.android.server.wm.TaskWindowContainerListener; -import com.android.server.wm.WindowManagerService; +import com.android.server.wm.ActivityStack.ActivityState; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java index 7bf4edb2c97a..8175c4a1b528 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java @@ -58,7 +58,7 @@ class TaskSnapshotCache { @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk, boolean reducedResolution) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { // Try the running cache. final CacheEntry entry = mRunningCache.get(taskId); if (entry != null) { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 0d5469bd4847..b84d20d5c63e 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -436,7 +436,7 @@ class TaskSnapshotController { // We can't take a snapshot when screen is off, so take a snapshot now! mHandler.post(() -> { try { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mTmpTasks.clear(); mService.mRoot.forAllTasks(task -> { if (task.isVisible()) { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 67d2be874a31..a7b0272d4b0d 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -149,7 +149,7 @@ class TaskSnapshotSurface implements StartingSurface { final int windowFlags; final int windowPrivateFlags; final int currentOrientation; - synchronized (service.mWindowMap) { + synchronized (service.mGlobalLock) { final WindowState mainWindow = token.findMainWindow(); final Task task = token.getTask(); if (task == null) { @@ -248,7 +248,7 @@ class TaskSnapshotSurface implements StartingSurface { @Override public void remove() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final long now = SystemClock.uptimeMillis(); if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) { mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS); @@ -288,7 +288,7 @@ class TaskSnapshotSurface implements StartingSurface { } else { drawSizeMatchSnapshot(buffer); } - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mShownTime = SystemClock.uptimeMillis(); mHasDrawn = true; } @@ -422,7 +422,7 @@ class TaskSnapshotSurface implements StartingSurface { case MSG_REPORT_DRAW: final boolean hasDrawn; final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj; - synchronized (surface.mService.mWindowMap) { + synchronized (surface.mService.mGlobalLock) { hasDrawn = surface.mHasDrawn; } if (hasDrawn) { diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index f39ba6d0db74..4dc2b8ec8858 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -23,6 +23,9 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; @@ -61,6 +64,7 @@ import android.util.EventLog; import android.util.Slog; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; +import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.Surface; import android.view.SurfaceControl; @@ -143,10 +147,6 @@ public class TaskStack extends WindowContainer<Task> implements private Rect mBoundsAnimationTarget = new Rect(); private Rect mBoundsAnimationSourceHintBounds = new Rect(); - // Temporary storage for the new bounds that should be used after the configuration change. - // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration(). - private final Rect mBoundsAfterRotation = new Rect(); - Rect mPreAnimationBounds = new Rect(); private Dimmer mDimmer = new Dimmer(this); @@ -292,8 +292,9 @@ public class TaskStack extends WindowContainer<Task> implements private int setBounds(Rect existing, Rect bounds) { int rotation = Surface.ROTATION_0; int density = DENSITY_DPI_UNDEFINED; - if (mDisplayContent != null) { - mDisplayContent.getBounds(mTmpRect); + WindowContainer parent = getParent(); + if (parent != null) { + parent.getBounds(mTmpRect); rotation = mDisplayContent.getDisplayInfo().rotation; density = mDisplayContent.getDisplayInfo().logicalDensityDpi; } @@ -443,20 +444,33 @@ public class TaskStack extends WindowContainer<Task> implements // If the rotation or density didn't match, we'll update it in onConfigurationChanged. } - /** @return true if bounds were updated to some non-empty value. */ - boolean updateBoundsAfterConfigChange() { - if (mDisplayContent == null) { - // If the stack is already detached we're not updating anything, - // as it's going away soon anyway. - return false; - } - - if (inPinnedWindowingMode()) { - getAnimationOrCurrentBounds(mTmpRect2); + /** + * Updates the passed-in {@code inOutBounds} based on how it would change when this container's + * override configuration is applied to the specified {@code parentConfig} and + * {@code prevConfig}. This gets run *after* the override configuration is updated, so it's + * safe to rely on wm hierarchy state in here (though eventually this dependence should be + * removed). + * + * This does NOT modify this TaskStack's configuration. However, it does, for the time-being, + * update various controller state (pinned/docked). + * + * @param parentConfig a parent configuration to compute relative to. + * @param prevConfig the full configuration used to produce the incoming {@code inOutBounds}. + * @param inOutBounds the bounds to update (both input and output). + * @return true if bounds were updated to some non-empty value. */ + boolean updateBoundsForConfigChange( + Configuration parentConfig, Configuration prevConfig, Rect inOutBounds) { + if (getOverrideWindowingMode() == WINDOWING_MODE_PINNED) { + if ((mBoundsAnimatingRequested || mBoundsAnimating) + && !mBoundsAnimationTarget.isEmpty()) { + getFinalAnimationBounds(mTmpRect2); + } else { + mTmpRect2.set(prevConfig.windowConfiguration.getBounds()); + } boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged( mTmpRect2, mTmpRect3); if (updated) { - mBoundsAfterRotation.set(mTmpRect3); + inOutBounds.set(mTmpRect3); // Once we've set the bounds based on the rotation of the old bounds in the new // orientation, clear the animation target bounds since they are obsolete, and @@ -464,72 +478,75 @@ public class TaskStack extends WindowContainer<Task> implements mBoundsAnimationTarget.setEmpty(); mBoundsAnimationSourceHintBounds.setEmpty(); mCancelCurrentBoundsAnimation = true; - return true; } + return updated; } - final int newRotation = getDisplayInfo().rotation; - final int newDensity = getDisplayInfo().logicalDensityDpi; + final int newRotation = parentConfig.windowConfiguration.getRotation(); + final int newDensity = parentConfig.densityDpi; - if (mRotation == newRotation && mDensity == newDensity) { - // Nothing to do here as we already update the state in updateDisplayInfo. + if (prevConfig.windowConfiguration.getRotation() == newRotation + && prevConfig.densityDpi == newDensity) { return false; } if (matchParentBounds()) { - // Update stack bounds again since rotation changed since updateDisplayInfo(). - setBounds(null); - // Return false since we don't need the client to resize. return false; } - mTmpRect2.set(getRawBounds()); - mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2); - if (inSplitScreenPrimaryWindowingMode()) { - repositionPrimarySplitScreenStackAfterRotation(mTmpRect2); - snapDockedStackAfterRotation(mTmpRect2); - final int newDockSide = getDockSide(mTmpRect2); - - // Update the dock create mode and clear the dock create bounds, these - // might change after a rotation and the original values will be invalid. - mService.setDockedStackCreateStateLocked( - (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP) - ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT - : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, - null); - mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); + mDisplayContent.rotateBounds(parentConfig.windowConfiguration.getBounds(), + prevConfig.windowConfiguration.getRotation(), newRotation, inOutBounds); + if (getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY + || getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { + boolean primary = getOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; + repositionSplitScreenStackAfterRotation(parentConfig, primary, inOutBounds); + final DisplayCutout cutout = mDisplayContent.getDisplayInfo().displayCutout; + snapDockedStackAfterRotation(parentConfig, cutout, inOutBounds); + if (primary) { + final int newDockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds); + + // Update the dock create mode and clear the dock create bounds, these + // might change after a rotation and the original values will be invalid. + mService.setDockedStackCreateStateLocked( + (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP) + ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT + : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, + null); + mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); + } } - mBoundsAfterRotation.set(mTmpRect2); return true; } - void getBoundsForNewConfiguration(Rect outBounds) { - outBounds.set(mBoundsAfterRotation); - mBoundsAfterRotation.setEmpty(); - } - /** * Some primary split screen sides are not allowed by the policy. This method queries the policy * and moves the primary stack around if needed. * - * @param inOutBounds the bounds of the primary stack to adjust + * @param parentConfig the configuration of the stack's parent. + * @param primary true if adjusting the primary docked stack, false for secondary. + * @param inOutBounds the bounds of the stack to adjust. */ - private void repositionPrimarySplitScreenStackAfterRotation(Rect inOutBounds) { - int dockSide = getDockSide(inOutBounds); - if (mDisplayContent.getDockedDividerController().canPrimaryStackDockTo(dockSide)) { + void repositionSplitScreenStackAfterRotation(Configuration parentConfig, boolean primary, + Rect inOutBounds) { + final int dockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds); + final int otherDockSide = DockedDividerUtils.invertDockSide(dockSide); + final int primaryDockSide = primary ? dockSide : otherDockSide; + if (mDisplayContent.getDockedDividerController() + .canPrimaryStackDockTo(primaryDockSide, + parentConfig.windowConfiguration.getBounds(), + parentConfig.windowConfiguration.getRotation())) { return; } - mDisplayContent.getBounds(mTmpRect); - dockSide = DockedDividerUtils.invertDockSide(dockSide); - switch (dockSide) { + final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); + switch (otherDockSide) { case DOCKED_LEFT: int movement = inOutBounds.left; inOutBounds.left -= movement; inOutBounds.right -= movement; break; case DOCKED_RIGHT: - movement = mTmpRect.right - inOutBounds.right; + movement = parentBounds.right - inOutBounds.right; inOutBounds.left += movement; inOutBounds.right += movement; break; @@ -539,7 +556,7 @@ public class TaskStack extends WindowContainer<Task> implements inOutBounds.bottom -= movement; break; case DOCKED_BOTTOM: - movement = mTmpRect.bottom - inOutBounds.bottom; + movement = parentBounds.bottom - inOutBounds.bottom; inOutBounds.top += movement; inOutBounds.bottom += movement; break; @@ -549,22 +566,22 @@ public class TaskStack extends WindowContainer<Task> implements /** * Snaps the bounds after rotation to the closest snap target for the docked stack. */ - private void snapDockedStackAfterRotation(Rect outBounds) { + void snapDockedStackAfterRotation(Configuration parentConfig, DisplayCutout displayCutout, + Rect outBounds) { // Calculate the current position. - final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth(); - final int dockSide = getDockSide(outBounds); + final int dockSide = getDockSide(parentConfig, outBounds); final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds, dockSide, dividerSize); - final int displayWidth = displayInfo.logicalWidth; - final int displayHeight = displayInfo.logicalHeight; + final int displayWidth = parentConfig.windowConfiguration.getBounds().width(); + final int displayHeight = parentConfig.windowConfiguration.getBounds().height(); // Snap the position to a target. - final int rotation = displayInfo.rotation; - final int orientation = mDisplayContent.getConfiguration().orientation; + final int rotation = parentConfig.windowConfiguration.getRotation(); + final int orientation = parentConfig.orientation; mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, - displayInfo.displayCutout, outBounds); + displayCutout, outBounds); final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm( mService.mContext.getResources(), displayWidth, displayHeight, dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds, @@ -573,7 +590,7 @@ public class TaskStack extends WindowContainer<Task> implements // Recalculate the bounds based on the position of the target. DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide, - outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight, + outBounds, displayWidth, displayHeight, dividerSize); } @@ -1473,27 +1490,27 @@ public class TaskStack extends WindowContainer<Task> implements * information which side of the screen was the dock anchored. */ int getDockSide() { - return getDockSide(getRawBounds()); + return getDockSide(mDisplayContent.getConfiguration(), getRawBounds()); } int getDockSideForDisplay(DisplayContent dc) { - return getDockSide(dc, getRawBounds()); + return getDockSide(dc, dc.getConfiguration(), getRawBounds()); } - private int getDockSide(Rect bounds) { + int getDockSide(Configuration parentConfig, Rect bounds) { if (mDisplayContent == null) { return DOCKED_INVALID; } - return getDockSide(mDisplayContent, bounds); + return getDockSide(mDisplayContent, parentConfig, bounds); } - private int getDockSide(DisplayContent dc, Rect bounds) { + private int getDockSide(DisplayContent dc, Configuration parentConfig, Rect bounds) { if (!inSplitScreenWindowingMode()) { return DOCKED_INVALID; } - dc.getBounds(mTmpRect); - final int orientation = dc.getConfiguration().orientation; - return dc.getDockedDividerController().getDockSide(bounds, mTmpRect, orientation); + return dc.getDockedDividerController().getDockSide(bounds, + parentConfig.windowConfiguration.getBounds(), + parentConfig.orientation, parentConfig.windowConfiguration.getRotation()); } boolean hasTaskForUser(int userId) { @@ -1622,7 +1639,7 @@ public class TaskStack extends WindowContainer<Task> implements public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) { // Hold the lock since this is called from the BoundsAnimator running on the UiThread - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mCancelCurrentBoundsAnimation) { return false; } @@ -1647,7 +1664,7 @@ public class TaskStack extends WindowContainer<Task> implements @Override // AnimatesBounds public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) { // Hold the lock since this is called from the BoundsAnimator running on the UiThread - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (!isAttached()) { // Don't run the animation if the stack is already detached return false; @@ -1726,7 +1743,7 @@ public class TaskStack extends WindowContainer<Task> implements @Override public boolean isAttached() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { return mDisplayContent != null; } } @@ -1735,7 +1752,7 @@ public class TaskStack extends WindowContainer<Task> implements * Called immediately prior to resizing the tasks at the end of the pinned stack animation. */ public void onPipAnimationEndResize() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mBoundsAnimating = false; for (int i = 0; i < mChildren.size(); i++) { final Task t = mChildren.get(i); @@ -1747,7 +1764,7 @@ public class TaskStack extends WindowContainer<Task> implements @Override public boolean shouldDeferStartOnMoveToFullscreen() { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { // Workaround for the recents animation -- normally we need to wait for the new activity // to show before starting the PiP animation, but because we start and show the home // activity early for the recents animation prior to the PiP animation starting, there diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java index 52f8510d6a99..53d2cb094c44 100644 --- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java +++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java @@ -47,7 +47,7 @@ public class TaskTapPointerEventListener implements PointerEventListener { mDisplayContent = displayContent; mHandler = new Handler(mService.mH.getLooper()); mMoveDisplayToTop = () -> { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mDisplayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent, true /* includingParents */); } diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java index 8b634b1bb938..59b2055193ae 100644 --- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java +++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java @@ -65,7 +65,7 @@ public class TaskWindowContainerController mTaskId = taskId; mHandler = new H(new WeakReference<>(this), service.mH.getLooper()); - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_STACK) Slog.i(TAG_WM, "TaskWindowContainerController: taskId=" + taskId + " stack=" + stackController + " bounds=" + bounds); @@ -93,7 +93,7 @@ public class TaskWindowContainerController @Override public void removeContainer() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId); return; @@ -108,7 +108,7 @@ public class TaskWindowContainerController } public void positionChildAt(AppWindowContainerController childController, int position) { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final AppWindowToken aToken = childController.mContainer; if (aToken == null) { Slog.w(TAG_WM, @@ -125,7 +125,7 @@ public class TaskWindowContainerController } public void reparent(StackWindowController stackController, int position, boolean moveParents) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_STACK) Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId + " to stack=" + stackController + " at " + position); if (mContainer == null) { @@ -144,7 +144,7 @@ public class TaskWindowContainerController } public void setResizeable(int resizeMode) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer != null) { mContainer.setResizeable(resizeMode); } @@ -152,7 +152,7 @@ public class TaskWindowContainerController } public void resize(boolean relayout, boolean forced) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { throw new IllegalArgumentException("resizeTask: taskId " + mTaskId + " not found."); } @@ -165,7 +165,7 @@ public class TaskWindowContainerController } public void getBounds(Rect bounds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer != null) { mContainer.getBounds(bounds); return; @@ -180,7 +180,7 @@ public class TaskWindowContainerController * @param resizing Whether to put the task into drag resize mode. */ public void setTaskDockedResizing(boolean resizing) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found."); return; @@ -190,7 +190,7 @@ public class TaskWindowContainerController } public void cancelWindowTransition() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found."); return; @@ -200,7 +200,7 @@ public class TaskWindowContainerController } public void setTaskDescription(TaskDescription taskDescription) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { Slog.w(TAG_WM, "setTaskDescription: taskId " + mTaskId + " not found."); return; @@ -210,7 +210,7 @@ public class TaskWindowContainerController } public boolean isDragResizing() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mContainer.isDragResizing(); } } diff --git a/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java b/services/core/java/com/android/server/wm/UnsupportedCompileSdkDialog.java index 7348a0d5a365..6a878b983543 100644 --- a/services/core/java/com/android/server/am/UnsupportedCompileSdkDialog.java +++ b/services/core/java/com/android/server/wm/UnsupportedCompileSdkDialog.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import android.app.AlertDialog; import android.content.Context; diff --git a/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java b/services/core/java/com/android/server/wm/UnsupportedDisplaySizeDialog.java index 1d6438c6e79f..4a800c41fdeb 100644 --- a/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java +++ b/services/core/java/com/android/server/wm/UnsupportedDisplaySizeDialog.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.am; +package com.android.server.wm; import com.android.internal.R; diff --git a/services/core/java/com/android/server/am/VrController.java b/services/core/java/com/android/server/wm/VrController.java index 51d86d66e6c1..abe40a731a43 100644 --- a/services/core/java/com/android/server/am/VrController.java +++ b/services/core/java/com/android/server/wm/VrController.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import android.content.ComponentName; import android.os.Process; @@ -24,6 +24,9 @@ import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoUtils; import com.android.server.LocalServices; +import com.android.server.am.ActivityManagerService; +import com.android.server.am.ProcessList; +import com.android.server.am.VrControllerProto; import com.android.server.vr.VrManagerInternal; /** diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 942cdb9c1559..29e1b2013ff1 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -340,7 +340,7 @@ class WallpaperController { try { if (DEBUG_WALLPAPER) Slog.v(TAG, "Waiting for offset complete..."); - mService.mWindowMap.wait(WALLPAPER_TIMEOUT); + mService.mGlobalLock.wait(WALLPAPER_TIMEOUT); } catch (InterruptedException e) { } if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!"); @@ -452,7 +452,7 @@ class WallpaperController { if (mWaitingOnWallpaper != null && mWaitingOnWallpaper.mClient.asBinder() == window) { mWaitingOnWallpaper = null; - mService.mWindowMap.notifyAll(); + mService.mGlobalLock.notifyAll(); } } @@ -460,7 +460,7 @@ class WallpaperController { if (mWaitingOnWallpaper != null && mWaitingOnWallpaper.mClient.asBinder() == window) { mWaitingOnWallpaper = null; - mService.mWindowMap.notifyAll(); + mService.mGlobalLock.notifyAll(); } } diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index bc0f19aa1b3a..46bb9810f460 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -94,7 +94,7 @@ public class WindowAnimator { () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */); mAnimationFrameCallback = frameTimeNs -> { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mAnimationFrameCallbackScheduled = false; } animate(frameTimeNs); @@ -130,7 +130,7 @@ public class WindowAnimator { */ private void animate(long frameTimeNs) { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (!mInitialized) { return; } @@ -139,7 +139,7 @@ public class WindowAnimator { scheduleAnimation(); } - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS; mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE; mAnimating = false; diff --git a/services/core/java/com/android/server/wm/WindowContainerController.java b/services/core/java/com/android/server/wm/WindowContainerController.java index eb23fafb47f0..7cb89c5ae1fe 100644 --- a/services/core/java/com/android/server/wm/WindowContainerController.java +++ b/services/core/java/com/android/server/wm/WindowContainerController.java @@ -32,7 +32,7 @@ class WindowContainerController<E extends WindowContainer, I extends WindowConta final WindowManagerService mService; final RootWindowContainer mRoot; - final WindowHashMap mWindowMap; + final WindowManagerGlobalLock mGlobalLock; // The window container this controller owns. E mContainer; @@ -43,7 +43,7 @@ class WindowContainerController<E extends WindowContainer, I extends WindowConta mListener = listener; mService = service; mRoot = mService != null ? mService.mRoot : null; - mWindowMap = mService != null ? mService.mWindowMap : null; + mGlobalLock = mService != null ? mService.mGlobalLock : null; } void setContainer(E container) { @@ -73,7 +73,7 @@ class WindowContainerController<E extends WindowContainer, I extends WindowConta @Override public void onOverrideConfigurationChanged(Configuration overrideConfiguration) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mContainer == null) { return; } diff --git a/services/core/java/com/android/server/wm/WindowManagerGlobalLock.java b/services/core/java/com/android/server/wm/WindowManagerGlobalLock.java new file mode 100644 index 000000000000..7ce11eebe0dd --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowManagerGlobalLock.java @@ -0,0 +1,9 @@ +package com.android.server.wm; + +/** + * Class that is used to generate an instance of the WM global lock. We are only doing this because + * we need a class for the pattern used in frameworks/base/services/core/Android.bp for CPU boost + * in the WM critical section. + */ +public class WindowManagerGlobalLock { +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 96fc2e241a48..7606a0bdd189 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -437,18 +437,11 @@ public class WindowManagerService extends IWindowManager.Stub */ final ArraySet<Session> mSessions = new ArraySet<>(); - /** - * Mapping from an IWindow IBinder to the server's Window object. - * This is also used as the lock for all of our state. - * NOTE: Never call into methods that lock ActivityManagerService while holding this object. - */ + /** Mapping from an IWindow IBinder to the server's Window object. */ final WindowHashMap mWindowMap = new WindowHashMap(); - /** - * List of window tokens that have finished starting their application, - * and now need to have the policy remove their windows. - */ - final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>(); + /** Global service lock used by the package the owns this service. */ + WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock(); /** * List of app window tokens that are waiting for replacing windows. If the @@ -780,7 +773,7 @@ public class WindowManagerService extends IWindowManager.Stub void openSurfaceTransaction() { try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction"); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { SurfaceControl.openTransaction(); } } finally { @@ -795,7 +788,7 @@ public class WindowManagerService extends IWindowManager.Stub void closeSurfaceTransaction(String where) { try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction"); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { try { traceStateLocked(where); } finally { @@ -937,7 +930,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void onLowPowerModeChanged(PowerSaveState result) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final boolean enabled = result.batterySaverEnabled; if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) { mAnimationsDisabled = enabled; @@ -1084,7 +1077,7 @@ public class WindowManagerService extends IWindowManager.Stub final int callingUid = Binder.getCallingUid(); final int type = attrs.type; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (!mDisplayReady) { throw new IllegalStateException("Display has not been initialialized"); } @@ -1455,7 +1448,7 @@ public class WindowManagerService extends IWindowManager.Stub if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addWindow: New client " + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5)); - if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(displayId)) { + if (win.isVisibleOrAdding() && displayContent.updateOrientationFromAppTokens()) { reportNewConfig = true; } } @@ -1594,7 +1587,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Only system can call refreshScreenCaptureDisabled."); } - synchronized(mWindowMap) { + synchronized (mGlobalLock) { // Update secure surface for all windows belonging to this user. mRoot.setSecureSurfaceState(userId, DevicePolicyCache.getInstance().getScreenCaptureDisabled(userId)); @@ -1602,7 +1595,7 @@ public class WindowManagerService extends IWindowManager.Stub } void removeWindow(Session session, IWindow client) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { WindowState win = windowForClientLocked(session, client, false); if (win == null) { return; @@ -1683,13 +1676,13 @@ public class WindowManagerService extends IWindowManager.Stub } private void updateHiddenWhileSuspendedState(ArraySet<String> packages, boolean suspended) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.updateHiddenWhileSuspendedState(packages, suspended); } } private void updateAppOpsState() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { mRoot.updateAppOpsState(); } } @@ -1720,7 +1713,7 @@ public class WindowManagerService extends IWindowManager.Stub void setTransparentRegionWindow(Session session, IWindow client, Region region) { long origId = Binder.clearCallingIdentity(); try { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState w = windowForClientLocked(session, client, false); if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, "transparentRegionHint=" + region, false); @@ -1738,7 +1731,7 @@ public class WindowManagerService extends IWindowManager.Stub Rect visibleInsets, Region touchableRegion) { long origId = Binder.clearCallingIdentity(); try { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState w = windowForClientLocked(session, client, false); if (DEBUG_LAYOUT) Slog.d(TAG, "setInsetsWindow " + w + ", contentInsets=" + w.mGivenContentInsets + " -> " + contentInsets @@ -1773,7 +1766,7 @@ public class WindowManagerService extends IWindowManager.Stub public void getWindowDisplayFrame(Session session, IWindow client, Rect outDisplayFrame) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { WindowState win = windowForClientLocked(session, client, false); if (win == null) { outDisplayFrame.setEmpty(); @@ -1784,7 +1777,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mAccessibilityController != null) { WindowState window = mWindowMap.get(token); //TODO (multidisplay): Magnification is supported only for the default display. @@ -1796,14 +1789,14 @@ public class WindowManagerService extends IWindowManager.Stub } public IWindowId getWindowId(IBinder token) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState window = mWindowMap.get(token); return window != null ? window.mWindowId : null; } } public void pokeDrawLock(Session session, IBinder token) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState window = windowForClientLocked(session, token, false); if (window != null) { window.pokeDrawLockLw(mDrawLockTimeoutMillis); @@ -1828,7 +1821,7 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); final int displayId; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { WindowState win = windowForClientLocked(session, client, false); if (win == null) { return 0; @@ -2067,7 +2060,7 @@ public class WindowManagerService extends IWindowManager.Stub Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: updateOrientationFromAppTokens"); - configChanged = updateOrientationFromAppTokensLocked(displayId); + configChanged = dc.updateOrientationFromAppTokens(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (toBeDisplayed && win.mIsWallpaper) { @@ -2222,7 +2215,7 @@ public class WindowManagerService extends IWindowManager.Stub final long origId = Binder.clearCallingIdentity(); try { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState win = windowForClientLocked(session, client, false); if (win == null) { return false; @@ -2237,7 +2230,7 @@ public class WindowManagerService extends IWindowManager.Stub void finishDrawingWindow(Session session, IWindow client) { final long origId = Binder.clearCallingIdentity(); try { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState win = windowForClientLocked(session, client, false); if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "finishDrawingWindow: " + win + " mDrawState=" + (win != null ? win.mWinAnimator.drawStateToString() : "null")); @@ -2277,7 +2270,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } - synchronized(mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG_WM, "addWindowToken: Attempted to add token: " + binder @@ -2309,7 +2302,7 @@ public class WindowManagerService extends IWindowManager.Stub final long origId = Binder.clearCallingIdentity(); try { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { Slog.w(TAG_WM, "removeWindowToken: Attempted to remove token: " + binder @@ -2347,7 +2340,7 @@ public class WindowManagerService extends IWindowManager.Stub final Configuration config; final long ident = Binder.clearCallingIdentity(); try { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded, displayId, forceUpdate); } @@ -2358,6 +2351,15 @@ public class WindowManagerService extends IWindowManager.Stub return config; } + /** + * Update orientation of the target display, returning a non-null new Configuration if it has + * changed from the current orientation. If a non-null configuration is returned, someone must + * call {@link #setNewDisplayOverrideConfiguration(Configuration, int)} to tell the window + * manager it can unfreeze the screen. This will typically be done by calling + * {@link #sendNewConfiguration(int)}. + * + * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int) + */ private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig, IBinder freezeThisOneIfNeeded, int displayId, boolean forceUpdate) { if (!mDisplayReady) { @@ -2365,7 +2367,8 @@ public class WindowManagerService extends IWindowManager.Stub } Configuration config = null; - if (updateOrientationFromAppTokensLocked(displayId, forceUpdate)) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc != null && dc.updateOrientationFromAppTokens(forceUpdate)) { // If we changed the orientation but mOrientationChangeComplete is already true, // we used seamless rotation, and we don't need to freeze the screen. if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) { @@ -2400,57 +2403,13 @@ public class WindowManagerService extends IWindowManager.Stub return config; } - /** - * Determine the new desired orientation of the display, returning a non-null new Configuration - * if it has changed from the current orientation. IF TRUE IS RETURNED SOMEONE MUST CALL - * {@link #setNewDisplayOverrideConfiguration(Configuration, int)} TO TELL THE WINDOW MANAGER IT - * CAN UNFREEZE THE SCREEN. This will typically be done for you if you call - * {@link #sendNewConfiguration(int)}. - * - * The orientation is computed from non-application windows first. If none of the - * non-application windows specify orientation, the orientation is computed from application - * tokens. - * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int) - */ - boolean updateOrientationFromAppTokensLocked(int displayId) { - return updateOrientationFromAppTokensLocked(displayId, false /* forceUpdate */); - } - - boolean updateOrientationFromAppTokensLocked(int displayId, boolean forceUpdate) { - long ident = Binder.clearCallingIdentity(); - try { - final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc == null) { - return false; - } - final int req = dc.getOrientation(); - if (req != dc.getLastOrientation() || forceUpdate) { - dc.setLastOrientation(req); - //send a message to Policy indicating orientation change to take - //action like disabling/enabling sensors etc., - dc.getDisplayRotation().setCurrentOrientation(req); - return dc.updateRotationUnchecked(forceUpdate); - } - return false; - } finally { - Binder.restoreCallingIdentity(ident); + void setNewDisplayOverrideConfiguration(Configuration overrideConfig, DisplayContent dc) { + if (mWaitingForConfig) { + mWaitingForConfig = false; + mLastFinishedFreezeSource = "new-config"; } - } - @Override - public int[] setNewDisplayOverrideConfiguration(Configuration overrideConfig, int displayId) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "setNewDisplayOverrideConfiguration()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - synchronized(mWindowMap) { - if (mWaitingForConfig) { - mWaitingForConfig = false; - mLastFinishedFreezeSource = "new-config"; - } - - return mRoot.setDisplayOverrideConfigurationIfNeeded(overrideConfig, displayId); - } + mRoot.setDisplayOverrideConfigurationIfNeeded(overrideConfig, dc); } // TODO(multi-display): remove when no default display use case. @@ -2468,7 +2427,7 @@ public class WindowManagerService extends IWindowManager.Stub public void overridePendingAppTransitionMultiThumbFuture( IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback, boolean scaleUp) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { // TODO(multi-display): sysui using this api only support default display. mRoot.getDisplayContent(DEFAULT_DISPLAY) .mAppTransition.overridePendingAppTransitionMultiThumbFuture(specsFuture, @@ -2483,7 +2442,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException( "Requires CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS permission"); } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { // TODO(multi-display): sysui using this api only support default display. mRoot.getDisplayContent(DEFAULT_DISPLAY) .mAppTransition.overridePendingAppTransitionRemote(remoteAnimationAdapter); @@ -2509,7 +2468,7 @@ public class WindowManagerService extends IWindowManager.Stub IRecentsAnimationRunner recentsAnimationRunner, RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId, SparseBooleanArray recentTaskIds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRecentsAnimationController = new RecentsAnimationController(this, recentsAnimationRunner, callbacks, displayId); mRoot.getDisplayContent(displayId).mAppTransition.updateBooster(); @@ -2531,7 +2490,7 @@ public class WindowManagerService extends IWindowManager.Stub * {@link RecentsAnimation#startRecentsActivity}. */ public boolean canStartRecentsAnimation() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { // TODO(multi-display): currently only default display support recent activity if (getDefaultDisplayContentLocked().mAppTransition.isTransitionSet()) { return false; @@ -2555,7 +2514,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mRecentsAnimationController != null) { final RecentsAnimationController controller = mRecentsAnimationController; mRecentsAnimationController = null; @@ -2567,7 +2526,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void setAppFullscreen(IBinder token, boolean toOpaque) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken atoken = mRoot.getAppWindowToken(token); if (atoken != null) { atoken.setFillsParent(toOpaque); @@ -2578,7 +2537,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void setWindowOpaque(IBinder token, boolean isOpaque) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { setWindowOpaqueLocked(token, isOpaque); } } @@ -2594,7 +2553,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void setDockedStackCreateState(int mode, Rect bounds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { setDockedStackCreateStateLocked(mode, bounds); } } @@ -2605,7 +2564,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void checkSplitScreenMinimizedChanged(boolean animate) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = getDefaultDisplayContentLocked(); displayContent.getDockedDividerController().checkMinimizeChanged(animate); } @@ -2619,7 +2578,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void getStackBounds(int windowingMode, int activityType, Rect bounds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final TaskStack stack = mRoot.getStack(windowingMode, activityType); if (stack != null) { stack.getBounds(bounds); @@ -2666,7 +2625,7 @@ public class WindowManagerService extends IWindowManager.Stub * layouting will be resumed once the last caller has called {@link #continueSurfaceLayout} */ public void deferSurfaceLayout() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mWindowPlacerLocked.deferLayout(); } } @@ -2675,7 +2634,7 @@ public class WindowManagerService extends IWindowManager.Stub * Resumes layout passes after deferring them. See {@link #deferSurfaceLayout()} */ public void continueSurfaceLayout() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mWindowPlacerLocked.continueLayout(); } } @@ -2685,7 +2644,7 @@ public class WindowManagerService extends IWindowManager.Stub * {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set */ public boolean containsShowWhenLockedWindow(IBinder token) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken wtoken = mRoot.getAppWindowToken(token); return wtoken != null && wtoken.containsShowWhenLockedWindow(); } @@ -2696,7 +2655,7 @@ public class WindowManagerService extends IWindowManager.Stub * {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set */ public boolean containsDismissKeyguardWindow(IBinder token) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken wtoken = mRoot.getAppWindowToken(token); return wtoken != null && wtoken.containsDismissKeyguardWindow(); } @@ -2709,26 +2668,26 @@ public class WindowManagerService extends IWindowManager.Stub */ void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId) { final Runnable wrappedCallback = callback != null - ? () -> { synchronized (mWindowMap) { callback.run(); } } + ? () -> { synchronized (mGlobalLock) { callback.run(); } } : null; mH.obtainMessage(H.NOTIFY_KEYGUARD_FLAGS_CHANGED, displayId, 0, wrappedCallback).sendToTarget(); } public boolean isKeyguardTrusted() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mPolicy.isKeyguardTrustedLw(); } } public void setKeyguardGoingAway(boolean keyguardGoingAway) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mKeyguardGoingAway = keyguardGoingAway; } } public void setKeyguardOrAodShowingOnDefaultDisplay(boolean showing) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mKeyguardOrAodShowingOnDefaultDisplay = showing; } } @@ -2744,7 +2703,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires FREEZE_SCREEN permission"); } - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (!mClientFreezingScreen) { mClientFreezingScreen = true; final long origId = Binder.clearCallingIdentity(); @@ -2766,7 +2725,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires FREEZE_SCREEN permission"); } - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mClientFreezingScreen) { mClientFreezingScreen = false; mLastFinishedFreezeSource = "client"; @@ -2869,7 +2828,7 @@ public class WindowManagerService extends IWindowManager.Stub } public boolean isShowingDream() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mPolicy.isShowingDreamLw(); } } @@ -2879,13 +2838,13 @@ public class WindowManagerService extends IWindowManager.Stub if (!checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard")) { throw new SecurityException("Requires CONTROL_KEYGUARD permission"); } - synchronized(mWindowMap) { + synchronized (mGlobalLock) { mPolicy.dismissKeyguardLw(callback, message); } } public void onKeyguardOccludedChanged(boolean occluded) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mPolicy.onKeyguardOccludedChangedLw(occluded); } } @@ -2897,7 +2856,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires INTERACT_ACROSS_USERS_FULL permission"); } mPolicy.setSwitchingUser(switching); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mSwitchingUser = switching; } } @@ -2908,7 +2867,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void closeSystemDialogs(String reason) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { mRoot.closeSystemDialogs(reason); } } @@ -2992,7 +2951,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public float getCurrentAnimatorScale() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { return mAnimationsDisabled ? 0 : mAnimatorDurationScaleSetting; } } @@ -3003,7 +2962,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void registerPointerEventListener(PointerEventListener listener, int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { displayContent.registerPointerEventListener(listener); @@ -3013,7 +2972,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void unregisterPointerEventListener(PointerEventListener listener, int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { displayContent.unregisterPointerEventListener(listener); @@ -3092,13 +3051,13 @@ public class WindowManagerService extends IWindowManager.Stub } public void setCurrentProfileIds(final int[] currentProfileIds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mCurrentProfileIds = currentProfileIds; } } public void setCurrentUser(final int newUserId, final int[] currentProfileIds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mCurrentUserId = newUserId; mCurrentProfileIds = currentProfileIds; mPolicy.setCurrentUserLw(newUserId); @@ -3142,7 +3101,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void enableScreenAfterBoot() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_BOOT) { RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); @@ -3168,7 +3127,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void enableScreenIfNeeded() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { enableScreenIfNeededLocked(); } } @@ -3192,7 +3151,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void performBootTimeout() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (mDisplayEnabled) { return; } @@ -3210,7 +3169,7 @@ public class WindowManagerService extends IWindowManager.Stub } private void performEnableScreen() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled + " mForceDisplayEnabled=" + mForceDisplayEnabled + " mShowingBootMessages=" + mShowingBootMessages @@ -3297,7 +3256,7 @@ public class WindowManagerService extends IWindowManager.Stub public void showBootMessage(final CharSequence msg, final boolean always) { boolean first = false; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_BOOT) { RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); @@ -3343,7 +3302,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setInTouchMode(boolean mode) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { mInTouchMode = mode; } } @@ -3353,7 +3312,7 @@ public class WindowManagerService extends IWindowManager.Stub && mContext.getResources().getBoolean( com.android.internal.R.bool.config_windowShowCircularMask)) { final int currentUserId; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { currentUserId = mCurrentUserId; } // Device configuration calls for a circular display mask, but we only enable the mask @@ -3378,7 +3337,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void showCircularMask(boolean visible) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION showCircularMask(visible=" + visible + ")"); @@ -3412,7 +3371,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void showEmulatorDisplayOverlay() { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION showEmulatorDisplayOverlay"); @@ -3453,7 +3412,7 @@ public class WindowManagerService extends IWindowManager.Stub private void showStrictModeViolation(int arg, int pid) { final boolean on = arg != 0; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { // Ignoring requests to enable the red border from clients which aren't on screen. // (e.g. Broadcast Receivers in the background..) if (on && !mRoot.canShowStrictModeViolation(pid)) { @@ -3492,7 +3451,7 @@ public class WindowManagerService extends IWindowManager.Stub } try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper"); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mRoot.mWallpaperController.screenshotWallpaperLocked(); } } finally { @@ -3512,7 +3471,7 @@ public class WindowManagerService extends IWindowManager.Stub } final Bitmap bm; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(DEFAULT_DISPLAY); if (displayContent == null) { if (DEBUG_SCREENSHOT) { @@ -3549,7 +3508,7 @@ public class WindowManagerService extends IWindowManager.Stub * model. */ public void removeObsoleteTaskFiles(ArraySet<Integer> persistentTaskIds, int[] runningUserIds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mTaskSnapshotController.removeObsoleteTaskFiles(persistentTaskIds, runningUserIds); } } @@ -3579,7 +3538,7 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); try { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent display = mRoot.getDisplayContent(displayId); if (display == null) { Slog.w(TAG, "Trying to freeze rotation for a missing display."); @@ -3615,7 +3574,7 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); try { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent display = mRoot.getDisplayContent(displayId); if (display == null) { Slog.w(TAG, "Trying to thaw rotation for a missing display."); @@ -3637,7 +3596,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean isDisplayRotationFrozen(int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent display = mRoot.getDisplayContent(displayId); if (display == null) { Slog.w(TAG, "Trying to thaw rotation for a missing display."); @@ -3669,7 +3628,7 @@ public class WindowManagerService extends IWindowManager.Stub long origId = Binder.clearCallingIdentity(); try { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { boolean layoutNeeded = false; final int displayCount = mRoot.mChildren.size(); for (int i = 0; i < displayCount; ++i) { @@ -3683,8 +3642,7 @@ public class WindowManagerService extends IWindowManager.Stub layoutNeeded = true; } if (rotationChanged || alwaysSendConfiguration) { - mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId()) - .sendToTarget(); + displayContent.sendNewConfiguration(); } } @@ -3703,14 +3661,14 @@ public class WindowManagerService extends IWindowManager.Stub @Override public WindowManagerPolicy.DisplayContentInfo getDefaultDisplayContentInfo() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return getDefaultDisplayContentLocked(); } } @Override public int getDefaultDisplayRotation() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return getDefaultDisplayContentLocked().getRotation(); } } @@ -3718,7 +3676,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public int watchRotation(IRotationWatcher watcher, int displayId) { final DisplayContent displayContent; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { displayContent = mRoot.getDisplayContent(displayId); } if (displayContent == null) { @@ -3730,7 +3688,7 @@ public class WindowManagerService extends IWindowManager.Stub IBinder.DeathRecipient dr = new IBinder.DeathRecipient() { @Override public void binderDied() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { for (int i=0; i<mRotationWatchers.size(); i++) { if (watcherBinder == mRotationWatchers.get(i).mWatcher.asBinder()) { RotationWatcher removed = mRotationWatchers.remove(i); @@ -3745,7 +3703,7 @@ public class WindowManagerService extends IWindowManager.Stub } }; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { try { watcher.asBinder().linkToDeath(dr, 0); mRotationWatchers.add(new RotationWatcher(watcher, dr, displayId)); @@ -3760,7 +3718,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void removeRotationWatcher(IRotationWatcher watcher) { final IBinder watcherBinder = watcher.asBinder(); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { for (int i=0; i<mRotationWatchers.size(); i++) { RotationWatcher rotationWatcher = mRotationWatchers.get(i); if (watcherBinder == rotationWatcher.mWatcher.asBinder()) { @@ -3778,7 +3736,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean registerWallpaperVisibilityListener(IWallpaperVisibilityListener listener, int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent == null) { throw new IllegalArgumentException("Trying to register visibility event " @@ -3792,7 +3750,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void unregisterWallpaperVisibilityListener(IWallpaperVisibilityListener listener, int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mWallpaperVisibilityListeners .unregisterWallpaperVisibilityListener(listener, displayId); } @@ -3800,7 +3758,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public int getPreferredOptionsPanelGravity(int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent == null) { return Gravity.CENTER | Gravity.BOTTOM; @@ -3918,7 +3876,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean result = true; final ArrayList<WindowState> windows = new ArrayList(); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.forAllWindows(w -> { windows.add(w); }, false /* traverseTopToBottom */); @@ -4100,20 +4058,20 @@ public class WindowManagerService extends IWindowManager.Stub } public void addWindowChangeListener(WindowChangeListener listener) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { mWindowChangeListeners.add(listener); } } public void removeWindowChangeListener(WindowChangeListener listener) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { mWindowChangeListeners.remove(listener); } } private void notifyWindowsChanged() { WindowChangeListener[] windowChangeListeners; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if(mWindowChangeListeners.isEmpty()) { return; } @@ -4128,7 +4086,7 @@ public class WindowManagerService extends IWindowManager.Stub private void notifyFocusChanged() { WindowChangeListener[] windowChangeListeners; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if(mWindowChangeListeners.isEmpty()) { return; } @@ -4147,7 +4105,7 @@ public class WindowManagerService extends IWindowManager.Stub return getFocusedWindow(); } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mRoot.getWindow((w) -> System.identityHashCode(w) == hashCode); } } @@ -4166,7 +4124,7 @@ public class WindowManagerService extends IWindowManager.Stub // E.g. changing device rotation by 180 degrees. Go ahead and perform surface // placement to unfreeze the display since we froze it when the rotation was updated // in DisplayContent#updateRotationUnchecked. - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mWaitingForConfig) { mWaitingForConfig = false; mLastFinishedFreezeSource = "config-unchanged"; @@ -4183,7 +4141,7 @@ public class WindowManagerService extends IWindowManager.Stub } public Configuration computeNewConfiguration(int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return computeNewConfigurationLocked(displayId); } } @@ -4201,7 +4159,7 @@ public class WindowManagerService extends IWindowManager.Stub void notifyHardKeyboardStatusChange() { final boolean available; final WindowManagerInternal.OnHardKeyboardStatusChangeListener listener; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { listener = mHardKeyboardStatusChangeListener; available = mHardKeyboardAvailable; } @@ -4223,7 +4181,7 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mEventDispatchingEnabled = enabled; if (mDisplayEnabled) { mInputManagerCallback.setEventDispatchingLw(enabled); @@ -4232,7 +4190,7 @@ public class WindowManagerService extends IWindowManager.Stub } private WindowState getFocusedWindow() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return getFocusedWindowLocked(); } } @@ -4301,7 +4259,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void displayReady() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mMaxUiWidth > 0) { mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth)); } @@ -4425,7 +4383,7 @@ public class WindowManagerService extends IWindowManager.Stub AccessibilityController accessibilityController = null; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { // TODO(multidisplay): Accessibility supported only of default desiplay. if (mAccessibilityController != null && displayContent.isDefaultDisplay) { accessibilityController = mAccessibilityController; @@ -4469,7 +4427,7 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayContent displayContent = (DisplayContent) msg.obj; ArrayList<WindowState> losers; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { losers = displayContent.mLosingFocus; displayContent.mLosingFocus = new ArrayList<>(); } @@ -4484,7 +4442,7 @@ public class WindowManagerService extends IWindowManager.Stub case WINDOW_FREEZE_TIMEOUT: { final DisplayContent displayContent = (DisplayContent) msg.obj; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { displayContent.onWindowFreezeTimeout(); } break; @@ -4532,7 +4490,7 @@ public class WindowManagerService extends IWindowManager.Stub } case FORCE_GC: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { // Since we're holding both mWindowMap and mAnimator we don't need to // hold mAnimator.mLayoutToAnim. if (mAnimator.isAnimating() || mAnimator.isAnimationScheduled()) { @@ -4557,7 +4515,7 @@ public class WindowManagerService extends IWindowManager.Stub } case APP_FREEZE_TIMEOUT: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { Slog.w(TAG_WM, "App freeze timeout expired."); mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT; for (int i = mAppFreezeListeners.size() - 1; i >=0 ; --i) { @@ -4568,7 +4526,7 @@ public class WindowManagerService extends IWindowManager.Stub } case CLIENT_FREEZE_TIMEOUT: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mClientFreezingScreen) { mClientFreezingScreen = false; mLastFinishedFreezeSource = "client-timeout"; @@ -4579,15 +4537,17 @@ public class WindowManagerService extends IWindowManager.Stub } case SEND_NEW_CONFIGURATION: { - removeMessages(SEND_NEW_CONFIGURATION, msg.obj); - final int displayId = (Integer) msg.obj; - if (mRoot.getDisplayContent(displayId) != null) { - sendNewConfiguration(displayId); + final DisplayContent displayContent = (DisplayContent) msg.obj; + removeMessages(SEND_NEW_CONFIGURATION, displayContent); + if (displayContent.isReady()) { + sendNewConfiguration(displayContent.getDisplayId()); } else { // Message could come after display has already been removed. if (DEBUG_CONFIGURATION) { - Slog.w(TAG, "Trying to send configuration to non-existing displayId=" - + displayId); + final String reason = displayContent.getParent() == null + ? "detached" : "unready"; + Slog.w(TAG, "Trying to send configuration to " + reason + " display=" + + displayContent); } } break; @@ -4595,7 +4555,7 @@ public class WindowManagerService extends IWindowManager.Stub case REPORT_WINDOWS_CHANGE: { if (mWindowsChanged) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mWindowsChanged = false; } notifyWindowsChanged(); @@ -4615,7 +4575,7 @@ public class WindowManagerService extends IWindowManager.Stub case WAITING_FOR_DRAWN_TIMEOUT: { Runnable callback = null; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { Slog.w(TAG_WM, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn); mWaitingForDrawn.clear(); callback = mWaitingForDrawnCallback; @@ -4650,7 +4610,7 @@ public class WindowManagerService extends IWindowManager.Stub break; case ALL_WINDOWS_DRAWN: { Runnable callback; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { callback = mWaitingForDrawnCallback; mWaitingForDrawnCallback = null; } @@ -4671,7 +4631,7 @@ public class WindowManagerService extends IWindowManager.Stub } else { ArrayList<IWindowSessionCallback> callbacks = new ArrayList<IWindowSessionCallback>(); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { for (int i=0; i<mSessions.size(); i++) { callbacks.add(mSessions.valueAt(i).mCallback); } @@ -4688,7 +4648,7 @@ public class WindowManagerService extends IWindowManager.Stub break; case CHECK_IF_BOOT_ANIMATION_FINISHED: { final boolean bootAnimationComplete; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (DEBUG_BOOT) Slog.i(TAG_WM, "CHECK_IF_BOOT_ANIMATION_FINISHED:"); bootAnimationComplete = checkBootAnimationCompleteLocked(); } @@ -4698,14 +4658,14 @@ public class WindowManagerService extends IWindowManager.Stub } break; case RESET_ANR_MESSAGE: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mLastANRState = null; } mAtmInternal.clearSavedANRState(); } break; case WALLPAPER_DRAW_PENDING_TIMEOUT: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mRoot.mWallpaperController.processWallpaperDrawPendingTimeout()) { mWindowPlacerLocked.performSurfacePlacement(); } @@ -4713,7 +4673,7 @@ public class WindowManagerService extends IWindowManager.Stub } break; case UPDATE_DOCKED_STACK_DIVIDER: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = getDefaultDisplayContentLocked(); displayContent.getDockedDividerController().reevaluateVisibility(false); displayContent.adjustForImeIfNeeded(); @@ -4721,7 +4681,7 @@ public class WindowManagerService extends IWindowManager.Stub } break; case WINDOW_REPLACEMENT_TIMEOUT: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { for (int i = mWindowReplacementTimeouts.size() - 1; i >= 0; i--) { final AppWindowToken token = mWindowReplacementTimeouts.get(i); token.onWindowReplacementTimeout(); @@ -4745,7 +4705,7 @@ public class WindowManagerService extends IWindowManager.Stub break; case WINDOW_HIDE_TIMEOUT: { final WindowState window = (WindowState) msg.obj; - synchronized(mWindowMap) { + synchronized (mGlobalLock) { // TODO: This is all about fixing b/21693547 // where partially initialized Toasts get stuck // around and keep the screen on. We'd like @@ -4769,14 +4729,14 @@ public class WindowManagerService extends IWindowManager.Stub } break; case RESTORE_POINTER_ICON: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { restorePointerIconLocked((DisplayContent)msg.obj, msg.arg1, msg.arg2); } } break; case SEAMLESS_ROTATION_TIMEOUT: { final DisplayContent displayContent = (DisplayContent) msg.obj; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { displayContent.onSeamlessRotationTimeout(); } } @@ -4798,7 +4758,7 @@ public class WindowManagerService extends IWindowManager.Stub } break; case ANIMATION_FAILSAFE: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mRecentsAnimationController != null) { mRecentsAnimationController.scheduleFailsafe(); } @@ -4806,7 +4766,7 @@ public class WindowManagerService extends IWindowManager.Stub } break; case RECOMPUTE_FOCUS: { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /* updateInputWindows */); } @@ -4844,7 +4804,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void getInitialDisplaySize(int displayId, Point size) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) { size.x = displayContent.mInitialDisplayWidth; @@ -4855,7 +4815,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void getBaseDisplaySize(int displayId, Point size) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) { size.x = displayContent.mBaseDisplayWidth; @@ -4875,7 +4835,7 @@ public class WindowManagerService extends IWindowManager.Stub final long ident = Binder.clearCallingIdentity(); try { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { displayContent.setForcedSize(width, height); @@ -4897,7 +4857,7 @@ public class WindowManagerService extends IWindowManager.Stub final long ident = Binder.clearCallingIdentity(); try { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { displayContent.setForcedScalingMode(mode); @@ -4911,7 +4871,6 @@ public class WindowManagerService extends IWindowManager.Stub /** The global settings only apply to default display. */ private void applyForcedPropertiesForDefaultDisplay() { final DisplayContent displayContent = getDefaultDisplayContentLocked(); - boolean changed = false; // Display size. String sizeStr = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.DISPLAY_SIZE_FORCED); @@ -4930,7 +4889,6 @@ public class WindowManagerService extends IWindowManager.Stub Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height); displayContent.updateBaseDisplayMetrics(width, height, displayContent.mBaseDisplayDensity); - changed = true; } } catch (NumberFormatException ex) { } @@ -4941,7 +4899,6 @@ public class WindowManagerService extends IWindowManager.Stub final int density = getForcedDisplayDensityForUserLocked(mCurrentUserId); if (density != 0) { displayContent.mBaseDisplayDensity = density; - changed = true; } // Display scaling mode. @@ -4950,11 +4907,6 @@ public class WindowManagerService extends IWindowManager.Stub if (mode != 0) { Slog.i(TAG_WM, "FORCED DISPLAY SCALING DISABLED"); displayContent.mDisplayScalingDisabled = true; - changed = true; - } - - if (changed) { - reconfigureDisplayLocked(displayContent); } } @@ -4969,7 +4921,7 @@ public class WindowManagerService extends IWindowManager.Stub final long ident = Binder.clearCallingIdentity(); try { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { displayContent.setForcedSize(displayContent.mInitialDisplayWidth, @@ -4983,7 +4935,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public int getInitialDisplayDensity(int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) { return displayContent.mInitialDisplayDensity; @@ -4994,7 +4946,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public int getBaseDisplayDensity(int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) { return displayContent.mBaseDisplayDensity; @@ -5017,7 +4969,7 @@ public class WindowManagerService extends IWindowManager.Stub null); final long ident = Binder.clearCallingIdentity(); try { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { displayContent.setForcedDensity(density, targetUserId); @@ -5042,7 +4994,7 @@ public class WindowManagerService extends IWindowManager.Stub null); final long ident = Binder.clearCallingIdentity(); try { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { displayContent.setForcedDensity(displayContent.mInitialDisplayDensity, @@ -5081,8 +5033,7 @@ public class WindowManagerService extends IWindowManager.Stub displayContent.configureDisplayPolicy(); displayContent.setLayoutNeeded(); - final int displayId = displayContent.getDisplayId(); - boolean configChanged = updateOrientationFromAppTokensLocked(displayId); + boolean configChanged = displayContent.updateOrientationFromAppTokens(); final Configuration currentDisplayConfig = displayContent.getConfiguration(); mTempConfiguration.setTo(currentDisplayConfig); displayContent.computeScreenConfiguration(mTempConfiguration); @@ -5092,7 +5043,7 @@ public class WindowManagerService extends IWindowManager.Stub mWaitingForConfig = true; startFreezingDisplayLocked(0 /* exitAnim */, 0 /* enterAnim */, displayContent); - mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget(); + displayContent.sendNewConfiguration(); } mWindowPlacerLocked.performSurfacePlacement(); @@ -5108,7 +5059,7 @@ public class WindowManagerService extends IWindowManager.Stub } final long ident = Binder.clearCallingIdentity(); try { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { setOverscanLocked(displayContent, left, top, right, bottom); @@ -5261,7 +5212,7 @@ public class WindowManagerService extends IWindowManager.Stub } void requestTraversal() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mWindowPlacerLocked.requestTraversal(); } } @@ -5396,7 +5347,6 @@ public class WindowManagerService extends IWindowManager.Stub if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) { if (DEBUG_ORIENTATION) Slog.i(TAG_WM, "**** Dismissing screen rotation animation"); - // TODO(multidisplay): rotation on main screen only. DisplayInfo displayInfo = displayContent.getDisplayInfo(); // Get rotation animation again, with new top window if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, false)) { @@ -5426,7 +5376,7 @@ public class WindowManagerService extends IWindowManager.Stub // to avoid inconsistent states. However, something interesting // could have actually changed during that time so re-evaluate it // now to catch that. - configChanged = updateOrientationFromAppTokensLocked(displayId); + configChanged = displayContent != null && displayContent.updateOrientationFromAppTokens(); // A little kludge: a lot could have happened while the // display was frozen, so now that we are coming back we @@ -5444,7 +5394,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (configChanged) { - mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget(); + displayContent.sendNewConfiguration(); } mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN); } @@ -5510,7 +5460,7 @@ public class WindowManagerService extends IWindowManager.Stub public void setRecentsVisibility(boolean visible) { mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR, "setRecentsVisibility()"); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mPolicy.setRecentsVisibilityLw(visible); } } @@ -5523,7 +5473,7 @@ public class WindowManagerService extends IWindowManager.Stub + android.Manifest.permission.STATUS_BAR); } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mPolicy.setPipVisibilityLw(visible); } } @@ -5532,7 +5482,7 @@ public class WindowManagerService extends IWindowManager.Stub public void setShelfHeight(boolean visible, int shelfHeight) { mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR, "setShelfHeight()"); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { getDefaultDisplayContentLocked().getPinnedStackController().setAdjustedForShelf(visible, shelfHeight); } @@ -5546,7 +5496,7 @@ public class WindowManagerService extends IWindowManager.Stub + android.Manifest.permission.STATUS_BAR); } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mLastStatusBarVisibility = visibility; visibility = mPolicy.adjustSystemUiVisibilityLw(visibility); updateStatusBarVisibilityLocked(visibility); @@ -5560,7 +5510,7 @@ public class WindowManagerService extends IWindowManager.Stub + android.Manifest.permission.STATUS_BAR); } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mPolicy.setNavBarVirtualKeyHapticFeedbackEnabledLw(enabled); } } @@ -5585,7 +5535,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void reevaluateStatusBarVisibility() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility); if (updateStatusBarVisibilityLocked(visibility)) { mWindowPlacerLocked.requestTraversal(); @@ -5601,7 +5551,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override @WindowManagerPolicy.NavigationBarPosition public int getNavBarPosition() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { // Perform layout if it was scheduled before to make sure that we get correct nav bar // position when doing rotations. final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked(); @@ -5614,7 +5564,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name, InputEventReceiver.Factory inputEventReceiverFactory, int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { return displayContent.getInputMonitor().createInputConsumer(looper, name, @@ -5628,7 +5578,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void createInputConsumer(IBinder token, String name, int displayId, InputChannel inputChannel) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { DisplayContent display = mRoot.getDisplayContent(displayId); if (display != null) { display.getInputMonitor().createInputConsumer(token, name, inputChannel, @@ -5639,7 +5589,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean destroyInputConsumer(String name, int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { DisplayContent display = mRoot.getDisplayContent(displayId); if (display != null) { return display.getInputMonitor().destroyInputConsumer(name); @@ -5653,7 +5603,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mContext.checkCallingOrSelfPermission(RESTRICTED_VR_ACCESS) != PERMISSION_GRANTED) { throw new SecurityException("getCurrentImeTouchRegion is restricted to VR services"); } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final Region r = new Region(); // TODO(b/111080190): this method is only return the recent focused IME touch region, // For Multi-Session IME, will need to add API for given display Id to @@ -5694,7 +5644,7 @@ public class WindowManagerService extends IWindowManager.Stub "clearWindowContentFrameStats()")) { throw new SecurityException("Requires FRAME_STATS permission"); } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState windowState = mWindowMap.get(token); if (windowState == null) { return false; @@ -5713,7 +5663,7 @@ public class WindowManagerService extends IWindowManager.Stub "getWindowContentFrameStats()")) { throw new SecurityException("Requires FRAME_STATS permission"); } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState windowState = mWindowMap.get(token); if (windowState == null) { return null; @@ -5734,7 +5684,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void notifyAppRelaunching(IBinder token) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken appWindow = mRoot.getAppWindowToken(token); if (appWindow != null) { appWindow.startRelaunching(); @@ -5743,7 +5693,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void notifyAppRelaunchingFinished(IBinder token) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken appWindow = mRoot.getAppWindowToken(token); if (appWindow != null) { appWindow.finishRelaunching(); @@ -5752,7 +5702,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void notifyAppRelaunchesCleared(IBinder token) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken appWindow = mRoot.getAppWindowToken(token); if (appWindow != null) { appWindow.clearRelaunching(); @@ -5761,7 +5711,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void notifyAppResumedFinished(IBinder token) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken appWindow = mRoot.getAppWindowToken(token); if (appWindow != null) { appWindow.getDisplayContent().mUnknownAppVisibilityController @@ -5774,7 +5724,7 @@ public class WindowManagerService extends IWindowManager.Stub * Returns true if the callingUid has any window currently visible to the user. */ public boolean isAnyWindowVisibleForUid(int callingUid) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mRoot.forAllWindows(w -> { return w.getOwningUid() == callingUid && w.isVisible(); }, true /* traverseTopToBottom */); @@ -5788,7 +5738,7 @@ public class WindowManagerService extends IWindowManager.Stub * container may not exist when this happens. */ public void notifyTaskRemovedFromRecents(int taskId, int userId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mTaskSnapshotController.notifyTaskRemovedFromRecents(taskId, userId); } } @@ -6030,7 +5980,7 @@ public class WindowManagerService extends IWindowManager.Stub if ("apps".equals(name) || "visible".equals(name) || "visible-apps".equals(name)) { final boolean appsOnly = name.contains("apps"); final boolean visibleOnly = name.contains("visible"); - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (appsOnly) { mRoot.dumpDisplayContents(pw); } @@ -6043,7 +5993,7 @@ public class WindowManagerService extends IWindowManager.Stub }, true /* traverseTopToBottom */); } } else { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { mRoot.getWindowsByName(windows, name); } } @@ -6052,7 +6002,7 @@ public class WindowManagerService extends IWindowManager.Stub return false; } - synchronized(mWindowMap) { + synchronized (mGlobalLock) { dumpWindowsLocked(pw, dumpAll, windows); } return true; @@ -6159,7 +6109,7 @@ public class WindowManagerService extends IWindowManager.Stub if (useProto) { final ProtoOutputStream proto = new ProtoOutputStream(fd); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { writeToProtoLocked(proto, false /* trim */); } proto.flush(); @@ -6170,47 +6120,47 @@ public class WindowManagerService extends IWindowManager.Stub String cmd = args[opti]; opti++; if ("lastanr".equals(cmd) || "l".equals(cmd)) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { dumpLastANRLocked(pw); } return; } else if ("policy".equals(cmd) || "p".equals(cmd)) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { dumpPolicyLocked(pw, args, true); } return; } else if ("animator".equals(cmd) || "a".equals(cmd)) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { dumpAnimatorLocked(pw, args, true); } return; } else if ("sessions".equals(cmd) || "s".equals(cmd)) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { dumpSessionsLocked(pw, true); } return; } else if ("displays".equals(cmd) || "d".equals(cmd)) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { mRoot.dumpDisplayContents(pw); } return; } else if ("tokens".equals(cmd) || "t".equals(cmd)) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { dumpTokensLocked(pw, true); } return; } else if ("windows".equals(cmd) || "w".equals(cmd)) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { dumpWindowsLocked(pw, true, null); } return; } else if ("all".equals(cmd) || "a".equals(cmd)) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { dumpWindowsLocked(pw, true, null); } return; } else if ("containers".equals(cmd)) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { mRoot.dumpChildrenNames(pw, " "); pw.println(" "); mRoot.forAllWindows(w -> {pw.println(w);}, true /* traverseTopToBottom */); @@ -6226,7 +6176,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - synchronized(mWindowMap) { + synchronized (mGlobalLock) { pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -6271,7 +6221,7 @@ public class WindowManagerService extends IWindowManager.Stub // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection). @Override public void monitor() { - synchronized (mWindowMap) { } + synchronized (mGlobalLock) { } } // There is an inherent assumption that this will never return null. @@ -6282,7 +6232,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void onOverlayChanged() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mRoot.forAllDisplays(displayContent -> { mPolicy.onOverlayChangedLw(displayContent); displayContent.updateDisplayInfo(); @@ -6292,7 +6242,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void onDisplayChanged(int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); if (displayContent != null) { displayContent.updateDisplayInfo(); @@ -6303,7 +6253,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public Object getWindowManagerLock() { - return mWindowMap; + return mGlobalLock; } /** @@ -6312,7 +6262,7 @@ public class WindowManagerService extends IWindowManager.Stub * @param token Application token for which the activity will be relaunched. */ public void setWillReplaceWindow(IBinder token, boolean animate) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); if (appWindowToken == null) { Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " @@ -6341,7 +6291,7 @@ public class WindowManagerService extends IWindowManager.Stub // TODO: The s at the end of the method name is the only difference with the name of the method // above. We should combine them or find better names. void setWillReplaceWindows(IBinder token, boolean childrenOnly) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); if (appWindowToken == null) { Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " @@ -6374,7 +6324,7 @@ public class WindowManagerService extends IWindowManager.Stub * @param replacing Whether the window is being replaced or not. */ public void scheduleClearWillReplaceWindows(IBinder token, boolean replacing) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token); if (appWindowToken == null) { Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token " @@ -6400,7 +6350,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public int getDockedStackSide() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final TaskStack dockedStack = getDefaultDisplayContentLocked() .getSplitScreenPrimaryStackIgnoringVisibility(); return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(); @@ -6408,7 +6358,7 @@ public class WindowManagerService extends IWindowManager.Stub } public void setDockedStackResizing(boolean resizing) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { getDefaultDisplayContentLocked().getDockedDividerController().setResizing(resizing); requestTraversal(); } @@ -6416,7 +6366,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setDockedStackDividerTouchRegion(Rect touchRegion) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = getDefaultDisplayContentLocked(); dc.getDockedDividerController().setTouchRegion(touchRegion); dc.updateTouchExcludeRegion(); @@ -6425,32 +6375,32 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer( visible, targetWindowingMode, alpha); } } public void setForceResizableTasks(boolean forceResizableTasks) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mForceResizableTasks = forceResizableTasks; } } public void setSupportsPictureInPicture(boolean supportsPictureInPicture) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mSupportsPictureInPicture = supportsPictureInPicture; } } public void setSupportsFreeformWindowManagement(boolean supportsFreeformWindowManagement) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mSupportsFreeformWindowManagement = supportsFreeformWindowManagement; } } public void setIsPc(boolean isPc) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mIsPc = isPc; } } @@ -6463,7 +6413,7 @@ public class WindowManagerService extends IWindowManager.Stub public void registerDockedStackListener(IDockedStackListener listener) { mAtmInternal.enforceCallerIsRecentsOrHasPermission(REGISTER_WINDOW_MANAGER_LISTENERS, "registerDockedStackListener()"); - synchronized (mWindowMap) { + synchronized (mGlobalLock) { // TODO(multi-display): The listener is registered on the default display only. getDefaultDisplayContentLocked().mDividerControllerLocked.registerDockedStackListener( listener); @@ -6479,7 +6429,7 @@ public class WindowManagerService extends IWindowManager.Stub if (!mSupportsPictureInPicture) { return; } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); displayContent.getPinnedStackController().registerPinnedStackListener(listener); } @@ -6498,7 +6448,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void getStableInsets(int displayId, Rect outInsets) throws RemoteException { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { getStableInsetsLocked(displayId, outInsets); } } @@ -6557,7 +6507,7 @@ public class WindowManagerService extends IWindowManager.Stub mouseY = mMousePositionTracker.mLatestMouseY; } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mDragDropController.dragDropActiveLocked()) { // Drag cursor overrides the app cursor. return; @@ -6612,7 +6562,7 @@ public class WindowManagerService extends IWindowManager.Stub */ void updateTapExcludeRegion(IWindow client, int regionId, int left, int top, int width, int height) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final WindowState callingWin = windowForClientLocked(null, client, false); if (callingWin == null) { Slog.w(TAG_WM, "Bad requesting window " + client); @@ -6626,7 +6576,7 @@ public class WindowManagerService extends IWindowManager.Stub public void dontOverrideDisplayInfo(int displayId) { final long token = Binder.clearCallingIdentity(); try { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = getDisplayContentOrCreate(displayId, null); if (dc == null) { throw new IllegalArgumentException( @@ -6692,7 +6642,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setMagnificationSpec(MagnificationSpec spec) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mAccessibilityController != null) { mAccessibilityController.setMagnificationSpecLocked(spec); } else { @@ -6706,7 +6656,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setForceShowMagnifiableBounds(boolean show) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mAccessibilityController != null) { mAccessibilityController.setForceShowMagnifiableBoundsLocked(show); } else { @@ -6717,7 +6667,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void getMagnificationRegion(@NonNull Region magnificationRegion) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mAccessibilityController != null) { mAccessibilityController.getMagnificationRegionLocked(magnificationRegion); } else { @@ -6728,7 +6678,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState windowState = mWindowMap.get(windowToken); if (windowState == null) { return null; @@ -6748,7 +6698,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setMagnificationCallbacks(@Nullable MagnificationCallbacks callbacks) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mAccessibilityController == null) { mAccessibilityController = new AccessibilityController( WindowManagerService.this); @@ -6762,7 +6712,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mAccessibilityController == null) { mAccessibilityController = new AccessibilityController( WindowManagerService.this); @@ -6781,7 +6731,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public IBinder getFocusedWindowToken() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState windowState = getFocusedWindowLocked(); if (windowState != null) { return windowState.mClient.asBinder(); @@ -6807,7 +6757,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void getWindowFrame(IBinder token, Rect outBounds) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState windowState = mWindowMap.get(token); if (windowState != null) { outBounds.set(windowState.getFrameLw()); @@ -6820,7 +6770,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void waitForAllWindowsDrawn(Runnable callback, long timeout) { boolean allWindowsDrawn = false; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mWaitingForDrawnCallback = callback; getDefaultDisplayContentLocked().waitForAllWindowsDrawn(); mWindowPlacerLocked.requestTraversal(); @@ -6844,7 +6794,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void removeWindowToken(IBinder binder, boolean removeWindows, int displayId) { - synchronized(mWindowMap) { + synchronized (mGlobalLock) { if (removeWindows) { final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { @@ -6870,14 +6820,14 @@ public class WindowManagerService extends IWindowManager.Stub // forwarding it to SystemUI for synchronizing status and navigation bar animations. @Override public void registerAppTransitionListener(AppTransitionListener listener) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { getDefaultDisplayContentLocked().mAppTransition.registerListenerLocked(listener); } } @Override public int getInputMethodWindowVisibleHeight(int displayId) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); return dc.mDisplayFrames.getInputMethodWindowVisibleHeight(); } @@ -6901,7 +6851,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean isHardKeyboardAvailable() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return mHardKeyboardAvailable; } } @@ -6909,14 +6859,14 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setOnHardKeyboardStatusChangeListener( OnHardKeyboardStatusChangeListener listener) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mHardKeyboardStatusChangeListener = listener; } } @Override public boolean isStackVisible(int windowingMode) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent dc = getDefaultDisplayContentLocked(); return dc.isStackVisible(windowingMode); } @@ -6924,7 +6874,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean isDockedDividerResizing() { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { return getDefaultDisplayContentLocked().getDockedDividerController().isResizing(); } } @@ -6932,7 +6882,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void computeWindowsForAccessibility() { final AccessibilityController accessibilityController; - synchronized (mWindowMap) { + synchronized (mGlobalLock) { accessibilityController = mAccessibilityController; } if (accessibilityController != null) { @@ -6962,7 +6912,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public int getWindowOwnerUserId(IBinder token) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { WindowState window = mWindowMap.get(token); if (window != null) { return UserHandle.getUserId(window.mOwnerUid); @@ -6973,7 +6923,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean isUidFocused(int uid) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { for (int i = mRoot.getChildCount() - 1; i >= 0; i--) { final DisplayContent displayContent = mRoot.getChildAt(i); if (displayContent.mCurrentFocus != null @@ -6990,7 +6940,7 @@ public class WindowManagerService extends IWindowManager.Stub if (displayId == Display.INVALID_DISPLAY) { return false; } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getTopFocusedDisplayContent(); if (displayContent == null || displayContent.getDisplayId() != displayId @@ -7025,7 +6975,7 @@ public class WindowManagerService extends IWindowManager.Stub if (displayId == Display.INVALID_DISPLAY) { return false; } - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); return displayContent != null && displayContent.hasAccess(uid); } @@ -7033,7 +6983,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public int getDisplayIdForWindow(IBinder windowToken) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { final WindowState window = mWindowMap.get(windowToken); if (window != null) { return window.getDisplayContent().getDisplayId(); @@ -7044,7 +6994,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void onProcessConfigurationChanged(int pid, Configuration newConfig) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { Configuration currentConfig = mProcessConfigurations.get(pid); if (currentConfig == null) { currentConfig = new Configuration(newConfig); @@ -7100,7 +7050,7 @@ public class WindowManagerService extends IWindowManager.Stub // The client depends on us to have resized the surface // by that point (b/36462635) - synchronized (mWindowMap) { + synchronized (mGlobalLock) { SurfaceControl.openTransaction(); try { exec.run(); @@ -7112,7 +7062,7 @@ public class WindowManagerService extends IWindowManager.Stub /** Called to inform window manager if non-Vr UI shoul be disabled or not. */ public void disableNonVrUi(boolean disable) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { // Allow alert window notifications to be shown if non-vr UI is enabled. final boolean showAlertWindowNotifications = !disable; if (showAlertWindowNotifications == mShowAlertWindowNotifications) { @@ -7182,6 +7132,10 @@ public class WindowManagerService extends IWindowManager.Stub mRotatingSeamlessly = true; } + boolean isRotatingSeamlessly() { + return mRotatingSeamlessly; + } + void finishSeamlessRotation() { mRotatingSeamlessly = false; } @@ -7196,7 +7150,7 @@ public class WindowManagerService extends IWindowManager.Stub * {@link ActivityManager#LOCK_TASK_MODE_PINNED}. */ public void onLockTaskStateChanged(int lockTaskState) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { mPolicy.onLockTaskStateChangedLw(lockTaskState); } } @@ -7207,7 +7161,7 @@ public class WindowManagerService extends IWindowManager.Stub * ensure the new value takes effect. */ public void setAodShowing(boolean aodShowing) { - synchronized (mWindowMap) { + synchronized (mGlobalLock) { if (mPolicy.setAodShowing(aodShowing)) { mWindowPlacerLocked.performSurfacePlacement(); } diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 1dd8c52f8207..bb1725477ac0 100644 --- a/services/core/java/com/android/server/am/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -14,28 +14,28 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.view.Display.INVALID_DISPLAY; import static com.android.server.am.ActivityManagerService.MY_PID; -import static com.android.server.am.ActivityStack.ActivityState.DESTROYED; -import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.am.ActivityStack.ActivityState.PAUSED; -import static com.android.server.am.ActivityStack.ActivityState.PAUSING; -import static com.android.server.am.ActivityStack.ActivityState.RESUMED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPING; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; -import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM; -import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.am.ActivityTaskManagerService +import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; +import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.wm.ActivityTaskManagerService .INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS; -import static com.android.server.am.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS; -import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE; +import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS; +import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; import android.app.Activity; import android.app.ActivityThread; @@ -55,17 +55,15 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.Watchdog; -import com.android.server.wm.ConfigurationContainer; -import com.android.server.wm.ConfigurationContainerListener; import java.io.PrintWriter; import java.util.ArrayList; /** * The Activity Manager (AM) package manages the lifecycle of processes in the system through - * {@link ProcessRecord}. However, it is important for the Window Manager (WM) package to be aware + * ProcessRecord. However, it is important for the Window Manager (WM) package to be aware * of the processes and their state since it affects how WM manages windows and activities. This - * class that allows the {@link ProcessRecord} object in the AM package to communicate important + * class that allows the ProcessRecord object in the AM package to communicate important * changes to its state to the WM package in a structured way. WM package also uses * {@link WindowProcessListener} to request changes to the process state on the AM side. * Note that public calls into this class are assumed to be originating from outside the @@ -156,8 +154,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // Registered display id as a listener to override config change private int mDisplayId; - WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, String name, - int uid, int userId, Object owner, WindowProcessListener listener) { + public WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, + String name, int uid, int userId, Object owner, WindowProcessListener listener) { mInfo = info; mName = name; mUid = uid; @@ -176,7 +174,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio mPid = pid; } - int getPid() { + public int getPid() { return mPid; } @@ -622,7 +620,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return minTaskLayer; } - int computeRelaunchReason() { + public int computeRelaunchReason() { synchronized (mAtm.mGlobalLock) { final int activitiesSize = mActivities.size(); for (int i = activitiesSize - 1; i >= 0; i--) { diff --git a/services/core/java/com/android/server/am/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java index 4a7e6e8a38fe..7f20f4b0add9 100644 --- a/services/core/java/com/android/server/am/WindowProcessListener.java +++ b/services/core/java/com/android/server/wm/WindowProcessListener.java @@ -14,10 +14,9 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import android.app.ProfilerInfo; -import android.content.pm.ApplicationInfo; import android.util.proto.ProtoOutputStream; /** diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 9dc77219e8db..99f65c327375 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -103,7 +103,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION; import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION; import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET; @@ -1942,8 +1941,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP removeImmediately(); // Removing a visible window will effect the computed orientation // So just update orientation if needed. - if (wasVisible && mService.updateOrientationFromAppTokensLocked(displayId)) { - mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget(); + if (wasVisible) { + final DisplayContent displayContent = getDisplayContent(); + if (displayContent.updateOrientationFromAppTokens()) { + displayContent.sendNewConfiguration(); + } } mService.updateFocusedWindowLocked(isFocused() ? UPDATE_FOCUS_REMOVING_FOCUS @@ -2314,7 +2316,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP public void binderDied() { try { boolean resetSplitScreenResizing = false; - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { final WindowState win = mService.windowForClientLocked(mSession, mClient, false); Slog.i(TAG, "WIN DEATH: " + win); if (win != null) { @@ -2984,7 +2986,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } public void registerFocusObserver(IWindowFocusObserver observer) { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mFocusCallbacks == null) { mFocusCallbacks = new RemoteCallbackList<IWindowFocusObserver>(); } @@ -2993,7 +2995,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } public void unregisterFocusObserver(IWindowFocusObserver observer) { - synchronized(mService.mWindowMap) { + synchronized (mService.mGlobalLock) { if (mFocusCallbacks != null) { mFocusCallbacks.unregister(observer); } @@ -4440,7 +4442,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP public boolean isFocused() { final WindowState outer = mOuter.get(); if (outer != null) { - synchronized (outer.mService.mWindowMap) { + synchronized (outer.mService.mGlobalLock) { return outer.isFocused(); } } diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index e82ffe8b271e..7d25b8c84960 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -61,7 +61,7 @@ class WindowSurfacePlacer { mService = service; mWallpaperControllerLocked = mService.mRoot.mWallpaperController; mPerformSurfacePlacement = () -> { - synchronized (mService.mWindowMap) { + synchronized (mService.mGlobalLock) { performSurfacePlacement(); } }; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java index 4514492c6ed0..e9b2d7f56108 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java @@ -53,8 +53,8 @@ final class NetworkLogger { private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() { @Override - public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount, - long timestamp, int uid) { + public void onDnsEvent(int netId, int eventType, int returnCode, String hostname, + String[] ipAddresses, int ipAddressesCount, long timestamp, int uid) { if (!mIsLoggingEnabled.get()) { return; } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b1b5a7a49b01..43190ac40a31 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -16,6 +16,12 @@ package com.android.server; +import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; +import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; +import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; +import static android.os.IServiceManager.DUMP_FLAG_PROTO; +import static android.view.Display.DEFAULT_DISPLAY; + import android.app.ActivityThread; import android.app.INotificationManager; import android.app.usage.UsageStatsManagerInternal; @@ -64,10 +70,12 @@ import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.EmergencyAffordanceManager; import com.android.internal.widget.ILockSettings; import com.android.server.am.ActivityManagerService; -import com.android.server.am.ActivityTaskManagerService; import com.android.server.appbinding.AppBindingService; import com.android.server.audio.AudioService; import com.android.server.biometrics.BiometricService; +import com.android.server.biometrics.face.FaceService; +import com.android.server.biometrics.fingerprint.FingerprintService; +import com.android.server.biometrics.iris.IrisService; import com.android.server.broadcastradio.BroadcastRadioService; import com.android.server.camera.CameraServiceProxy; import com.android.server.clipboard.ClipboardService; @@ -78,8 +86,6 @@ import com.android.server.display.ColorDisplayService; import com.android.server.display.DisplayManagerService; import com.android.server.dreams.DreamManagerService; import com.android.server.emergency.EmergencyAffordanceService; -import com.android.server.biometrics.face.FaceService; -import com.android.server.biometrics.fingerprint.FingerprintService; import com.android.server.hdmi.HdmiControlService; import com.android.server.input.InputManagerService; import com.android.server.inputmethod.InputMethodManagerService; @@ -87,8 +93,8 @@ import com.android.server.job.JobSchedulerService; import com.android.server.lights.LightsService; import com.android.server.media.MediaResourceMonitorService; import com.android.server.media.MediaRouterService; -import com.android.server.media.MediaUpdateService; import com.android.server.media.MediaSessionService; +import com.android.server.media.MediaUpdateService; import com.android.server.media.projection.MediaProjectionManagerService; import com.android.server.net.NetworkPolicyManagerService; import com.android.server.net.NetworkStatsService; @@ -109,6 +115,7 @@ import com.android.server.pm.UserManagerService; import com.android.server.policy.PhoneWindowManager; import com.android.server.power.PowerManagerService; import com.android.server.power.ShutdownThread; +import com.android.server.power.ThermalManagerService; import com.android.server.restrictions.RestrictionsManagerService; import com.android.server.security.KeyAttestationApplicationIdProviderService; import com.android.server.security.KeyChainSystemService; @@ -127,6 +134,7 @@ import com.android.server.uri.UriGrantsManagerService; import com.android.server.usage.UsageStatsService; import com.android.server.vr.VrManagerService; import com.android.server.webkit.WebViewUpdateService; +import com.android.server.wm.ActivityTaskManagerService; import com.android.server.wm.WindowManagerService; import dalvik.system.VMRuntime; @@ -138,12 +146,6 @@ import java.util.Timer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; -import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; -import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; -import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; -import static android.os.IServiceManager.DUMP_FLAG_PROTO; -import static android.view.Display.DEFAULT_DISPLAY; - public final class SystemServer { private static final String TAG = "SystemServer"; @@ -229,6 +231,8 @@ public final class SystemServer { "com.android.server.wallpaper.WallpaperManagerService$Lifecycle"; private static final String AUTO_FILL_MANAGER_SERVICE_CLASS = "com.android.server.autofill.AutofillManagerService"; + private static final String INTELLIGENCE_MANAGER_SERVICE_CLASS = + "com.android.server.intelligence.IntelligenceManagerService"; private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS = "com.android.server.timezone.RulesManagerService$Lifecycle"; private static final String IOT_SERVICE_CLASS = @@ -604,6 +608,10 @@ public final class SystemServer { mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class); traceEnd(); + traceBeginAndSlog("StartThermalManager"); + mSystemServiceManager.startService(ThermalManagerService.class); + traceEnd(); + // Now that the power manager has been started, let the activity manager // initialize power management features. traceBeginAndSlog("InitPowerManagement"); @@ -794,6 +802,8 @@ public final class SystemServer { boolean disableSystemTextClassifier = SystemProperties.getBoolean( "config.disable_systemtextclassifier", false); + boolean disableIntelligence = SystemProperties.getBoolean( + "config.disable_intelligence", false); boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false); boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice", @@ -1589,6 +1599,8 @@ public final class SystemServer { final boolean hasFeatureFace = mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE); + final boolean hasFeatureIris + = mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS); final boolean hasFeatureFingerprint = mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT); @@ -1598,13 +1610,19 @@ public final class SystemServer { traceEnd(); } + if (hasFeatureIris) { + traceBeginAndSlog("StartIrisSensor"); + mSystemServiceManager.startService(IrisService.class); + traceEnd(); + } + if (hasFeatureFingerprint) { traceBeginAndSlog("StartFingerprintSensor"); mSystemServiceManager.startService(FingerprintService.class); traceEnd(); } - if (hasFeatureFace || hasFeatureFingerprint) { + if (hasFeatureFace || hasFeatureIris || hasFeatureFingerprint) { // Start this service after all biometric services. traceBeginAndSlog("StartBiometricPromptService"); mSystemServiceManager.startService(BiometricService.class); @@ -1728,6 +1746,12 @@ public final class SystemServer { traceEnd(); } + if (!disableIntelligence) { + traceBeginAndSlog("StartIntelligenceService"); + mSystemServiceManager.startService(INTELLIGENCE_MANAGER_SERVICE_CLASS); + traceEnd(); + } + traceBeginAndSlog("AppServiceManager"); mSystemServiceManager.startService(AppBindingService.Lifecycle.class); traceEnd(); diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index 878179bb251d..e2f899555aca 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -33,7 +33,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ testables \ testng \ ub-uiautomator\ - platformprotosnano + platformprotosnano \ + hamcrest-library LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 863e48792c0d..fa17b6125983 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -206,11 +206,11 @@ </intent-filter> </activity-alias> - <activity android:name="com.android.server.am.TaskStackChangedListenerTest$ActivityA" /> - <activity android:name="com.android.server.am.TaskStackChangedListenerTest$ActivityB" /> - <activity android:name="com.android.server.am.TaskStackChangedListenerTest$ActivityRequestedOrientationChange" /> - <activity android:name="com.android.server.am.TaskStackChangedListenerTest$ActivityTaskChangeCallbacks" /> - <activity android:name="com.android.server.am.TaskStackChangedListenerTest$ActivityTaskDescriptionChange" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityA" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityB" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityRequestedOrientationChange" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskChangeCallbacks" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskDescriptionChange" /> <receiver android:name="com.android.server.appwidget.DummyAppWidget"> <intent-filter> diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java index e53518cca21f..69d8e2574d8c 100644 --- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java @@ -28,8 +28,9 @@ import android.content.pm.PackageManagerInternal; import android.os.UserHandle; import android.os.UserManagerInternal; import android.os.storage.StorageManagerInternal; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java index 8c27e256456f..e4fe5995ce2f 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.am; @@ -23,30 +23,18 @@ import android.app.ActivityManagerInternal; import android.os.SystemClock; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** * Test class for {@link ActivityManagerInternal}. * - * To run the tests, use - * - * runtest -c com.android.server.am.ActivityManagerInternalTest frameworks-services - * - * or the following steps: - * - * Build: m FrameworksServicesTests - * Install: adb install -r \ - * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk - * Run: adb shell am instrument -e class com.android.server.am.ActivityManagerInternalTest -w \ - * com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner + * Build/Install/Run: + * atest FrameworksServicesTests:ActivityManagerInternalTest */ -@RunWith(AndroidJUnit4.class) public class ActivityManagerInternalTest { private static final int TEST_UID1 = 111; private static final int TEST_UID2 = 112; @@ -59,6 +47,7 @@ public class ActivityManagerInternalTest { private ActivityManagerService mAms; private ActivityManagerInternal mAmi; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -147,18 +136,19 @@ public class ActivityManagerInternalTest { private final Object mLock; private Runnable mRunnable; - boolean mNotified; + public boolean mNotified; - public CustomThread(Object lock) { + CustomThread(Object lock) { mLock = lock; } - public CustomThread(Object lock, Runnable runnable) { + CustomThread(Object lock, Runnable runnable) { super(runnable); mLock = lock; mRunnable = runnable; } + @SuppressWarnings("WaitNotInLoop") @Override public void run() { if (mRunnable != null) { @@ -168,7 +158,7 @@ public class ActivityManagerInternalTest { try { mLock.wait(); } catch (InterruptedException e) { - Thread.currentThread().interrupted(); + Thread.interrupted(); } } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 060c55d41bea..767eb60de4f8 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.am; @@ -67,14 +67,12 @@ import android.os.SystemClock; import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.AppOpsService; import org.junit.After; 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; @@ -90,21 +88,11 @@ import java.util.function.Function; /** * Test class for {@link ActivityManagerService}. * - * To run the tests, use - * - * runtest -c com.android.server.am.ActivityManagerServiceTest frameworks-services - * - * or the following steps: - * - * Build: m FrameworksServicesTests - * Install: adb install -r \ - * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk - * Run: adb shell am instrument -e class com.android.server.am.ActivityManagerServiceTest -w \ - * com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner + * Build/Install/Run: + * atest FrameworksServicesTests:ActivityManagerServiceTest */ @SmallTest @FlakyTest(bugId = 113616538) -@RunWith(AndroidJUnit4.class) public class ActivityManagerServiceTest { private static final String TAG = ActivityManagerServiceTest.class.getSimpleName(); @@ -149,6 +137,7 @@ public class ActivityManagerServiceTest { mHandlerThread.quit(); } + @SuppressWarnings("GuardedBy") @MediumTest @Test public void incrementProcStateSeqAndNotifyAppsLocked() throws Exception { @@ -175,6 +164,7 @@ public class ActivityManagerServiceTest { true); // expectNotify // Explicitly setting the seq counter for more verification. + // @SuppressWarnings("GuardedBy") mAms.mProcessList.mProcStateSeqCounter = 42; // Uid state is not moving from background to foreground or vice versa. @@ -267,6 +257,7 @@ public class ActivityManagerServiceTest { return uidRec; } + @SuppressWarnings("GuardedBy") private void verifySeqCounterAndInteractions(UidRecord uidRec, int prevState, int curState, int expectedGlobalCounter, int expectedCurProcStateSeq, int expectedBlockState, boolean expectNotify) throws Exception { @@ -277,6 +268,7 @@ public class ActivityManagerServiceTest { uidRec.setCurProcState(curState); mAms.incrementProcStateSeqAndNotifyAppsLocked(); + // @SuppressWarnings("GuardedBy") assertEquals(expectedGlobalCounter, mAms.mProcessList.mProcStateSeqCounter); assertEquals(expectedCurProcStateSeq, uidRec.curProcStateSeq); @@ -561,8 +553,8 @@ public class ActivityManagerServiceTest { ActivityManager.PROCESS_STATE_SERVICE, ActivityManager.PROCESS_STATE_RECEIVER }; - final ArrayList<UidRecord.ChangeItem> pendingItemsForUids - = new ArrayList<>(changesForPendingItems.length); + final ArrayList<UidRecord.ChangeItem> pendingItemsForUids = + new ArrayList<>(changesForPendingItems.length); for (int i = 0; i < changesForPendingItems.length; ++i) { final UidRecord.ChangeItem item = new UidRecord.ChangeItem(); item.uid = i; @@ -621,7 +613,7 @@ public class ActivityManagerServiceTest { } mAms.mPendingUidChanges.addAll(pendingItemsForUids); mAms.dispatchUidsChanged(); - assertEquals("validateUids should be empty, validateUids: " + mAms.mValidateUids, + assertEquals("validateUids should be empty, size=" + mAms.mValidateUids.size(), 0, mAms.mValidateUids.size()); } @@ -775,7 +767,7 @@ public class ActivityManagerServiceTest { mAms.mActiveUids.clear(); } - private class TestHandler extends Handler { + private static class TestHandler extends Handler { private static final long WAIT_FOR_MSG_TIMEOUT_MS = 4000; // 4 sec private static final long WAIT_FOR_MSG_INTERVAL_MS = 400; // 0.4 sec diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java index 2dfb3751c021..8965152257c6 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java @@ -27,33 +27,33 @@ import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; +import androidx.test.filters.FlakyTest; + import org.junit.Before; import org.junit.Test; import java.util.List; -import androidx.test.filters.FlakyTest; - /** * Tests for {@link ActivityManager}. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.am.ActivityManagerTest + * atest FrameworksServicesTests:ActivityManagerTest */ -@Presubmit @FlakyTest(detail = "Promote to presubmit if stable") +@Presubmit public class ActivityManagerTest { - private IActivityManager service; + private IActivityManager mService; @Before public void setUp() throws Exception { - service = ActivityManager.getService(); + mService = ActivityManager.getService(); } @Test public void testTaskIdsForRunningUsers() throws RemoteException { - int[] runningUserIds = service.getRunningUserIds(); + int[] runningUserIds = mService.getRunningUserIds(); assertThat(runningUserIds).isNotEmpty(); for (int userId : runningUserIds) { testTaskIdsForUser(userId); @@ -61,7 +61,7 @@ public class ActivityManagerTest { } private void testTaskIdsForUser(int userId) throws RemoteException { - List<?> recentTasks = service.getRecentTasks(100, 0, userId).getList(); + List<?> recentTasks = mService.getRecentTasks(100, 0, userId).getList(); if (recentTasks != null) { for (Object elem : recentTasks) { assertThat(elem).isInstanceOf(RecentTaskInfo.class); diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java index 3a7a24d2e103..05cb48b7d64d 100644 --- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java +++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java @@ -16,27 +16,26 @@ package com.android.server.am; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import android.content.Context; import android.os.Handler; -import androidx.test.InstrumentationRegistry; import androidx.test.annotation.UiThreadTest; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.AppOpsService; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.io.File; /** - * runtest -c com.android.server.am.AppErrorDialogTest frameworks-services + * Build/Install/Run: + * atest FrameworksServicesTests:AppErrorDialogTest */ -@RunWith(AndroidJUnit4.class) @SmallTest @FlakyTest(bugId = 113616538) public class AppErrorDialogTest { @@ -46,7 +45,7 @@ public class AppErrorDialogTest { @Before public void setUp() throws Exception { - mContext = InstrumentationRegistry.getTargetContext(); + mContext = getInstrumentation().getTargetContext(); mService = new ActivityManagerService(new ActivityManagerService.Injector() { @Override public AppOpsService getAppOpsService(File file, Handler handler) { @@ -67,7 +66,7 @@ public class AppErrorDialogTest { @Test @UiThreadTest - public void testCreateWorks() throws Exception { + public void testCreateWorks() { AppErrorDialog.Data data = new AppErrorDialog.Data(); data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345); data.result = new AppErrorResult(); diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java index 75f7c4c2cdff..0889265dd663 100644 --- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java +++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java @@ -27,10 +27,8 @@ import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Collections; @@ -40,11 +38,10 @@ import java.util.List; * Test class for {@link BroadcastRecord}. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.am.BroadcastRecordTest + * atest FrameworksServicesTests:BroadcastRecordTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class BroadcastRecordTest { @Test diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java index 719e0edc20b7..9626990efdcd 100644 --- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java +++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java @@ -11,15 +11,18 @@ * 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 + * limitations under the License. */ package com.android.server.am; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static com.android.server.am.ActivityManagerService.Injector; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.mockito.Mockito.when; import android.content.Context; @@ -28,9 +31,7 @@ import android.os.Handler; import android.provider.Settings; import android.test.mock.MockContentResolver; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.AppOpsService; @@ -39,7 +40,6 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -48,20 +48,10 @@ import java.io.File; /** * Test class for {@link CoreSettingsObserver}. * - * To run the tests, use - * - * runtest -c com.android.server.am.CoreSettingsObserverTest frameworks-services - * - * or the following steps: - * - * Build: m FrameworksServicesTests - * Install: adb install -r \ - * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk - * Run: adb shell am instrument -e class com.android.server.am.CoreSettingsObserverTest -w \ - * com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner + * Build/Install/Run: + * atest FrameworksServicesTests:CoreSettingsObserverTest */ @SmallTest -@RunWith(AndroidJUnit4.class) public class CoreSettingsObserverTest { private static final String TEST_SETTING_SECURE_INT = "secureInt"; private static final String TEST_SETTING_GLOBAL_FLOAT = "globalFloat"; @@ -94,7 +84,7 @@ public class CoreSettingsObserverTest { public void setUp() { MockitoAnnotations.initMocks(this); - final Context originalContext = InstrumentationRegistry.getContext(); + final Context originalContext = getInstrumentation().getTargetContext(); when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo()); mContentResolver = new MockContentResolver(mContext); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); @@ -124,12 +114,12 @@ public class CoreSettingsObserverTest { public void testPopulateSettings_settingNotSet() { final Bundle settingsBundle = getPopulatedBundle(); - assertFalse("Bundle should not contain " + TEST_SETTING_SECURE_INT, - settingsBundle.containsKey(TEST_SETTING_SECURE_INT)); - assertFalse("Bundle should not contain " + TEST_SETTING_GLOBAL_FLOAT, - settingsBundle.containsKey(TEST_SETTING_GLOBAL_FLOAT)); - assertFalse("Bundle should not contain " + TEST_SETTING_SYSTEM_STRING, - settingsBundle.containsKey(TEST_SETTING_SYSTEM_STRING)); + assertWithMessage("Bundle should not contain " + TEST_SETTING_SECURE_INT) + .that(settingsBundle.keySet()).doesNotContain(TEST_SETTING_SECURE_INT); + assertWithMessage("Bundle should not contain " + TEST_SETTING_GLOBAL_FLOAT) + .that(settingsBundle.keySet()).doesNotContain(TEST_SETTING_GLOBAL_FLOAT); + assertWithMessage("Bundle should not contain " + TEST_SETTING_SYSTEM_STRING) + .that(settingsBundle.keySet()).doesNotContain(TEST_SETTING_SYSTEM_STRING); } @Test @@ -150,8 +140,8 @@ public class CoreSettingsObserverTest { Settings.Global.putString(mContentResolver, TEST_SETTING_GLOBAL_FLOAT, null); settingsBundle = getPopulatedBundle(); - assertFalse("Bundle should not contain " + TEST_SETTING_GLOBAL_FLOAT, - settingsBundle.containsKey(TEST_SETTING_GLOBAL_FLOAT)); + assertWithMessage("Bundle should not contain " + TEST_SETTING_GLOBAL_FLOAT) + .that(settingsBundle.keySet()).doesNotContain(TEST_SETTING_GLOBAL_FLOAT); assertEquals("Unexpected value of " + TEST_SETTING_SECURE_INT, TEST_INT, settingsBundle.getInt(TEST_SETTING_SECURE_INT)); assertEquals("Unexpected value of " + TEST_SETTING_SYSTEM_STRING, @@ -170,6 +160,7 @@ public class CoreSettingsObserverTest { return mContext; } + @Override public AppOpsService getAppOpsService(File file, Handler handler) { return null; } diff --git a/services/tests/servicestests/src/com/android/server/am/GlobalSettingsToPropertiesMapperTest.java b/services/tests/servicestests/src/com/android/server/am/GlobalSettingsToPropertiesMapperTest.java index 765aaad45efb..c162c3b9cc42 100644 --- a/services/tests/servicestests/src/com/android/server/am/GlobalSettingsToPropertiesMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/am/GlobalSettingsToPropertiesMapperTest.java @@ -11,34 +11,37 @@ * 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 + * limitations under the License. */ package com.android.server.am; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + import android.content.ContentResolver; import android.provider.Settings; import android.test.mock.MockContentResolver; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.Preconditions; import com.android.internal.util.test.FakeSettingsProvider; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.HashMap; import java.util.Map; /** * Tests for {@link GlobalSettingsToPropertiesMapper} + * + * Build/Install/Run: + * atest FrameworksServicesTests:GlobalSettingsToPropertiesMapperTest */ -@RunWith(AndroidJUnit4.class) @SmallTest public class GlobalSettingsToPropertiesMapperTest { private static final String[][] TEST_MAPPING = new String[][] { @@ -51,7 +54,7 @@ public class GlobalSettingsToPropertiesMapperTest { @Before public void setup() { // Use FakeSettingsProvider to not affect global state - mMockContentResolver = new MockContentResolver(InstrumentationRegistry.getContext()); + mMockContentResolver = new MockContentResolver(getInstrumentation().getTargetContext()); mMockContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mTestMapper = new TestMapper(mMockContentResolver); } @@ -63,21 +66,21 @@ public class GlobalSettingsToPropertiesMapperTest { mTestMapper.updatePropertiesFromGlobalSettings(); String propValue = mTestMapper.systemPropertiesGet("TestProperty"); - Assert.assertEquals("testValue", propValue); + assertEquals("testValue", propValue); Settings.Global.putString(mMockContentResolver, Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue2"); mTestMapper.updatePropertyFromSetting(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "TestProperty"); propValue = mTestMapper.systemPropertiesGet("TestProperty"); - Assert.assertEquals("testValue2", propValue); + assertEquals("testValue2", propValue); Settings.Global.putString(mMockContentResolver, Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, null); mTestMapper.updatePropertyFromSetting(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "TestProperty"); propValue = mTestMapper.systemPropertiesGet("TestProperty"); - Assert.assertEquals("", propValue); + assertEquals("", propValue); } @Test @@ -85,7 +88,7 @@ public class GlobalSettingsToPropertiesMapperTest { // Test that empty property will not not be set if setting is not set mTestMapper.updatePropertiesFromGlobalSettings(); String propValue = mTestMapper.systemPropertiesGet("TestProperty"); - Assert.assertNull("Property should not be set if setting is null", propValue); + assertNull("Property should not be set if setting is null", propValue); } private static class TestMapper extends GlobalSettingsToPropertiesMapper { @@ -108,6 +111,5 @@ public class GlobalSettingsToPropertiesMapperTest { mProps.put(key, value); } } - } diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java index 72c5b105cfef..c7409d7f8335 100644 --- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java +++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java @@ -29,14 +29,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.Collections; -@RunWith(AndroidJUnit4.class) +/** + * Build/Install/Run: + * atest FrameworksServicesTests:MemoryStatUtilTest + */ @SmallTest public class MemoryStatUtilTest { private static final String MEMORY_STAT_CONTENTS = String.join( @@ -130,51 +131,51 @@ public class MemoryStatUtilTest { "0"); private static final String PROC_STATUS_CONTENTS = "Name:\tandroid.youtube\n" - + "State:\tS (sleeping)\n" - + "Tgid:\t12088\n" - + "Pid:\t12088\n" - + "PPid:\t723\n" - + "TracerPid:\t0\n" - + "Uid:\t10083\t10083\t10083\t10083\n" - + "Gid:\t10083\t10083\t10083\t10083\n" - + "Ngid:\t0\n" - + "FDSize:\t128\n" - + "Groups:\t3003 9997 20083 50083 \n" - + "VmPeak:\t 4546844 kB\n" - + "VmSize:\t 4542636 kB\n" - + "VmLck:\t 0 kB\n" - + "VmPin:\t 0 kB\n" - + "VmHWM:\t 137668 kB\n" // RSS high watermark - + "VmRSS:\t 126776 kB\n" - + "RssAnon:\t 37860 kB\n" - + "RssFile:\t 88764 kB\n" - + "RssShmem:\t 152 kB\n" - + "VmData:\t 4125112 kB\n" - + "VmStk:\t 8192 kB\n" - + "VmExe:\t 24 kB\n" - + "VmLib:\t 102432 kB\n" - + "VmPTE:\t 1300 kB\n" - + "VmPMD:\t 36 kB\n" - + "VmSwap:\t 0 kB\n" - + "Threads:\t95\n" - + "SigQ:\t0/13641\n" - + "SigPnd:\t0000000000000000\n" - + "ShdPnd:\t0000000000000000\n" - + "SigBlk:\t0000000000001204\n" - + "SigIgn:\t0000000000000001\n" - + "SigCgt:\t00000006400084f8\n" - + "CapInh:\t0000000000000000\n" - + "CapPrm:\t0000000000000000\n" - + "CapEff:\t0000000000000000\n" - + "CapBnd:\t0000000000000000\n" - + "CapAmb:\t0000000000000000\n" - + "Seccomp:\t2\n" - + "Cpus_allowed:\tff\n" - + "Cpus_allowed_list:\t0-7\n" - + "Mems_allowed:\t1\n" - + "Mems_allowed_list:\t0\n" - + "voluntary_ctxt_switches:\t903\n" - + "nonvoluntary_ctxt_switches:\t104\n"; + + "State:\tS (sleeping)\n" + + "Tgid:\t12088\n" + + "Pid:\t12088\n" + + "PPid:\t723\n" + + "TracerPid:\t0\n" + + "Uid:\t10083\t10083\t10083\t10083\n" + + "Gid:\t10083\t10083\t10083\t10083\n" + + "Ngid:\t0\n" + + "FDSize:\t128\n" + + "Groups:\t3003 9997 20083 50083 \n" + + "VmPeak:\t 4546844 kB\n" + + "VmSize:\t 4542636 kB\n" + + "VmLck:\t 0 kB\n" + + "VmPin:\t 0 kB\n" + + "VmHWM:\t 137668 kB\n" // RSS high watermark + + "VmRSS:\t 126776 kB\n" + + "RssAnon:\t 37860 kB\n" + + "RssFile:\t 88764 kB\n" + + "RssShmem:\t 152 kB\n" + + "VmData:\t 4125112 kB\n" + + "VmStk:\t 8192 kB\n" + + "VmExe:\t 24 kB\n" + + "VmLib:\t 102432 kB\n" + + "VmPTE:\t 1300 kB\n" + + "VmPMD:\t 36 kB\n" + + "VmSwap:\t 0 kB\n" + + "Threads:\t95\n" + + "SigQ:\t0/13641\n" + + "SigPnd:\t0000000000000000\n" + + "ShdPnd:\t0000000000000000\n" + + "SigBlk:\t0000000000001204\n" + + "SigIgn:\t0000000000000001\n" + + "SigCgt:\t00000006400084f8\n" + + "CapInh:\t0000000000000000\n" + + "CapPrm:\t0000000000000000\n" + + "CapEff:\t0000000000000000\n" + + "CapBnd:\t0000000000000000\n" + + "CapAmb:\t0000000000000000\n" + + "Seccomp:\t2\n" + + "Cpus_allowed:\tff\n" + + "Cpus_allowed_list:\t0-7\n" + + "Mems_allowed:\t1\n" + + "Mems_allowed_list:\t0\n" + + "voluntary_ctxt_switches:\t903\n" + + "nonvoluntary_ctxt_switches:\t104\n"; @Test public void testParseMemoryStatFromMemcg_parsesCorrectValues() { diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java index 75e1d0d800db..bd03a8d22643 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.am; @@ -19,6 +19,8 @@ package com.android.server.am; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static com.android.server.am.UserController.CONTINUE_USER_SWITCH_MSG; import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG; import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG; @@ -49,8 +51,6 @@ import static org.mockito.Mockito.validateMockitoUsage; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static androidx.test.InstrumentationRegistry.getTargetContext; - import android.app.IUserSwitchObserver; import android.content.Context; import android.content.IIntentReceiver; @@ -68,6 +68,9 @@ import android.os.UserManagerInternal; import android.platform.test.annotations.Presubmit; import android.util.Log; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; + import com.android.server.pm.UserManagerService; import com.android.server.wm.WindowManagerService; @@ -81,20 +84,18 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import androidx.test.filters.SmallTest; - /** * Tests for {@link UserController}. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.am.UserControllerTest + * atest FrameworksServicesTests:UserControllerTest */ -@Presubmit @SmallTest +@Presubmit public class UserControllerTest { private static final int TEST_USER_ID = 10; private static final int NONEXIST_USER_ID = 2; - private static String TAG = UserControllerTest.class.getSimpleName(); + private static final String TAG = UserControllerTest.class.getSimpleName(); private UserController mUserController; private TestInjector mInjector; @@ -121,7 +122,7 @@ public class UserControllerTest { @Before public void setUp() throws Exception { runWithDexmakerShareClassLoader(() -> { - mInjector = spy(new TestInjector(getTargetContext())); + mInjector = spy(new TestInjector(getInstrumentation().getTargetContext())); doNothing().when(mInjector).clearAllLockedTasks(anyString()); doNothing().when(mInjector).startHomeActivity(anyInt(), anyString()); doReturn(false).when(mInjector).stackSupervisorSwitchUser(anyInt(), any()); @@ -133,7 +134,7 @@ public class UserControllerTest { @After public void tearDown() throws Exception { - mInjector.handlerThread.quit(); + mInjector.mHandlerThread.quit(); validateMockitoUsage(); } @@ -148,6 +149,7 @@ public class UserControllerTest { startForegroundUserAssertions(); } + @FlakyTest(bugId = 118932054) @Test public void testStartUser_background() { mUserController.startUser(TEST_USER_ID, false /* foreground */); @@ -169,8 +171,8 @@ public class UserControllerTest { private void startUserAssertions( List<String> expectedActions, Set<Integer> expectedMessageCodes) { - assertEquals(expectedActions, getActions(mInjector.sentIntents)); - Set<Integer> actualCodes = mInjector.handler.getMessageCodes(); + assertEquals(expectedActions, getActions(mInjector.mSentIntents)); + Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes(); assertEquals("Unexpected message sent", expectedMessageCodes, actualCodes); } @@ -180,7 +182,7 @@ public class UserControllerTest { private void startForegroundUserAssertions() { startUserAssertions(START_FOREGROUND_USER_ACTIONS, START_FOREGROUND_USER_MESSAGE_CODES); - Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG); + Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); UserState userState = (UserState) reportMsg.obj; assertNotNull(userState); @@ -211,19 +213,19 @@ public class UserControllerTest { mUserController.registerUserSwitchObserver(observer, "mock"); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, true); - Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG); + Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); UserState userState = (UserState) reportMsg.obj; int oldUserId = reportMsg.arg1; int newUserId = reportMsg.arg2; // Call dispatchUserSwitch and verify that observer was called only once - mInjector.handler.clearAllRecordedMessages(); + mInjector.mHandler.clearAllRecordedMessages(); mUserController.dispatchUserSwitch(userState, oldUserId, newUserId); verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any()); Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG); - Set<Integer> actualCodes = mInjector.handler.getMessageCodes(); + Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes(); assertEquals("Unexpected message sent", expectedCodes, actualCodes); - Message conMsg = mInjector.handler.getMessageForCode(CONTINUE_USER_SWITCH_MSG); + Message conMsg = mInjector.mHandler.getMessageForCode(CONTINUE_USER_SWITCH_MSG); assertNotNull(conMsg); userState = (UserState) conMsg.obj; assertNotNull(userState); @@ -241,17 +243,17 @@ public class UserControllerTest { mUserController.registerUserSwitchObserver(observer, "mock"); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, true); - Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG); + Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); UserState userState = (UserState) reportMsg.obj; int oldUserId = reportMsg.arg1; int newUserId = reportMsg.arg2; // Call dispatchUserSwitch and verify that observer was called only once - mInjector.handler.clearAllRecordedMessages(); + mInjector.mHandler.clearAllRecordedMessages(); mUserController.dispatchUserSwitch(userState, oldUserId, newUserId); verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any()); // Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout) - Set<Integer> actualCodes = mInjector.handler.getMessageCodes(); + Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes(); assertWithMessage("No messages should be sent").that(actualCodes).isEmpty(); } @@ -259,12 +261,12 @@ public class UserControllerTest { public void testContinueUserSwitch() { // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, true); - Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG); + Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); UserState userState = (UserState) reportMsg.obj; int oldUserId = reportMsg.arg1; int newUserId = reportMsg.arg2; - mInjector.handler.clearAllRecordedMessages(); + mInjector.mHandler.clearAllRecordedMessages(); // Verify that continueUserSwitch worked as expected mUserController.continueUserSwitch(userState, oldUserId, newUserId); verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen(); @@ -276,12 +278,12 @@ public class UserControllerTest { mUserController.mUserSwitchUiEnabled = false; // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, true); - Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG); + Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); UserState userState = (UserState) reportMsg.obj; int oldUserId = reportMsg.arg1; int newUserId = reportMsg.arg2; - mInjector.handler.clearAllRecordedMessages(); + mInjector.mHandler.clearAllRecordedMessages(); // Verify that continueUserSwitch worked as expected mUserController.continueUserSwitch(userState, oldUserId, newUserId); verify(mInjector.getWindowManager(), never()).stopFreezingScreen(); @@ -290,9 +292,9 @@ public class UserControllerTest { private void continueUserSwitchAssertions() { Set<Integer> expectedCodes = Collections.singleton(REPORT_USER_SWITCH_COMPLETE_MSG); - Set<Integer> actualCodes = mInjector.handler.getMessageCodes(); + Set<Integer> actualCodes = mInjector.mHandler.getMessageCodes(); assertEquals("Unexpected message sent", expectedCodes, actualCodes); - Message msg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_COMPLETE_MSG); + Message msg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_COMPLETE_MSG); assertNotNull(msg); assertEquals("Unexpected userId", TEST_USER_ID, msg.arg1); } @@ -305,10 +307,10 @@ public class UserControllerTest { mUserController.registerUserSwitchObserver(observer, "mock"); // Start user -- this will update state of mUserController mUserController.startUser(TEST_USER_ID, true); - Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG); + Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG); assertNotNull(reportMsg); int newUserId = reportMsg.arg2; - mInjector.handler.clearAllRecordedMessages(); + mInjector.mHandler.clearAllRecordedMessages(); // Mockito can't reset only interactions, so just verify that this hasn't been // called with 'false' until after dispatchUserSwitchComplete. verify(mInjector.getWindowManager(), never()).setSwitchingUser(false); @@ -321,7 +323,7 @@ public class UserControllerTest { private void setUpUser(int userId, int flags) { UserInfo userInfo = new UserInfo(userId, "User" + userId, flags); - when(mInjector.userManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo); + when(mInjector.mUserManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo); } private static List<String> getActions(List<Intent> intents) { @@ -334,45 +336,46 @@ public class UserControllerTest { // Should be public to allow mocking private static class TestInjector extends UserController.Injector { - TestHandler handler; - TestHandler uiHandler; - HandlerThread handlerThread; - UserManagerService userManagerMock; - UserManagerInternal userManagerInternalMock; - WindowManagerService windowManagerMock; - private Context mCtx; - List<Intent> sentIntents = new ArrayList<>(); + public final TestHandler mHandler; + public final HandlerThread mHandlerThread; + public final UserManagerService mUserManagerMock; + public final List<Intent> mSentIntents = new ArrayList<>(); + + private final TestHandler mUiHandler; + private final UserManagerInternal mUserManagerInternalMock; + private final WindowManagerService mWindowManagerMock; + private final Context mCtx; TestInjector(Context ctx) { super(null); mCtx = ctx; - handlerThread = new HandlerThread(TAG); - handlerThread.start(); - handler = new TestHandler(handlerThread.getLooper()); - uiHandler = new TestHandler(handlerThread.getLooper()); - userManagerMock = mock(UserManagerService.class); - userManagerInternalMock = mock(UserManagerInternal.class); - windowManagerMock = mock(WindowManagerService.class); + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + mHandler = new TestHandler(mHandlerThread.getLooper()); + mUiHandler = new TestHandler(mHandlerThread.getLooper()); + mUserManagerMock = mock(UserManagerService.class); + mUserManagerInternalMock = mock(UserManagerInternal.class); + mWindowManagerMock = mock(WindowManagerService.class); } @Override protected Handler getHandler(Handler.Callback callback) { - return handler; + return mHandler; } @Override protected Handler getUiHandler(Handler.Callback callback) { - return uiHandler; + return mUiHandler; } @Override protected UserManagerService getUserManager() { - return userManagerMock; + return mUserManagerMock; } @Override UserManagerInternal getUserManagerInternal() { - return userManagerInternalMock; + return mUserManagerInternalMock; } @Override @@ -388,7 +391,7 @@ public class UserControllerTest { @Override WindowManagerService getWindowManager() { - return windowManagerMock; + return mWindowManagerMock; } @Override @@ -402,7 +405,7 @@ public class UserControllerTest { String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { Log.i(TAG, "broadcastIntentLocked " + intent); - sentIntents.add(intent); + mSentIntents.add(intent); return 0; } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index 2b5b812af4c7..a847b6ab105c 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -38,12 +38,13 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.security.KeyChain; -import android.support.annotation.NonNull; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.Pair; import android.view.IWindowManager; +import androidx.annotation.NonNull; + import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.widget.LockPatternUtils; import com.android.server.net.NetworkPolicyManagerInternal; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 213961c1e1d9..be00bb662d17 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -30,11 +30,12 @@ import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; import android.os.UserManagerInternal; -import android.support.annotation.NonNull; import android.test.mock.MockContext; import android.util.ArrayMap; import android.util.ExceptionUtils; +import androidx.annotation.NonNull; + import com.android.internal.util.FunctionalUtils; import org.junit.Assert; diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java index b5a354ccefe6..9c8a38219a9c 100644 --- a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java @@ -51,7 +51,9 @@ import java.util.concurrent.TimeUnit; @MediumTest public class NetworkWatchlistServiceTests { - private static final long NETWOR_EVENT_TIMEOUT_SEC = 1; + private static final long NETWORK_EVENT_TIMEOUT_SEC = 1; + private static final int TEST_NETID = 100; + private static final int TEST_EVENT_TYPE = 1; private static final String TEST_HOST = "testhost.com"; private static final String TEST_IP = "7.6.8.9"; private static final String[] TEST_IPS = @@ -180,8 +182,9 @@ public class NetworkWatchlistServiceTests { } }; mWatchlistService.mNetworkWatchlistHandler = testDnsHandler; - connectivityMetrics.callback.onDnsEvent(TEST_HOST, TEST_IPS, TEST_IPS.length, 123L, 456); - if (!testDnsLatch.await(NETWOR_EVENT_TIMEOUT_SEC, TimeUnit.SECONDS)) { + connectivityMetrics.callback.onDnsEvent(TEST_NETID, TEST_EVENT_TYPE, 0, + TEST_HOST, TEST_IPS, TEST_IPS.length, 123L, 456); + if (!testDnsLatch.await(NETWORK_EVENT_TIMEOUT_SEC, TimeUnit.SECONDS)) { fail("Timed out waiting for network event"); } assertEquals(TEST_HOST, dnsParams[0]); @@ -206,7 +209,7 @@ public class NetworkWatchlistServiceTests { }; mWatchlistService.mNetworkWatchlistHandler = testConnectHandler; connectivityMetrics.callback.onConnectEvent(TEST_IP, 80, 123L, 456); - if (!testConnectLatch.await(NETWOR_EVENT_TIMEOUT_SEC, TimeUnit.SECONDS)) { + if (!testConnectLatch.await(NETWORK_EVENT_TIMEOUT_SEC, TimeUnit.SECONDS)) { fail("Timed out waiting for network event"); } assertNull(connectParams[0]); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index b0b7defe8da6..ebac8fb712be 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -38,12 +38,12 @@ import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import libcore.io.IoUtils; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import libcore.io.IoUtils; - import java.io.File; import java.lang.reflect.Array; import java.lang.reflect.Field; @@ -490,7 +490,7 @@ public class PackageParserTest { pkg.usesLibraryFiles = new String[] { "foo13"}; pkg.usesLibraryInfos = new ArrayList<>(); - pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null)); + pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null, null)); pkg.mOriginalPackages = new ArrayList<>(); pkg.mOriginalPackages.add("foo14"); diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java index 416a616b0546..bd42b7318158 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -401,15 +401,7 @@ public class DexManagerTests { List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths(); notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0); - PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader); - assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false); - assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); - // We expect that all the contexts are unsupported. - String[] expectedContexts = - Collections.nCopies(secondaries.size(), - PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]); - assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries, - /*isUsedByOtherApps*/false, mUser0, expectedContexts); + assertNoUseInfo(mBarUser0UnsupportedClassLoader); } @Test @@ -438,27 +430,18 @@ public class DexManagerTests { } @Test - public void testNotifyUnsupportedClassLoaderDoesNotChange() { - List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths(); - notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0); - - PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader); - assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false); - assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); - // We expect that all the contexts are unsupported. - String[] expectedContexts = - Collections.nCopies(secondaries.size(), - PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]); - assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries, - /*isUsedByOtherApps*/false, mUser0, expectedContexts); + public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() { + List<String> secondaries = mBarUser0.getSecondaryDexPaths(); - // Record bar secondaries again with a different class loader. This will change the context. - // However, because the context was already marked as unsupported we should not chage it. - notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0); - pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader); - assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries, - /*isUsedByOtherApps*/false, mUser0, expectedContexts); + notifyDexLoad(mBarUser0, secondaries, mUser0); + PackageUseInfo pui = getPackageUseInfo(mBarUser0); + assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0); + // Record bar secondaries again with an unsupported class loader. This should not change the + // context. + notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0); + pui = getPackageUseInfo(mBarUser0); + assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0); } @Test diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java index 3e93dcf3ba92..7755e94369af 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java @@ -399,20 +399,6 @@ public class PackageDexUsageTests { } @Test - public void testRecordClassLoaderContextUnsupportedContext() { - // Record a secondary dex file. - assertTrue(record(mFooSecondary1User0)); - // Now update its context. - TestData unsupportedContext = mFooSecondary1User0.updateClassLoaderContext( - PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT); - assertTrue(record(unsupportedContext)); - - assertPackageDexUsage(null, unsupportedContext); - writeAndReadBack(); - assertPackageDexUsage(null, unsupportedContext); - } - - @Test public void testRecordClassLoaderContextTransitionFromUnknown() { // Record a secondary dex file. TestData unknownContext = mFooSecondary1User0.updateClassLoaderContext( @@ -440,29 +426,41 @@ public class PackageDexUsageTests { PackageDexUsage.DexUseInfo validContext = new DexUseInfo(isUsedByOtherApps, userId, "valid_context", "arm"); assertFalse(validContext.isUnknownClassLoaderContext()); - assertFalse(validContext.isUnsupportedClassLoaderContext()); assertFalse(validContext.isVariableClassLoaderContext()); - PackageDexUsage.DexUseInfo unsupportedContext = new DexUseInfo(isUsedByOtherApps, userId, - PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT, "arm"); - assertFalse(unsupportedContext.isUnknownClassLoaderContext()); - assertTrue(unsupportedContext.isUnsupportedClassLoaderContext()); - assertFalse(unsupportedContext.isVariableClassLoaderContext()); - PackageDexUsage.DexUseInfo variableContext = new DexUseInfo(isUsedByOtherApps, userId, PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, "arm"); assertFalse(variableContext.isUnknownClassLoaderContext()); - assertFalse(variableContext.isUnsupportedClassLoaderContext()); assertTrue(variableContext.isVariableClassLoaderContext()); PackageDexUsage.DexUseInfo unknownContext = new DexUseInfo(isUsedByOtherApps, userId, PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT, "arm"); assertTrue(unknownContext.isUnknownClassLoaderContext()); - assertFalse(unknownContext.isUnsupportedClassLoaderContext()); assertFalse(unknownContext.isVariableClassLoaderContext()); } @Test + public void testUnsupportedClassLoaderDiscardedOnRead() throws Exception { + String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__2\n" + + mBarSecondary1User0.mPackageName + "\n" + + "#" + mBarSecondary1User0.mDexFile + "\n" + + "0,0," + mBarSecondary1User0.mLoaderIsa + "\n" + + "@\n" + + "=UnsupportedClassLoaderContext=\n" + + + mFooSecondary1User0.mPackageName + "\n" + + "#" + mFooSecondary1User0.mDexFile + "\n" + + "0,0," + mFooSecondary1User0.mLoaderIsa + "\n" + + "@\n" + + mFooSecondary1User0.mClassLoaderContext + "\n"; + + mPackageDexUsage.read(new StringReader(content)); + + assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0); + assertPackageDexUsage(mBarBaseUser0); + } + + @Test public void testReadVersion1() { String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); // Equivalent to diff --git a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java index b5fe8b159c47..a9071612a725 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -29,11 +29,9 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -41,12 +39,11 @@ import org.mockito.MockitoAnnotations; * Tests for the {@link TaskStack} class. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.AnimatingAppWindowTokenRegistryTest + * atest FrameworksServicesTests:AnimatingAppWindowTokenRegistryTest */ @SmallTest @Presubmit @FlakyTest(detail = "Promote once confirmed non-flaky") -@RunWith(AndroidJUnit4.class) public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase { @Mock @@ -56,14 +53,14 @@ public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase { Runnable mMockEndDeferFinishCallback1; @Mock Runnable mMockEndDeferFinishCallback2; + @Before public void setUp() throws Exception { - super.setUp(); MockitoAnnotations.initMocks(this); } @Test - public void testDeferring() throws Exception { + public void testDeferring() { final AppWindowToken window1 = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD, @@ -85,7 +82,7 @@ public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase { } @Test - public void testContainerRemoved() throws Exception { + public void testContainerRemoved() { final AppWindowToken window1 = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD, diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java index aa495f7d4515..5e12a950c560 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -27,28 +27,28 @@ import android.platform.test.annotations.Presubmit; import android.view.WindowManager; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; +/** + * Build/Install/Run: + * atest FrameworksServicesTests:AppTransitionControllerTest + */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class AppTransitionControllerTest extends WindowTestsBase { private AppTransitionController mAppTransitionController; @Before public void setUp() throws Exception { - super.setUp(); - mAppTransitionController = new AppTransitionController(sWm, mDisplayContent); + mAppTransitionController = new AppTransitionController(mWm, mDisplayContent); } @Test - public void testTranslucentOpen() throws Exception { - synchronized (sWm.mWindowMap) { + public void testTranslucentOpen() { + synchronized (mWm.mGlobalLock) { final AppWindowToken behind = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent, @@ -64,8 +64,8 @@ public class AppTransitionControllerTest extends WindowTestsBase { } @Test - public void testTranslucentClose() throws Exception { - synchronized (sWm.mWindowMap) { + public void testTranslucentClose() { + synchronized (mWm.mGlobalLock) { final AppWindowToken behind = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent, diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java index ee6fbac3f19f..f12619c6e337 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -32,81 +32,75 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; -import android.content.Context; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.Display; import android.view.IApplicationToken; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Test class for {@link AppTransition}. * - * atest AppTransitionTests + * Build/Install/Run: + * atest FrameworksServicesTests:AppTransitionTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class AppTransitionTests extends WindowTestsBase { private DisplayContent mDc; @Before public void setUp() throws Exception { - super.setUp(); - final Context context = InstrumentationRegistry.getTargetContext(); - mDc = sWm.getDefaultDisplayContentLocked(); + mDc = mWm.getDefaultDisplayContentLocked(); // For unit test, we don't need to test performSurfacePlacement to prevent some // abnormal interaction with surfaceflinger native side. - sWm.mRoot = spy(sWm.mRoot); - doNothing().when(sWm.mRoot).performSurfacePlacement(anyBoolean()); + mWm.mRoot = spy(mWm.mRoot); + doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean()); } @Test - public void testKeyguardOverride() throws Exception { - sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */); - sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */); + public void testKeyguardOverride() { + mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */); + mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */); assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition()); } @Test - public void testKeyguardKeep() throws Exception { - sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */); - sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */); + public void testKeyguardKeep() { + mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */); + mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */); assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition()); } @Test - public void testForceOverride() throws Exception { - sWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */); + public void testForceOverride() { + mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */); mDc.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */); assertEquals(TRANSIT_ACTIVITY_OPEN, mDc.mAppTransition.getAppTransition()); } @Test - public void testCrashing() throws Exception { - sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */); - sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); + public void testCrashing() { + mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */); + mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); assertEquals(TRANSIT_CRASHING_ACTIVITY_CLOSE, mDc.mAppTransition.getAppTransition()); } @Test - public void testKeepKeyguard_withCrashing() throws Exception { - sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */); - sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); + public void testKeepKeyguard_withCrashing() { + mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */); + mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition()); } @Test - public void testAppTransitionStateForMultiDisplay() throws Exception { + public void testAppTransitionStateForMultiDisplay() { // Create 2 displays & presume both display the state is ON for ready to display & animate. final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON); final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON); @@ -149,7 +143,7 @@ public class AppTransitionTests extends WindowTestsBase { } @Test - public void testCleanAppTransitionWhenTaskStackReparent() throws Exception { + public void testCleanAppTransitionWhenTaskStackReparent() { // Create 2 displays & presume both display the state is ON for ready to display & animate. final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON); final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON); diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java index fcd8a39e4d07..415b5d93d90e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java @@ -21,6 +21,8 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.res.Configuration.EMPTY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -29,10 +31,8 @@ import static org.junit.Assert.fail; import android.platform.test.annotations.Presubmit; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.wm.WindowTestUtils.TestTaskWindowContainerController; @@ -41,16 +41,17 @@ import org.junit.Test; /** * Test class for {@link AppWindowContainerController}. * - * atest FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests + * atest FrameworksServicesTests:AppWindowContainerControllerTests */ +@FlakyTest(bugId = 74078662) @SmallTest @Presubmit -@FlakyTest(bugId = 74078662) -@org.junit.runner.RunWith(AndroidJUnit4.class) public class AppWindowContainerControllerTests extends WindowTestsBase { + private final String mPackageName = getInstrumentation().getTargetContext().getPackageName(); + @Test - public void testRemoveContainer() throws Exception { + public void testRemoveContainer() { final WindowTestUtils.TestAppWindowContainerController controller = createAppWindowController(); @@ -68,7 +69,7 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { } @Test - public void testSetOrientation() throws Exception { + public void testSetOrientation() { final WindowTestUtils.TestAppWindowContainerController controller = createAppWindowController(); @@ -84,7 +85,7 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation()); // Reset display frozen state - sWm.mDisplayFrozen = false; + mWm.mDisplayFrozen = false; } private void assertHasStartingWindow(AppWindowToken atoken) { @@ -103,10 +104,10 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { } @Test - public void testCreateRemoveStartingWindow() throws Exception { + public void testCreateRemoveStartingWindow() { final WindowTestUtils.TestAppWindowContainerController controller = createAppWindowController(); - controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), + controller.addStartingWindow(mPackageName, android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, false, false); waitUntilHandlersIdle(); @@ -118,34 +119,34 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { } @Test - public void testAddRemoveRace() throws Exception { - + public void testAddRemoveRace() { // There was once a race condition between adding and removing starting windows for (int i = 0; i < 1000; i++) { final WindowTestUtils.TestAppWindowContainerController controller = createAppWindowController(); - controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), + controller.addStartingWindow(mPackageName, android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, false, false); controller.removeStartingWindow(); waitUntilHandlersIdle(); assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent)); - controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately(); + controller.getAppWindowToken( + mDisplayContent).getParent().getParent().removeImmediately(); } } @Test - public void testTransferStartingWindow() throws Exception { + public void testTransferStartingWindow() { final WindowTestUtils.TestAppWindowContainerController controller1 = createAppWindowController(); final WindowTestUtils.TestAppWindowContainerController controller2 = createAppWindowController(); - controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), + controller1.addStartingWindow(mPackageName, android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, false, false); waitUntilHandlersIdle(); - controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), + controller2.addStartingWindow(mPackageName, android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(), true, true, false, true, false, false); waitUntilHandlersIdle(); @@ -154,19 +155,19 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { } @Test - public void testTransferStartingWindowWhileCreating() throws Exception { + public void testTransferStartingWindowWhileCreating() { final WindowTestUtils.TestAppWindowContainerController controller1 = createAppWindowController(); final WindowTestUtils.TestAppWindowContainerController controller2 = createAppWindowController(); - ((TestWindowManagerPolicy) sWm.mPolicy).setRunnableWhenAddingSplashScreen(() -> { + ((TestWindowManagerPolicy) mWm.mPolicy).setRunnableWhenAddingSplashScreen(() -> { // Surprise, ...! Transfer window in the middle of the creation flow. - controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), + controller2.addStartingWindow(mPackageName, android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(), true, true, false, true, false, false); }); - controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), + controller1.addStartingWindow(mPackageName, android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, false, false); waitUntilHandlersIdle(); @@ -175,7 +176,7 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { } @Test - public void testTryTransferStartingWindowFromHiddenAboveToken() throws Exception { + public void testTryTransferStartingWindowFromHiddenAboveToken() { // Add two tasks on top of each other. TestTaskWindowContainerController taskController = @@ -186,7 +187,7 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { createAppWindowController(taskController); // Add a starting window. - controllerTop.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), + controllerTop.addStartingWindow(mPackageName, android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, false, false); waitUntilHandlersIdle(); @@ -202,7 +203,7 @@ public class AppWindowContainerControllerTests extends WindowTestsBase { } @Test - public void testReparent() throws Exception { + public void testReparent() { final StackWindowController stackController = createStackControllerOnDisplay(mDisplayContent); final WindowTestUtils.TestTaskWindowContainerController taskController1 = diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java index e3ab5cf4fc52..4522494349a3 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -26,15 +26,14 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - import android.view.SurfaceControl; +import androidx.test.filters.SmallTest; + import com.android.server.wm.WindowTestUtils.TestAppWindowToken; +import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -43,10 +42,9 @@ import org.mockito.MockitoAnnotations; * Animation related tests for the {@link AppWindowToken} class. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.AppWindowTokenAnimationTests + * atest FrameworksServicesTests:AppWindowTokenAnimationTests */ @SmallTest -@RunWith(AndroidJUnit4.class) public class AppWindowTokenAnimationTests extends WindowTestsBase { private TestAppWindowToken mToken; @@ -56,9 +54,8 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { @Mock private AnimationAdapter mSpec; - @Override + @Before public void setUp() throws Exception { - super.setUp(); MockitoAnnotations.initMocks(this); mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, @@ -67,7 +64,7 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { } @Test - public void clipAfterAnim_boundsLayerIsCreated() throws Exception { + public void clipAfterAnim_boundsLayerIsCreated() { mToken.mNeedsAnimationBoundsLayer = true; mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); @@ -78,7 +75,7 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { } @Test - public void clipAfterAnim_boundsLayerIsDestroyed() throws Exception { + public void clipAfterAnim_boundsLayerIsDestroyed() { mToken.mNeedsAnimationBoundsLayer = true; mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); final SurfaceControl leash = mToken.mSurfaceAnimator.mLeash; @@ -95,7 +92,7 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { } @Test - public void clipAfterAnimCancelled_boundsLayerIsDestroyed() throws Exception { + public void clipAfterAnimCancelled_boundsLayerIsDestroyed() { mToken.mNeedsAnimationBoundsLayer = true; mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); final SurfaceControl leash = mToken.mSurfaceAnimator.mLeash; @@ -108,7 +105,7 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { } @Test - public void clipNoneAnim_boundsLayerIsNotCreated() throws Exception { + public void clipNoneAnim_boundsLayerIsNotCreated() { mToken.mNeedsAnimationBoundsLayer = false; mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java index 7935ec168142..552390d19419 100644 --- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -47,31 +47,27 @@ import android.view.WindowManager; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; +import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link AppWindowToken} class. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests + * atest FrameworksServicesTests:AppWindowTokenTests */ +@FlakyTest(bugId = 68267650) @SmallTest -// TODO: b/68267650 -// @Presubmit -@RunWith(AndroidJUnit4.class) +@Presubmit public class AppWindowTokenTests extends WindowTestsBase { TaskStack mStack; Task mTask; WindowTestUtils.TestAppWindowToken mToken; - @Override + @Before public void setUp() throws Exception { - super.setUp(); - mStack = createTaskStackOnDisplay(mDisplayContent); mTask = createTaskInStack(mStack, 0 /* userId */); mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent); @@ -81,7 +77,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test @Presubmit - public void testAddWindow_Order() throws Exception { + public void testAddWindow_Order() { assertEquals(0, mToken.getWindowsCount()); final WindowState win1 = createWindow(null, TYPE_APPLICATION, mToken, "win1"); @@ -107,7 +103,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test @Presubmit - public void testFindMainWindow() throws Exception { + public void testFindMainWindow() { assertNull(mToken.findMainWindow()); final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mToken, "window1"); @@ -123,7 +119,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test @Presubmit - public void testGetTopFullscreenWindow() throws Exception { + public void testGetTopFullscreenWindow() { assertNull(mToken.getTopFullscreenWindow()); final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mToken, "window1"); @@ -138,10 +134,10 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test - public void testLandscapeSeascapeRotationByApp() throws Exception { + public void testLandscapeSeascapeRotationByApp() { // Some plumbing to get the service ready for rotation updates. - sWm.mDisplayReady = true; - sWm.mDisplayEnabled = true; + mWm.mDisplayReady = true; + mWm.mDisplayEnabled = true; final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); @@ -151,26 +147,26 @@ public class AppWindowTokenTests extends WindowTestsBase { // Set initial orientation and update. mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); - sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null, + mWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null, mDisplayContent.getDisplayId()); assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation()); appWindow.resizeReported = false; // Update the orientation to perform 180 degree rotation and check that resize was reported. mToken.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE); - sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null, + mWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null, mDisplayContent.getDisplayId()); - sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); + mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation()); assertTrue(appWindow.resizeReported); appWindow.removeImmediately(); } @Test - public void testLandscapeSeascapeRotationByPolicy() throws Exception { + public void testLandscapeSeascapeRotationByPolicy() { // Some plumbing to get the service ready for rotation updates. - sWm.mDisplayReady = true; - sWm.mDisplayEnabled = true; + mWm.mDisplayReady = true; + mWm.mDisplayEnabled = true; final DisplayRotation spiedRotation = spy(mDisplayContent.getDisplayRotation()); mDisplayContent.setDisplayRotation(spiedRotation); @@ -194,15 +190,19 @@ public class AppWindowTokenTests extends WindowTestsBase { private void performRotation(DisplayRotation spiedRotation, int rotationToReport) { doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt()); - sWm.updateRotation(false, false); + int oldRotation = mDisplayContent.getRotation(); + mWm.updateRotation(false, false); + // Must manually apply here since ATM doesn't know about the display during this test + // (meaning it can't perform the normal sendNewConfiguration flow). + mDisplayContent.applyRotationLocked(oldRotation, mDisplayContent.getRotation()); // Prevent the next rotation from being deferred by animation. - sWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null); - sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); + mWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null); + mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); } @Test @Presubmit - public void testGetOrientation() throws Exception { + public void testGetOrientation() { mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); mToken.setFillsParent(false); @@ -220,7 +220,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test @Presubmit - public void testKeyguardFlagsDuringRelaunch() throws Exception { + public void testKeyguardFlagsDuringRelaunch() { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD; @@ -246,7 +246,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test @FlakyTest(detail = "Promote once confirmed non-flaky") - public void testStuckExitingWindow() throws Exception { + public void testStuckExitingWindow() { final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, "closingWindow"); closingWindow.mAnimatingExit = true; diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java index d65055cf0e07..1c5391ed3a6c 100644 --- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java @@ -11,12 +11,12 @@ * 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 + * limitations under the License. */ package com.android.server.wm; -import static android.view.Display.DEFAULT_DISPLAY; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS; import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END; @@ -24,11 +24,11 @@ import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_ import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import android.animation.ValueAnimator; import android.content.Context; @@ -37,16 +37,14 @@ import android.os.Handler; import android.os.Looper; import android.platform.test.annotations.Presubmit; -import androidx.test.InstrumentationRegistry; import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.wm.BoundsAnimationController.BoundsAnimator; import com.android.server.wm.WindowManagerInternal.AppTransitionListener; +import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Test class for {@link BoundsAnimationController} to ensure that it sends the right callbacks @@ -59,21 +57,20 @@ import org.junit.runner.RunWith; * appropriately. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.BoundsAnimationControllerTests + * atest FrameworksServicesTests:BoundsAnimationControllerTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class BoundsAnimationControllerTests extends WindowTestsBase { /** * Mock value animator to simulate updates with. */ - private class MockValueAnimator extends ValueAnimator { + private static class MockValueAnimator extends ValueAnimator { private float mFraction; - public MockValueAnimator getWithValue(float fraction) { + MockValueAnimator getWithValue(float fraction) { mFraction = fraction; return this; } @@ -87,12 +84,12 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { /** * Mock app transition to fire notifications to the bounds animator. */ - private class MockAppTransition extends AppTransition { + private static class MockAppTransition extends AppTransition { private AppTransitionListener mListener; - MockAppTransition(Context context) { - super(context, sWm, mDisplayContent); + MockAppTransition(Context context, WindowManagerService wm, DisplayContent displayContent) { + super(context, wm, displayContent); } @Override @@ -120,7 +117,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { /** * A test animate bounds user to track callbacks from the bounds animation. */ - private class TestBoundsAnimationTarget implements BoundsAnimationTarget { + private static class TestBoundsAnimationTarget implements BoundsAnimationTarget { boolean mAwaitingAnimationStart; boolean mMovedToFullscreen; @@ -193,21 +190,23 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { /** * Drives the animations, makes common assertions along the way. */ - private class BoundsAnimationDriver { + private static class BoundsAnimationDriver { - private BoundsAnimationController mController; - private TestBoundsAnimationTarget mTarget; - private BoundsAnimator mAnimator; + private final BoundsAnimationController mController; + private final TestBoundsAnimationTarget mTarget; + private final MockValueAnimator mMockAnimator; + private BoundsAnimator mAnimator; private Rect mFrom; private Rect mTo; private Rect mLargerBounds; private Rect mExpectedFinalBounds; BoundsAnimationDriver(BoundsAnimationController controller, - TestBoundsAnimationTarget target) { + TestBoundsAnimationTarget target, MockValueAnimator mockValueAnimator) { mController = controller; mTarget = target; + mMockAnimator = mockValueAnimator; } BoundsAnimationDriver start(Rect from, Rect to) { @@ -222,7 +221,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { // Started, not running assertTrue(mTarget.mAwaitingAnimationStart); - assertTrue(!mTarget.mAnimationStarted); + assertFalse(mTarget.mAnimationStarted); startImpl(from, to); @@ -236,7 +235,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { } // Started and running - assertTrue(!mTarget.mAwaitingAnimationStart); + assertFalse(mTarget.mAwaitingAnimationStart); assertTrue(mTarget.mAnimationStarted); return this; @@ -268,7 +267,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { assertTrue(mTarget.mForcePipModeChangedCallback); } else { // No animation start for replacing animation - assertTrue(!mTarget.mAnimationStarted); + assertFalse(mTarget.mAnimationStarted); } mTarget.mAnimationStarted = true; return this; @@ -297,7 +296,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { // Animating to larger size if (mFrom.equals(mLargerBounds)) { - assertTrue(!mAnimator.animatingToLargerSize()); + assertFalse(mAnimator.animatingToLargerSize()); } else if (mTo.equals(mLargerBounds)) { assertTrue(mAnimator.animatingToLargerSize()); } @@ -339,10 +338,10 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(0.5f)); // Not started, not running, cancel reset - assertTrue(!mTarget.mCancelRequested); + assertFalse(mTarget.mCancelRequested); // Stack/task bounds not updated - assertTrue(!mTarget.mBoundsUpdated); + assertFalse(mTarget.mBoundsUpdated); // Callback made assertTrue(mTarget.mAnimationEnded); @@ -372,14 +371,10 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { return this; } - private Rect getLargerBounds(Rect r1, Rect r2) { + private static Rect getLargerBounds(Rect r1, Rect r2) { int r1Area = r1.width() * r1.height(); int r2Area = r2.width() * r2.height(); - if (r1Area <= r2Area) { - return r2; - } else { - return r1; - } + return (r1Area <= r2Area) ? r2 : r1; } } @@ -395,32 +390,29 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { // Common private MockAppTransition mMockAppTransition; - private MockValueAnimator mMockAnimator; private TestBoundsAnimationTarget mTarget; private BoundsAnimationController mController; private BoundsAnimationDriver mDriver; // Temp - private Rect mTmpRect = new Rect(); + private static final Rect sTmpRect = new Rect(); - @Override + @Before public void setUp() throws Exception { - super.setUp(); - - final Context context = InstrumentationRegistry.getTargetContext(); + final Context context = getInstrumentation().getTargetContext(); final Handler handler = new Handler(Looper.getMainLooper()); - mMockAppTransition = new MockAppTransition(context); - mMockAnimator = new MockValueAnimator(); + mMockAppTransition = new MockAppTransition(context, mWm, mDisplayContent); mTarget = new TestBoundsAnimationTarget(); mController = new BoundsAnimationController(context, mMockAppTransition, handler, null); - mDriver = new BoundsAnimationDriver(mController, mTarget); + final MockValueAnimator mockValueAnimator = new MockValueAnimator(); + mDriver = new BoundsAnimationDriver(mController, mTarget, mockValueAnimator); } /** BASE TRANSITIONS **/ @UiThreadTest @Test - public void testFullscreenToFloatingTransition() throws Exception { + public void testFullscreenToFloatingTransition() { mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0f) @@ -432,7 +424,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFloatingToFullscreenTransition() throws Exception { + public void testFloatingToFullscreenTransition() { mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) .expectStarted(SCHEDULE_PIP_MODE_CHANGED) .update(0f) @@ -444,7 +436,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFloatingToSmallerFloatingTransition() throws Exception { + public void testFloatingToSmallerFloatingTransition() { mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0f) @@ -456,7 +448,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFloatingToLargerFloatingTransition() throws Exception { + public void testFloatingToLargerFloatingTransition() { mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0f) @@ -470,7 +462,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFullscreenToFloatingCancelFromTarget() throws Exception { + public void testFullscreenToFloatingCancelFromTarget() { mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) @@ -480,7 +472,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFullscreenToFloatingCancelFromAnimationToSameBounds() throws Exception { + public void testFullscreenToFloatingCancelFromAnimationToSameBounds() { mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) @@ -491,7 +483,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() throws Exception { + public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() { mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) @@ -503,7 +495,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() throws Exception { + public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() { // When animating from fullscreen and the animation is interruped, we expect the animation // start callback to be made, with a forced pip mode change callback mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING) @@ -518,7 +510,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFloatingToFullscreenCancelFromTarget() throws Exception { + public void testFloatingToFullscreenCancelFromTarget() { mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) .expectStarted(SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) @@ -528,7 +520,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFloatingToFullscreenCancelFromAnimationToSameBounds() throws Exception { + public void testFloatingToFullscreenCancelFromAnimationToSameBounds() { mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) .expectStarted(SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) @@ -539,7 +531,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() throws Exception { + public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() { mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL) .expectStarted(SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) @@ -553,7 +545,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFloatingToSmallerFloatingCancelFromTarget() throws Exception { + public void testFloatingToSmallerFloatingCancelFromTarget() { mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) @@ -563,7 +555,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testFloatingToLargerFloatingCancelFromTarget() throws Exception { + public void testFloatingToLargerFloatingCancelFromTarget() { mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING) .expectStarted(!SCHEDULE_PIP_MODE_CHANGED) .update(0.25f) @@ -575,7 +567,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { @UiThreadTest @Test - public void testBoundsAreCopied() throws Exception { + public void testBoundsAreCopied() { Rect from = new Rect(0, 0, 100, 100); Rect to = new Rect(25, 25, 75, 75); mDriver.start(from, to) @@ -588,9 +580,9 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { /** * @return whether the task and stack bounds would be the same if they were at the same offset. */ - private boolean assertEqualSizeAtOffset(Rect stackBounds, Rect taskBounds) { - mTmpRect.set(taskBounds); - mTmpRect.offsetTo(stackBounds.left, stackBounds.top); - return stackBounds.equals(mTmpRect); + private static boolean assertEqualSizeAtOffset(Rect stackBounds, Rect taskBounds) { + sTmpRect.set(taskBounds); + sTmpRect.offsetTo(stackBounds.left, stackBounds.top); + return stackBounds.equals(sTmpRect); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java index 21555e38a7e8..b6a7cfba7dc4 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -32,26 +32,22 @@ import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.SurfaceSession; -import androidx.test.runner.AndroidJUnit4; - import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.DimmerTests; + * atest FrameworksServicesTests:DimmerTests; */ @Presubmit -@RunWith(AndroidJUnit4.class) public class DimmerTests extends WindowTestsBase { - private class TestWindowContainer extends WindowContainer<TestWindowContainer> { + private static class TestWindowContainer extends WindowContainer<TestWindowContainer> { final SurfaceControl mControl = mock(SurfaceControl.class); final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class); - TestWindowContainer() { - super(sWm); + TestWindowContainer(WindowManagerService wm) { + super(wm); } @Override @@ -65,13 +61,13 @@ public class DimmerTests extends WindowTestsBase { } } - private class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> { + private static class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> { final SurfaceSession mSession = new SurfaceSession(); final SurfaceControl mHostControl = mock(SurfaceControl.class); final SurfaceControl.Transaction mHostTransaction = mock(SurfaceControl.Transaction.class); - MockSurfaceBuildingContainer() { - super(sWm); + MockSurfaceBuildingContainer(WindowManagerService wm) { + super(wm); } class MockSurfaceBuilder extends SurfaceControl.Builder { @@ -116,15 +112,14 @@ public class DimmerTests extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); - mHost = new MockSurfaceBuildingContainer(); + mHost = new MockSurfaceBuildingContainer(mWm); mSurfaceAnimatorStarter = spy(new SurfaceAnimatorStarterImpl()); mTransaction = mock(SurfaceControl.Transaction.class); mDimmer = new Dimmer(mHost, mSurfaceAnimatorStarter); } @Test - public void testDimAboveNoChildCreatesSurface() throws Exception { + public void testDimAboveNoChildCreatesSurface() { final float alpha = 0.8f; mDimmer.dimAbove(mTransaction, alpha); @@ -137,7 +132,7 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testDimAboveNoChildRedundantlyUpdatesAlphaOnExistingSurface() throws Exception { + public void testDimAboveNoChildRedundantlyUpdatesAlphaOnExistingSurface() { float alpha = 0.8f; mDimmer.dimAbove(mTransaction, alpha); final SurfaceControl firstSurface = getDimLayer(); @@ -150,7 +145,7 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testUpdateDimsAppliesSize() throws Exception { + public void testUpdateDimsAppliesSize() { mDimmer.dimAbove(mTransaction, 0.8f); int width = 100; @@ -163,7 +158,7 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testDimAboveNoChildNotReset() throws Exception { + public void testDimAboveNoChildNotReset() { mDimmer.dimAbove(mTransaction, 0.8f); SurfaceControl dimLayer = getDimLayer(); mDimmer.resetDimStates(); @@ -174,8 +169,8 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testDimAboveWithChildCreatesSurfaceAboveChild() throws Exception { - TestWindowContainer child = new TestWindowContainer(); + public void testDimAboveWithChildCreatesSurfaceAboveChild() { + TestWindowContainer child = new TestWindowContainer(mWm); mHost.addChild(child, 0); final float alpha = 0.8f; @@ -189,8 +184,8 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild() throws Exception { - TestWindowContainer child = new TestWindowContainer(); + public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild() { + TestWindowContainer child = new TestWindowContainer(mWm); mHost.addChild(child, 0); final float alpha = 0.8f; @@ -204,8 +199,8 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testDimBelowWithChildSurfaceDestroyedWhenReset() throws Exception { - TestWindowContainer child = new TestWindowContainer(); + public void testDimBelowWithChildSurfaceDestroyedWhenReset() { + TestWindowContainer child = new TestWindowContainer(mWm); mHost.addChild(child, 0); final float alpha = 0.8f; @@ -220,8 +215,8 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testDimBelowWithChildSurfaceNotDestroyedWhenPersisted() throws Exception { - TestWindowContainer child = new TestWindowContainer(); + public void testDimBelowWithChildSurfaceNotDestroyedWhenPersisted() { + TestWindowContainer child = new TestWindowContainer(mWm); mHost.addChild(child, 0); final float alpha = 0.8f; @@ -236,9 +231,9 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testDimUpdateWhileDimming() throws Exception { + public void testDimUpdateWhileDimming() { Rect bounds = new Rect(); - TestWindowContainer child = new TestWindowContainer(); + TestWindowContainer child = new TestWindowContainer(mWm); mHost.addChild(child, 0); final float alpha = 0.8f; @@ -258,8 +253,8 @@ public class DimmerTests extends WindowTestsBase { } @Test - public void testRemoveDimImmediately() throws Exception { - TestWindowContainer child = new TestWindowContainer(); + public void testRemoveDimImmediately() { + TestWindowContainer child = new TestWindowContainer(mWm); mHost.addChild(child, 0); mDimmer.dimAbove(mTransaction, child, 1); diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java index cb8ca7e4bfc6..f4da4b338cef 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -53,7 +53,6 @@ import android.graphics.Rect; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; -import android.util.SparseIntArray; import android.view.DisplayCutout; import android.view.Gravity; import android.view.MotionEvent; @@ -61,12 +60,10 @@ import android.view.Surface; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; @@ -78,16 +75,15 @@ import java.util.List; * Tests for the {@link DisplayContent} class. * * Build/Install/Run: - * atest com.android.server.wm.DisplayContentTests + * atest FrameworksServicesTests:DisplayContentTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class DisplayContentTests extends WindowTestsBase { @Test @FlakyTest(bugId = 77772044) - public void testForAllWindows() throws Exception { + public void testForAllWindows() { final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "exiting app"); final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken; @@ -108,11 +104,11 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - public void testForAllWindows_WithAppImeTarget() throws Exception { + public void testForAllWindows_WithAppImeTarget() { final WindowState imeAppTarget = createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget"); - sWm.mInputMethodTarget = imeAppTarget; + mWm.mInputMethodTarget = imeAppTarget; assertForAllWindowsOrder(Arrays.asList( mWallpaperWindow, @@ -128,8 +124,8 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - public void testForAllWindows_WithChildWindowImeTarget() throws Exception { - sWm.mInputMethodTarget = mChildAppWindowAbove; + public void testForAllWindows_WithChildWindowImeTarget() { + mWm.mInputMethodTarget = mChildAppWindowAbove; assertForAllWindowsOrder(Arrays.asList( mWallpaperWindow, @@ -144,8 +140,8 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - public void testForAllWindows_WithStatusBarImeTarget() throws Exception { - sWm.mInputMethodTarget = mStatusBarWindow; + public void testForAllWindows_WithStatusBarImeTarget() { + mWm.mInputMethodTarget = mStatusBarWindow; assertForAllWindowsOrder(Arrays.asList( mWallpaperWindow, @@ -160,7 +156,7 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - public void testForAllWindows_WithInBetweenWindowToken() throws Exception { + public void testForAllWindows_WithInBetweenWindowToken() { // This window is set-up to be z-ordered between some windows that go in the same token like // the nav bar and status bar. final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION, @@ -180,7 +176,7 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - public void testComputeImeTarget() throws Exception { + public void testComputeImeTarget() { // Verify that an app window can be an ime target. final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin"); appWin.setHasSurface(true); @@ -203,7 +199,7 @@ public class DisplayContentTests extends WindowTestsBase { * container references updates. */ @Test - public void testMoveStackBetweenDisplays() throws Exception { + public void testMoveStackBetweenDisplays() { // Create a second display. final DisplayContent dc = createNewDisplay(); @@ -233,8 +229,7 @@ public class DisplayContentTests extends WindowTestsBase { * This tests override configuration updates for display content. */ @Test - public void testDisplayOverrideConfigUpdate() throws Exception { - final int displayId = mDisplayContent.getDisplayId(); + public void testDisplayOverrideConfigUpdate() { final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration(); // Create new, slightly changed override configuration and apply it to the display. @@ -242,7 +237,7 @@ public class DisplayContentTests extends WindowTestsBase { newOverrideConfig.densityDpi += 120; newOverrideConfig.fontScale += 0.3; - sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId); + mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, mDisplayContent); // Check that override config is applied. assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration()); @@ -252,24 +247,25 @@ public class DisplayContentTests extends WindowTestsBase { * This tests global configuration updates when default display config is updated. */ @Test - public void testDefaultDisplayOverrideConfigUpdate() throws Exception { - final Configuration currentConfig = mDisplayContent.getConfiguration(); + public void testDefaultDisplayOverrideConfigUpdate() { + DisplayContent defaultDisplay = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY); + final Configuration currentConfig = defaultDisplay.getConfiguration(); // Create new, slightly changed override configuration and apply it to the display. final Configuration newOverrideConfig = new Configuration(currentConfig); newOverrideConfig.densityDpi += 120; newOverrideConfig.fontScale += 0.3; - sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY); + mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, defaultDisplay); // Check that global configuration is updated, as we've updated default display's config. - Configuration globalConfig = sWm.mRoot.getConfiguration(); + Configuration globalConfig = mWm.mRoot.getConfiguration(); assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi); assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */); // Return back to original values. - sWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY); - globalConfig = sWm.mRoot.getConfiguration(); + mWm.setNewDisplayOverrideConfiguration(currentConfig, defaultDisplay); + globalConfig = mWm.mRoot.getConfiguration(); assertEquals(currentConfig.densityDpi, globalConfig.densityDpi); assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */); } @@ -278,8 +274,8 @@ public class DisplayContentTests extends WindowTestsBase { * Tests tapping on a stack in different display results in window gaining focus. */ @Test - public void testInputEventBringsCorrectDisplayInFocus() throws Exception { - DisplayContent dc0 = sWm.getDefaultDisplayContentLocked(); + public void testInputEventBringsCorrectDisplayInFocus() { + DisplayContent dc0 = mWm.getDefaultDisplayContentLocked(); // Create a second display final DisplayContent dc1 = createNewDisplay(); @@ -303,51 +299,51 @@ public class DisplayContentTests extends WindowTestsBase { // tap on primary display. tapOnDisplay(dc0); // Check focus is on primary display. - assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus, + assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus, dc0.findFocusedWindow()); // Tap on secondary display. tapOnDisplay(dc1); // Check focus is on secondary. - assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus, + assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus, dc1.findFocusedWindow()); } @Test - public void testFocusedWindowMultipleDisplays() throws Exception { + public void testFocusedWindowMultipleDisplays() { // Create a focusable window and check that focus is calculated correctly final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1"); updateFocusedWindow(); assertTrue(window1.isFocused()); - assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); + assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); // Check that a new display doesn't affect focus final DisplayContent dc = createNewDisplay(); updateFocusedWindow(); assertTrue(window1.isFocused()); - assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); + assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); // Add a window to the second display, and it should be focused final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2"); updateFocusedWindow(); assertTrue(window1.isFocused()); assertTrue(window2.isFocused()); - assertEquals(window2, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); + assertEquals(window2, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); // Move the first window to the to including parents, and make sure focus is updated window1.getParent().positionChildAt(POSITION_TOP, window1, true); updateFocusedWindow(); assertTrue(window1.isFocused()); assertTrue(window2.isFocused()); - assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); + assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus); } /** * This tests setting the maximum ui width on a display. */ @Test - public void testMaxUiWidth() throws Exception { + public void testMaxUiWidth() { // Prevent base display metrics for test from being updated to the value of real display. final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo(); final int baseWidth = 1440; @@ -439,8 +435,8 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - public void testDisplayCutout_rot0() throws Exception { - synchronized (sWm.getWindowManagerLock()) { + public void testDisplayCutout_rot0() { + synchronized (mWm.getWindowManagerLock()) { final DisplayContent dc = createNewDisplay(); dc.mInitialDisplayWidth = 200; dc.mInitialDisplayHeight = 400; @@ -458,8 +454,8 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - public void testDisplayCutout_rot90() throws Exception { - synchronized (sWm.getWindowManagerLock()) { + public void testDisplayCutout_rot90() { + synchronized (mWm.getWindowManagerLock()) { // Prevent mInitialDisplayCutout from being updated from real display (e.g. null // if the device has no cutout). final DisplayContent dc = createDisplayNoUpdateDisplayInfo(); @@ -476,7 +472,8 @@ public class DisplayContentTests extends WindowTestsBase { final Rect r1 = new Rect(left, top, right, bottom); final DisplayCutout cutout = new WmDisplayCutout( - fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), null) + fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), + null) .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout(); dc.mInitialDisplayCutout = cutout; @@ -500,8 +497,8 @@ public class DisplayContentTests extends WindowTestsBase { } @Test - public void testLayoutSeq_assignedDuringLayout() throws Exception { - synchronized (sWm.getWindowManagerLock()) { + public void testLayoutSeq_assignedDuringLayout() { + synchronized (mWm.getWindowManagerLock()) { final DisplayContent dc = createNewDisplay(); final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w"); @@ -533,7 +530,7 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals("Visible keyguard must influence device orientation", SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation()); - sWm.setKeyguardGoingAway(true); + mWm.setKeyguardGoingAway(true); assertEquals("Keyguard that is going away must not influence device orientation", SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation()); } @@ -543,10 +540,10 @@ public class DisplayContentTests extends WindowTestsBase { final DisplayContent dc = createNewDisplay(); assertTrue(dc.mShouldOverrideDisplayConfiguration); - sWm.dontOverrideDisplayInfo(dc.getDisplayId()); + mWm.dontOverrideDisplayInfo(dc.getDisplayId()); assertFalse(dc.mShouldOverrideDisplayConfiguration); - verify(sWm.mDisplayManagerInternal, times(1)) + verify(mWm.mDisplayManagerInternal, times(1)) .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null); } @@ -572,7 +569,7 @@ public class DisplayContentTests extends WindowTestsBase { } private boolean isOptionsPanelAtRight(int displayId) { - return (sWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT; + return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT; } private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth, @@ -583,8 +580,8 @@ public class DisplayContentTests extends WindowTestsBase { } private void updateFocusedWindow() { - synchronized (sWm.mWindowMap) { - sWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false); + synchronized (mWm.mGlobalLock) { + mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java index 3be125815d21..f0c49c8ab0b3 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java @@ -12,11 +12,12 @@ * 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.server.wm; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -31,15 +32,13 @@ import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.policy.WindowManagerPolicy; +import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.io.File; @@ -47,14 +46,13 @@ import java.io.File; * Tests for the {@link DisplaySettings} class. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.DisplaySettingsTests + * atest FrameworksServicesTests:DisplaySettingsTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class DisplaySettingsTests extends WindowTestsBase { - private File mTestFolder; + private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir(); private DisplaySettings mTarget; private DisplayContent mPrimaryDisplay; @@ -62,21 +60,23 @@ public class DisplaySettingsTests extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); - - mTestFolder = InstrumentationRegistry.getContext().getCacheDir(); - deleteRecursively(mTestFolder); + deleteRecursively(TEST_FOLDER); - sWm.setSupportsFreeformWindowManagement(false); - sWm.setIsPc(false); + mWm.setSupportsFreeformWindowManagement(false); + mWm.setIsPc(false); - mTarget = new DisplaySettings(sWm, mTestFolder); + mTarget = new DisplaySettings(mWm, TEST_FOLDER); - mPrimaryDisplay = sWm.getDefaultDisplayContentLocked(); + mPrimaryDisplay = mWm.getDefaultDisplayContentLocked(); mSecondaryDisplay = mDisplayContent; assertNotEquals(Display.DEFAULT_DISPLAY, mSecondaryDisplay.getDisplayId()); } + @After + public void tearDown() { + deleteRecursively(TEST_FOLDER); + } + @Test public void testPrimaryDisplayDefaultToFullscreenWithoutFreeformSupport() { mTarget.applySettingsToDisplayLocked(mPrimaryDisplay); @@ -87,7 +87,7 @@ public class DisplaySettingsTests extends WindowTestsBase { @Test public void testPrimaryDisplayDefaultToFullscreenWithFreeformSupportNonPc() { - sWm.setSupportsFreeformWindowManagement(true); + mWm.setSupportsFreeformWindowManagement(true); mTarget.applySettingsToDisplayLocked(mPrimaryDisplay); @@ -97,8 +97,8 @@ public class DisplaySettingsTests extends WindowTestsBase { @Test public void testPrimaryDisplayDefaultToFreeformWithFreeformIsPc() { - sWm.setSupportsFreeformWindowManagement(true); - sWm.setIsPc(true); + mWm.setSupportsFreeformWindowManagement(true); + mWm.setIsPc(true); mTarget.applySettingsToDisplayLocked(mPrimaryDisplay); @@ -116,7 +116,7 @@ public class DisplaySettingsTests extends WindowTestsBase { @Test public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportNonPc() { - sWm.setSupportsFreeformWindowManagement(true); + mWm.setSupportsFreeformWindowManagement(true); mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); @@ -126,8 +126,8 @@ public class DisplaySettingsTests extends WindowTestsBase { @Test public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportIsPc() { - sWm.setSupportsFreeformWindowManagement(true); - sWm.setIsPc(true); + mWm.setSupportsFreeformWindowManagement(true); + mWm.setIsPc(true); mTarget.applySettingsToDisplayLocked(mSecondaryDisplay); @@ -157,7 +157,7 @@ public class DisplaySettingsTests extends WindowTestsBase { doAnswer(invocation -> { ((DisplayInfo) invocation.getArguments()[1]).copyFrom(originalInfo); return null; - }).when(sWm.mDisplayManagerInternal).getNonOverrideDisplayInfo(anyInt(), any()); + }).when(mWm.mDisplayManagerInternal).getNonOverrideDisplayInfo(anyInt(), any()); mTarget.setForcedSize(mSecondaryDisplay, 1000 /* width */, 2000 /* height */); applySettingsToDisplayByNewInstance(mSecondaryDisplay); @@ -165,7 +165,7 @@ public class DisplaySettingsTests extends WindowTestsBase { assertEquals(1000 /* width */, mSecondaryDisplay.mBaseDisplayWidth); assertEquals(2000 /* height */, mSecondaryDisplay.mBaseDisplayHeight); - sWm.clearForcedDisplaySize(mSecondaryDisplay.getDisplayId()); + mWm.clearForcedDisplaySize(mSecondaryDisplay.getDisplayId()); assertEquals(mSecondaryDisplay.mInitialDisplayWidth, mSecondaryDisplay.mBaseDisplayWidth); assertEquals(mSecondaryDisplay.mInitialDisplayHeight, mSecondaryDisplay.mBaseDisplayHeight); } @@ -177,7 +177,7 @@ public class DisplaySettingsTests extends WindowTestsBase { assertEquals(600 /* density */, mSecondaryDisplay.mBaseDisplayDensity); - sWm.clearForcedDisplayDensityForUser(mSecondaryDisplay.getDisplayId(), 0 /* userId */); + mWm.clearForcedDisplayDensityForUser(mSecondaryDisplay.getDisplayId(), 0 /* userId */); assertEquals(mSecondaryDisplay.mInitialDisplayDensity, mSecondaryDisplay.mBaseDisplayDensity); } @@ -189,7 +189,7 @@ public class DisplaySettingsTests extends WindowTestsBase { assertTrue(mSecondaryDisplay.mDisplayScalingDisabled); - sWm.setForcedDisplayScalingMode(mSecondaryDisplay.getDisplayId(), + mWm.setForcedDisplayScalingMode(mSecondaryDisplay.getDisplayId(), DisplayContent.FORCE_SCALING_MODE_AUTO); assertFalse(mSecondaryDisplay.mDisplayScalingDisabled); } @@ -298,20 +298,20 @@ public class DisplaySettingsTests extends WindowTestsBase { * that also means the previous state must be written correctly. */ private void applySettingsToDisplayByNewInstance(DisplayContent display) { - new DisplaySettings(sWm, mTestFolder).applySettingsToDisplayLocked(display); + new DisplaySettings(mWm, TEST_FOLDER).applySettingsToDisplayLocked(display); } private static boolean deleteRecursively(File file) { + boolean fullyDeleted = true; if (file.isFile()) { return file.delete(); + } else if (file.isDirectory()) { + final File[] files = file.listFiles(); + for (File child : files) { + fullyDeleted &= deleteRecursively(child); + } + fullyDeleted &= file.delete(); } - - boolean fullyDeleted = true; - final File[] files = file.listFiles(); - for (File child : files) { - fullyDeleted &= deleteRecursively(child); - } - fullyDeleted &= file.delete(); return fullyDeleted; } } diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java index 3c8b2a036c9b..55e766da09fc 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -40,23 +40,24 @@ import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; -import com.android.internal.annotations.GuardedBy; +import androidx.test.filters.SmallTest; + import com.android.server.LocalServices; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import androidx.test.filters.SmallTest; - /** * Tests for the {@link DragDropController} class. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.DragDropControllerTests + * atest FrameworksServicesTests:DragDropControllerTests */ @SmallTest @Presubmit @@ -67,7 +68,6 @@ public class DragDropControllerTests extends WindowTestsBase { private IBinder mToken; static class TestDragDropController extends DragDropController { - @GuardedBy("sWm.mWindowMap") private Runnable mCloseCallback; TestDragDropController(WindowManagerService service, Looper looper) { @@ -107,31 +107,34 @@ public class DragDropControllerTests extends WindowTestsBase { return window; } - @Override - @Before - public void setUp() throws Exception { + @BeforeClass + public static void setUpOnce() { final UserManagerInternal userManager = mock(UserManagerInternal.class); LocalServices.addService(UserManagerInternal.class, userManager); + } - super.setUp(); + @AfterClass + public static void tearDownOnce() { + LocalServices.removeServiceForTest(UserManagerInternal.class); + } - mTarget = new TestDragDropController(sWm, sWm.mH.getLooper()); + @Before + public void setUp() throws Exception { + mTarget = new TestDragDropController(mWm, mWm.mH.getLooper()); mDisplayContent = spy(mDisplayContent); mWindow = createDropTargetWindow("Drag test window", 0); doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0); - when(sWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true); + when(mWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true); - synchronized (sWm.mWindowMap) { - sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); + synchronized (mWm.mGlobalLock) { + mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); } } - @Override @After public void tearDown() throws Exception { - LocalServices.removeServiceForTest(UserManagerInternal.class); final CountDownLatch latch; - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { if (!mTarget.dragDropActiveLocked()) { return; } @@ -142,8 +145,6 @@ public class DragDropControllerTests extends WindowTestsBase { mTarget.setOnClosedCallbackLocked(latch::countDown); } assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - super.tearDown(); } @Test @@ -174,7 +175,7 @@ public class DragDropControllerTests extends WindowTestsBase { .setFormat(PixelFormat.TRANSLUCENT) .build(); - assertTrue(sWm.mInputManager.transferTouchFocus(null, null)); + assertTrue(mWm.mInputManager.transferTouchFocus(null, null)); mToken = mTarget.performDrag( new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0, data); diff --git a/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java index 7222a999e23c..1fae317f3af8 100644 --- a/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.server.wm; import static android.view.Display.DEFAULT_DISPLAY; @@ -16,17 +32,18 @@ import android.platform.test.annotations.Presubmit; import android.view.IPinnedStackListener; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +/** + * Build/Install/Run: + * atest FrameworksServicesTests:PinnedStackControllerTest + */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class PinnedStackControllerTest extends WindowTestsBase { @Mock private IPinnedStackListener mIPinnedStackListener; @@ -34,15 +51,15 @@ public class PinnedStackControllerTest extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); MockitoAnnotations.initMocks(this); + when(mIPinnedStackListener.asBinder()).thenReturn(mIPinnedStackListenerStub); } @Test public void setShelfHeight_shelfVisibilityChangedTriggered() throws RemoteException { - sWm.mSupportsPictureInPicture = true; - sWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener); + mWm.mSupportsPictureInPicture = true; + mWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener); verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0); verify(mIPinnedStackListener).onShelfVisibilityChanged(false, 0); @@ -55,7 +72,7 @@ public class PinnedStackControllerTest extends WindowTestsBase { final int SHELF_HEIGHT = 300; - sWm.setShelfHeight(true, SHELF_HEIGHT); + mWm.setShelfHeight(true, SHELF_HEIGHT); verify(mIPinnedStackListener).onShelfVisibilityChanged(true, SHELF_HEIGHT); verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false), eq(true), anyInt()); diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 088e22972cc9..fe5fc068a36b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -24,9 +24,9 @@ import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; -import static org.junit.Assert.fail; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.verify; @@ -42,22 +42,20 @@ import android.view.SurfaceControl; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * atest FrameworksServicesTests:com.android.server.wm.RecentsAnimationControllerTest + * Build/Install/Run: + * atest FrameworksServicesTests:RecentsAnimationControllerTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class RecentsAnimationControllerTest extends WindowTestsBase { @Mock SurfaceControl mMockLeash; @@ -69,10 +67,10 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); MockitoAnnotations.initMocks(this); + when(mMockRunner.asBinder()).thenReturn(new Binder()); - mController = new RecentsAnimationController(sWm, mMockRunner, mAnimationCallbacks, + mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks, DEFAULT_DISPLAY); } @@ -96,7 +94,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { } @Test - public void testCancelAfterRemove_expectIgnored() throws Exception { + public void testCancelAfterRemove_expectIgnored() { final AppWindowToken appWindow = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); AnimationAdapter adapter = mController.addAnimation(appWindow.getTask(), @@ -114,10 +112,10 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { } } - @Test @FlakyTest(bugId = 117117823) - public void testIncludedApps_expectTargetAndVisible() throws Exception { - sWm.setRecentsAnimationController(mController); + @Test + public void testIncludedApps_expectTargetAndVisible() { + mWm.setRecentsAnimationController(mController); final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); final AppWindowToken appWindow = createAppWindowToken(mDisplayContent, diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java index ae92984ebf65..fa5379576e8b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -39,7 +39,6 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.testutils.OffsettableClock; import com.android.server.testutils.TestHandler; @@ -47,17 +46,16 @@ import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * atest FrameworksServicesTests:com.android.server.wm.RemoteAnimationControllerTest + * Build/Install/Run: + * atest FrameworksServicesTests:RemoteAnimationControllerTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class RemoteAnimationControllerTest extends WindowTestsBase { @Mock SurfaceControl mMockLeash; @@ -71,15 +69,13 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); MockitoAnnotations.initMocks(this); + when(mMockRunner.asBinder()).thenReturn(new Binder()); mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50); mAdapter.setCallingPid(123); - sWm.mH.runWithScissors(() -> { - mHandler = new TestHandler(null, mClock); - }, 0); - mController = new RemoteAnimationController(sWm, mAdapter, mHandler); + mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0); + mController = new RemoteAnimationController(mWm, mAdapter, mHandler); } @Test @@ -91,7 +87,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { new Point(50, 100), new Rect(50, 100, 150, 150)); adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); mController.goodToGo(); - sWm.mAnimator.executeAfterPrepareSurfacesRunnables(); + mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor = ArgumentCaptor.forClass(RemoteAnimationTarget[].class); final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor = @@ -146,7 +142,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { @Test public void testTimeout_scaled() throws Exception { - sWm.setAnimationScale(2, 5.0f); + mWm.setAnimationScale(2, 5.0f); try{ final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken, @@ -165,19 +161,19 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { verify(mMockRunner).onAnimationCancelled(); verify(mFinishedCallback).onAnimationFinished(eq(adapter)); } finally { - sWm.setAnimationScale(2, 1.0f); + mWm.setAnimationScale(2, 1.0f); } } @Test - public void testZeroAnimations() throws Exception { + public void testZeroAnimations() { mController.goodToGo(); verifyNoMoreInteractionsExceptAsBinder(mMockRunner); } @Test - public void testNotReallyStarted() throws Exception { + public void testNotReallyStarted() { final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); mController.createAnimationAdapter(win.mAppToken, new Point(50, 100), new Rect(50, 100, 150, 150)); @@ -195,7 +191,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { new Point(50, 100), new Rect(50, 100, 150, 150)); adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback); mController.goodToGo(); - sWm.mAnimator.executeAfterPrepareSurfacesRunnables(); + mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor = ArgumentCaptor.forClass(RemoteAnimationTarget[].class); final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor = @@ -206,7 +202,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { } @Test - public void testRemovedBeforeStarted() throws Exception { + public void testRemovedBeforeStarted() { final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken, new Point(50, 100), new Rect(50, 100, 150, 150)); diff --git a/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java deleted file mode 100644 index c1db6a6a4def..000000000000 --- a/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.android.server.wm; - -import static org.junit.Assert.assertTrue; - -import android.content.res.Configuration; -import android.graphics.Rect; -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Tests for the {@link RootWindowContainer} class. - * - * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.RootWindowContainerTests - */ -@SmallTest -@Presubmit -@RunWith(AndroidJUnit4.class) -public class RootWindowContainerTests extends WindowTestsBase { - @Test - public void testSetDisplayOverrideConfigurationIfNeeded() throws Exception { - synchronized (sWm.mWindowMap) { - // Add first stack we expect to be updated with configuration change. - final TaskStack stack = createTaskStackOnDisplay(mDisplayContent); - stack.getOverrideConfiguration().windowConfiguration.setBounds(new Rect(0, 0, 5, 5)); - - // Add second task that will be set for deferred removal that should not be returned - // with the configuration change. - final TaskStack deferredDeletedStack = createTaskStackOnDisplay(mDisplayContent); - deferredDeletedStack.getOverrideConfiguration().windowConfiguration.setBounds( - new Rect(0, 0, 5, 5)); - deferredDeletedStack.mDeferRemoval = true; - - final Configuration override = new Configuration( - mDisplayContent.getOverrideConfiguration()); - override.windowConfiguration.setBounds(new Rect(0, 0, 10, 10)); - - // Set display override. - final int[] results = sWm.mRoot.setDisplayOverrideConfigurationIfNeeded(override, - mDisplayContent.getDisplayId()); - - // Ensure only first stack is returned. - assertTrue(results.length == 1); - assertTrue(results[0] == stack.mStackId); - } - } -} diff --git a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java index 9f2645cc98ae..ce5b13cab1a7 100644 --- a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -25,10 +25,8 @@ import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; /** * Test class for {@link StackWindowController}. @@ -38,10 +36,9 @@ import org.junit.runner.RunWith; */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class StackWindowControllerTests extends WindowTestsBase { @Test - public void testRemoveContainer() throws Exception { + public void testRemoveContainer() { final StackWindowController stackController = createStackControllerOnDisplay(mDisplayContent); final WindowTestUtils.TestTaskWindowContainerController taskController = @@ -61,7 +58,7 @@ public class StackWindowControllerTests extends WindowTestsBase { } @Test - public void testRemoveContainer_deferRemoval() throws Exception { + public void testRemoveContainer_deferRemoval() { final StackWindowController stackController = createStackControllerOnDisplay(mDisplayContent); final WindowTestUtils.TestTaskWindowContainerController taskController = @@ -87,7 +84,7 @@ public class StackWindowControllerTests extends WindowTestsBase { } @Test - public void testReparent() throws Exception { + public void testReparent() { // Create first stack on primary display. final StackWindowController stack1Controller = createStackControllerOnDisplay(mDisplayContent); diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java index 4551c3611102..584f2695891b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -27,6 +27,8 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static java.util.concurrent.TimeUnit.SECONDS; + import android.animation.AnimationHandler.AnimationFrameCallbackProvider; import android.animation.ValueAnimator; import android.graphics.Matrix; @@ -42,30 +44,27 @@ import android.view.animation.TranslateAnimation; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import static java.util.concurrent.TimeUnit.SECONDS; - import java.util.concurrent.CountDownLatch; /** * Test class for {@link SurfaceAnimationRunner}. * - * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimationRunnerTest + * Build/Install/Run: + * atest FrameworksServicesTests:SurfaceAnimationRunnerTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class SurfaceAnimationRunnerTest extends WindowTestsBase { @Mock SurfaceControl mMockSurface; @@ -79,7 +78,8 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); + MockitoAnnotations.initMocks(this); + mFinishCallbackLatch = new CountDownLatch(1); mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */, null, mMockTransaction, mMockPowerManager); @@ -112,7 +112,7 @@ public class SurfaceAnimationRunnerTest extends WindowTestsBase { } @Test - public void testCancel_notStarted() throws Exception { + public void testCancel_notStarted() { mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null, mMockTransaction, mMockPowerManager); mSurfaceAnimationRunner diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java index 7b5e8deeeb65..6833dc5f0497 100644 --- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -35,14 +35,13 @@ import android.view.SurfaceSession; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.wm.SurfaceAnimator.Animatable; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; +import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -50,11 +49,11 @@ import org.mockito.MockitoAnnotations; /** * Test class for {@link SurfaceAnimatorTest}. * - * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimatorTest + * Build/Install/Run: + * atest FrameworksServicesTests:SurfaceAnimatorTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class SurfaceAnimatorTest extends WindowTestsBase { @Mock AnimationAdapter mSpec; @@ -68,15 +67,24 @@ public class SurfaceAnimatorTest extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); MockitoAnnotations.initMocks(this); - mAnimatable = new MyAnimatable(); - mAnimatable2 = new MyAnimatable(); - mDeferFinishAnimatable = new DeferFinishAnimatable(); + + mAnimatable = new MyAnimatable(mWm, mSession, mTransaction); + mAnimatable2 = new MyAnimatable(mWm, mSession, mTransaction); + mDeferFinishAnimatable = new DeferFinishAnimatable(mWm, mSession, mTransaction); + } + + @After + public void tearDown() { + mAnimatable = null; + mAnimatable2 = null; + mDeferFinishAnimatable = null; + mSession.kill(); + mSession = null; } @Test - public void testRunAnimation() throws Exception { + public void testRunAnimation() { mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass( OnAnimationFinishedCallback.class); @@ -92,7 +100,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { } @Test - public void testOverrideAnimation() throws Exception { + public void testOverrideAnimation() { mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); final SurfaceControl firstLeash = mAnimatable.mLeash; mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */); @@ -117,7 +125,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { } @Test - public void testCancelAnimation() throws Exception { + public void testCancelAnimation() { mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); assertAnimating(mAnimatable); mAnimatable.mSurfaceAnimator.cancelAnimation(); @@ -128,7 +136,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { } @Test - public void testDelayingAnimationStart() throws Exception { + public void testDelayingAnimationStart() { mAnimatable.mSurfaceAnimator.startDelayingAnimationStart(); mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); verifyZeroInteractions(mSpec); @@ -139,7 +147,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { } @Test - public void testDelayingAnimationStartAndCancelled() throws Exception { + public void testDelayingAnimationStartAndCancelled() { mAnimatable.mSurfaceAnimator.startDelayingAnimationStart(); mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); mAnimatable.mSurfaceAnimator.cancelAnimation(); @@ -150,7 +158,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { } @Test - public void testTransferAnimation() throws Exception { + public void testTransferAnimation() { mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */); final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass( @@ -171,7 +179,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { @Test @FlakyTest(detail = "Promote once confirmed non-flaky") - public void testDeferFinish() throws Exception { + public void testDeferFinish() { // Start animation mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, @@ -186,7 +194,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { assertAnimating(mDeferFinishAnimatable); // Now end defer finishing. - mDeferFinishAnimatable.endDeferFinishCallback.run(); + mDeferFinishAnimatable.mEndDeferFinishCallback.run(); assertNotAnimating(mAnimatable2); assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled); verify(mTransaction).destroy(eq(mDeferFinishAnimatable.mLeash)); @@ -202,26 +210,30 @@ public class SurfaceAnimatorTest extends WindowTestsBase { assertNull(animatable.mSurfaceAnimator.getAnimation()); } - private class MyAnimatable implements Animatable { + private static class MyAnimatable implements Animatable { + private final SurfaceSession mSession; + private final Transaction mTransaction; final SurfaceControl mParent; final SurfaceControl mSurface; final SurfaceAnimator mSurfaceAnimator; SurfaceControl mLeash; boolean mFinishedCallbackCalled; - MyAnimatable() { - mParent = sWm.makeSurfaceBuilder(mSession) + MyAnimatable(WindowManagerService wm, SurfaceSession session, Transaction transaction) { + mSession = session; + mTransaction = transaction; + mParent = wm.makeSurfaceBuilder(mSession) .setName("test surface parent") .setSize(3000, 3000) .build(); - mSurface = sWm.makeSurfaceBuilder(mSession) + mSurface = wm.makeSurfaceBuilder(mSession) .setName("test surface") .setSize(1, 1) .build(); mFinishedCallbackCalled = false; mLeash = null; - mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm); + mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, wm); } @Override @@ -281,13 +293,18 @@ public class SurfaceAnimatorTest extends WindowTestsBase { private final Runnable mFinishedCallback = () -> mFinishedCallbackCalled = true; } - private class DeferFinishAnimatable extends MyAnimatable { + private static class DeferFinishAnimatable extends MyAnimatable { - Runnable endDeferFinishCallback; + Runnable mEndDeferFinishCallback; + + DeferFinishAnimatable(WindowManagerService wm, SurfaceSession session, + Transaction transaction) { + super(wm, session, transaction); + } @Override public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { - this.endDeferFinishCallback = endDeferFinishCallback; + mEndDeferFinishCallback = endDeferFinishCallback; return true; } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java index 17b7fc1fd0f0..785b955863db 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -35,24 +35,22 @@ import android.util.Log; import android.view.Display; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mockito; /** * Tests for the {@link TaskPositioner} class. * - * runtest frameworks-services -c com.android.server.wm.TaskPositionerTests + * Build/Install/Run: + * atest FrameworksServicesTests:TaskPositionerTests */ @SmallTest -@RunWith(AndroidJUnit4.class) public class TaskPositionerTests extends WindowTestsBase { - private final boolean DEBUGGING = false; - private final String TAG = "TaskPositionerTest"; + private static final boolean DEBUGGING = false; + private static final String TAG = "TaskPositionerTest"; private final static int MOUSE_DELTA_X = 5; private final static int MOUSE_DELTA_Y = 5; @@ -65,8 +63,6 @@ public class TaskPositionerTests extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); - TaskPositioner.setFactory(null); final Display display = mDisplayContent.getDisplay(); @@ -77,7 +73,7 @@ public class TaskPositionerTests extends WindowTestsBase { mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm); - mPositioner = new TaskPositioner(sWm, Mockito.mock(IActivityTaskManager.class)); + mPositioner = new TaskPositioner(mWm, Mockito.mock(IActivityTaskManager.class)); mPositioner.register(mDisplayContent); mWindow = Mockito.spy(createWindow(null, TYPE_BASE_APPLICATION, "window")); @@ -94,7 +90,7 @@ public class TaskPositionerTests extends WindowTestsBase { } @Test - public void testOverrideFactory() throws Exception { + public void testOverrideFactory() { final boolean[] created = new boolean[1]; created[0] = false; TaskPositioner.setFactory(new TaskPositioner.Factory() { @@ -105,7 +101,7 @@ public class TaskPositionerTests extends WindowTestsBase { } }); - assertNull(TaskPositioner.create(sWm)); + assertNull(TaskPositioner.create(mWm)); assertTrue(created[0]); } @@ -114,7 +110,7 @@ public class TaskPositionerTests extends WindowTestsBase { * as does some basic tests (e.g. dragging in Y only will keep X stable). */ @Test - public void testBasicFreeWindowResizing() throws Exception { + public void testBasicFreeWindowResizing() { final Rect r = new Rect(100, 220, 700, 520); final int midY = (r.top + r.bottom) / 2; mDimBounds.set(r); @@ -175,7 +171,7 @@ public class TaskPositionerTests extends WindowTestsBase { * This tests that by dragging any edge, the fixed / opposite edge(s) remains anchored. */ @Test - public void testFreeWindowResizingTestAllEdges() throws Exception { + public void testFreeWindowResizingTestAllEdges() { final Rect r = new Rect(100, 220, 700, 520); final int midX = (r.left + r.right) / 2; final int midY = (r.top + r.bottom) / 2; @@ -260,7 +256,7 @@ public class TaskPositionerTests extends WindowTestsBase { * right things upon resizing when dragged from the top left corner. */ @Test - public void testLandscapePreservedWindowResizingDragTopLeft() throws Exception { + public void testLandscapePreservedWindowResizingDragTopLeft() { final Rect r = new Rect(100, 220, 700, 520); mDimBounds.set(r); @@ -298,7 +294,7 @@ public class TaskPositionerTests extends WindowTestsBase { * right things upon resizing when dragged from the left corner. */ @Test - public void testLandscapePreservedWindowResizingDragLeft() throws Exception { + public void testLandscapePreservedWindowResizingDragLeft() { final Rect r = new Rect(100, 220, 700, 520); final int midY = (r.top + r.bottom) / 2; mDimBounds.set(r); @@ -339,7 +335,7 @@ public class TaskPositionerTests extends WindowTestsBase { * right things upon resizing when dragged from the top corner. */ @Test - public void testLandscapePreservedWindowResizingDragTop() throws Exception { + public void testLandscapePreservedWindowResizingDragTop() { final Rect r = new Rect(100, 220, 700, 520); final int midX = (r.left + r.right) / 2; mDimBounds.set(r); @@ -376,7 +372,7 @@ public class TaskPositionerTests extends WindowTestsBase { * right things upon resizing when dragged from the top left corner. */ @Test - public void testPortraitPreservedWindowResizingDragTopLeft() throws Exception { + public void testPortraitPreservedWindowResizingDragTopLeft() { final Rect r = new Rect(330, 100, 630, 600); mDimBounds.set(r); @@ -409,7 +405,7 @@ public class TaskPositionerTests extends WindowTestsBase { * right things upon resizing when dragged from the left corner. */ @Test - public void testPortraitPreservedWindowResizingDragLeft() throws Exception { + public void testPortraitPreservedWindowResizingDragLeft() { final Rect r = new Rect(330, 100, 630, 600); final int midY = (r.top + r.bottom) / 2; mDimBounds.set(r); @@ -452,7 +448,7 @@ public class TaskPositionerTests extends WindowTestsBase { * right things upon resizing when dragged from the top corner. */ @Test - public void testPortraitPreservedWindowResizingDragTop() throws Exception { + public void testPortraitPreservedWindowResizingDragTop() { final Rect r = new Rect(330, 100, 630, 600); final int midX = (r.left + r.right) / 2; mDimBounds.set(r); @@ -485,7 +481,7 @@ public class TaskPositionerTests extends WindowTestsBase { mPositioner.getWindowDragBounds()); } - private void assertBoundsEquals(Rect expected, Rect actual) { + private static void assertBoundsEquals(Rect expected, Rect actual) { if (DEBUGGING) { if (!expected.equals(actual)) { Log.e(TAG, "rect(" + actual.toString() + ") != isRect(" + actual.toString() diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java index f8e740390291..00b462954bd9 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -32,70 +32,66 @@ import android.view.InputChannel; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link TaskPositioningController} class. * - * atest com.android.server.wm.TaskPositioningControllerTests + * Build/Install/Run: + * atest FrameworksServicesTests:TaskPositioningControllerTests */ -@SmallTest @FlakyTest(bugId = 117924387) -@RunWith(AndroidJUnit4.class) +@SmallTest @Presubmit public class TaskPositioningControllerTests extends WindowTestsBase { private static final int TIMEOUT_MS = 1000; + private TaskPositioningController mTarget; private WindowState mWindow; @Before public void setUp() throws Exception { - super.setUp(); + assertNotNull(mWm.mTaskPositioningController); + mTarget = mWm.mTaskPositioningController; - assertNotNull(sWm.mTaskPositioningController); - mTarget = sWm.mTaskPositioningController; - - when(sWm.mInputManager.transferTouchFocus( + when(mWm.mInputManager.transferTouchFocus( any(InputChannel.class), any(InputChannel.class))).thenReturn(true); mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window"); mWindow.mInputChannel = new InputChannel(); - synchronized (sWm.mWindowMap) { - sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); + synchronized (mWm.mGlobalLock) { + mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); } } @Test - public void testStartAndFinishPositioning() throws Exception { - synchronized (sWm.mWindowMap) { + public void testStartAndFinishPositioning() { + synchronized (mWm.mGlobalLock) { assertFalse(mTarget.isPositioningLocked()); assertNull(mTarget.getDragWindowHandleLocked()); } assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0)); - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { assertTrue(mTarget.isPositioningLocked()); assertNotNull(mTarget.getDragWindowHandleLocked()); } mTarget.finishTaskPositioning(); // Wait until the looper processes finishTaskPositioning. - assertTrue(sWm.mH.runWithScissors(() -> {}, TIMEOUT_MS)); + assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS)); assertFalse(mTarget.isPositioningLocked()); assertNull(mTarget.getDragWindowHandleLocked()); } @Test - public void testHandleTapOutsideTask() throws Exception { - synchronized (sWm.mWindowMap) { - + public void testHandleTapOutsideTask() { + synchronized (mWm.mGlobalLock) { assertFalse(mTarget.isPositioningLocked()); assertNull(mTarget.getDragWindowHandleLocked()); } @@ -106,16 +102,16 @@ public class TaskPositioningControllerTests extends WindowTestsBase { mTarget.handleTapOutsideTask(content, 0, 0); // Wait until the looper processes finishTaskPositioning. - assertTrue(sWm.mH.runWithScissors(() -> {}, TIMEOUT_MS)); + assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS)); - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { assertTrue(mTarget.isPositioningLocked()); assertNotNull(mTarget.getDragWindowHandleLocked()); } mTarget.finishTaskPositioning(); // Wait until the looper processes finishTaskPositioning. - assertTrue(sWm.mH.runWithScissors(() -> {}, TIMEOUT_MS)); + assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS)); assertFalse(mTarget.isPositioningLocked()); assertNull(mTarget.getDragWindowHandleLocked()); diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java index c9d800449ff9..1c6afd545b1f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -24,32 +24,32 @@ import static junit.framework.Assert.assertNull; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Test class for {@link TaskSnapshotCache}. * - * runtest frameworks-services -c com.android.server.wm.TaskSnapshotCacheTest + * Build/Install/Run: + * atest FrameworksServicesTests:TaskSnapshotCacheTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase { private TaskSnapshotCache mCache; + @Override @Before - public void setUp() throws Exception { + public void setUp() { super.setUp(); - mCache = new TaskSnapshotCache(sWm, mLoader); + + mCache = new TaskSnapshotCache(mWm, mLoader); } @Test - public void testAppRemoved() throws Exception { + public void testAppRemoved() { final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); mCache.putSnapshot(window.getTask(), createSnapshot()); assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, @@ -60,7 +60,7 @@ public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase { } @Test - public void testAppDied() throws Exception { + public void testAppDied() { final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); mCache.putSnapshot(window.getTask(), createSnapshot()); assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, @@ -71,7 +71,7 @@ public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase { } @Test - public void testTaskRemoved() throws Exception { + public void testTaskRemoved() { final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); mCache.putSnapshot(window.getTask(), createSnapshot()); assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */, @@ -82,32 +82,32 @@ public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase { } @Test - public void testReduced_notCached() throws Exception { + public void testReduced_notCached() { final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); - mPersister.persistSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, createSnapshot()); + mPersister.persistSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, createSnapshot()); mPersister.waitForQueueEmpty(); - assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, + assertNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, false /* restoreFromDisk */, false /* reducedResolution */)); // Load it from disk - assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, + assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, true /* restoreFromDisk */, true /* reducedResolution */)); // Make sure it's not in the cache now. - assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, + assertNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, false /* restoreFromDisk */, false /* reducedResolution */)); } @Test - public void testRestoreFromDisk() throws Exception { + public void testRestoreFromDisk() { final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window"); - mPersister.persistSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, createSnapshot()); + mPersister.persistSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, createSnapshot()); mPersister.waitForQueueEmpty(); - assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, + assertNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, false /* restoreFromDisk */, false /* reducedResolution */)); // Load it from disk - assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, + assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, true /* restoreFromDisk */, false /* reducedResolution */)); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java index efce063c8fca..d2c07651d83c 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -20,7 +20,8 @@ import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.TRANSIT_UNSET; -import static com.android.server.wm.TaskSnapshotController.*; +import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_APP_THEME; +import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_REAL; import static junit.framework.Assert.assertEquals; @@ -28,25 +29,23 @@ import android.platform.test.annotations.Presubmit; import android.util.ArraySet; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.google.android.collect.Sets; import org.junit.Test; -import org.junit.runner.RunWith; /** * Test class for {@link TaskSnapshotController}. * - * runtest frameworks-services -c com.android.server.wm.TaskSnapshotControllerTest + * Build/Install/Run: + * * atest FrameworksServicesTests:TaskSnapshotControllerTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class TaskSnapshotControllerTest extends WindowTestsBase { @Test - public void testGetClosingApps_closing() throws Exception { + public void testGetClosingApps_closing() { final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, "closingWindow"); closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, @@ -54,13 +53,13 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { final ArraySet<AppWindowToken> closingApps = new ArraySet<>(); closingApps.add(closingWindow.mAppToken); final ArraySet<Task> closingTasks = new ArraySet<>(); - sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks); + mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks); assertEquals(1, closingTasks.size()); assertEquals(closingWindow.mAppToken.getTask(), closingTasks.valueAt(0)); } @Test - public void testGetClosingApps_notClosing() throws Exception { + public void testGetClosingApps_notClosing() { final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, "closingWindow"); final WindowState openingWindow = createAppWindow(closingWindow.getTask(), @@ -72,12 +71,12 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { final ArraySet<AppWindowToken> closingApps = new ArraySet<>(); closingApps.add(closingWindow.mAppToken); final ArraySet<Task> closingTasks = new ArraySet<>(); - sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks); + mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks); assertEquals(0, closingTasks.size()); } @Test - public void testGetClosingApps_skipClosingAppsSnapshotTasks() throws Exception { + public void testGetClosingApps_skipClosingAppsSnapshotTasks() { final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, "closingWindow"); closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET, @@ -85,29 +84,29 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { final ArraySet<AppWindowToken> closingApps = new ArraySet<>(); closingApps.add(closingWindow.mAppToken); final ArraySet<Task> closingTasks = new ArraySet<>(); - sWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks( + mWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks( Sets.newArraySet(closingWindow.mAppToken.getTask())); - sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks); + mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks); assertEquals(0, closingTasks.size()); } @Test - public void testGetSnapshotMode() throws Exception { + public void testGetSnapshotMode() { final WindowState disabledWindow = createWindow(null, FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow"); disabledWindow.mAppToken.setDisablePreviewScreenshots(true); assertEquals(SNAPSHOT_MODE_APP_THEME, - sWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask())); + mWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask())); final WindowState normalWindow = createWindow(null, FIRST_APPLICATION_WINDOW, mDisplayContent, "normalWindow"); assertEquals(SNAPSHOT_MODE_REAL, - sWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask())); + mWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask())); final WindowState secureWindow = createWindow(null, FIRST_APPLICATION_WINDOW, mDisplayContent, "secureWindow"); secureWindow.mAttrs.flags |= FLAG_SECURE; assertEquals(SNAPSHOT_MODE_APP_THEME, - sWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask())); + mWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask())); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java index 600b2e52b083..b0eafeeae043 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -34,23 +34,22 @@ import android.util.ArraySet; import android.view.View; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem; import org.junit.Test; -import org.junit.runner.RunWith; import java.io.File; +import java.util.function.Predicate; /** * Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader} * - * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest + * Build/Install/Run: + * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest */ @MediumTest @Presubmit -@RunWith(AndroidJUnit4.class) public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase { private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40); @@ -59,9 +58,9 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa public void testPersistAndLoadSnapshot() { mPersister.persistSnapshot(1 , mTestUserId, createSnapshot()); mPersister.waitForQueueEmpty(); - final File[] files = new File[] { new File(sFilesDir.getPath() + "/snapshots/1.proto"), - new File(sFilesDir.getPath() + "/snapshots/1.jpg"), - new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg")}; + final File[] files = new File[] { new File(FILES_DIR.getPath() + "/snapshots/1.proto"), + new File(FILES_DIR.getPath() + "/snapshots/1.jpg"), + new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")}; assertTrueForFiles(files, File::exists, " must exist"); final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* reduced */); assertNotNull(snapshot); @@ -70,9 +69,10 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation()); } - private void assertTrueForFiles(File[] files, Predicate<File> predicate, String message) { + private static void assertTrueForFiles(File[] files, Predicate<File> predicate, + String message) { for (File file : files) { - assertTrue(file.getName() + message, predicate.apply(file)); + assertTrue(file.getName() + message, predicate.test(file)); } } @@ -81,9 +81,9 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa mPersister.persistSnapshot(1, mTestUserId, createSnapshot()); mPersister.onTaskRemovedFromRecents(1, mTestUserId); mPersister.waitForQueueEmpty(); - assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.proto").exists()); - assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.jpg").exists()); - assertFalse(new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg").exists()); + assertFalse(new File(FILES_DIR.getPath() + "/snapshots/1.proto").exists()); + assertFalse(new File(FILES_DIR.getPath() + "/snapshots/1.jpg").exists()); + assertFalse(new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg").exists()); } /** @@ -120,12 +120,12 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa // Make sure 1,2 were purged but removeObsoleteFiles wasn't. final File[] existsFiles = new File[] { - new File(sFilesDir.getPath() + "/snapshots/3.proto"), - new File(sFilesDir.getPath() + "/snapshots/4.proto")}; + new File(FILES_DIR.getPath() + "/snapshots/3.proto"), + new File(FILES_DIR.getPath() + "/snapshots/4.proto")}; final File[] nonExistsFiles = new File[] { - new File(sFilesDir.getPath() + "/snapshots/100.proto"), - new File(sFilesDir.getPath() + "/snapshots/1.proto"), - new File(sFilesDir.getPath() + "/snapshots/1.proto")}; + new File(FILES_DIR.getPath() + "/snapshots/100.proto"), + new File(FILES_DIR.getPath() + "/snapshots/1.proto"), + new File(FILES_DIR.getPath() + "/snapshots/1.proto")}; assertTrueForFiles(existsFiles, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); } @@ -149,10 +149,10 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa assertTrue(a.isReducedResolution()); mPersister.persistSnapshot(1 , mTestUserId, a); mPersister.waitForQueueEmpty(); - final File[] files = new File[] { new File(sFilesDir.getPath() + "/snapshots/1.proto"), - new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg")}; + final File[] files = new File[] { new File(FILES_DIR.getPath() + "/snapshots/1.proto"), + new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")}; final File[] nonExistsFiles = new File[] { - new File(sFilesDir.getPath() + "/snapshots/1.jpg"), + new File(FILES_DIR.getPath() + "/snapshots/1.jpg"), }; assertTrueForFiles(files, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); @@ -195,8 +195,8 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa TaskSnapshot b = new TaskSnapshotBuilder() .setWindowingMode(WINDOWING_MODE_PINNED) .build(); - assertTrue(a.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); - assertTrue(b.getWindowingMode() == WINDOWING_MODE_PINNED); + assertEquals(WINDOWING_MODE_FULLSCREEN, a.getWindowingMode()); + assertEquals(WINDOWING_MODE_PINNED, b.getWindowingMode()); mPersister.persistSnapshot(1, mTestUserId, a); mPersister.persistSnapshot(2, mTestUserId, b); mPersister.waitForQueueEmpty(); @@ -204,8 +204,8 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */); assertNotNull(snapshotA); assertNotNull(snapshotB); - assertTrue(snapshotA.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); - assertTrue(snapshotB.getWindowingMode() == WINDOWING_MODE_PINNED); + assertEquals(WINDOWING_MODE_FULLSCREEN, snapshotA.getWindowingMode()); + assertEquals(WINDOWING_MODE_PINNED, snapshotB.getWindowingMode()); } @Test @@ -239,8 +239,8 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa TaskSnapshot b = new TaskSnapshotBuilder() .setSystemUiVisibility(lightBarFlags) .build(); - assertTrue(a.getSystemUiVisibility() == 0); - assertTrue(b.getSystemUiVisibility() == lightBarFlags); + assertEquals(0, a.getSystemUiVisibility()); + assertEquals(lightBarFlags, b.getSystemUiVisibility()); mPersister.persistSnapshot(1, mTestUserId, a); mPersister.persistSnapshot(2, mTestUserId, b); mPersister.waitForQueueEmpty(); @@ -248,8 +248,8 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */); assertNotNull(snapshotA); assertNotNull(snapshotB); - assertTrue(snapshotA.getSystemUiVisibility() == 0); - assertTrue(snapshotB.getSystemUiVisibility() == lightBarFlags); + assertEquals(0, snapshotA.getSystemUiVisibility()); + assertEquals(lightBarFlags, snapshotB.getSystemUiVisibility()); } @Test @@ -261,13 +261,13 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa mPersister.removeObsoleteFiles(taskIds, new int[] { mTestUserId }); mPersister.waitForQueueEmpty(); final File[] existsFiles = new File[] { - new File(sFilesDir.getPath() + "/snapshots/1.proto"), - new File(sFilesDir.getPath() + "/snapshots/1.jpg"), - new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg") }; + new File(FILES_DIR.getPath() + "/snapshots/1.proto"), + new File(FILES_DIR.getPath() + "/snapshots/1.jpg"), + new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg") }; final File[] nonExistsFiles = new File[] { - new File(sFilesDir.getPath() + "/snapshots/2.proto"), - new File(sFilesDir.getPath() + "/snapshots/2.jpg"), - new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")}; + new File(FILES_DIR.getPath() + "/snapshots/2.proto"), + new File(FILES_DIR.getPath() + "/snapshots/2.jpg"), + new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")}; assertTrueForFiles(existsFiles, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); } @@ -281,24 +281,12 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa mPersister.persistSnapshot(2, mTestUserId, createSnapshot()); mPersister.waitForQueueEmpty(); final File[] existsFiles = new File[] { - new File(sFilesDir.getPath() + "/snapshots/1.proto"), - new File(sFilesDir.getPath() + "/snapshots/1.jpg"), - new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg"), - new File(sFilesDir.getPath() + "/snapshots/2.proto"), - new File(sFilesDir.getPath() + "/snapshots/2.jpg"), - new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")}; + new File(FILES_DIR.getPath() + "/snapshots/1.proto"), + new File(FILES_DIR.getPath() + "/snapshots/1.jpg"), + new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"), + new File(FILES_DIR.getPath() + "/snapshots/2.proto"), + new File(FILES_DIR.getPath() + "/snapshots/2.jpg"), + new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")}; assertTrueForFiles(existsFiles, File::exists, " must exist"); } - - /** - * Private predicate definition. - * - * This is needed because com.android.internal.util.Predicate is deprecated - * and can only be used with classes fron android.test.runner. This cannot - * use java.util.function.Predicate because that is not present on all API - * versions that this test must run on. - */ - private interface Predicate<T> { - boolean apply(T t); - } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index 33b137ef33e2..0f9b82586e0e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -21,6 +21,8 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE; import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import android.app.ActivityManager.TaskSnapshot; import android.graphics.Canvas; import android.graphics.Color; @@ -31,51 +33,37 @@ import android.os.UserManager; import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import java.io.File; -import androidx.test.InstrumentationRegistry; - /** * Base class for tests that use a {@link TaskSnapshotPersister}. */ class TaskSnapshotPersisterTestBase extends WindowTestsBase { private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40); + static final File FILES_DIR = getInstrumentation().getTargetContext().getFilesDir(); TaskSnapshotPersister mPersister; TaskSnapshotLoader mLoader; int mTestUserId; - static File sFilesDir; - - @BeforeClass - public static void setUpUser() { - sFilesDir = InstrumentationRegistry.getContext().getFilesDir(); - } - @Override @Before - public void setUp() throws Exception { - super.setUp(); - - final UserManager um = UserManager.get(InstrumentationRegistry.getContext()); + public void setUp() { + final UserManager um = UserManager.get(getInstrumentation().getTargetContext()); mTestUserId = um.getUserHandle(); - mPersister = new TaskSnapshotPersister(userId -> sFilesDir); + mPersister = new TaskSnapshotPersister(userId -> FILES_DIR); mLoader = new TaskSnapshotLoader(mPersister); mPersister.start(); } - @Override @After - public void tearDown() throws Exception { + public void tearDown() { cleanDirectory(); - - super.tearDown(); } private void cleanDirectory() { - final File[] files = new File(sFilesDir, "snapshots").listFiles(); + final File[] files = new File(FILES_DIR, "snapshots").listFiles(); if (files == null) { return; } @@ -99,7 +87,7 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { /** * Builds a TaskSnapshot. */ - class TaskSnapshotBuilder { + static class TaskSnapshotBuilder { private float mScale = 1f; private boolean mIsRealSnapshot = true; @@ -107,32 +95,32 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; private int mSystemUiVisibility = 0; - public TaskSnapshotBuilder setScale(float scale) { + TaskSnapshotBuilder setScale(float scale) { mScale = scale; return this; } - public TaskSnapshotBuilder setIsRealSnapshot(boolean isRealSnapshot) { + TaskSnapshotBuilder setIsRealSnapshot(boolean isRealSnapshot) { mIsRealSnapshot = isRealSnapshot; return this; } - public TaskSnapshotBuilder setIsTranslucent(boolean isTranslucent) { + TaskSnapshotBuilder setIsTranslucent(boolean isTranslucent) { mIsTranslucent = isTranslucent; return this; } - public TaskSnapshotBuilder setWindowingMode(int windowingMode) { + TaskSnapshotBuilder setWindowingMode(int windowingMode) { mWindowingMode = windowingMode; return this; } - public TaskSnapshotBuilder setSystemUiVisibility(int systemUiVisibility) { + TaskSnapshotBuilder setSystemUiVisibility(int systemUiVisibility) { mSystemUiVisibility = systemUiVisibility; return this; } - public TaskSnapshot build() { + TaskSnapshot build() { final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); Canvas c = buffer.lockCanvas(); @@ -142,6 +130,5 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { mScale < 1f /* reducedResolution */, mScale, mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, mIsTranslucent); } - } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index 91074b9db081..7c16191efec4 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -39,21 +39,19 @@ import android.platform.test.annotations.Presubmit; import android.view.Surface; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.wm.TaskSnapshotSurface.Window; import org.junit.Test; -import org.junit.runner.RunWith; /** * Test class for {@link TaskSnapshotSurface}. * - * runtest frameworks-services -c com.android.server.wm.TaskSnapshotSurfaceTest + * Build/Install/Run: + * atest FrameworksServicesTests:TaskSnapshotSurfaceTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class TaskSnapshotSurfaceTest extends WindowTestsBase { private TaskSnapshotSurface mSurface; @@ -65,7 +63,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { final TaskSnapshot snapshot = new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */); - mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test", + mSurface = new TaskSnapshotSurface(mWm, new Window(), new Surface(), snapshot, "Test", Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds, ORIENTATION_PORTRAIT); } @@ -76,7 +74,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { } @Test - public void fillEmptyBackground_fillHorizontally() throws Exception { + public void fillEmptyBackground_fillHorizontally() { setupSurface(200, 100); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(200); @@ -86,7 +84,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { } @Test - public void fillEmptyBackground_fillVertically() throws Exception { + public void fillEmptyBackground_fillVertically() { setupSurface(100, 200); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); @@ -96,7 +94,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { } @Test - public void fillEmptyBackground_fillBoth() throws Exception { + public void fillEmptyBackground_fillBoth() { setupSurface(200, 200); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(200); @@ -107,7 +105,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { } @Test - public void fillEmptyBackground_dontFill_sameSize() throws Exception { + public void fillEmptyBackground_dontFill_sameSize() { setupSurface(100, 100); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); @@ -117,7 +115,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { } @Test - public void fillEmptyBackground_dontFill_bitmapLarger() throws Exception { + public void fillEmptyBackground_dontFill_bitmapLarger() { setupSurface(100, 100); final Canvas mockCanvas = mock(Canvas.class); when(mockCanvas.getWidth()).thenReturn(100); diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java index 0e9a63ce728b..f01e9f0662c9 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -27,17 +27,17 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; +import androidx.test.filters.SmallTest; + import org.junit.After; import org.junit.Before; import org.junit.Test; -import androidx.test.filters.SmallTest; - /** * Tests for the {@link DisplayContent.TaskStackContainers} container in {@link DisplayContent}. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.TaskStackContainersTests + * atest FrameworksServicesTests:TaskStackContainersTests */ @SmallTest @Presubmit @@ -45,11 +45,8 @@ public class TaskStackContainersTests extends WindowTestsBase { private TaskStack mPinnedStack; - @Override @Before public void setUp() throws Exception { - super.setUp(); - mPinnedStack = createStackControllerOnStackOnDisplay( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer; // Stack should contain visible app window to be considered visible. @@ -61,12 +58,9 @@ public class TaskStackContainersTests extends WindowTestsBase { assertTrue(mPinnedStack.isVisible()); } - @Override @After public void tearDown() throws Exception { mPinnedStack.removeImmediately(); - - super.tearDown(); } @Test @@ -121,14 +115,14 @@ public class TaskStackContainersTests extends WindowTestsBase { final Task task = createTaskInStack(stack, 0 /* userId */); // Add another display at top. - sWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(), + mWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(), false /* includingParents */); // Move the task of {@code mDisplayContent} to top. stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */); - final int indexOfDisplayWithPinnedStack = sWm.mRoot.mChildren.indexOf(mDisplayContent); + final int indexOfDisplayWithPinnedStack = mWm.mRoot.mChildren.indexOf(mDisplayContent); assertEquals("The testing DisplayContent should be moved to top with task", - sWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack); + mWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java index cb5c1cd67092..7ac331829fb1 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -25,24 +25,21 @@ import static org.junit.Assert.assertNull; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link TaskStack} class. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.TaskStackTests + * atest FrameworksServicesTests:TaskStackTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class TaskStackTests extends WindowTestsBase { @Test - public void testStackPositionChildAt() throws Exception { + public void testStackPositionChildAt() { final TaskStack stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); final Task task2 = createTaskInStack(stack, 1 /* userId */); @@ -59,7 +56,7 @@ public class TaskStackTests extends WindowTestsBase { } @Test - public void testClosingAppDifferentStackOrientation() throws Exception { + public void testClosingAppDifferentStackOrientation() { final TaskStack stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); WindowTestUtils.TestAppWindowToken appWindowToken1 = @@ -79,7 +76,7 @@ public class TaskStackTests extends WindowTestsBase { } @Test - public void testMoveTaskToBackDifferentStackOrientation() throws Exception { + public void testMoveTaskToBackDifferentStackOrientation() { final TaskStack stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); WindowTestUtils.TestAppWindowToken appWindowToken1 = @@ -99,7 +96,7 @@ public class TaskStackTests extends WindowTestsBase { } @Test - public void testStackRemoveImmediately() throws Exception { + public void testStackRemoveImmediately() { final TaskStack stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); assertEquals(stack, task.mStack); diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java index edd76647f4a8..1af79e41fe37 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -24,24 +24,21 @@ import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; /** * Test class for {@link TaskWindowContainerController}. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.TaskWindowContainerControllerTests + * atest FrameworksServicesTests:TaskWindowContainerControllerTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class TaskWindowContainerControllerTests extends WindowTestsBase { @Test - public void testRemoveContainer() throws Exception { + public void testRemoveContainer() { final WindowTestUtils.TestTaskWindowContainerController taskController = new WindowTestUtils.TestTaskWindowContainerController(this); final WindowTestUtils.TestAppWindowContainerController appController = @@ -54,7 +51,7 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { } @Test - public void testRemoveContainer_deferRemoval() throws Exception { + public void testRemoveContainer_deferRemoval() { final WindowTestUtils.TestTaskWindowContainerController taskController = new WindowTestUtils.TestTaskWindowContainerController(this); final WindowTestUtils.TestAppWindowContainerController appController = @@ -79,7 +76,7 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { } @Test - public void testReparent() throws Exception { + public void testReparent() { final StackWindowController stackController1 = createStackControllerOnDisplay(mDisplayContent); final WindowTestUtils.TestTaskWindowContainerController taskController = @@ -116,7 +113,7 @@ public class TaskWindowContainerControllerTests extends WindowTestsBase { } @Test - public void testReparent_BetweenDisplays() throws Exception { + public void testReparent_BetweenDisplays() { // Create first stack on primary display. final StackWindowController stack1Controller = createStackControllerOnDisplay(mDisplayContent); diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java index 353aa7deb534..e8d0a066dade 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java @@ -11,13 +11,11 @@ * 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 + * limitations under the License. */ package com.android.server.wm; -import com.android.internal.os.IResultReceiver; - import android.graphics.Rect; import android.os.Bundle; import android.os.ParcelFileDescriptor; @@ -27,87 +25,71 @@ import android.view.DisplayCutout; import android.view.DragEvent; import android.view.IWindow; +import com.android.internal.os.IResultReceiver; + public class TestIWindow extends IWindow.Stub { @Override public void executeCommand(String command, String parameters, - ParcelFileDescriptor descriptor) - throws RemoteException { - + ParcelFileDescriptor descriptor) throws RemoteException { } @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId, - DisplayCutout.ParcelableWrapper displayCutout) - throws RemoteException { - + DisplayCutout.ParcelableWrapper displayCutout) throws RemoteException { } @Override public void moved(int newX, int newY) throws RemoteException { - } @Override public void dispatchAppVisibility(boolean visible) throws RemoteException { - } @Override public void dispatchGetNewSurface() throws RemoteException { - } @Override - public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) - throws RemoteException { - + public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) throws RemoteException { } @Override public void closeSystemDialogs(String reason) throws RemoteException { - } @Override - public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, - boolean sync) + public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync) throws RemoteException { - } @Override public void dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync) throws RemoteException { - } @Override public void dispatchDragEvent(DragEvent event) throws RemoteException { - } @Override public void updatePointerIcon(float x, float y) throws RemoteException { - } @Override public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges) throws RemoteException { - } @Override public void dispatchWindowShown() throws RemoteException { - } @Override public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) throws RemoteException { - } @Override diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index 51595514624c..0165e7d4e84b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -46,8 +46,6 @@ import java.io.PrintWriter; import java.util.function.Supplier; class TestWindowManagerPolicy implements WindowManagerPolicy { - private static final String TAG = "TestWindowManagerPolicy"; - private final Supplier<WindowManagerService> mWmSupplier; int rotationToReport = 0; @@ -55,21 +53,18 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { private Runnable mRunnableWhenAddingSplashScreen; - public TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier) { - + TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier) { mWmSupplier = wmSupplier; } @Override public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver) throws RemoteException { - } @Override public void init(Context context, IWindowManager windowManager, WindowManagerFuncs windowManagerFuncs) { - } public void setDefaultDisplay(DisplayContentInfo displayContentInfo) { @@ -93,7 +88,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void adjustConfigurationLw(Configuration config, int keyboardPresence, int navigationPresence) { - } @Override @@ -150,7 +144,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { final com.android.server.wm.WindowState window; final AppWindowToken atoken; final WindowManagerService wm = mWmSupplier.get(); - synchronized (wm.mWindowMap) { + synchronized (wm.mGlobalLock) { atoken = wm.mRoot.getAppWindowToken(appToken); IWindow iWindow = mock(IWindow.class); doReturn(mock(IBinder.class)).when(iWindow).asBinder(); @@ -164,7 +158,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { mRunnableWhenAddingSplashScreen = null; } return () -> { - synchronized (wm.mWindowMap) { + synchronized (wm.mGlobalLock) { atoken.removeChild(window); atoken.startingWindow = null; } @@ -179,7 +173,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void removeWindowLw(WindowState win) { - } @Override @@ -189,7 +182,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void selectRotationAnimationLw(int[] anim) { - } @Override @@ -220,14 +212,12 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, - int policyFlags) { + public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) { return 0; } @Override - public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, - int policyFlags) { + public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) { return null; } @@ -238,12 +228,11 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) { - } @Override - public void applyPostLayoutPolicyLw(WindowState win, - WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget) { + public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, + WindowState attached, WindowState imeTarget) { } @Override @@ -257,49 +246,40 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public int focusChangedLw(WindowState lastFocus, - WindowState newFocus) { + public int focusChangedLw(WindowState lastFocus, WindowState newFocus) { return 0; } @Override public void startedWakingUp() { - } @Override public void finishedWakingUp() { - } @Override public void startedGoingToSleep(int why) { - } @Override public void finishedGoingToSleep(int why) { - } @Override public void screenTurningOn(ScreenOnListener screenOnListener) { - } @Override public void screenTurnedOn() { - } @Override public void screenTurningOff(ScreenOffListener screenOffListener) { - } @Override public void screenTurnedOff() { - } @Override @@ -314,22 +294,18 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { - } @Override public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) { - } @Override public void enableKeyguard(boolean enabled) { - } @Override public void exitKeyguardSecurely(OnKeyguardExitResult callback) { - } @Override @@ -382,53 +358,44 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } public void setSafeMode(boolean safeMode) { - } @Override public void systemReady() { - } @Override public void systemBooted() { - } @Override public void showBootMessage(CharSequence msg, boolean always) { - } @Override public void hideBootMessages() { - } @Override public void userActivity() { - } @Override public void enableScreenAfterBoot() { - } @Override - public boolean performHapticFeedbackLw(WindowState win, int effectId, - boolean always, String reason) { + public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always, + String reason) { return false; } @Override public void keepScreenOnStartedLw() { - } @Override public void keepScreenOnStoppedLw() { - } @Override @@ -443,37 +410,30 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void lockNow(Bundle options) { - } @Override public void showRecentApps() { - } @Override public void showGlobalActions() { - } @Override public void setCurrentUserLw(int newUserId) { - } @Override public void setSwitchingUser(boolean switching) { - } @Override public void writeToProto(ProtoOutputStream proto, long fieldId) { - } @Override public void dump(String prefix, PrintWriter writer, String[] args) { - } @Override @@ -483,13 +443,11 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { - } @Override public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight, DisplayCutout cutout, Rect outInsets) { - } @Override @@ -506,7 +464,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight, DisplayCutout cutout, Rect outInsets) { - } @Override @@ -517,7 +474,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void onConfigurationChanged(DisplayContentInfo displayContentInfo) { - } @Override @@ -528,12 +484,10 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { @Override public void setPipVisibilityLw(boolean visible) { - } @Override public void setRecentsVisibilityLw(boolean visible) { - } @Override diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java index 54456fbd6f3b..9e22c0a86d96 100644 --- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java @@ -11,52 +11,50 @@ * 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 + * limitations under the License. */ package com.android.server.wm; import static junit.framework.Assert.assertTrue; +import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Test class for {@link AppTransition}. * - * runtest frameworks-services -c com.android.server.wm.UnknownAppVisibilityControllerTest + * Build/Install/Run: + * atest FrameworksServicesTests:UnknownAppVisibilityControllerTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); mDisplayContent.mUnknownAppVisibilityController.clear(); } @Test - public void testFlow() throws Exception { + public void testFlow() { final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token); mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(token); mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token); // Make sure our handler processed the message. - Thread.sleep(100); + SystemClock.sleep(100); assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved()); } @Test - public void testMultiple() throws Exception { + public void testMultiple() { final AppWindowToken token1 = WindowTestUtils.createTestAppWindowToken(mDisplayContent); final AppWindowToken token2 = WindowTestUtils.createTestAppWindowToken(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token1); @@ -67,12 +65,12 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token2); // Make sure our handler processed the message. - Thread.sleep(100); + SystemClock.sleep(100); assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved()); } @Test - public void testClear() throws Exception { + public void testClear() { final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token); mDisplayContent.mUnknownAppVisibilityController.clear();; @@ -80,7 +78,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { } @Test - public void testAppRemoved() throws Exception { + public void testAppRemoved() { final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token); mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(token); diff --git a/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java index 882e78924629..25e73e3740c5 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; @@ -13,33 +29,30 @@ import android.os.IBinder; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link WallpaperController} class. * * Build/Install/Run: - * atest com.android.server.wm.WallpaperControllerTests + * atest FrameworksServicesTests:WallpaperControllerTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class WallpaperControllerTests extends WindowTestsBase { @Test public void testWallpaperScreenshot() { WindowSurfaceController windowSurfaceController = mock(WindowSurfaceController.class); - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { // No wallpaper final DisplayContent dc = createNewDisplay(); - Bitmap wallpaperBitmap = sWm.mRoot.mWallpaperController.screenshotWallpaperLocked(); + Bitmap wallpaperBitmap = mWm.mRoot.mWallpaperController.screenshotWallpaperLocked(); assertNull(wallpaperBitmap); // No wallpaper WSA Surface - WindowToken wallpaperWindowToken = new WallpaperWindowToken(sWm, mock(IBinder.class), + WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class), true, dc, true /* ownerCanManageAppTokens */); WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER, wallpaperWindowToken, "wallpaperWindow"); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java index e7cc2859ff62..3643457f061f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java @@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOW_CONFIG_ALWAYS_ON_TOP; import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS; +import static android.app.WindowConfiguration.WINDOW_CONFIG_ROTATION; import static android.app.WindowConfiguration.WINDOW_CONFIG_WINDOWING_MODE; import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION; @@ -33,29 +34,28 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.DisplayInfo; +import android.view.Surface; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; +import org.junit.Before; import org.junit.Test; /** * Test class to for {@link android.app.WindowConfiguration}. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.WindowConfigurationTests + * atest FrameworksServicesTests:WindowConfigurationTests */ -@SmallTest @FlakyTest(bugId = 74078662) +@SmallTest @Presubmit -@org.junit.runner.RunWith(AndroidJUnit4.class) public class WindowConfigurationTests extends WindowTestsBase { private Rect mParentBounds; - @Override + @Before public void setUp() throws Exception { - super.setUp(); mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/); } @@ -68,11 +68,13 @@ public class WindowConfigurationTests extends WindowTestsBase { final WindowConfiguration winConfig2 = config2.windowConfiguration; final Configuration config3 = new Configuration(); final WindowConfiguration winConfig3 = config3.windowConfiguration; + final Configuration config4 = new Configuration(); + final WindowConfiguration winConfig4 = config4.windowConfiguration; winConfig1.setAppBounds(0, 1, 1, 0); winConfig2.setAppBounds(1, 2, 2, 1); winConfig3.setAppBounds(winConfig1.getAppBounds()); - + winConfig4.setRotation(Surface.ROTATION_90); assertEquals(CONFIG_WINDOW_CONFIGURATION, config1.diff(config2)); assertEquals(0, config1.diffPublicOnly(config2)); @@ -88,6 +90,9 @@ public class WindowConfigurationTests extends WindowTestsBase { | WINDOW_CONFIG_ALWAYS_ON_TOP, winConfig1.diff(winConfig2, false /* compareUndefined */)); + assertEquals(WINDOW_CONFIG_ROTATION, + winConfig1.diff(winConfig4, false /* compareUndefined */)); + assertEquals(0, config1.diff(config3)); assertEquals(0, config1.diffPublicOnly(config3)); assertEquals(0, winConfig1.diff(winConfig3, false /* compareUndefined */)); @@ -95,7 +100,7 @@ public class WindowConfigurationTests extends WindowTestsBase { /** Tests {@link android.app.WindowConfiguration#compareTo(WindowConfiguration)}. */ @Test - public void testConfigurationCompareTo() throws Exception { + public void testConfigurationCompareTo() { final Configuration blankConfig = new Configuration(); final WindowConfiguration blankWinConfig = new WindowConfiguration(); @@ -125,17 +130,24 @@ public class WindowConfigurationTests extends WindowTestsBase { winConfig2.setAppBounds(0, 2, 3, 4); assertNotEquals(config1.compareTo(config2), 0); assertNotEquals(winConfig1.compareTo(winConfig2), 0); + winConfig2.setAppBounds(winConfig1.getAppBounds()); // No bounds assertEquals(config1.compareTo(blankConfig), -1); assertEquals(winConfig1.compareTo(blankWinConfig), -1); + // Different rotation + winConfig2.setRotation(Surface.ROTATION_180); + assertNotEquals(config1.compareTo(config2), 0); + assertNotEquals(winConfig1.compareTo(winConfig2), 0); + winConfig2.setRotation(winConfig1.getRotation()); + assertEquals(blankConfig.compareTo(config1), 1); assertEquals(blankWinConfig.compareTo(winConfig1), 1); } @Test - public void testSetActivityType() throws Exception { + public void testSetActivityType() { final WindowConfiguration config = new WindowConfiguration(); config.setActivityType(ACTIVITY_TYPE_HOME); assertEquals(ACTIVITY_TYPE_HOME, config.getActivityType()); @@ -147,12 +159,12 @@ public class WindowConfigurationTests extends WindowTestsBase { /** Ensures the configuration app bounds at the root level match the app dimensions. */ @Test - public void testAppBounds_RootConfigurationBounds() throws Exception { + public void testAppBounds_RootConfigurationBounds() { final DisplayInfo info = mDisplayContent.getDisplayInfo(); info.appWidth = 1024; info.appHeight = 768; - final Rect appBounds = sWm.computeNewConfiguration( + final Rect appBounds = mWm.computeNewConfiguration( mDisplayContent.getDisplayId()).windowConfiguration.getAppBounds(); // The bounds should always be positioned in the top left. assertEquals(appBounds.left, 0); @@ -165,7 +177,7 @@ public class WindowConfigurationTests extends WindowTestsBase { /** Ensures that bounds are clipped to their parent. */ @Test - public void testAppBounds_BoundsClipping() throws Exception { + public void testAppBounds_BoundsClipping() { final Rect shiftedBounds = new Rect(mParentBounds); shiftedBounds.offset(10, 10); final Rect expectedBounds = new Rect(mParentBounds); @@ -176,7 +188,7 @@ public class WindowConfigurationTests extends WindowTestsBase { /** Ensures that empty bounds are not propagated to the configuration. */ @Test - public void testAppBounds_EmptyBounds() throws Exception { + public void testAppBounds_EmptyBounds() { final Rect emptyBounds = new Rect(); testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, emptyBounds, null /*ExpectedBounds*/); @@ -184,7 +196,7 @@ public class WindowConfigurationTests extends WindowTestsBase { /** Ensures that bounds on freeform stacks are not clipped. */ @Test - public void testAppBounds_FreeFormBounds() throws Exception { + public void testAppBounds_FreeFormBounds() { final Rect freeFormBounds = new Rect(mParentBounds); freeFormBounds.offset(10, 10); testStackBoundsConfiguration(WINDOWING_MODE_FREEFORM, mParentBounds, freeFormBounds, @@ -193,7 +205,7 @@ public class WindowConfigurationTests extends WindowTestsBase { /** Ensures that fully contained bounds are not clipped. */ @Test - public void testAppBounds_ContainedBounds() throws Exception { + public void testAppBounds_ContainedBounds() { final Rect insetBounds = new Rect(mParentBounds); insetBounds.inset(5, 5, 5, 5); testStackBoundsConfiguration( @@ -202,7 +214,7 @@ public class WindowConfigurationTests extends WindowTestsBase { /** Ensures that full screen free form bounds are clipped */ @Test - public void testAppBounds_FullScreenFreeFormBounds() throws Exception { + public void testAppBounds_FullScreenFreeFormBounds() { final Rect fullScreenBounds = new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, fullScreenBounds, diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java index 6b1feb87aa42..7592f1c1fca0 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -28,7 +28,6 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; @@ -36,18 +35,17 @@ import org.junit.Test; * Test class for {@link WindowContainerController}. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.WindowContainerControllerTests + * atest FrameworksServicesTests:WindowContainerControllerTests */ +@FlakyTest(bugId = 74078662) @SmallTest @Presubmit -@FlakyTest(bugId = 74078662) -@org.junit.runner.RunWith(AndroidJUnit4.class) public class WindowContainerControllerTests extends WindowTestsBase { @Test - public void testCreation() throws Exception { - final WindowContainerController controller = new WindowContainerController(null, sWm); - final WindowContainer container = new WindowContainer(sWm); + public void testCreation() { + final WindowContainerController controller = new WindowContainerController<>(null, mWm); + final WindowContainer container = new WindowContainer(mWm); container.setController(controller); assertEquals(controller, container.getController()); @@ -55,9 +53,9 @@ public class WindowContainerControllerTests extends WindowTestsBase { } @Test - public void testSetContainer() throws Exception { - final WindowContainerController controller = new WindowContainerController(null, sWm); - final WindowContainer container = new WindowContainer(sWm); + public void testSetContainer() { + final WindowContainerController controller = new WindowContainerController<>(null, mWm); + final WindowContainer container = new WindowContainer(mWm); controller.setContainer(container); assertEquals(controller.mContainer, container); @@ -65,7 +63,7 @@ public class WindowContainerControllerTests extends WindowTestsBase { // Assert we can't change the container to another one once set boolean gotException = false; try { - controller.setContainer(new WindowContainer(sWm)); + controller.setContainer(new WindowContainer(mWm)); } catch (IllegalArgumentException e) { gotException = true; } @@ -77,9 +75,9 @@ public class WindowContainerControllerTests extends WindowTestsBase { } @Test - public void testRemoveContainer() throws Exception { - final WindowContainerController controller = new WindowContainerController(null, sWm); - final WindowContainer container = new WindowContainer(sWm); + public void testRemoveContainer() { + final WindowContainerController controller = new WindowContainerController<>(null, mWm); + final WindowContainer container = new WindowContainer(mWm); controller.setContainer(container); assertEquals(controller.mContainer, container); @@ -89,9 +87,9 @@ public class WindowContainerControllerTests extends WindowTestsBase { } @Test - public void testOnOverrideConfigurationChanged() throws Exception { - final WindowContainerController controller = new WindowContainerController(null, sWm); - final WindowContainer container = new WindowContainer(sWm); + public void testOnOverrideConfigurationChanged() { + final WindowContainerController controller = new WindowContainerController<>(null, mWm); + final WindowContainer container = new WindowContainer(mWm); controller.setContainer(container); assertEquals(controller.mContainer, container); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java index dc763b9bb079..e59afd656420 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -46,10 +46,8 @@ import android.view.SurfaceSession; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.Comparator; @@ -57,24 +55,23 @@ import java.util.Comparator; * Test class for {@link WindowContainer}. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.WindowContainerTests + * atest FrameworksServicesTests:WindowContainerTests */ @SmallTest @Presubmit @FlakyTest(bugId = 74078662) -@RunWith(AndroidJUnit4.class) public class WindowContainerTests extends WindowTestsBase { @Test - public void testCreation() throws Exception { - final TestWindowContainer w = new TestWindowContainerBuilder().setLayer(0).build(); + public void testCreation() { + final TestWindowContainer w = new TestWindowContainerBuilder(mWm).setLayer(0).build(); assertNull("window must have no parent", w.getParentWindow()); assertEquals("window must have no children", 0, w.getChildrenCount()); } @Test - public void testAdd() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testAdd() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer layer1 = root.addChildWindow(builder.setLayer(1)); @@ -113,23 +110,24 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testAddChildSetsSurfacePosition() throws Exception { - MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(); + public void testAddChildSetsSurfacePosition() { + try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) { - final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class); - sWm.mTransactionFactory = () -> transaction; + final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class); + mWm.mTransactionFactory = () -> transaction; - WindowContainer child = new WindowContainer(sWm); - child.setBounds(1, 1, 10, 10); + WindowContainer child = new WindowContainer(mWm); + child.setBounds(1, 1, 10, 10); - verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat()); - top.addChild(child, 0); - verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f)); + verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat()); + top.addChild(child, 0); + verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f)); + } } @Test - public void testAdd_AlreadyHasParent() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testAdd_AlreadyHasParent() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(); @@ -153,8 +151,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testHasChild() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testHasChild() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(); @@ -183,8 +181,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testRemoveImmediately() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testRemoveImmediately() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(); @@ -218,9 +216,9 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testRemoveImmediately_WithController() throws Exception { - final WindowContainer container = new WindowContainer(sWm); - final WindowContainerController controller = new WindowContainerController(null, sWm); + public void testRemoveImmediately_WithController() { + final WindowContainer container = new WindowContainer(mWm); + final WindowContainerController controller = new WindowContainerController<>(null, mWm); container.setController(controller); assertEquals(controller, container.getController()); @@ -232,9 +230,9 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testSetController() throws Exception { - final WindowContainerController controller = new WindowContainerController(null, sWm); - final WindowContainer container = new WindowContainer(sWm); + public void testSetController() { + final WindowContainerController controller = new WindowContainerController<>(null, mWm); + final WindowContainer container = new WindowContainer(mWm); container.setController(controller); assertEquals(controller, container.getController()); @@ -243,7 +241,7 @@ public class WindowContainerTests extends WindowTestsBase { // Assert we can't change the controller to another one once set boolean gotException = false; try { - container.setController(new WindowContainerController(null, sWm)); + container.setController(new WindowContainerController<>(null, mWm)); } catch (IllegalArgumentException e) { gotException = true; } @@ -256,8 +254,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testAddChildByIndex() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testAddChildByIndex() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child = root.addChildWindow(); @@ -283,8 +281,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testPositionChildAt() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testPositionChildAt() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(); @@ -307,8 +305,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testPositionChildAtIncludeParents() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testPositionChildAtIncludeParents() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(); @@ -349,12 +347,11 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testPositionChildAtInvalid() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testPositionChildAtInvalid() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(); - final TestWindowContainer child2 = root.addChildWindow(); boolean gotException = false; try { @@ -376,8 +373,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testIsAnimating() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testIsAnimating() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(builder.setIsAnimating(true)); @@ -402,8 +399,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testIsVisible() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testIsVisible() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(builder.setIsVisible(true)); @@ -422,7 +419,7 @@ public class WindowContainerTests extends WindowTestsBase { @Test public void testOverrideConfigurationAncestorNotification() { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer grandparent = builder.setLayer(0).build(); final TestWindowContainer parent = grandparent.addChildWindow(); @@ -433,8 +430,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testRemoveChild() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testRemoveChild() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(); final TestWindowContainer child2 = root.addChildWindow(); @@ -460,7 +457,7 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testGetOrientation_childSpecified() throws Exception { + public void testGetOrientation_childSpecified() { testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE, SCREEN_ORIENTATION_LANDSCAPE); testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET, @@ -469,7 +466,7 @@ public class WindowContainerTests extends WindowTestsBase { private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation, int expectedOrientation) { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); root.setFillsParent(true); @@ -486,16 +483,16 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testGetOrientation_Unset() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testGetOrientation_Unset() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); // Unspecified well because we didn't specify anything... assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation()); } @Test - public void testGetOrientation_InvisibleParentUnsetVisibleChildren() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testGetOrientation_InvisibleParentUnsetVisibleChildren() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); builder.setIsVisible(false).setLayer(-1); @@ -516,12 +513,11 @@ public class WindowContainerTests extends WindowTestsBase { visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET); assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation()); assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation()); - } @Test - public void testGetOrientation_setBehind() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testGetOrientation_setBehind() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); builder.setIsVisible(true).setLayer(-1); @@ -541,8 +537,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testGetOrientation_fillsParent() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testGetOrientation_fillsParent() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build(); builder.setIsVisible(true).setLayer(-1); @@ -577,8 +573,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testCompareTo() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testCompareTo() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); final TestWindowContainer child1 = root.addChildWindow(); @@ -588,8 +584,6 @@ public class WindowContainerTests extends WindowTestsBase { final TestWindowContainer child2 = root.addChildWindow(); final TestWindowContainer child21 = child2.addChildWindow(); final TestWindowContainer child22 = child2.addChildWindow(); - final TestWindowContainer child23 = child2.addChildWindow(); - final TestWindowContainer child221 = child22.addChildWindow(); final TestWindowContainer child222 = child22.addChildWindow(); final TestWindowContainer child223 = child22.addChildWindow(); final TestWindowContainer child2221 = child222.addChildWindow(); @@ -620,8 +614,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testPrefixOrderIndex() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testPrefixOrderIndex() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.build(); final TestWindowContainer child1 = root.addChildWindow(); @@ -654,8 +648,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testPrefixOrder_addEntireSubtree() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testPrefixOrder_addEntireSubtree() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.build(); final TestWindowContainer subtree = builder.build(); final TestWindowContainer subtree2 = builder.build(); @@ -677,8 +671,8 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testPrefixOrder_remove() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testPrefixOrder_remove() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.build(); final TestWindowContainer child1 = root.addChildWindow(); @@ -705,8 +699,8 @@ public class WindowContainerTests extends WindowTestsBase { * is invoked with overridden bounds. */ @Test - public void testOnParentResizePropagation() throws Exception { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(); + public void testOnParentResizePropagation() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.build(); final TestWindowContainer child = root.addChildWindow(); @@ -731,7 +725,7 @@ public class WindowContainerTests extends WindowTestsBase { } /* Used so we can gain access to some protected members of the {@link WindowContainer} class */ - private class TestWindowContainer extends WindowContainer<TestWindowContainer> { + private static class TestWindowContainer extends WindowContainer<TestWindowContainer> { private final int mLayer; private boolean mIsAnimating; private boolean mIsVisible; @@ -745,7 +739,7 @@ public class WindowContainerTests extends WindowTestsBase { * Compares 2 window layers and returns -1 if the first is lesser than the second in terms * of z-order and 1 otherwise. */ - private final Comparator<TestWindowContainer> mWindowSubLayerComparator = (w1, w2) -> { + private static final Comparator<TestWindowContainer> SUBLAYER_COMPARATOR = (w1, w2) -> { final int layer1 = w1.mLayer; final int layer2 = w2.mLayer; if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) { @@ -753,12 +747,14 @@ public class WindowContainerTests extends WindowTestsBase { // the negative one should go below others; the positive one should go above others. return -1; } + if (layer1 == layer2) return 0; return 1; }; - TestWindowContainer(int layer, boolean isAnimating, boolean isVisible, - Integer orientation) { - super(sWm); + TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating, + boolean isVisible, Integer orientation) { + super(wm); + mLayer = layer; mIsAnimating = isAnimating; mIsVisible = isVisible; @@ -775,18 +771,18 @@ public class WindowContainerTests extends WindowTestsBase { } TestWindowContainer addChildWindow(TestWindowContainer child) { - addChild(child, mWindowSubLayerComparator); + addChild(child, SUBLAYER_COMPARATOR); return child; } TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) { TestWindowContainer child = childBuilder.build(); - addChild(child, mWindowSubLayerComparator); + addChild(child, SUBLAYER_COMPARATOR); return child; } TestWindowContainer addChildWindow() { - return addChildWindow(new TestWindowContainerBuilder().setLayer(1)); + return addChildWindow(new TestWindowContainerBuilder(mService).setLayer(1)); } @Override @@ -830,14 +826,19 @@ public class WindowContainerTests extends WindowTestsBase { } } - private class TestWindowContainerBuilder { + private static class TestWindowContainerBuilder { + private final WindowManagerService mWm; private int mLayer; private boolean mIsAnimating; private boolean mIsVisible; private Integer mOrientation; - public TestWindowContainerBuilder() { - reset(); + TestWindowContainerBuilder(WindowManagerService wm) { + mWm = wm; + mLayer = 0; + mIsAnimating = false; + mIsVisible = false; + mOrientation = null; } TestWindowContainerBuilder setLayer(int layer) { @@ -860,27 +861,20 @@ public class WindowContainerTests extends WindowTestsBase { return this; } - TestWindowContainerBuilder reset() { - mLayer = 0; - mIsAnimating = false; - mIsVisible = false; - mOrientation = null; - return this; - } - TestWindowContainer build() { - return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible, mOrientation); + return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible, mOrientation); } } - private class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer> { - final SurfaceSession mSession = new SurfaceSession(); + private static class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer> + implements AutoCloseable { + private final SurfaceSession mSession = new SurfaceSession(); - MockSurfaceBuildingContainer() { - super(sWm); + MockSurfaceBuildingContainer(WindowManagerService wm) { + super(wm); } - class MockSurfaceBuilder extends SurfaceControl.Builder { + static class MockSurfaceBuilder extends SurfaceControl.Builder { MockSurfaceBuilder(SurfaceSession ss) { super(ss); } @@ -895,5 +889,10 @@ public class WindowContainerTests extends WindowTestsBase { SurfaceControl.Builder makeChildSurface(WindowContainer child) { return new MockSurfaceBuilder(mSession); } + + @Override + public void close() { + mSession.kill(); + } } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java index ffc86226cd39..2b8b93428701 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -28,23 +28,23 @@ import static org.mockito.Mockito.verify; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.function.Consumer; /** * Tests for {@link WindowContainer#forAllWindows} and various implementations. + * + * Build/Install/Run: + * atest FrameworksServicesTests:WindowContainerTraversalTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class WindowContainerTraversalTests extends WindowTestsBase { @Test - public void testDockedDividerPosition() throws Exception { + public void testDockedDividerPosition() { final WindowState splitScreenWindow = createWindowOnStack(null, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenWindow"); @@ -52,7 +52,7 @@ public class WindowContainerTraversalTests extends WindowTestsBase { WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow"); - sWm.mInputMethodTarget = splitScreenWindow; + mWm.mInputMethodTarget = splitScreenWindow; Consumer<WindowState> c = mock(Consumer.class); mDisplayContent.forAllWindows(c, false); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java index 7cd131420049..b0c8d8bfee1b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java @@ -11,14 +11,14 @@ * 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 + * limitations under the License. */ package com.android.server.wm; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; -import static android.view.WindowManager.LayoutParams.FILL_PARENT; +import static android.view.WindowManager.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static org.junit.Assert.assertEquals; @@ -33,33 +33,32 @@ import android.view.IWindow; import android.view.WindowManager; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery. * - * Build/Install/Run: bit FrameworksServicesTests:com.android.server.wm.WindowFrameTests + * Build/Install/Run: + * atest FrameworksServicesTests:WindowFrameTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class WindowFrameTests extends WindowTestsBase { private WindowToken mWindowToken; private final IWindow mIWindow = new TestIWindow(); private final Rect mEmptyRect = new Rect(); - class WindowStateWithTask extends WindowState { + static class WindowStateWithTask extends WindowState { final Task mTask; boolean mDockedResizingForTest = false; - WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) { - super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0, + WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken, + WindowManager.LayoutParams attrs, Task t) { + super(wm, null, iWindow, windowToken, null, 0, 0, attrs, 0, 0, false /* ownerCanAddInternalSystemWindow */); mTask = t; } @@ -73,14 +72,15 @@ public class WindowFrameTests extends WindowTestsBase { boolean isDockedResizing() { return mDockedResizingForTest; } - }; + } - class TaskWithBounds extends Task { + private static class TaskWithBounds extends Task { final Rect mBounds; final Rect mInsetBounds = new Rect(); boolean mFullscreenForTest = true; - TaskWithBounds(Rect bounds) { - super(0, mStubStack, 0, sWm, 0, false, new TaskDescription(), null); + + TaskWithBounds(TaskStack stack, WindowManagerService wm, Rect bounds) { + super(0, stack, 0, wm, 0, false, new TaskDescription(), null); mBounds = bounds; setBounds(bounds); } @@ -113,14 +113,12 @@ public class WindowFrameTests extends WindowTestsBase { @Before public void setUp() throws Exception { - super.setUp(); - // Just any non zero value. - sWm.mSystemDecorLayer = 10000; + mWm.mSystemDecorLayer = 10000; mWindowToken = WindowTestUtils.createTestAppWindowToken( - sWm.getDefaultDisplayContentLocked()); - mStubStack = new TaskStack(sWm, 0, null); + mWm.getDefaultDisplayContentLocked()); + mStubStack = new TaskStack(mWm, 0, null); } // Do not use this function directly in the tests below. Instead, use more explicit function @@ -170,9 +168,10 @@ public class WindowFrameTests extends WindowTestsBase { } @Test - public void testLayoutInFullscreenTaskInsets() throws Exception { - Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame - WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); + public void testLayoutInFullscreenTaskInsets() { + // fullscreen task doesn't use bounds for computeFrame + final Task task = new TaskWithBounds(mStubStack, mWm, null); + WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; final int bottomContentInset = 100; @@ -227,9 +226,10 @@ public class WindowFrameTests extends WindowTestsBase { } @Test - public void testLayoutInFullscreenTaskNoInsets() throws Exception { - Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame - WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); + public void testLayoutInFullscreenTaskNoInsets() { + // fullscreen task doesn't use bounds for computeFrame + final Task task = new TaskWithBounds(mStubStack, mWm, null); + WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; // With no insets or system decor all the frames incoming from PhoneWindowManager @@ -307,7 +307,7 @@ public class WindowFrameTests extends WindowTestsBase { @Test public void testLayoutNonfullscreenTask() { - final DisplayInfo displayInfo = sWm.getDefaultDisplayContentLocked().getDisplayInfo(); + final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo(); final int logicalWidth = displayInfo.logicalWidth; final int logicalHeight = displayInfo.logicalHeight; @@ -316,9 +316,9 @@ public class WindowFrameTests extends WindowTestsBase { final int taskRight = logicalWidth / 4 * 3; final int taskBottom = logicalHeight / 4 * 3; final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom); - TaskWithBounds task = new TaskWithBounds(taskBounds); + final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds); task.mFullscreenForTest = false; - WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); + WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); @@ -367,7 +367,7 @@ public class WindowFrameTests extends WindowTestsBase { @Test public void testCalculatePolicyCrop() { final WindowStateWithTask w = createWindow( - new TaskWithBounds(null), FILL_PARENT, FILL_PARENT); + new TaskWithBounds(mStubStack, mWm, null), MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo(); @@ -423,7 +423,7 @@ public class WindowFrameTests extends WindowTestsBase { @Test public void testLayoutLetterboxedWindow() { // First verify task behavior in multi-window mode. - final DisplayInfo displayInfo = sWm.getDefaultDisplayContentLocked().getDisplayInfo(); + final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo(); final int logicalWidth = displayInfo.logicalWidth; final int logicalHeight = displayInfo.logicalHeight; @@ -432,10 +432,10 @@ public class WindowFrameTests extends WindowTestsBase { final int taskRight = logicalWidth / 4 * 3; final int taskBottom = logicalHeight / 4 * 3; final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom); - TaskWithBounds task = new TaskWithBounds(taskBounds); + final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds); task.mInsetBounds.set(taskLeft, taskTop, taskRight, taskBottom); task.mFullscreenForTest = false; - WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); + WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); @@ -467,8 +467,8 @@ public class WindowFrameTests extends WindowTestsBase { @Test public void testDisplayCutout() { // Regular fullscreen task and window - Task task = new TaskWithBounds(null); - WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); + final Task task = new TaskWithBounds(mStubStack, mWm, null); + WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; final Rect pf = new Rect(0, 0, 1000, 2000); @@ -491,10 +491,11 @@ public class WindowFrameTests extends WindowTestsBase { @Test public void testDisplayCutout_tempInsetBounds() { // Regular fullscreen task and window - TaskWithBounds task = new TaskWithBounds(new Rect(0, -500, 1000, 1500)); + final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, + new Rect(0, -500, 1000, 1500)); task.mFullscreenForTest = false; task.mInsetBounds.set(0, 0, 1000, 2000); - WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT); + WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; final Rect pf = new Rect(0, -500, 1000, 1500); @@ -519,7 +520,6 @@ public class WindowFrameTests extends WindowTestsBase { attrs.width = width; attrs.height = height; - return new WindowStateWithTask(attrs, task); + return new WindowStateWithTask(mWm, mIWindow, mWindowToken, attrs, task); } - } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java index 012c4be75fe5..4e75ec9e8348 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java @@ -19,6 +19,8 @@ package com.android.server.wm; import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; import static android.view.Display.DEFAULT_DISPLAY; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static org.mockito.ArgumentMatchers.any; @@ -51,8 +53,6 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -import androidx.test.InstrumentationRegistry; - /** * A test rule that sets up a fresh WindowManagerService instance before each test and makes sure * to properly tear it down after. @@ -89,7 +89,7 @@ public class WindowManagerServiceRule implements TestRule { } private void setUp() { - final Context context = InstrumentationRegistry.getTargetContext(); + final Context context = getInstrumentation().getTargetContext(); removeServices(); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java index 570a853a62ca..343d35959df4 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java @@ -22,13 +22,14 @@ import static org.junit.Assert.assertThat; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +/** + * Build/InstallRun: + * atest FrameworksServicesTests:WindowManagerServiceRuleTest + */ @Presubmit @SmallTest public class WindowManagerServiceRuleTest { @@ -40,4 +41,4 @@ public class WindowManagerServiceRuleTest { public void testWindowManagerSetUp() { assertThat(mRule.getWindowManagerService(), notNullValue()); } -}
\ No newline at end of file +} diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java index 3637baf13c72..118ce8962259 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -58,32 +58,28 @@ import android.view.DisplayCutout; import android.view.SurfaceControl; import android.view.WindowManager; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; + import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Test; -import org.junit.runner.RunWith; -import java.util.Arrays; import java.util.LinkedList; -import androidx.test.filters.FlakyTest; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - /** * Tests for the {@link WindowState} class. * - * atest FrameworksServicesTests:com.android.server.wm.WindowStateTests + * Build/Install/Run: + * atest FrameworksServicesTests:WindowStateTests */ -@SmallTest @FlakyTest(bugId = 74078662) -// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed. -// @Presubmit -@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit public class WindowStateTests extends WindowTestsBase { @Test - public void testIsParentWindowHidden() throws Exception { + public void testIsParentWindowHidden() { final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow"); final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1"); final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2"); @@ -98,11 +94,10 @@ public class WindowStateTests extends WindowTestsBase { assertFalse(parentWindow.isParentWindowHidden()); assertFalse(child1.isParentWindowHidden()); assertFalse(child2.isParentWindowHidden()); - } @Test - public void testIsChildWindow() throws Exception { + public void testIsChildWindow() { final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow"); final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1"); final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2"); @@ -115,7 +110,7 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testHasChild() throws Exception { + public void testHasChild() { final WindowState win1 = createWindow(null, TYPE_APPLICATION, "win1"); final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW, "win11"); final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW, "win12"); @@ -136,7 +131,7 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testGetParentWindow() throws Exception { + public void testGetParentWindow() { final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow"); final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1"); final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2"); @@ -157,7 +152,7 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testGetTopParentWindow() throws Exception { + public void testGetTopParentWindow() { final WindowState root = createWindow(null, TYPE_APPLICATION, "root"); final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1"); final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, "child2"); @@ -183,7 +178,7 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testCanBeImeTarget() throws Exception { + public void testCanBeImeTarget() { final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow"); final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, "imeWindow"); @@ -219,7 +214,7 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testGetWindow() throws Exception { + public void testGetWindow() { final WindowState root = createWindow(null, TYPE_APPLICATION, "root"); final WindowState mediaChild = createWindow(root, TYPE_APPLICATION_MEDIA, "mediaChild"); final WindowState mediaOverlayChild = createWindow(root, @@ -231,7 +226,7 @@ public class WindowStateTests extends WindowTestsBase { final WindowState aboveSubPanelChild = createWindow(root, TYPE_APPLICATION_ABOVE_SUB_PANEL, "aboveSubPanelChild"); - final LinkedList<WindowState> windows = new LinkedList(); + final LinkedList<WindowState> windows = new LinkedList<>(); root.getWindow(w -> { windows.addLast(w); @@ -249,7 +244,7 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testPrepareWindowToDisplayDuringRelayout() throws Exception { + public void testPrepareWindowToDisplayDuringRelayout() { testPrepareWindowToDisplayDuringRelayout(false /*wasVisible*/); testPrepareWindowToDisplayDuringRelayout(true /*wasVisible*/); @@ -262,14 +257,14 @@ public class WindowStateTests extends WindowTestsBase { final WindowState second = createWindow(null, TYPE_APPLICATION, appWindowToken, "second"); second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; - reset(mPowerManagerWrapper); + reset(sPowerManagerWrapper); first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/); - verify(mPowerManagerWrapper, never()).wakeUp(anyLong(), anyString()); + verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyString()); assertTrue(appWindowToken.canTurnScreenOn()); - reset(mPowerManagerWrapper); + reset(sPowerManagerWrapper); second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/); - verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString()); + verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString()); assertFalse(appWindowToken.canTurnScreenOn()); // Call prepareWindowToDisplayDuringRelayout for two window that have FLAG_TURN_SCREEN_ON @@ -278,14 +273,14 @@ public class WindowStateTests extends WindowTestsBase { first.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; - reset(mPowerManagerWrapper); + reset(sPowerManagerWrapper); first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/); - verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString()); + verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString()); assertFalse(appWindowToken.canTurnScreenOn()); - reset(mPowerManagerWrapper); + reset(sPowerManagerWrapper); second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/); - verify(mPowerManagerWrapper, never()).wakeUp(anyLong(), anyString()); + verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyString()); assertFalse(appWindowToken.canTurnScreenOn()); // Call prepareWindowToDisplayDuringRelayout for a windows that are not children of an @@ -299,17 +294,17 @@ public class WindowStateTests extends WindowTestsBase { firstWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; secondWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; - reset(mPowerManagerWrapper); + reset(sPowerManagerWrapper); firstWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/); - verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString()); + verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString()); - reset(mPowerManagerWrapper); + reset(sPowerManagerWrapper); secondWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/); - verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString()); + verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString()); } @Test - public void testCanAffectSystemUiFlags() throws Exception { + public void testCanAffectSystemUiFlags() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); app.mToken.setHidden(false); assertTrue(app.canAffectSystemUiFlags()); @@ -318,11 +313,10 @@ public class WindowStateTests extends WindowTestsBase { app.mToken.setHidden(false); app.mAttrs.alpha = 0.0f; assertFalse(app.canAffectSystemUiFlags()); - } @Test - public void testCanAffectSystemUiFlags_disallow() throws Exception { + public void testCanAffectSystemUiFlags_disallow() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); app.mToken.setHidden(false); assertTrue(app.canAffectSystemUiFlags()); @@ -331,7 +325,7 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testIsSelfOrAncestorWindowAnimating() throws Exception { + public void testIsSelfOrAncestorWindowAnimating() { final WindowState root = createWindow(null, TYPE_APPLICATION, "root"); final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1"); final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, "child2"); @@ -344,7 +338,7 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testLayoutSeqResetOnReparent() throws Exception { + public void testLayoutSeqResetOnReparent() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); app.mLayoutSeq = 1; mDisplayContent.mLayoutSeq = 1; @@ -355,7 +349,7 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testDisplayIdUpdatedOnReparent() throws Exception { + public void testDisplayIdUpdatedOnReparent() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); // fake a different display app.mInputWindowHandle.displayId = mDisplayContent.getDisplayId() + 1; @@ -418,11 +412,11 @@ public class WindowStateTests extends WindowTestsBase { } private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) { - reset(mPowerManagerWrapper); + reset(sPowerManagerWrapper); final WindowState root = createWindow(null, TYPE_APPLICATION, "root"); root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/); - verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString()); + verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString()); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java index a1b164065696..9e12f020d06e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java @@ -11,38 +11,39 @@ * 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 + * limitations under the License. */ package com.android.server.wm; -import android.app.ActivityManager; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Rect; -import android.os.Binder; -import android.os.IBinder; -import android.view.Display; -import android.view.IApplicationToken; -import android.view.IWindow; -import android.view.Surface; -import android.view.SurfaceControl; -import android.view.SurfaceControl.Transaction; -import android.view.WindowManager; - import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static com.android.server.wm.WindowContainer.POSITION_TOP; + import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyFloat; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import android.app.ActivityManager; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.os.Binder; +import android.os.IBinder; +import android.view.Display; +import android.view.IApplicationToken; +import android.view.IWindow; +import android.view.Surface; +import android.view.SurfaceControl.Transaction; +import android.view.WindowManager; + import org.mockito.invocation.InvocationOnMock; /** @@ -50,15 +51,13 @@ import org.mockito.invocation.InvocationOnMock; * to WindowManager related test functionality. */ public class WindowTestUtils { - public static int sNextTaskId = 0; + private static int sNextTaskId = 0; - /** - * Retrieves an instance of a mock {@link WindowManagerService}. - */ - public static WindowManagerService getMockWindowManagerService() { + /** Retrieves an instance of a mock {@link WindowManagerService}. */ + static WindowManagerService getMockWindowManagerService() { final WindowManagerService service = mock(WindowManagerService.class); - final WindowHashMap windowMap = new WindowHashMap(); - when(service.getWindowManagerLock()).thenReturn(windowMap); + final WindowManagerGlobalLock lock = new WindowManagerGlobalLock(); + doReturn(lock).when(service).getWindowManagerLock(); return service; } @@ -116,7 +115,7 @@ public class WindowTestUtils { /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */ public static Task createTaskInStack(WindowManagerService service, TaskStack stack, int userId) { - synchronized (service.mWindowMap) { + synchronized (service.mGlobalLock) { final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false, new ActivityManager.TaskDescription(), null); stack.addTask(newTask, POSITION_TOP); @@ -140,7 +139,7 @@ public class WindowTestUtils { } static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) { - synchronized (dc.mService.mWindowMap) { + synchronized (dc.mService.mGlobalLock) { return new TestAppWindowToken(dc); } } @@ -213,7 +212,7 @@ public class WindowTestUtils { static TestWindowToken createTestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { - synchronized (dc.mService.mWindowMap) { + synchronized (dc.mService.mGlobalLock) { return new TestWindowToken(type, dc, persistOnEmpty); } } @@ -278,35 +277,33 @@ public class WindowTestUtils { */ public static class TestTaskWindowContainerController extends TaskWindowContainerController { - TestTaskWindowContainerController(WindowTestsBase testsBase) { - this(testsBase.createStackControllerOnDisplay(testsBase.mDisplayContent)); - } - - TestTaskWindowContainerController(StackWindowController stackController) { - super(sNextTaskId++, new TaskWindowContainerListener() { - @Override - public void registerConfigurationChangeListener( - ConfigurationContainerListener listener) { - - } + static final TaskWindowContainerListener NOP_LISTENER = new TaskWindowContainerListener() { + @Override + public void registerConfigurationChangeListener( + ConfigurationContainerListener listener) { + } - @Override - public void unregisterConfigurationChangeListener( - ConfigurationContainerListener listener) { + @Override + public void unregisterConfigurationChangeListener( + ConfigurationContainerListener listener) { + } - } + @Override + public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { + } - @Override - public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) { + @Override + public void requestResize(Rect bounds, int resizeMode) { + } + }; - } - - @Override - public void requestResize(Rect bounds, int resizeMode) { + TestTaskWindowContainerController(WindowTestsBase testsBase) { + this(testsBase.createStackControllerOnDisplay(testsBase.mDisplayContent)); + } - } - }, stackController, 0 /* userId */, null /* bounds */, RESIZE_MODE_UNRESIZEABLE, - false /* supportsPictureInPicture */, true /* toTop*/, + TestTaskWindowContainerController(StackWindowController stackController) { + super(sNextTaskId++, NOP_LISTENER, stackController, 0 /* userId */, null /* bounds */, + RESIZE_MODE_UNRESIZEABLE, false /* supportsPictureInPicture */, true /* toTop*/, true /* showForAllUsers */, new ActivityManager.TaskDescription(), stackController.mService); } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java index dcfe55602e81..945cbb91b029 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -35,6 +35,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static org.mockito.Mockito.mock; import android.content.Context; @@ -52,13 +54,12 @@ import com.android.server.AttributeCache; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Rule; import java.util.HashSet; import java.util.LinkedList; -import androidx.test.InstrumentationRegistry; - /** * Common base class for window manager unit test classes. * @@ -66,7 +67,8 @@ import androidx.test.InstrumentationRegistry; */ class WindowTestsBase { private static final String TAG = WindowTestsBase.class.getSimpleName(); - WindowManagerService sWm = null; // TODO(roosa): rename to mWm in follow-up CL + + WindowManagerService mWm; private final IWindow mIWindow = new TestIWindow(); private Session mMockSession; // The default display is removed in {@link #setUp} and then we iterate over all displays to @@ -97,32 +99,36 @@ class WindowTestsBase { @Rule public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule(); - static WindowState.PowerManagerWrapper mPowerManagerWrapper; // TODO(roosa): make non-static. + static WindowState.PowerManagerWrapper sPowerManagerWrapper; // TODO(roosa): make non-static. + + @BeforeClass + public static void setUpOnceBase() { + AttributeCache.init(getInstrumentation().getTargetContext()); + sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); + } @Before - public void setUp() throws Exception { + public void setUpBase() { // If @Before throws an exception, the error isn't logged. This will make sure any failures // in the set up are clear. This can be removed when b/37850063 is fixed. try { mMockSession = mock(Session.class); - mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); - final Context context = InstrumentationRegistry.getTargetContext(); - AttributeCache.init(context); + final Context context = getInstrumentation().getTargetContext(); - sWm = mWmRule.getWindowManagerService(); + mWm = mWmRule.getWindowManagerService(); beforeCreateDisplay(); - mWallpaperController = new WallpaperController(sWm); + mWallpaperController = new WallpaperController(mWm); context.getDisplay().getDisplayInfo(mDisplayInfo); mDisplayContent = createNewDisplay(); - sWm.mDisplayEnabled = true; - sWm.mDisplayReady = true; + mWm.mDisplayEnabled = true; + mWm.mDisplayReady = true; // Set-up some common windows. - mCommonWindows = new HashSet(); - synchronized (sWm.mWindowMap) { + mCommonWindows = new HashSet<>(); + synchronized (mWm.mGlobalLock) { mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow"); mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow"); mDisplayContent.mInputMethodWindow = mImeWindow; @@ -154,7 +160,7 @@ class WindowTestsBase { } @After - public void tearDown() throws Exception { + public void tearDownBase() { // If @After throws an exception, the error isn't logged. This will make sure any failures // in the tear down are clear. This can be removed when b/37850063 is fixed. try { @@ -164,8 +170,8 @@ class WindowTestsBase { final LinkedList<WindowState> nonCommonWindows = new LinkedList<>(); - synchronized (sWm.mWindowMap) { - sWm.mRoot.forAllWindows(w -> { + synchronized (mWm.mGlobalLock) { + mWm.mRoot.forAllWindows(w -> { if (!mCommonWindows.contains(w)) { nonCommonWindows.addLast(w); } @@ -175,18 +181,18 @@ class WindowTestsBase { nonCommonWindows.pollLast().removeImmediately(); } - for (int i = sWm.mRoot.mChildren.size() - 1; i >= 0; --i) { - final DisplayContent displayContent = sWm.mRoot.mChildren.get(i); + for (int i = mWm.mRoot.mChildren.size() - 1; i >= 0; --i) { + final DisplayContent displayContent = mWm.mRoot.mChildren.get(i); if (!displayContent.isDefaultDisplay) { displayContent.removeImmediately(); } } // Remove app transition & window freeze timeout callbacks to prevent unnecessary // actions after test. - sWm.getDefaultDisplayContentLocked().mAppTransition + mWm.getDefaultDisplayContentLocked().mAppTransition .removeAppTransitionTimeoutCallbacks(); - sWm.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT); - sWm.mInputMethodTarget = null; + mWm.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT); + mWm.mInputMethodTarget = null; } // Wait until everything is really cleaned up. @@ -198,7 +204,7 @@ class WindowTestsBase { } private WindowState createCommonWindow(WindowState parent, int type, String name) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { final WindowState win = createWindow(parent, type, name); mCommonWindows.add(win); // Prevent common windows from been IMe targets @@ -216,7 +222,7 @@ class WindowTestsBase { private WindowToken createWindowToken( DisplayContent dc, int windowingMode, int activityType, int type) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) { return WindowTestUtils.createTestWindowToken(type, dc); } @@ -241,7 +247,7 @@ class WindowTestsBase { } WindowState createWindow(WindowState parent, int type, String name) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { return (parent == null) ? createWindow(parent, type, mDisplayContent, name) : createWindow(parent, type, parent.mToken, name); @@ -250,14 +256,14 @@ class WindowTestsBase { WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType, int type, DisplayContent dc, String name) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { final WindowToken token = createWindowToken(dc, windowingMode, activityType, type); return createWindow(parent, type, token, name); } } WindowState createAppWindow(Task task, int type, String name) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent); task.addChild(token, 0); return createWindow(null, type, token, name); @@ -265,7 +271,7 @@ class WindowTestsBase { } WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { final WindowToken token = createWindowToken( dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type); return createWindow(parent, type, token, name); @@ -274,7 +280,7 @@ class WindowTestsBase { WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name, boolean ownerCanAddInternalSystemWindow) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { final WindowToken token = createWindowToken( dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type); return createWindow(parent, type, token, name, 0 /* ownerId */, @@ -283,7 +289,7 @@ class WindowTestsBase { } WindowState createWindow(WindowState parent, int type, WindowToken token, String name) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { return createWindow(parent, type, token, name, 0 /* ownerId */, false /* ownerCanAddInternalSystemWindow */); } @@ -292,20 +298,20 @@ class WindowTestsBase { WindowState createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow) { return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow, - sWm, mMockSession, mIWindow); + mWm, mMockSession, mIWindow); } static WindowState createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow, WindowManagerService service, Session session, IWindow iWindow) { - synchronized (service.mWindowMap) { + synchronized (service.mGlobalLock) { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type); attrs.setTitle(name); final WindowState w = new WindowState(service, session, iWindow, token, parent, OP_NONE, 0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, - mPowerManagerWrapper); + sPowerManagerWrapper); // TODO: Probably better to make this call in the WindowState ctor to avoid errors with // adding it to the token... token.addWindow(w); @@ -315,13 +321,13 @@ class WindowTestsBase { /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */ TaskStack createTaskStackOnDisplay(DisplayContent dc) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { return createStackControllerOnDisplay(dc).mContainer; } } StackWindowController createStackControllerOnDisplay(DisplayContent dc) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { return createStackControllerOnStackOnDisplay( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc); } @@ -329,13 +335,13 @@ class WindowTestsBase { StackWindowController createStackControllerOnStackOnDisplay( int windowingMode, int activityType, DisplayContent dc) { - synchronized (sWm.mWindowMap) { + synchronized (mWm.mGlobalLock) { final Configuration overrideConfig = new Configuration(); overrideConfig.windowConfiguration.setWindowingMode(windowingMode); overrideConfig.windowConfiguration.setActivityType(activityType); final int stackId = ++sNextStackId; final StackWindowController controller = new StackWindowController(stackId, null, - dc.getDisplayId(), true /* onTop */, new Rect(), sWm); + dc.getDisplayId(), true /* onTop */, new Rect(), mWm); controller.onOverrideConfigurationChanged(overrideConfig); return controller; } @@ -343,7 +349,7 @@ class WindowTestsBase { /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */ Task createTaskInStack(TaskStack stack, int userId) { - return WindowTestUtils.createTaskInStack(sWm, stack, userId); + return WindowTestUtils.createTaskInStack(mWm, stack, userId); } /** Creates a {@link DisplayContent} and adds it to the system. */ @@ -351,8 +357,8 @@ class WindowTestsBase { final int displayId = sNextDisplayId++; final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS); - synchronized (sWm.mWindowMap) { - return new DisplayContent(display, sWm, mWallpaperController, + synchronized (mWm.mGlobalLock) { + return new DisplayContent(display, mWm, mWallpaperController, mock(DisplayWindowController.class)); } } @@ -375,20 +381,19 @@ class WindowTestsBase { final int displayId = sNextDisplayId++; final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS); - final DisplayWindowController dcw = new DisplayWindowController(display, sWm); - synchronized (sWm.mWindowMap) { + final DisplayWindowController dcw = new DisplayWindowController(display, mWm); + synchronized (mWm.mGlobalLock) { // Display creation is driven by DisplayWindowController via ActivityStackSupervisor. // We skip those steps here. - return sWm.mRoot.createDisplayContent(display, dcw); + return mWm.mRoot.createDisplayContent(display, dcw); } } /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */ WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs, WindowToken token) { - synchronized (sWm.mWindowMap) { - return new WindowTestUtils.TestWindowState(sWm, mMockSession, mIWindow, attrs, token); + synchronized (mWm.mGlobalLock) { + return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token); } } - } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java index 3732486f4a07..3048f1a3487b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -30,25 +30,22 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link WindowToken} class. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests + * atest FrameworksServicesTests:WindowTokenTests */ -@SmallTest @FlakyTest(bugId = 74078662) +@SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class WindowTokenTests extends WindowTestsBase { @Test - public void testAddWindow() throws Exception { + public void testAddWindow() { final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(0, mDisplayContent); @@ -78,7 +75,7 @@ public class WindowTokenTests extends WindowTestsBase { } @Test - public void testChildRemoval() throws Exception { + public void testChildRemoval() { final DisplayContent dc = mDisplayContent; final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(0, dc); @@ -102,7 +99,7 @@ public class WindowTokenTests extends WindowTestsBase { * Tokens should only be removed from the system when all their windows are gone. */ @Test - public void testTokenRemovalProcess() throws Exception { + public void testTokenRemovalProcess() { final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken( TYPE_TOAST, mDisplayContent, true /* persistOnEmpty */); diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java index 3a8c4ae73493..32e4e0265193 100644 --- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -38,27 +38,30 @@ import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.SurfaceSession; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; + import org.junit.After; import org.junit.Test; import java.util.HashMap; import java.util.LinkedList; -import androidx.test.filters.FlakyTest; -import androidx.test.filters.SmallTest; - /** - * Tests for the {@link WindowLayersController} class. + * Tests for the {@link DisplayContent#assignChildLayers(SurfaceControl.Transaction)} method. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.ZOrderingTests + * atest FrameworksServicesTests:ZOrderingTests */ -@SmallTest @FlakyTest(bugId = 74078662) +@SmallTest @Presubmit public class ZOrderingTests extends WindowTestsBase { - private class LayerRecordingTransaction extends SurfaceControl.Transaction { + private static class LayerRecordingTransaction extends SurfaceControl.Transaction { + // We have WM use our Hierarchy recording subclass of SurfaceControl.Builder + // such that we can keep track of the parents of Surfaces as they are constructed. + private final HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>(); HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap<>(); HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap<>(); @@ -85,17 +88,28 @@ public class ZOrderingTests extends WindowTestsBase { private SurfaceControl getRelativeLayer(SurfaceControl sc) { return mRelativeLayersForControl.get(sc); } - } - // We have WM use our Hierarchy recording subclass of SurfaceControl.Builder - // such that we can keep track of the parents of Surfaces as they are constructed. - private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>(); + void addParentFor(SurfaceControl child, SurfaceControl parent) { + mParentFor.put(child, parent); + } - private class HierarchyRecorder extends SurfaceControl.Builder { - SurfaceControl mPendingParent; + SurfaceControl getParentFor(SurfaceControl child) { + return mParentFor.get(child); + } - HierarchyRecorder(SurfaceSession s) { + @Override + public void close() { + + } + } + + private static class HierarchyRecorder extends SurfaceControl.Builder { + private LayerRecordingTransaction mTransaction; + private SurfaceControl mPendingParent; + + HierarchyRecorder(SurfaceSession s, LayerRecordingTransaction transaction) { super(s); + mTransaction = transaction; } @Override @@ -106,16 +120,26 @@ public class ZOrderingTests extends WindowTestsBase { @Override public SurfaceControl build() { - SurfaceControl sc = super.build(); - mParentFor.put(sc, mPendingParent); + final SurfaceControl sc = super.build(); + mTransaction.addParentFor(sc, mPendingParent); + mTransaction = null; mPendingParent = null; return sc; } } - private class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory { + private static class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory { + private LayerRecordingTransaction mTransaction; + + HierarchyRecordingBuilderFactory(LayerRecordingTransaction transaction) { + mTransaction = transaction; + } + + @Override public SurfaceControl.Builder make(SurfaceSession s) { - return new HierarchyRecorder(s); + final LayerRecordingTransaction transaction = mTransaction; + mTransaction = null; + return new HierarchyRecorder(s, transaction); } } @@ -127,18 +151,17 @@ public class ZOrderingTests extends WindowTestsBase { // which is after construction of the DisplayContent, meaning the HierarchyRecorder // would miss construction of the top-level layers. mTransaction = new LayerRecordingTransaction(); - sWm.mSurfaceBuilderFactory = new HierarchyRecordingBuilderFactory(); - sWm.mTransactionFactory = () -> mTransaction; + mWm.mSurfaceBuilderFactory = new HierarchyRecordingBuilderFactory(mTransaction); + mWm.mTransactionFactory = () -> mTransaction; } @After - public void after() { + public void tearDown() { mTransaction.close(); - mParentFor.keySet().forEach(SurfaceControl::destroy); - mParentFor.clear(); } - LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t, SurfaceControl sc) { + private static LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t, + SurfaceControl sc) { LinkedList<SurfaceControl> p = new LinkedList<>(); SurfaceControl current = sc; do { @@ -148,23 +171,22 @@ public class ZOrderingTests extends WindowTestsBase { if (rs != null) { current = rs; } else { - current = mParentFor.get(current); + current = t.getParentFor(current); } } while (current != null); return p; } - void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left, + private static void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left, SurfaceControl right) { final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left); final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right); - SurfaceControl commonAncestor = null; SurfaceControl leftTop = leftParentChain.peekLast(); SurfaceControl rightTop = rightParentChain.peekLast(); while (leftTop != null && rightTop != null && leftTop == rightTop) { - commonAncestor = leftParentChain.removeLast(); + leftParentChain.removeLast(); rightParentChain.removeLast(); leftTop = leftParentChain.peekLast(); rightTop = rightParentChain.peekLast(); @@ -189,7 +211,7 @@ public class ZOrderingTests extends WindowTestsBase { @Test public void testAssignWindowLayers_ForImeWithNoTarget() { - sWm.mInputMethodTarget = null; + mWm.mInputMethodTarget = null; mDisplayContent.assignChildLayers(mTransaction); // The Ime has an higher base layer than app windows and lower base layer than system @@ -207,7 +229,7 @@ public class ZOrderingTests extends WindowTestsBase { @Test public void testAssignWindowLayers_ForImeWithAppTarget() { final WindowState imeAppTarget = createWindow("imeAppTarget"); - sWm.mInputMethodTarget = imeAppTarget; + mWm.mInputMethodTarget = imeAppTarget; mDisplayContent.assignChildLayers(mTransaction); @@ -233,7 +255,7 @@ public class ZOrderingTests extends WindowTestsBase { TYPE_APPLICATION_MEDIA_OVERLAY, imeAppTarget.mToken, "imeAppTargetChildBelowWindow"); - sWm.mInputMethodTarget = imeAppTarget; + mWm.mInputMethodTarget = imeAppTarget; mDisplayContent.assignChildLayers(mTransaction); // Ime should be above all app windows except for child windows that are z-ordered above it @@ -255,7 +277,7 @@ public class ZOrderingTests extends WindowTestsBase { final WindowState imeAppTarget = createWindow("imeAppTarget"); final WindowState appAboveImeTarget = createWindow("appAboveImeTarget"); - sWm.mInputMethodTarget = imeAppTarget; + mWm.mInputMethodTarget = imeAppTarget; mDisplayContent.assignChildLayers(mTransaction); // Ime should be above all app windows except for non-fullscreen app window above it and @@ -278,7 +300,7 @@ public class ZOrderingTests extends WindowTestsBase { mDisplayContent, "imeSystemOverlayTarget", true /* ownerCanAddInternalSystemWindow */); - sWm.mInputMethodTarget = imeSystemOverlayTarget; + mWm.mInputMethodTarget = imeSystemOverlayTarget; mDisplayContent.assignChildLayers(mTransaction); // The IME target base layer is higher than all window except for the nav bar window, so the @@ -301,7 +323,7 @@ public class ZOrderingTests extends WindowTestsBase { @Test public void testAssignWindowLayers_ForStatusBarImeTarget() { - sWm.mInputMethodTarget = mStatusBarWindow; + mWm.mInputMethodTarget = mStatusBarWindow; mDisplayContent.assignChildLayers(mTransaction); assertWindowHigher(mImeWindow, mChildAppWindowAbove); @@ -322,8 +344,8 @@ public class ZOrderingTests extends WindowTestsBase { final WindowState dockedStackWindow = createWindowOnStack(null, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent, "dockedStackWindow"); - final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION, + final WindowState assistantStackWindow = createWindowOnStack(null, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION, mDisplayContent, "assistantStackWindow"); final WindowState homeActivityWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, TYPE_BASE_APPLICATION, @@ -368,7 +390,8 @@ public class ZOrderingTests extends WindowTestsBase { final WindowState anyWindow = createWindow("anyWindow"); final WindowState child = createWindow(anyWindow, TYPE_APPLICATION_MEDIA, mDisplayContent, "TypeApplicationMediaChild"); - final WindowState mediaOverlayChild = createWindow(anyWindow, TYPE_APPLICATION_MEDIA_OVERLAY, + final WindowState mediaOverlayChild = createWindow(anyWindow, + TYPE_APPLICATION_MEDIA_OVERLAY, mDisplayContent, "TypeApplicationMediaOverlayChild"); mDisplayContent.assignChildLayers(mTransaction); @@ -388,8 +411,8 @@ public class ZOrderingTests extends WindowTestsBase { final WindowState splitScreenSecondaryWindow = createWindowOnStack(null, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow"); - final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION, + final WindowState assistantStackWindow = createWindowOnStack(null, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION, mDisplayContent, "assistantStackWindow"); mDisplayContent.assignChildLayers(mTransaction); diff --git a/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java index 1222b59e92b9..69db38438609 100644 --- a/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java +++ b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java @@ -152,7 +152,7 @@ public class TestHandler extends Handler { @Override public int compareTo(MsgInfo o) { - return (int) (sendTime - o.sendTime); + return Long.compare(sendTime, o.sendTime); } @Override diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java index 6c125d1648f3..32f389a4fa2d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java @@ -71,7 +71,8 @@ public class ZenModeFilteringTest extends UiServiceTestCase { private NotificationRecord getNotificationRecord(NotificationChannel c) { StatusBarNotification sbn = mock(StatusBarNotification.class); - when(sbn.getNotification()).thenReturn(mock(Notification.class)); + Notification notification = mock(Notification.class); + when(sbn.getNotification()).thenReturn(notification); return new NotificationRecord(mContext, sbn, c); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index b19cc86a3404..38d8e3990e00 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -21,13 +21,14 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCRE import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; -import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; import static junit.framework.TestCase.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; @@ -45,13 +46,14 @@ import android.app.NotificationManager.Policy; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioManagerInternal; -import android.media.VolumePolicy; import android.media.AudioSystem; +import android.media.VolumePolicy; import android.net.Uri; import android.provider.Settings; import android.provider.Settings.Global; @@ -67,9 +69,9 @@ import android.util.Xml; import com.android.internal.R; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; -import com.android.server.notification.ManagedServices.UserProfiles; import com.android.internal.util.FastXmlSerializer; import com.android.server.UiServiceTestCase; +import com.android.server.notification.ManagedServices.UserProfiles; import org.junit.Before; import org.junit.Test; @@ -87,12 +89,16 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.util.Objects; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class ZenModeHelperTest extends UiServiceTestCase { + private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE"; + private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE"; + ConditionProviders mConditionProviders; @Mock NotificationManager mNotificationManager; private Resources mResources; @@ -108,7 +114,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { mTestableLooper = TestableLooper.get(this); mContext = spy(getContext()); mContentResolver = mContext.getContentResolver(); - mResources = spy(mContext.getResources()); try { when(mResources.getXml(R.xml.default_zen_mode_config)).thenReturn( @@ -132,12 +137,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { + "reminders=\"false\" events=\"false\" callsFrom=\"1\" messagesFrom=\"2\" " + "visualScreenOff=\"true\" alarms=\"true\" " + "media=\"true\" system=\"false\" />\n" - + "<automatic ruleId=\"EVENTS_DEFAULT_RULE\" enabled=\"false\" snoozing=\"false\"" + + "<automatic ruleId=\"" + EVENTS_DEFAULT_RULE_ID + + "\" enabled=\"false\" snoozing=\"false\"" + " name=\"Event\" zen=\"1\"" + " component=\"android/com.android.server.notification.EventConditionProvider\"" + " conditionId=\"condition://android/event?userId=-10000&calendar=&" + "reply=1\"/>\n" - + "<automatic ruleId=\"EVERY_NIGHT_DEFAULT_RULE\" enabled=\"false\"" + + "<automatic ruleId=\"" + SCHEDULE_DEFAULT_RULE_ID + "\" enabled=\"false\"" + " snoozing=\"false\" name=\"Sleeping\" zen=\"1\"" + " component=\"android/com.android.server.notification.ScheduleConditionProvider\"" + " conditionId=\"condition://android/schedule?days=1.2.3.4.5.6.7 &start=22.0" @@ -770,8 +776,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.readXml(parser, false); assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT - | SUPPRESSED_EFFECT_LIGHTS - | SUPPRESSED_EFFECT_PEEK, + | SUPPRESSED_EFFECT_LIGHTS + | SUPPRESSED_EFFECT_PEEK, mZenModeHelperSpy.mConfig.suppressedVisualEffects); xml = "<zen version=\"6\" user=\"0\">\n" @@ -1007,6 +1013,90 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.updateDefaultZenRules(); // shouldn't throw null pointer } + @Test + public void testDoNotUpdateModifiedDefaultAutoRule() { + // mDefaultConfig is set to default config in setup by getDefaultConfigParser + when(mContext.checkCallingPermission(anyString())) + .thenReturn(PackageManager.PERMISSION_GRANTED); + + // shouldn't update rule that's been modified + ZenModeConfig.ZenRule updatedDefaultRule = new ZenModeConfig.ZenRule(); + updatedDefaultRule.modified = true; + updatedDefaultRule.enabled = false; + updatedDefaultRule.creationTime = 0; + updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID; + updatedDefaultRule.name = "Schedule Default Rule"; + updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo()); + updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider"); + + ArrayMap<String, ZenModeConfig.ZenRule> autoRules = new ArrayMap<>(); + autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule); + mZenModeHelperSpy.mConfig.automaticRules = autoRules; + + mZenModeHelperSpy.updateDefaultZenRules(); + assertEquals(updatedDefaultRule, + mZenModeHelperSpy.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID)); + } + + @Test + public void testDoNotUpdateEnabledDefaultAutoRule() { + // mDefaultConfig is set to default config in setup by getDefaultConfigParser + when(mContext.checkCallingPermission(anyString())) + .thenReturn(PackageManager.PERMISSION_GRANTED); + + // shouldn't update the rule that's enabled + ZenModeConfig.ZenRule updatedDefaultRule = new ZenModeConfig.ZenRule(); + updatedDefaultRule.enabled = true; + updatedDefaultRule.modified = false; + updatedDefaultRule.creationTime = 0; + updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID; + updatedDefaultRule.name = "Schedule Default Rule"; + updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo()); + updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider"); + + ArrayMap<String, ZenModeConfig.ZenRule> autoRules = new ArrayMap<>(); + autoRules.put(SCHEDULE_DEFAULT_RULE_ID, updatedDefaultRule); + mZenModeHelperSpy.mConfig.automaticRules = autoRules; + + mZenModeHelperSpy.updateDefaultZenRules(); + assertEquals(updatedDefaultRule, + mZenModeHelperSpy.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID)); + } + + @Test + public void testUpdateDefaultAutoRule() { + // mDefaultConfig is set to default config in setup by getDefaultConfigParser + final String defaultRuleName = "rule name test"; + when(mContext.checkCallingPermission(anyString())) + .thenReturn(PackageManager.PERMISSION_GRANTED); + + // will update rule that is not enabled and modified + ZenModeConfig.ZenRule customDefaultRule = new ZenModeConfig.ZenRule(); + customDefaultRule.enabled = false; + customDefaultRule.modified = false; + customDefaultRule.creationTime = 0; + customDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID; + customDefaultRule.name = "Schedule Default Rule"; + customDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo()); + customDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider"); + + ArrayMap<String, ZenModeConfig.ZenRule> autoRules = new ArrayMap<>(); + autoRules.put(SCHEDULE_DEFAULT_RULE_ID, customDefaultRule); + mZenModeHelperSpy.mConfig.automaticRules = autoRules; + + mZenModeHelperSpy.updateDefaultZenRules(); + ZenModeConfig.ZenRule ruleAfterUpdating = + mZenModeHelperSpy.mConfig.automaticRules.get(SCHEDULE_DEFAULT_RULE_ID); + assertEquals(customDefaultRule.enabled, ruleAfterUpdating.enabled); + assertEquals(customDefaultRule.modified, ruleAfterUpdating.modified); + assertEquals(customDefaultRule.id, ruleAfterUpdating.id); + assertEquals(customDefaultRule.conditionId, ruleAfterUpdating.conditionId); + assertFalse(Objects.equals(defaultRuleName, ruleAfterUpdating.name)); // update name + } + private void setupZenConfig() { mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowAlarms = false; diff --git a/services/tests/wmtests/Android.mk b/services/tests/wmtests/Android.mk index c095ae0dd2ff..9655b3d1e258 100644 --- a/services/tests/wmtests/Android.mk +++ b/services/tests/wmtests/Android.mk @@ -11,12 +11,19 @@ LOCAL_MODULE_TAGS := tests # Include all test java files. LOCAL_SRC_FILES := \ $(call all-java-files-under, src) \ - $(call all-java-files-under, ../servicestests/utils) + $(call all-java-files-under, ../servicestests/utils) \ LOCAL_STATIC_JAVA_LIBRARIES := \ + frameworks-base-testutils \ + services.core \ androidx.test.runner \ + androidx.test.rules \ mockito-target-minus-junit4 \ platform-test-annotations \ + truth-prebuilt \ + testables \ + ub-uiautomator \ + hamcrest-library LOCAL_JAVA_LIBRARIES := \ android.test.mock \ diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index 1fb947309028..ff8480373f4e 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -22,7 +22,28 @@ android:minSdkVersion="1" android:targetSdkVersion="28" /> - <application android:testOnly="true" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" /> + <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" /> + <uses-permission android:name="android.permission.MANAGE_USERS" /> + <uses-permission android:name="android.permission.STORAGE_INTERNAL" /> + <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" /> + <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> + <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /> + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" /> + <uses-permission android:name="android.permission.READ_FRAME_BUFFER" /> + + <application android:testOnly="true"> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityA" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityB" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityRequestedOrientationChange" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskChangeCallbacks" /> + <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskDescriptionChange" /> + <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity" + android:showWhenLocked="true" /> + </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/wmtests/src/com/android/server/policy/FakeWindowState.java index d34f951ffd61..d4f2b061d570 100644 --- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java +++ b/services/tests/wmtests/src/com/android/server/policy/FakeWindowState.java @@ -16,17 +16,13 @@ package com.android.server.policy; -import android.annotation.Nullable; -import android.graphics.Point; import android.graphics.Rect; import android.util.proto.ProtoOutputStream; import android.view.Display; -import android.view.DisplayCutout; import android.view.IApplicationToken; import android.view.WindowManager; import com.android.server.wm.WindowFrames; -import com.android.server.wm.utils.WmDisplayCutout; public class FakeWindowState implements WindowManagerPolicy.WindowState { @@ -243,10 +239,12 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { } @Override - public boolean canReceiveKeys() { return false; } + public boolean canReceiveKeys() { + return false; + } @Override - public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId){ + public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { throw new UnsupportedOperationException("not implemented"); } diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerInsetsTest.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerInsetsTest.java index cce6ba718400..f024fe77aaf7 100644 --- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerInsetsTest.java +++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerInsetsTest.java @@ -29,15 +29,16 @@ import android.view.Display; import android.view.DisplayInfo; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; -import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +/** + * Build/Install/Run: + * atest WmTests:PhoneWindowManagerInsetsTest + */ @SmallTest @Presubmit public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { @@ -52,7 +53,7 @@ public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { } @Test - public void portrait() throws Exception { + public void portrait() { DisplayInfo di = displayInfoForRotation(ROTATION_0, false /* withCutout */); verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); @@ -61,7 +62,7 @@ public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { } @Test - public void portrait_withCutout() throws Exception { + public void portrait_withCutout() { DisplayInfo di = displayInfoForRotation(ROTATION_0, true /* withCutout */); verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); @@ -70,7 +71,7 @@ public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { } @Test - public void landscape() throws Exception { + public void landscape() { DisplayInfo di = displayInfoForRotation(ROTATION_90, false /* withCutout */); verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); @@ -79,7 +80,7 @@ public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { } @Test - public void landscape_withCutout() throws Exception { + public void landscape_withCutout() { DisplayInfo di = displayInfoForRotation(ROTATION_90, true /* withCutout */); verifyStableInsets(di, DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0); @@ -88,7 +89,7 @@ public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { } @Test - public void seascape() throws Exception { + public void seascape() { DisplayInfo di = displayInfoForRotation(ROTATION_270, false /* withCutout */); verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0); @@ -97,7 +98,7 @@ public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { } @Test - public void seascape_withCutout() throws Exception { + public void seascape_withCutout() { DisplayInfo di = displayInfoForRotation(ROTATION_270, true /* withCutout */); verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0); @@ -106,7 +107,7 @@ public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { } @Test - public void upsideDown() throws Exception { + public void upsideDown() { DisplayInfo di = displayInfoForRotation(ROTATION_180, false /* withCutout */); verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT); @@ -115,7 +116,7 @@ public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { } @Test - public void upsideDown_withCutout() throws Exception { + public void upsideDown_withCutout() { DisplayInfo di = displayInfoForRotation(ROTATION_180, true /* withCutout */); verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT); @@ -181,4 +182,4 @@ public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase { return mPolicy.getConfigDisplayHeight(di.logicalWidth, di.logicalHeight, di.rotation, 0 /* ui */, Display.DEFAULT_DISPLAY, di.displayCutout); } -}
\ No newline at end of file +} diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java index fee761dd92d3..e8f767a873d3 100644 --- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java +++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java @@ -43,13 +43,14 @@ import android.view.DisplayCutout; import android.view.WindowManager; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +/** + * Build/Install/Run: + * atest WmTests:PhoneWindowManagerLayoutTest + */ @SmallTest @Presubmit public class PhoneWindowManagerLayoutTest extends PhoneWindowManagerTestBase { @@ -69,7 +70,7 @@ public class PhoneWindowManagerLayoutTest extends PhoneWindowManagerTestBase { } @Test - public void layoutWindowLw_appDrawsBars() throws Exception { + public void layoutWindowLw_appDrawsBars() { mAppWindow.attrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; mPolicy.addWindow(mAppWindow); @@ -84,7 +85,7 @@ public class PhoneWindowManagerLayoutTest extends PhoneWindowManagerTestBase { } @Test - public void layoutWindowLw_appWontDrawBars() throws Exception { + public void layoutWindowLw_appWontDrawBars() { mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; mPolicy.addWindow(mAppWindow); @@ -99,7 +100,7 @@ public class PhoneWindowManagerLayoutTest extends PhoneWindowManagerTestBase { } @Test - public void layoutWindowLw_appWontDrawBars_forceStatus() throws Exception { + public void layoutWindowLw_appWontDrawBars_forceStatus() { mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; mAppWindow.attrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND; mPolicy.addWindow(mAppWindow); @@ -391,4 +392,4 @@ public class PhoneWindowManagerLayoutTest extends PhoneWindowManagerTestBase { assertThat(outOutsets, is(new Rect())); assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper())); } -}
\ No newline at end of file +} diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTest.java index d92d7e03ef3b..6c44d655459e 100644 --- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java +++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTest.java @@ -47,12 +47,13 @@ import android.platform.test.annotations.Presubmit; import android.view.WindowManager; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +/** + * Build/Install/Run: + * atest WmTests:PhoneWindowManagerTest + */ @SmallTest @Presubmit public class PhoneWindowManagerTest { @@ -95,7 +96,7 @@ public class PhoneWindowManagerTest { @Test - public void testChooseNavigationColorWindowLw() throws Exception { + public void testChooseNavigationColorWindowLw() { final FakeWindowState opaque = createOpaqueFullscreen(false); final FakeWindowState dimmingImTarget = createDimmingDialogWindow(true); @@ -147,14 +148,14 @@ public class PhoneWindowManagerTest { } @Test - public void testUpdateLightNavigationBarLw() throws Exception { + public void testUpdateLightNavigationBarLw() { final FakeWindowState opaqueDarkNavBar = createOpaqueFullscreen(false); final FakeWindowState opaqueLightNavBar = createOpaqueFullscreen(true); final FakeWindowState dimming = createDimmingDialogWindow(false); - final FakeWindowState imeDrawDarkNavBar = createInputMethodWindow(true,true, false); - final FakeWindowState imeDrawLightNavBar = createInputMethodWindow(true,true, true); + final FakeWindowState imeDrawDarkNavBar = createInputMethodWindow(true, true, false); + final FakeWindowState imeDrawLightNavBar = createInputMethodWindow(true, true, true); assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, PhoneWindowManager.updateLightNavigationBarLw( @@ -204,7 +205,7 @@ public class PhoneWindowManagerTest { } @Test - public void testIsDockSideAllowedDockTop() throws Exception { + public void testIsDockSideAllowedDockTop() { // Docked top is always allowed assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, NAV_BAR_BOTTOM, true /* navigationBarCanMove */)); @@ -213,14 +214,14 @@ public class PhoneWindowManagerTest { } @Test - public void testIsDockSideAllowedDockBottom() throws Exception { + public void testIsDockSideAllowedDockBottom() { // Cannot dock bottom assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_BOTTOM, DOCKED_LEFT, NAV_BAR_BOTTOM, true /* navigationBarCanMove */)); } @Test - public void testIsDockSideAllowedNavigationBarMovable() throws Exception { + public void testIsDockSideAllowedNavigationBarMovable() { assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM, true /* navigationBarCanMove */)); assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_LEFT, @@ -236,7 +237,7 @@ public class PhoneWindowManagerTest { } @Test - public void testIsDockSideAllowedNavigationBarNotMovable() throws Exception { + public void testIsDockSideAllowedNavigationBarNotMovable() { // Navigation bar is not movable such as tablets assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM, false /* navigationBarCanMove */)); diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTestBase.java index e16f118cd63b..fc8fe2377bf0 100644 --- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java +++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTestBase.java @@ -64,7 +64,7 @@ import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Before; -public class PhoneWindowManagerTestBase { +class PhoneWindowManagerTestBase { static final int DISPLAY_WIDTH = 500; static final int DISPLAY_HEIGHT = 1000; @@ -82,7 +82,7 @@ public class PhoneWindowManagerTestBase { private int mRotation = ROTATION_0; @Before - public void setUpBase() throws Exception { + public void setUpBase() { mContext = new TestContextWrapper(InstrumentationRegistry.getTargetContext()); mContext.getResourceMocker().addOverride( com.android.internal.R.dimen.status_bar_height_portrait, STATUS_BAR_HEIGHT); @@ -207,7 +207,7 @@ public class PhoneWindowManagerTestBase { static class TestContextWrapper extends ContextWrapper { private final TestableResources mResourceMocker; - public TestContextWrapper(Context targetContext) { + TestContextWrapper(Context targetContext) { super(targetContext); mResourceMocker = new TestableResources(targetContext.getResources()); } @@ -234,7 +234,7 @@ public class PhoneWindowManagerTestBase { static class TestablePhoneWindowManager extends PhoneWindowManager { - public TestablePhoneWindowManager() { + TestablePhoneWindowManager() { } @Override diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java index 59c40673f105..d3f1a0a53760 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -11,10 +11,10 @@ * 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. + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -22,7 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; -import static com.android.server.am.ActivityStackSupervisor.ON_TOP; +import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -32,11 +32,9 @@ import static org.mockito.Mockito.doReturn; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link ActivityDisplay} class. @@ -46,13 +44,10 @@ import org.junit.runner.RunWith; */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class ActivityDisplayTests extends ActivityTestsBase { @Before - @Override public void setUp() throws Exception { - super.setUp(); setupActivityTaskManagerService(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java new file mode 100644 index 000000000000..215c51d79abc --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import static android.app.ActivityManager.START_SUCCESS; +import static android.app.ActivityManager.START_TASK_TO_FRONT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.content.Intent; +import android.os.SystemClock; +import android.platform.test.annotations.Presubmit; +import android.util.SparseIntArray; + +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests for the {@link ActivityMetricsLaunchObserver} class. + * + * Build/Install/Run: + * atest WmTests:ActivityMetricsLaunchObserverTests + */ +@SmallTest +@Presubmit +@FlakyTest(detail="promote once confirmed non-flaky") +public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { + private ActivityMetricsLogger mActivityMetricsLogger; + private ActivityMetricsLaunchObserver mLaunchObserver; + + private TestActivityStack mStack; + private TaskRecord mTask; + private ActivityRecord mActivityRecord; + private ActivityRecord mActivityRecordTrampoline; + + @Before + public void setUpAMLO() throws Exception { + setupActivityTaskManagerService(); + + mActivityMetricsLogger = + new ActivityMetricsLogger(mSupervisor, mService.mContext, mService.mH.getLooper()); + + mLaunchObserver = mock(ActivityMetricsLaunchObserver.class); + + // TODO: Use ActivityMetricsLaunchObserverRegistry . + java.lang.reflect.Field f = + mActivityMetricsLogger.getClass().getDeclaredField("mLaunchObserver"); + f.setAccessible(true); + f.set(mActivityMetricsLogger, mLaunchObserver); + + // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful. + // This seems to be the easiest way to create an ActivityRecord. + mStack = mSupervisor.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + mTask = new TaskBuilder(mSupervisor).setStack(mStack).build(); + mActivityRecord = new ActivityBuilder(mService).setTask(mTask).build(); + mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build(); + } + + @Test + public void testOnIntentStarted() throws Exception { + Intent intent = new Intent("action 1"); + + mActivityMetricsLogger.notifyActivityLaunching(intent); + + verify(mLaunchObserver).onIntentStarted(eq(intent)); + verifyNoMoreInteractions(mLaunchObserver); + } + + @Test + public void testOnIntentFailed() throws Exception { + testOnIntentStarted(); + + ActivityRecord activityRecord = null; + + // Bringing an intent that's already running 'to front' is not considered + // as an ACTIVITY_LAUNCHED state transition. + mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, + activityRecord); + + verify(mLaunchObserver).onIntentFailed(); + verifyNoMoreInteractions(mLaunchObserver); + } + + @Test + public void testOnActivityLaunched() throws Exception { + testOnIntentStarted(); + + mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, + mActivityRecord); + + verify(mLaunchObserver).onActivityLaunched(eq(mActivityRecord), anyInt()); + verifyNoMoreInteractions(mLaunchObserver); + } + + @Test + public void testOnActivityLaunchFinished() throws Exception { + testOnActivityLaunched(); + + mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), + SystemClock.uptimeMillis()); + + mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(), + SystemClock.uptimeMillis()); + + verify(mLaunchObserver).onActivityLaunchFinished(eq(mActivityRecord)); + verifyNoMoreInteractions(mLaunchObserver); + } + + @Test + public void testOnActivityLaunchCancelled() throws Exception { + testOnActivityLaunched(); + + mActivityRecord.nowVisible = true; + + // Cannot time already-visible activities. + mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord); + + verify(mLaunchObserver).onActivityLaunchCancelled(eq(mActivityRecord)); + verifyNoMoreInteractions(mLaunchObserver); + } + + @Test + public void testOnActivityLaunchedTrampoline() throws Exception { + testOnIntentStarted(); + + mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, + mActivityRecord); + + verify(mLaunchObserver).onActivityLaunched(eq(mActivityRecord), anyInt()); + + // A second, distinct, activity launch is coalesced into the the current app launch sequence + mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, + mActivityRecordTrampoline); + + verifyNoMoreInteractions(mLaunchObserver); + } + + @Test + public void testOnActivityLaunchFinishedTrampoline() throws Exception { + testOnActivityLaunchedTrampoline(); + + mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), + SystemClock.uptimeMillis()); + + mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(), + SystemClock.uptimeMillis()); + + verify(mLaunchObserver).onActivityLaunchFinished(eq(mActivityRecordTrampoline)); + verifyNoMoreInteractions(mLaunchObserver); + } + + @Test + public void testOnActivityLaunchCancelledTrampoline() throws Exception { + testOnActivityLaunchedTrampoline(); + + mActivityRecordTrampoline.nowVisible = true; + + // Cannot time already-visible activities. + mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, + mActivityRecordTrampoline); + + verify(mLaunchObserver).onActivityLaunchCancelled(eq(mActivityRecordTrampoline)); + verifyNoMoreInteractions(mLaunchObserver); + } +} diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java index d15bff4f6378..c449049164e4 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; @@ -22,23 +22,22 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import android.app.ActivityOptions; import android.os.Bundle; import android.platform.test.annotations.Presubmit; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; /** - * atest FrameworksServicesTests:ActivityOptionsTest + * Build/Install/Run: + * atest WmTests:ActivityOptionsTest */ @MediumTest @Presubmit -@RunWith(AndroidJUnit4.class) public class ActivityOptionsTest { @Test @@ -64,12 +63,12 @@ public class ActivityOptionsTest { assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchDisplayId()); assertEquals(ACTIVITY_TYPE_STANDARD, restoredOpts.getLaunchActivityType()); assertEquals(WINDOWING_MODE_FULLSCREEN, restoredOpts.getLaunchWindowingMode()); - assertEquals(true, restoredOpts.getAvoidMoveToFront()); + assertTrue(restoredOpts.getAvoidMoveToFront()); assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchTaskId()); - assertEquals(true, restoredOpts.getLockTaskMode()); + assertTrue(restoredOpts.getLockTaskMode()); assertEquals(ROTATION_ANIMATION_ROTATE, restoredOpts.getRotationAnimationHint()); - assertEquals(true, restoredOpts.getTaskOverlay()); - assertEquals(true, restoredOpts.canTaskOverlayResume()); + assertTrue(restoredOpts.getTaskOverlay()); + assertTrue(restoredOpts.canTaskOverlayResume()); assertEquals(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, restoredOpts.getSplitScreenCreateMode()); } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 101500812265..b865772a4192 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,18 +14,14 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING; -import static com.android.server.am.ActivityStack.ActivityState.PAUSING; -import static com.android.server.am.ActivityStack.ActivityState.STOPPED; -import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING; +import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT; @@ -37,11 +33,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityOptions; @@ -52,32 +44,26 @@ import android.platform.test.annotations.Presubmit; import android.util.MutableBoolean; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.invocation.InvocationOnMock; /** * Tests for the {@link ActivityRecord} class. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.am.ActivityRecordTests + * atest WmTests:ActivityRecordTests */ @MediumTest @Presubmit -@RunWith(AndroidJUnit4.class) public class ActivityRecordTests extends ActivityTestsBase { private TestActivityStack mStack; private TaskRecord mTask; private ActivityRecord mActivity; @Before - @Override public void setUp() throws Exception { - super.setUp(); - setupActivityTaskManagerService(); mStack = new StackBuilder(mSupervisor).build(); mTask = mStack.getChildAt(0); @@ -85,26 +71,26 @@ public class ActivityRecordTests extends ActivityTestsBase { } @Test - public void testStackCleanupOnClearingTask() throws Exception { + public void testStackCleanupOnClearingTask() { mActivity.setTask(null); assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1); } @Test - public void testStackCleanupOnActivityRemoval() throws Exception { + public void testStackCleanupOnActivityRemoval() { mTask.removeActivity(mActivity); assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1); } @Test - public void testStackCleanupOnTaskRemoval() throws Exception { + public void testStackCleanupOnTaskRemoval() { mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING); // Stack should be gone on task removal. assertNull(mService.mStackSupervisor.getStack(mStack.mStackId)); } @Test - public void testNoCleanupMovingActivityInSameStack() throws Exception { + public void testNoCleanupMovingActivityInSameStack() { final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack) .build(); mActivity.reparent(newTask, 0, null /*reason*/); @@ -157,19 +143,19 @@ public class ActivityRecordTests extends ActivityTestsBase { } @Test - public void testPositionLimitedAspectRatioNavBarBottom() throws Exception { + public void testPositionLimitedAspectRatioNavBarBottom() { verifyPositionWithLimitedAspectRatio(NAV_BAR_BOTTOM, new Rect(0, 0, 1000, 2000), 1.5f, new Rect(0, 0, 1000, 1500)); } @Test - public void testPositionLimitedAspectRatioNavBarLeft() throws Exception { + public void testPositionLimitedAspectRatioNavBarLeft() { verifyPositionWithLimitedAspectRatio(NAV_BAR_LEFT, new Rect(0, 0, 2000, 1000), 1.5f, new Rect(500, 0, 2000, 1000)); } @Test - public void testPositionLimitedAspectRatioNavBarRight() throws Exception { + public void testPositionLimitedAspectRatioNavBarRight() { verifyPositionWithLimitedAspectRatio(NAV_BAR_RIGHT, new Rect(0, 0, 2000, 1000), 1.5f, new Rect(0, 0, 1500, 1000)); } @@ -186,7 +172,7 @@ public class ActivityRecordTests extends ActivityTestsBase { } @Test - public void testCanBeLaunchedOnDisplay() throws Exception { + public void testCanBeLaunchedOnDisplay() { mService.mSupportsMultiWindow = true; final ActivityRecord activity = new ActivityBuilder(mService).build(); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java index 8ab22105c3ae..c2ef478406e7 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.START_DELIVERED_TO_TOP; import static android.app.ActivityManager.START_TASK_TO_FRONT; @@ -26,9 +26,12 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; -import static com.android.server.am.ActivityDisplay.POSITION_TOP; -import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; -import static com.android.server.am.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; +import static com.android.server.wm.ActivityDisplay.POSITION_TOP; +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; +import static com.android.server.wm.ActivityStackSupervisor.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; + + +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -55,11 +58,9 @@ import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.ArrayList; @@ -67,19 +68,15 @@ import java.util.ArrayList; * Tests for the {@link ActivityStackSupervisor} class. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests + * atest WmTests:ActivityStackSupervisorTests */ @MediumTest @Presubmit -@RunWith(AndroidJUnit4.class) public class ActivityStackSupervisorTests extends ActivityTestsBase { private ActivityStack mFullscreenStack; @Before - @Override public void setUp() throws Exception { - super.setUp(); - setupActivityTaskManagerService(); mFullscreenStack = mService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -90,7 +87,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { * should expect {@code null} to be returned in this case. */ @Test - public void testRestoringInvalidTask() throws Exception { + public void testRestoringInvalidTask() { ((TestActivityDisplay) mSupervisor.getDefaultDisplay()).removeAllTasks(); TaskRecord task = mSupervisor.anyTaskForIdLocked(0 /*taskId*/, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */); @@ -102,7 +99,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { * activity stack when a new task is added. */ @Test - public void testReplacingTaskInPinnedStack() throws Exception { + public void testReplacingTaskInPinnedStack() { final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(mFullscreenStack).build(); final TaskRecord firstTask = firstActivity.getTask(); @@ -156,7 +153,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { * Ensures that an activity is removed from the stopping activities list once it is resumed. */ @Test - public void testStoppingActivityRemovedWhenResumed() throws Exception { + public void testStoppingActivityRemovedWhenResumed() { final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(mFullscreenStack).build(); mSupervisor.mStoppingActivities.add(firstActivity); @@ -169,8 +166,9 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { /** * Ensures that waiting results are notified of launches. */ + @SuppressWarnings("SynchronizeOnNonFinalField") @Test - public void testReportWaitingActivityLaunchedIfNeeded() throws Exception { + public void testReportWaitingActivityLaunchedIfNeeded() { final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) .setStack(mFullscreenStack).build(); @@ -181,23 +179,23 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait); mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT); - assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty()); + assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty(); assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT); - assertEquals(taskToFrontWait.who, null); + assertNull(taskToFrontWait.who); final WaitResult deliverToTopWait = new WaitResult(); mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait); mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_DELIVERED_TO_TOP); - assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty()); + assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty(); assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP); assertEquals(deliverToTopWait.who, firstActivity.realActivity); } } @Test - public void testApplySleepTokensLocked() throws Exception { + public void testApplySleepTokensLocked() { final ActivityDisplay display = mSupervisor.getDefaultDisplay(); final KeyguardController keyguard = mSupervisor.getKeyguardController(); final ActivityStack stack = mock(ActivityStack.class); @@ -253,7 +251,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { * Verifies that removal of activity with task and stack is done correctly. */ @Test - public void testRemovingStackOnAppCrash() throws Exception { + public void testRemovingStackOnAppCrash() { final ActivityDisplay defaultDisplay = mService.mStackSupervisor.getDefaultDisplay(); final int originalStackCount = defaultDisplay.getChildCount(); final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( @@ -272,7 +270,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { } @Test - public void testFocusability() throws Exception { + public void testFocusability() { final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) @@ -316,7 +314,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { * primary stack. */ @Test - public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() throws Exception { + public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() { // Create primary split-screen stack with a task and an activity. final ActivityStack primaryStack = mService.mStackSupervisor.getDefaultDisplay() .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, @@ -339,9 +337,9 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { * {@link android.app.IActivityTaskManager#resizeDockedStack} as expect. */ @Test - public void testResizeDockedStackForSplitScreenPrimary() throws Exception { - final Rect TASK_SIZE = new Rect(0, 0, 600, 600); - final Rect STACK_SIZE = new Rect(0, 0, 300, 300); + public void testResizeDockedStackForSplitScreenPrimary() { + final Rect taskSize = new Rect(0, 0, 600, 600); + final Rect stackSize = new Rect(0, 0, 300, 300); // Create primary split-screen stack with a task. final ActivityStack primaryStack = mService.mStackSupervisor.getDefaultDisplay() @@ -350,18 +348,18 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build(); // Resize dock stack. - mService.resizeDockedStack(STACK_SIZE, TASK_SIZE, null, null, null); + mService.resizeDockedStack(stackSize, taskSize, null, null, null); // Verify dock stack & its task bounds if is equal as resized result. - assertEquals(primaryStack.getBounds(), STACK_SIZE); - assertEquals(task.getBounds(), TASK_SIZE); + assertEquals(primaryStack.getBounds(), stackSize); + assertEquals(task.getBounds(), taskSize); } /** * Verify that home stack would be moved to front when the top activity is Recents. */ @Test - public void testFindTaskToMoveToFrontWhenRecentsOnTop() throws Exception { + public void testFindTaskToMoveToFrontWhenRecentsOnTop() { // Create stack/task on default display. final ActivityDisplay display = mSupervisor.getDefaultDisplay(); final TestActivityStack targetStack = new StackBuilder(mSupervisor).setOnTop(false).build(); @@ -383,7 +381,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { * Recents. */ @Test - public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() throws Exception { + public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() { // Create stack/task on default display. final ActivityDisplay display = mSupervisor.getDefaultDisplay(); final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN, @@ -410,7 +408,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { * the stack is the top focused. */ @Test - public void testResumeActivityWhenNonTopmostStackIsTopFocused() throws Exception { + public void testResumeActivityWhenNonTopmostStackIsTopFocused() { // Create a stack at bottom. final ActivityDisplay display = mSupervisor.getDefaultDisplay(); final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN, @@ -460,4 +458,23 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { assertNotNull(secondDisplay.getTopStack()); assertTrue(secondDisplay.getTopStack().isActivityTypeHome()); } + + /** + * Tests that home activities won't be started before booting when display added. + */ + @Test + public void testNotStartHomeBeforeBoot() throws Exception { + final int displayId = 1; + final boolean isBooting = mService.mAmInternal.isBooting(); + final boolean isBooted = mService.mAmInternal.isBooted(); + try { + mService.mAmInternal.setBooting(false); + mService.mAmInternal.setBooted(false); + mSupervisor.onDisplayAdded(displayId); + verify(mSupervisor, never()).startHomeOnDisplay(anyInt(), any(), anyInt()); + } finally { + mService.mAmInternal.setBooting(isBooting); + mService.mAmInternal.setBooted(isBooted); + } + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 839792d71bca..62767e33b3bf 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; @@ -26,12 +26,14 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static com.android.server.am.ActivityStack.ActivityState.STOPPING; -import static com.android.server.am.ActivityStack.ActivityState.DESTROYING; -import static com.android.server.am.ActivityStack.ActivityState.PAUSED; -import static com.android.server.am.ActivityStack.ActivityState.PAUSING; -import static com.android.server.am.ActivityStack.ActivityState.RESUMED; -import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; +import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; +import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; +import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; +import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; + +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -52,31 +54,25 @@ import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link ActivityStack} class. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.am.ActivityStackTests + * atest WmTests:ActivityStackTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class ActivityStackTests extends ActivityTestsBase { private ActivityDisplay mDefaultDisplay; private ActivityStack mStack; private TaskRecord mTask; @Before - @Override public void setUp() throws Exception { - super.setUp(); - setupActivityTaskManagerService(); mDefaultDisplay = mSupervisor.getDefaultDisplay(); mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, @@ -85,14 +81,14 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testEmptyTaskCleanupOnRemove() throws Exception { + public void testEmptyTaskCleanupOnRemove() { assertNotNull(mTask.getWindowContainerController()); mStack.removeTask(mTask, "testEmptyTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); assertNull(mTask.getWindowContainerController()); } @Test - public void testOccupiedTaskCleanupOnRemove() throws Exception { + public void testOccupiedTaskCleanupOnRemove() { final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); assertNotNull(mTask.getWindowContainerController()); mStack.removeTask(mTask, "testOccupiedTaskCleanupOnRemove", REMOVE_TASK_MODE_DESTROYING); @@ -100,13 +96,13 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testResumedActivity() throws Exception { + public void testResumedActivity() { final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); - assertEquals(mStack.getResumedActivity(), null); + assertNull(mStack.getResumedActivity()); r.setState(RESUMED, "testResumedActivity"); - assertEquals(mStack.getResumedActivity(), r); + assertEquals(r, mStack.getResumedActivity()); r.setState(PAUSING, "testResumedActivity"); - assertEquals(mStack.getResumedActivity(), null); + assertNull(mStack.getResumedActivity()); } @Test @@ -114,7 +110,7 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); // Ensure moving task between two stacks updates resumed activity r.setState(RESUMED, "testResumedActivityFromTaskReparenting"); - assertEquals(mStack.getResumedActivity(), r); + assertEquals(r, mStack.getResumedActivity()); final ActivityStack destStack = mService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -123,8 +119,8 @@ public class ActivityStackTests extends ActivityTestsBase { false /* animate */, true /* deferResume*/, "testResumedActivityFromTaskReparenting"); - assertEquals(mStack.getResumedActivity(), null); - assertEquals(destStack.getResumedActivity(), r); + assertNull(mStack.getResumedActivity()); + assertEquals(r, destStack.getResumedActivity()); } @Test @@ -132,7 +128,7 @@ public class ActivityStackTests extends ActivityTestsBase { final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); // Ensure moving task between two stacks updates resumed activity r.setState(RESUMED, "testResumedActivityFromActivityReparenting"); - assertEquals(mStack.getResumedActivity(), r); + assertEquals(r, mStack.getResumedActivity()); final ActivityStack destStack = mService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -141,60 +137,60 @@ public class ActivityStackTests extends ActivityTestsBase { mTask.removeActivity(r); destTask.addActivityToTop(r); - assertEquals(mStack.getResumedActivity(), null); - assertEquals(destStack.getResumedActivity(), r); + assertNull(mStack.getResumedActivity()); + assertEquals(r, destStack.getResumedActivity()); } @Test - public void testPrimarySplitScreenRestoresWhenMovedToBack() throws Exception { + public void testPrimarySplitScreenRestoresWhenMovedToBack() { // Create primary splitscreen stack. This will create secondary stacks and places the // existing fullscreen stack on the bottom. final ActivityStack primarySplitScreen = mDefaultDisplay.createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Assert windowing mode. - assertEquals(primarySplitScreen.getWindowingMode(), WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode()); // Move primary to back. primarySplitScreen.moveToBack("testPrimarySplitScreenToFullscreenWhenMovedToBack", null /* task */); // Assert that stack is at the bottom. - assertEquals(mDefaultDisplay.getIndexOf(primarySplitScreen), 0); + assertEquals(0, mDefaultDisplay.getIndexOf(primarySplitScreen)); // Ensure no longer in splitscreen. - assertEquals(primarySplitScreen.getWindowingMode(), WINDOWING_MODE_FULLSCREEN); + assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode()); // Ensure that the override mode is restored to undefined - assertEquals(primarySplitScreen.getOverrideWindowingMode(), WINDOWING_MODE_UNDEFINED); + assertEquals(WINDOWING_MODE_UNDEFINED, primarySplitScreen.getOverrideWindowingMode()); } @Test - public void testPrimarySplitScreenRestoresPreviousWhenMovedToBack() throws Exception { + public void testPrimarySplitScreenRestoresPreviousWhenMovedToBack() { // This time, start with a fullscreen activitystack final ActivityStack primarySplitScreen = mDefaultDisplay.createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); primarySplitScreen.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); // Assert windowing mode. - assertEquals(primarySplitScreen.getWindowingMode(), WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode()); // Move primary to back. primarySplitScreen.moveToBack("testPrimarySplitScreenToFullscreenWhenMovedToBack", - null /* task */); + null /* task */); // Assert that stack is at the bottom. - assertEquals(mDefaultDisplay.getIndexOf(primarySplitScreen), 0); + assertEquals(0, mDefaultDisplay.getIndexOf(primarySplitScreen)); // Ensure that the override mode is restored to what it was (fullscreen) - assertEquals(primarySplitScreen.getOverrideWindowingMode(), WINDOWING_MODE_FULLSCREEN); + assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getOverrideWindowingMode()); } @Test - public void testStackInheritsDisplayWindowingMode() throws Exception { + public void testStackInheritsDisplayWindowingMode() { final ActivityStack primarySplitScreen = mDefaultDisplay.createStack( - WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode()); assertEquals(WINDOWING_MODE_UNDEFINED, primarySplitScreen.getOverrideWindowingMode()); @@ -205,9 +201,9 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testStackOverridesDisplayWindowingMode() throws Exception { + public void testStackOverridesDisplayWindowingMode() { final ActivityStack primarySplitScreen = mDefaultDisplay.createStack( - WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode()); assertEquals(WINDOWING_MODE_UNDEFINED, primarySplitScreen.getOverrideWindowingMode()); @@ -221,7 +217,7 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testStopActivityWhenActivityDestroyed() throws Exception { + public void testStopActivityWhenActivityDestroyed() { final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build(); r.info.flags |= ActivityInfo.FLAG_NO_HISTORY; mStack.moveToFront("testStopActivityWithDestroy"); @@ -231,7 +227,7 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testFindTaskWithOverlay() throws Exception { + public void testFindTaskWithOverlay() { final ActivityRecord r = new ActivityBuilder(mService) .setCreateTask(true) .setStack(mStack) @@ -247,8 +243,8 @@ public class ActivityStackTests extends ActivityTestsBase { new ActivityStackSupervisor.FindTaskResult(); mStack.findTaskLocked(r, result); - assertEquals(task.getTopActivity(false /* includeOverlays */), r); - assertEquals(task.getTopActivity(true /* includeOverlays */), taskOverlay); + assertEquals(r, task.getTopActivity(false /* includeOverlays */)); + assertEquals(taskOverlay, task.getTopActivity(true /* includeOverlays */)); assertNotNull(result.mRecord); } @@ -273,7 +269,7 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testShouldBeVisible_Fullscreen() throws Exception { + public void testShouldBeVisible_Fullscreen() { final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, @@ -298,14 +294,16 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testShouldBeVisible_SplitScreen() throws Exception { + public void testShouldBeVisible_SplitScreen() { final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); // Home stack should always be fullscreen for this test. homeStack.setSupportsSplitScreen(false); - final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(mDefaultDisplay, + final TestActivityStack splitScreenPrimary = + createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(mDefaultDisplay, + final TestActivityStack splitScreenSecondary = + createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Home stack shouldn't be visible if both halves of split-screen are opaque. @@ -321,7 +319,8 @@ public class ActivityStackTests extends ActivityTestsBase { assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */)); assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */)); - final TestActivityStack splitScreenSecondary2 = createStackForShouldBeVisibleTest(mDefaultDisplay, + final TestActivityStack splitScreenSecondary2 = + createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); // First split-screen secondary shouldn't be visible behind another opaque split-split // secondary. @@ -364,7 +363,7 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testShouldBeVisible_Finishing() throws Exception { + public void testShouldBeVisible_Finishing() { final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); final TestActivityStack translucentStack = createStackForShouldBeVisibleTest( @@ -403,9 +402,9 @@ public class ActivityStackTests extends ActivityTestsBase { // Ensure that we don't move the home stack if it is already behind the top fullscreen stack int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack); + assertEquals(fullscreenStack, mDefaultDisplay.getStackAbove(homeStack)); mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack); - assertTrue(mDefaultDisplay.getIndexOf(homeStack) == homeStackIndex); + assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack)); } @Test @@ -422,9 +421,9 @@ public class ActivityStackTests extends ActivityTestsBase { // Ensure that we don't move the home stack if it is already behind the top fullscreen stack int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack); + assertEquals(fullscreenStack, mDefaultDisplay.getStackAbove(homeStack)); mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack); - assertTrue(mDefaultDisplay.getIndexOf(homeStack) == homeStackIndex); + assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack)); } @Test @@ -441,9 +440,9 @@ public class ActivityStackTests extends ActivityTestsBase { // Ensure we don't move the home stack if it is already on top int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == null); + assertNull(mDefaultDisplay.getStackAbove(homeStack)); mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack); - assertTrue(mDefaultDisplay.getIndexOf(homeStack) == homeStackIndex); + assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack)); } @Test @@ -458,7 +457,7 @@ public class ActivityStackTests extends ActivityTestsBase { final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final TestActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, + final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); homeStack.setIsTranslucent(false); @@ -467,13 +466,14 @@ public class ActivityStackTests extends ActivityTestsBase { // Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the // pinned stack - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack1); + assertEquals(fullscreenStack1, mDefaultDisplay.getStackAbove(homeStack)); mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack2); + assertEquals(fullscreenStack2, mDefaultDisplay.getStackAbove(homeStack)); } @Test - public void testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreenAndTranslucent() { + public void + testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreenAndTranslucent() { mDefaultDisplay.removeChild(mStack); final TestActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay, @@ -491,9 +491,9 @@ public class ActivityStackTests extends ActivityTestsBase { // Ensure that we move the home stack behind the bottom most non-translucent fullscreen // stack - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack1); + assertEquals(fullscreenStack1, mDefaultDisplay.getStackAbove(homeStack)); mDefaultDisplay.moveStackBehindBottomMostVisibleStack(homeStack); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack1); + assertEquals(fullscreenStack1, mDefaultDisplay.getStackAbove(homeStack)); } @Test @@ -516,7 +516,7 @@ public class ActivityStackTests extends ActivityTestsBase { // Ensure we don't move the home stack behind itself int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack); mDefaultDisplay.moveStackBehindStack(homeStack, homeStack); - assertTrue(mDefaultDisplay.getIndexOf(homeStack) == homeStackIndex); + assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack)); } @Test @@ -539,13 +539,13 @@ public class ActivityStackTests extends ActivityTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack1); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack1); + assertEquals(fullscreenStack1, mDefaultDisplay.getStackAbove(homeStack)); mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack2); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack2); + assertEquals(fullscreenStack2, mDefaultDisplay.getStackAbove(homeStack)); mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack4); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack4); + assertEquals(fullscreenStack4, mDefaultDisplay.getStackAbove(homeStack)); mDefaultDisplay.moveStackBehindStack(homeStack, fullscreenStack2); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == fullscreenStack2); + assertEquals(fullscreenStack2, mDefaultDisplay.getStackAbove(homeStack)); } @Test @@ -554,7 +554,7 @@ public class ActivityStackTests extends ActivityTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */); - assertTrue(mDefaultDisplay.getStackAbove(homeStack) == pinnedStack); + assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(homeStack)); final TestActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, @@ -562,13 +562,13 @@ public class ActivityStackTests extends ActivityTestsBase { alwaysOnTopStack.setAlwaysOnTop(true); assertTrue(alwaysOnTopStack.isAlwaysOnTop()); // Ensure (non-pinned) always on top stack is put below pinned stack. - assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack) == pinnedStack); + assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(alwaysOnTopStack)); final TestActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Ensure non always on top stack is put below always on top stacks. - assertTrue(mDefaultDisplay.getStackAbove(nonAlwaysOnTopStack) == alwaysOnTopStack); + assertEquals(alwaysOnTopStack, mDefaultDisplay.getStackAbove(nonAlwaysOnTopStack)); final TestActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, @@ -576,25 +576,25 @@ public class ActivityStackTests extends ActivityTestsBase { alwaysOnTopStack2.setAlwaysOnTop(true); assertTrue(alwaysOnTopStack2.isAlwaysOnTop()); // Ensure newly created always on top stack is placed above other all always on top stacks. - assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == pinnedStack); + assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(alwaysOnTopStack2)); alwaysOnTopStack2.setAlwaysOnTop(false); // Ensure, when always on top is turned off for a stack, the stack is put just below all // other always on top stacks. - assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == alwaysOnTopStack); + assertEquals(alwaysOnTopStack, mDefaultDisplay.getStackAbove(alwaysOnTopStack2)); alwaysOnTopStack2.setAlwaysOnTop(true); // Ensure always on top state changes properly when windowing mode changes. alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FULLSCREEN); assertFalse(alwaysOnTopStack2.isAlwaysOnTop()); - assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == alwaysOnTopStack); + assertEquals(alwaysOnTopStack, mDefaultDisplay.getStackAbove(alwaysOnTopStack2)); alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FREEFORM); assertTrue(alwaysOnTopStack2.isAlwaysOnTop()); - assertTrue(mDefaultDisplay.getStackAbove(alwaysOnTopStack2) == pinnedStack); + assertEquals(pinnedStack, mDefaultDisplay.getStackAbove(alwaysOnTopStack2)); } @Test - public void testSplitScreenMoveToFront() throws Exception { + public void testSplitScreenMoveToFront() { final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest( mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -619,6 +619,7 @@ public class ActivityStackTests extends ActivityTestsBase { assertFalse(assistantStack.shouldBeVisible(null /* starting */)); } + @SuppressWarnings("TypeParameterUnusedInFormals") private <T extends ActivityStack> T createStackForShouldBeVisibleTest( ActivityDisplay display, int windowingMode, int activityType, boolean onTop) { final T stack; @@ -639,7 +640,7 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testFinishDisabledPackageActivities() throws Exception { + public void testFinishDisabledPackageActivities() { final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build(); @@ -648,17 +649,17 @@ public class ActivityStackTests extends ActivityTestsBase { secondActivity.mTaskOverlay = true; secondActivity.app = null; - assertEquals(mTask.mActivities.size(), 2); + assertEquals(2, mTask.mActivities.size()); mStack.finishDisabledPackageActivitiesLocked(firstActivity.packageName, null, true /* doit */, true /* evenPersistent */, UserHandle.USER_ALL); - assertTrue(mTask.mActivities.isEmpty()); - assertTrue(mStack.getAllTasks().isEmpty()); + assertThat(mTask.mActivities).isEmpty(); + assertThat(mStack.getAllTasks()).isEmpty(); } @Test - public void testHandleAppDied() throws Exception { + public void testHandleAppDied() { final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build(); @@ -671,12 +672,12 @@ public class ActivityStackTests extends ActivityTestsBase { // second activity will be immediately removed as it has no state. secondActivity.haveState = false; - assertEquals(mTask.mActivities.size(), 2); + assertEquals(2, mTask.mActivities.size()); mStack.handleAppDiedLocked(secondActivity.app); - assertTrue(mTask.mActivities.isEmpty()); - assertTrue(mStack.getAllTasks().isEmpty()); + assertThat(mTask.mActivities).isEmpty(); + assertThat(mStack.getAllTasks()).isEmpty(); } @Test @@ -693,7 +694,7 @@ public class ActivityStackTests extends ActivityTestsBase { stack2.getTopActivity().visible = true; final ActivityRecord activity2 = finishCurrentActivity(stack2); assertEquals(STOPPING, activity2.getState()); - assertTrue(mSupervisor.mStoppingActivities.contains(activity2)); + assertThat(mSupervisor.mStoppingActivities).contains(activity2); // The display becomes empty. Since there is no next activity to be idle, the activity // should be destroyed immediately with updating configuration to restore original state. @@ -714,7 +715,7 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testShouldSleepActivities() throws Exception { + public void testShouldSleepActivities() { // When focused activity and keyguard is going away, we should not sleep regardless // of the display state verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/, @@ -732,7 +733,7 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testStackOrderChangedOnRemoveStack() throws Exception { + public void testStackOrderChangedOnRemoveStack() { StackOrderChangedListener listener = new StackOrderChangedListener(); mDefaultDisplay.registerStackOrderChangedListener(listener); try { @@ -740,11 +741,11 @@ public class ActivityStackTests extends ActivityTestsBase { } finally { mDefaultDisplay.unregisterStackOrderChangedListener(listener); } - assertTrue(listener.changed); + assertTrue(listener.mChanged); } @Test - public void testStackOrderChangedOnAddPositionStack() throws Exception { + public void testStackOrderChangedOnAddPositionStack() { mDefaultDisplay.removeChild(mStack); StackOrderChangedListener listener = new StackOrderChangedListener(); @@ -754,11 +755,11 @@ public class ActivityStackTests extends ActivityTestsBase { } finally { mDefaultDisplay.unregisterStackOrderChangedListener(listener); } - assertTrue(listener.changed); + assertTrue(listener.mChanged); } @Test - public void testStackOrderChangedOnPositionStack() throws Exception { + public void testStackOrderChangedOnPositionStack() { StackOrderChangedListener listener = new StackOrderChangedListener(); try { final TestActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest( @@ -769,7 +770,7 @@ public class ActivityStackTests extends ActivityTestsBase { } finally { mDefaultDisplay.unregisterStackOrderChangedListener(listener); } - assertTrue(listener.changed); + assertTrue(listener.mChanged); } private void verifyShouldSleepActivities(boolean focusedStack, @@ -785,12 +786,13 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(expected, mStack.shouldSleepActivities()); } - private class StackOrderChangedListener implements ActivityDisplay.OnStackOrderChangedListener { - boolean changed = false; + private static class StackOrderChangedListener + implements ActivityDisplay.OnStackOrderChangedListener { + public boolean mChanged = false; @Override public void onStackOrderChanged() { - changed = true; + mChanged = true; } } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java index e1ebbcf8f653..e8de05cf4935 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -32,13 +32,12 @@ import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; -import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; -import com.android.server.am.ActivityStarter.Factory; +import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch; +import com.android.server.wm.ActivityStarter.Factory; +import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.Random; @@ -46,20 +45,17 @@ import java.util.Random; * Tests for the {@link ActivityStartController} class. * * Build/Install/Run: - * atest FrameworksServicesTests:ActivityStartControllerTests + * atest WmTests:ActivityStartControllerTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class ActivityStartControllerTests extends ActivityTestsBase { - private ActivityTaskManagerService mService; private ActivityStartController mController; private Factory mFactory; private ActivityStarter mStarter; - @Override + @Before public void setUp() throws Exception { - super.setUp(); mService = createActivityTaskManagerService(); mFactory = mock(Factory.class); mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory); @@ -100,7 +96,7 @@ public class ActivityStartControllerTests extends ActivityTestsBase { * Ensures instances are recycled after execution. */ @Test - public void testRecycling() throws Exception { + public void testRecycling() { final Intent intent = new Intent(); final ActivityStarter optionStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor, mock(ActivityStartInterceptor.class)); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java index 270d394ead34..dda077ecf20d 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java @@ -1,20 +1,20 @@ /* - * Copyright 2017, The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; @@ -48,6 +48,7 @@ import com.android.internal.app.HarmfulAppWarningActivity; import com.android.internal.app.SuspendedAppActivity; import com.android.internal.app.UnlaunchableAppActivity; import com.android.server.LocalServices; +import com.android.server.am.ActivityManagerService; import com.android.server.pm.PackageManagerService; import org.junit.Before; @@ -60,10 +61,10 @@ import org.mockito.MockitoAnnotations; * Unit tests for {@link ActivityStartInterceptorTest}. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.am.ActivityStartInterceptorTest + * atest WmTests:ActivityStartInterceptorTest */ -@Presubmit @SmallTest +@Presubmit public class ActivityStartInterceptorTest { private static final int TEST_USER_ID = 1; private static final int TEST_REAL_CALLING_UID = 2; @@ -133,8 +134,8 @@ public class ActivityStartInterceptorTest { // Mock KeyguardManager when(mContext.getSystemService(Context.KEYGUARD_SERVICE)).thenReturn(mKeyguardManager); when(mKeyguardManager.createConfirmDeviceCredentialIntent( - nullable(CharSequence.class), nullable(CharSequence.class), eq(TEST_USER_ID))). - thenReturn(CONFIRM_CREDENTIALS_INTENT); + nullable(CharSequence.class), nullable(CharSequence.class), eq(TEST_USER_ID))) + .thenReturn(CONFIRM_CREDENTIALS_INTENT); // Mock PackageManager when(mService.getPackageManager()).thenReturn(mPackageManager); @@ -221,8 +222,8 @@ public class ActivityStartInterceptorTest { assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null)); // THEN the returned intent is the harmful app warning intent - assertTrue(mInterceptor.mIntent.getComponent().getClassName().equals( - HarmfulAppWarningActivity.class.getName())); + assertEquals(HarmfulAppWarningActivity.class.getName(), + mInterceptor.mIntent.getComponent().getClassName()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index fb11a04ece50..f7d7ad6d986f 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.START_ABORTED; import static android.app.ActivityManager.START_CLASS_NOT_FOUND; @@ -36,12 +36,13 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; -import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM; -import static com.android.server.am.ActivityDisplay.POSITION_TOP; -import static com.android.server.am.ActivityTaskManagerService.ANIMATE; +import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM; +import static com.android.server.wm.ActivityDisplay.POSITION_TOP; +import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; + +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -74,23 +75,21 @@ import android.service.voice.IVoiceInteractionSession; import android.view.Gravity; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; -import com.android.server.am.LaunchParamsController.LaunchParamsModifier; -import com.android.server.am.TaskRecord.TaskRecordFactory; +import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; +import com.android.server.wm.TaskRecord.TaskRecordFactory; +import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link ActivityStarter} class. * * Build/Install/Run: - * atest FrameworksServicesTests:ActivityStarterTests + * atest WmTests:ActivityStarterTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class ActivityStarterTests extends ActivityTestsBase { private ActivityStarter mStarter; private ActivityStartController mController; @@ -112,9 +111,8 @@ public class ActivityStarterTests extends ActivityTestsBase { private static final int FAKE_REAL_CALLING_UID = 667; private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude"; - @Override + @Before public void setUp() throws Exception { - super.setUp(); setupActivityTaskManagerService(); mController = mock(ActivityStartController.class); mActivityMetricsLogger = mock(ActivityMetricsLogger.class); @@ -124,7 +122,7 @@ public class ActivityStarterTests extends ActivityTestsBase { } @Test - public void testUpdateLaunchBounds() throws Exception { + public void testUpdateLaunchBounds() { // When in a non-resizeable stack, the task bounds should be updated. final TaskRecord task = new TaskBuilder(mService.mStackSupervisor) .setStack(mService.mStackSupervisor.getDefaultDisplay().createStack( @@ -133,7 +131,7 @@ public class ActivityStarterTests extends ActivityTestsBase { final Rect bounds = new Rect(10, 10, 100, 100); mStarter.updateBounds(task, bounds); - assertEquals(task.getOverrideBounds(), bounds); + assertEquals(bounds, task.getOverrideBounds()); assertEquals(new Rect(), task.getStack().getOverrideBounds()); // When in a resizeable stack, the stack bounds should be updated as well. @@ -141,7 +139,7 @@ public class ActivityStarterTests extends ActivityTestsBase { .setStack(mService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */)) .build(); - assertTrue(task2.getStack() instanceof PinnedActivityStack); + assertThat((Object) task2.getStack()).isInstanceOf(PinnedActivityStack.class); mStarter.updateBounds(task2, bounds); verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId), @@ -149,15 +147,15 @@ public class ActivityStarterTests extends ActivityTestsBase { // In the case of no animation, the stack and task bounds should be set immediately. if (!ANIMATE) { - assertEquals(task2.getStack().getOverrideBounds(), bounds); - assertEquals(task2.getOverrideBounds(), bounds); + assertEquals(bounds, task2.getStack().getOverrideBounds()); + assertEquals(bounds, task2.getOverrideBounds()); } else { - assertEquals(task2.getOverrideBounds(), new Rect()); + assertEquals(new Rect(), task2.getOverrideBounds()); } } @Test - public void testStartActivityPreconditions() throws Exception { + public void testStartActivityPreconditions() { verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED); verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT, START_INTENT_NOT_RESOLVED); @@ -211,7 +209,7 @@ public class ActivityStarterTests extends ActivityTestsBase { final WindowProcessController wpc = containsConditions(preconditions, PRECONDITION_NO_CALLER_APP) ? null : new WindowProcessController( - service, mock(ApplicationInfo.class),null, 0, -1, null, null); + service, mock(ApplicationInfo.class), null, 0, -1, null, null); doReturn(wpc).when(service).getProcessController(anyObject()); final Intent intent = new Intent(); @@ -250,7 +248,7 @@ public class ActivityStarterTests extends ActivityTestsBase { anyInt(), anyInt(), anyInt(), anyInt(), any()); } - if (containsConditions(preconditions,PRECONDITION_CANNOT_START_ANY_ACTIVITY)) { + if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) { doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission( any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), anyBoolean(), anyBoolean(), any(), any(), any()); @@ -448,7 +446,7 @@ public class ActivityStarterTests extends ActivityTestsBase { final int result = starter.setReason("testSplitScreenDeliverToTop").execute(); // Ensure result is delivering intent to top. - assertEquals(result, START_DELIVERED_TO_TOP); + assertEquals(START_DELIVERED_TO_TOP, result); } /** @@ -480,7 +478,7 @@ public class ActivityStarterTests extends ActivityTestsBase { final int result = starter.setReason("testSplitScreenMoveToFront").execute(); // Ensure result is moving task to front. - assertEquals(result, START_TASK_TO_FRONT); + assertEquals(START_TASK_TO_FRONT, result); } /** @@ -506,7 +504,7 @@ public class ActivityStarterTests extends ActivityTestsBase { private void assertNoTasks(ActivityDisplay display) { for (int i = display.getChildCount() - 1; i >= 0; --i) { final ActivityStack stack = display.getChildAt(i); - assertTrue(stack.getAllTasks().isEmpty()); + assertThat(stack.getAllTasks()).isEmpty(); } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 57960efee3c7..9d28c5754040 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; @@ -24,8 +24,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; -import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; -import static com.android.server.am.ActivityStackSupervisor.ON_TOP; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; +import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; @@ -60,27 +62,17 @@ import android.testing.DexmakerShareClassLoaderRule; import android.view.Display; import android.view.DisplayInfo; -import androidx.test.InstrumentationRegistry; - import com.android.internal.app.IVoiceInteractor; import com.android.server.AppOpsService; import com.android.server.AttributeCache; import com.android.server.ServiceThread; +import com.android.server.am.ActivityManagerService; import com.android.server.uri.UriGrantsManagerInternal; -import com.android.server.wm.ActivityTaskManagerInternal; -import com.android.server.wm.AppWindowContainerController; -import com.android.server.wm.DisplayWindowController; -import com.android.server.wm.PinnedStackWindowController; -import com.android.server.wm.RootWindowContainerController; -import com.android.server.wm.StackWindowController; -import com.android.server.wm.TaskWindowContainerController; -import com.android.server.wm.WindowManagerService; -import com.android.server.wm.WindowTestUtils; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Rule; -import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import java.io.File; @@ -89,16 +81,14 @@ import java.util.List; /** * A base class to handle common operations in activity related unit tests. */ -public class ActivityTestsBase { - private static boolean sOneTimeSetupDone = false; - +class ActivityTestsBase { private static int sNextDisplayId = DEFAULT_DISPLAY + 1; @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); - private final Context mContext = InstrumentationRegistry.getContext(); + final Context mContext = getInstrumentation().getTargetContext(); final TestInjector mTestInjector = new TestInjector(); ActivityTaskManagerService mService; @@ -110,22 +100,22 @@ public class ActivityTestsBase { // Default base activity name private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity"; + @BeforeClass + public static void setUpOnceBase() { + AttributeCache.init(getInstrumentation().getTargetContext()); + } + @Before - public void setUp() throws Exception { - if (!sOneTimeSetupDone) { - sOneTimeSetupDone = true; - MockitoAnnotations.initMocks(this); - AttributeCache.init(mContext); - } + public void setUpBase() { mTestInjector.setUp(); } @After - public void tearDown() { + public void tearDownBase() { mTestInjector.tearDown(); } - protected ActivityTaskManagerService createActivityTaskManagerService() { + ActivityTaskManagerService createActivityTaskManagerService() { final TestActivityTaskManagerService atm = spy(new TestActivityTaskManagerService(mContext)); setupActivityManagerService(atm); @@ -396,10 +386,10 @@ public class ActivityTestsBase { } private static class TestTaskRecord extends TaskRecord { - TestTaskRecord(ActivityTaskManagerService service, int _taskId, ActivityInfo info, - Intent _intent, IVoiceInteractionSession _voiceSession, - IVoiceInteractor _voiceInteractor) { - super(service, _taskId, info, _intent, _voiceSession, _voiceInteractor); + TestTaskRecord(ActivityTaskManagerService service, int taskId, ActivityInfo info, + Intent intent, IVoiceInteractionSession voiceSession, + IVoiceInteractor voiceInteractor) { + super(service, taskId, info, intent, voiceSession, voiceInteractor); } @Override @@ -451,7 +441,7 @@ public class ActivityTestsBase { } @Override - final protected ActivityStackSupervisor createStackSupervisor() { + protected final ActivityStackSupervisor createStackSupervisor() { if (mTestStackSupervisor == null) { final ActivityStackSupervisor supervisor = spy(createTestSupervisor()); final KeyguardController keyguardController = mock(KeyguardController.class); @@ -486,10 +476,13 @@ public class ActivityTestsBase { return mInternal; } + @Override PackageManagerInternal getPackageManagerInternalLocked() { if (mPmInternal == null) { mPmInternal = mock(PackageManagerInternal.class); - doReturn(false).when(mPmInternal).isPermissionsReviewRequired(anyString(), anyInt()); + doReturn(false) + .when(mPmInternal) + .isPermissionsReviewRequired(anyString(), anyInt()); } return mPmInternal; } @@ -500,7 +493,7 @@ public class ActivityTestsBase { @Override public Context getContext() { - return InstrumentationRegistry.getContext(); + return getInstrumentation().getTargetContext(); } @Override @@ -611,6 +604,7 @@ public class ActivityTestsBase { mSupervisor = supervisor; } + @SuppressWarnings("TypeParameterUnusedInFormals") @Override <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop) { @@ -798,6 +792,7 @@ public class ActivityTestsBase { return this; } + @SuppressWarnings("TypeParameterUnusedInFormals") <T extends ActivityStack> T build() { final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId(); if (mWindowingMode == WINDOWING_MODE_PINNED) { diff --git a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java index 1b823ff8c6b4..c6c1c5261b17 100644 --- a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,10 +11,10 @@ * 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. + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_ERRORED; @@ -22,6 +22,9 @@ import static android.app.AppOpsManager.OP_ASSIST_SCREENSHOT; import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE; import static android.graphics.Bitmap.Config.ARGB_8888; +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -45,16 +48,14 @@ import android.os.Looper; import android.util.Log; import android.view.IWindowManager; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; +import com.android.server.am.AssistDataRequester; import com.android.server.am.AssistDataRequester.AssistDataRequesterCallbacks; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.List; @@ -65,11 +66,11 @@ import java.util.concurrent.TimeUnit; * Note: Currently, we only support fetching the screenshot for the current application, so the * screenshot checks are hardcoded accordingly. * - * runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java + * Build/Install/Run: + * atest WmTests:AssistDataRequesterTest */ @MediumTest @FlakyTest(bugId = 113616538) -@RunWith(AndroidJUnit4.class) public class AssistDataRequesterTest extends ActivityTestsBase { private static final String TAG = AssistDataRequesterTest.class.getSimpleName(); @@ -105,14 +106,11 @@ public class AssistDataRequesterTest extends ActivityTestsBase { private CountDownLatch mGate; @Before - @Override public void setUp() throws Exception { - super.setUp(); mAm = mock(IActivityManager.class); mAtm = mock(IActivityTaskManager.class); mWm = mock(IWindowManager.class); mAppOpsManager = mock(AppOpsManager.class); - mContext = InstrumentationRegistry.getContext(); mHandler = new Handler(Looper.getMainLooper()); mCallbacksLock = new Object(); mCallbacks = new Callbacks(); @@ -190,35 +188,35 @@ public class AssistDataRequesterTest extends ActivityTestsBase { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED, CALLER_ASSIST_SCREENSHOT_ALLOWED); - mCallbacks.canHandleReceivedData = false; + mCallbacks.mCanHandleReceivedData = false; mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS, ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE); - assertTrue(mDataRequester.getPendingDataCount() == 5); - assertTrue(mDataRequester.getPendingScreenshotCount() == 1); + assertEquals(5, mDataRequester.getPendingDataCount()); + assertEquals(1, mDataRequester.getPendingScreenshotCount()); mGate.countDown(); waitForIdle(mHandler); // Callbacks still not ready to receive, but all pending data is received - assertTrue(mDataRequester.getPendingDataCount() == 0); - assertTrue(mDataRequester.getPendingScreenshotCount() == 0); - assertTrue(mCallbacks.receivedData.isEmpty()); - assertTrue(mCallbacks.receivedScreenshots.isEmpty()); - assertFalse(mCallbacks.requestCompleted); + assertEquals(0, mDataRequester.getPendingDataCount()); + assertEquals(0, mDataRequester.getPendingScreenshotCount()); + assertThat(mCallbacks.mReceivedData).isEmpty(); + assertThat(mCallbacks.mReceivedScreenshots).isEmpty(); + assertFalse(mCallbacks.mRequestCompleted); - mCallbacks.canHandleReceivedData = true; + mCallbacks.mCanHandleReceivedData = true; mDataRequester.processPendingAssistData(); // Since we are posting the callback for the request-complete, flush the handler as well mGate.countDown(); waitForIdle(mHandler); - assertTrue(mCallbacks.receivedData.size() == 5); - assertTrue(mCallbacks.receivedScreenshots.size() == 1); - assertTrue(mCallbacks.requestCompleted); + assertEquals(5, mCallbacks.mReceivedData.size()); + assertEquals(1, mCallbacks.mReceivedScreenshots.size()); + assertTrue(mCallbacks.mRequestCompleted); // Clear the state and ensure that we only process pending data once mCallbacks.reset(); mDataRequester.processPendingAssistData(); - assertTrue(mCallbacks.receivedData.isEmpty()); - assertTrue(mCallbacks.receivedScreenshots.isEmpty()); + assertThat(mCallbacks.mReceivedData).isEmpty(); + assertThat(mCallbacks.mReceivedScreenshots).isEmpty(); } @Test @@ -281,13 +279,13 @@ public class AssistDataRequesterTest extends ActivityTestsBase { setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, !CALLER_ASSIST_STRUCTURE_ALLOWED, !CALLER_ASSIST_SCREENSHOT_ALLOWED); - mCallbacks.canHandleReceivedData = false; + mCallbacks.mCanHandleReceivedData = false; mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS, ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE); mGate.countDown(); waitForIdle(mHandler); - assertTrue(mCallbacks.receivedData.isEmpty()); - assertTrue(mCallbacks.receivedScreenshots.isEmpty()); + assertThat(mCallbacks.mReceivedData).isEmpty(); + assertThat(mCallbacks.mReceivedScreenshots).isEmpty(); } @Test @@ -302,22 +300,22 @@ public class AssistDataRequesterTest extends ActivityTestsBase { private void assertReceivedDataCount(int numPendingData, int numReceivedData, int numPendingScreenshots, int numReceivedScreenshots) throws Exception { - assertTrue("Expected " + numPendingData + " pending data, got " + assertEquals("Expected " + numPendingData + " pending data, got " + mDataRequester.getPendingDataCount(), - mDataRequester.getPendingDataCount() == numPendingData); - assertTrue("Expected " + numPendingScreenshots + " pending screenshots, got " + numPendingData, mDataRequester.getPendingDataCount()); + assertEquals("Expected " + numPendingScreenshots + " pending screenshots, got " + mDataRequester.getPendingScreenshotCount(), - mDataRequester.getPendingScreenshotCount() == numPendingScreenshots); - assertFalse("Expected request NOT completed", mCallbacks.requestCompleted); + numPendingScreenshots, mDataRequester.getPendingScreenshotCount()); + assertFalse("Expected request NOT completed", mCallbacks.mRequestCompleted); mGate.countDown(); waitForIdle(mHandler); - assertTrue("Expected " + numReceivedData + " data, received " - + mCallbacks.receivedData.size(), - mCallbacks.receivedData.size() == numReceivedData); - assertTrue("Expected " + numReceivedScreenshots + " screenshots, received " - + mCallbacks.receivedScreenshots.size(), - mCallbacks.receivedScreenshots.size() == numReceivedScreenshots); - assertTrue("Expected request completed", mCallbacks.requestCompleted); + assertEquals("Expected " + numReceivedData + " data, received " + + mCallbacks.mReceivedData.size(), + numReceivedData, mCallbacks.mReceivedData.size()); + assertEquals("Expected " + numReceivedScreenshots + " screenshots, received " + + mCallbacks.mReceivedScreenshots.size(), + numReceivedScreenshots, mCallbacks.mReceivedScreenshots.size()); + assertTrue("Expected request completed", mCallbacks.mRequestCompleted); } private List<IBinder> createActivityList(int size) { @@ -339,30 +337,30 @@ public class AssistDataRequesterTest extends ActivityTestsBase { private class Callbacks implements AssistDataRequesterCallbacks { - boolean canHandleReceivedData = true; - boolean requestCompleted = false; - ArrayList<Bundle> receivedData = new ArrayList<>(); - ArrayList<Bitmap> receivedScreenshots = new ArrayList<>(); + public boolean mCanHandleReceivedData = true; + public boolean mRequestCompleted = false; + public final ArrayList<Bundle> mReceivedData = new ArrayList<>(); + public final ArrayList<Bitmap> mReceivedScreenshots = new ArrayList<>(); void reset() { - canHandleReceivedData = true; - receivedData.clear(); - receivedScreenshots.clear(); + mCanHandleReceivedData = true; + mReceivedData.clear(); + mReceivedScreenshots.clear(); } @Override public boolean canHandleReceivedAssistDataLocked() { - return canHandleReceivedData; + return mCanHandleReceivedData; } @Override public void onAssistDataReceivedLocked(Bundle data, int activityIndex, int activityCount) { - receivedData.add(data); + mReceivedData.add(data); } @Override public void onAssistScreenshotReceivedLocked(Bitmap screenshot) { - receivedScreenshots.add(screenshot); + mReceivedScreenshots.add(screenshot); } @Override @@ -370,7 +368,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase { mHandler.post(() -> { try { mGate.await(10, TimeUnit.SECONDS); - requestCompleted = true; + mRequestCompleted = true; } catch (InterruptedException e) { Log.e(TAG, "Failed to wait", e); } diff --git a/services/tests/servicestests/src/com/android/server/am/ClientLifecycleManagerTests.java b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java index b4ad183db386..f1d840d0dc52 100644 --- a/services/tests/servicestests/src/com/android/server/am/ClientLifecycleManagerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java @@ -1,4 +1,20 @@ -package com.android.server.am; +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -11,12 +27,13 @@ import android.os.Binder; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +/** + * Build/Install/Run: + * atest WmTests:ClientLifecycleManagerTests + */ @SmallTest @Presubmit public class ClientLifecycleManagerTests { diff --git a/services/tests/servicestests/src/com/android/server/wm/ConfigurationContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java index 2b8214d162c9..82a200bc207f 100644 --- a/services/tests/servicestests/src/com/android/server/wm/ConfigurationContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java @@ -11,13 +11,12 @@ * 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 + * limitations under the License. */ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; @@ -36,10 +35,8 @@ import android.content.res.Configuration; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.List; @@ -48,15 +45,14 @@ import java.util.List; * Test class for {@link ConfigurationContainer}. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.ConfigurationContainerTests + * atest WmTests:ConfigurationContainerTests */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class ConfigurationContainerTests { @Test - public void testConfigurationInit() throws Exception { + public void testConfigurationInit() { // Check root container initial config. final TestConfigurationContainer root = new TestConfigurationContainer(); assertEquals(EMPTY, root.getOverrideConfiguration()); @@ -93,7 +89,7 @@ public class ConfigurationContainerTests { } @Test - public void testConfigurationChangeOnAddRemove() throws Exception { + public void testConfigurationChangeOnAddRemove() { // Init root's config. final TestConfigurationContainer root = new TestConfigurationContainer(); final Configuration rootOverrideConfig = new Configuration(); @@ -135,7 +131,7 @@ public class ConfigurationContainerTests { } @Test - public void testConfigurationChangePropagation() throws Exception { + public void testConfigurationChangePropagation() { // Builds 3-level vertical hierarchy with one configuration container on each level. // In addition to different overrides on each level, everyone in hierarchy will have one // common overridden value - orientation; @@ -212,7 +208,7 @@ public class ConfigurationContainerTests { } @Test - public void testSetWindowingMode() throws Exception { + public void testSetWindowingMode() { final TestConfigurationContainer root = new TestConfigurationContainer(); root.setWindowingMode(WINDOWING_MODE_UNDEFINED); final TestConfigurationContainer child = root.addChild(); @@ -226,7 +222,7 @@ public class ConfigurationContainerTests { } @Test - public void testSetActivityType() throws Exception { + public void testSetActivityType() { final TestConfigurationContainer root = new TestConfigurationContainer(); root.setActivityType(ACTIVITY_TYPE_UNDEFINED); final TestConfigurationContainer child = root.addChild(); @@ -272,7 +268,7 @@ public class ConfigurationContainerTests { } @Test - public void testRegisterConfigurationChangeListener() throws Exception { + public void testRegisterConfigurationChangeListener() { final TestConfigurationContainer container = new TestConfigurationContainer(); final TestConfigurationChangeListener listener = new TestConfigurationChangeListener(); final Configuration config = new Configuration(); @@ -328,10 +324,11 @@ public class ConfigurationContainerTests { } } - private class TestConfigurationChangeListener implements ConfigurationContainerListener { + private static class TestConfigurationChangeListener implements ConfigurationContainerListener { final Configuration mOverrideConfiguration = new Configuration(); + @Override public void onOverrideConfigurationChanged(Configuration overrideConfiguration) { mOverrideConfiguration.setTo(overrideConfiguration); } diff --git a/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java index 2fb10e13ab0b..40c20a4b85a3 100644 --- a/services/tests/servicestests/src/com/android/server/am/LaunchParamsControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,15 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; -import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; -import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -41,32 +41,26 @@ import android.content.pm.ActivityInfo.WindowLayout; import android.platform.test.annotations.Presubmit; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; -import com.android.server.am.LaunchParamsController.LaunchParams; -import com.android.server.am.LaunchParamsController.LaunchParamsModifier; +import com.android.server.wm.LaunchParamsController.LaunchParams; +import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for exercising {@link LaunchParamsController}. * * Build/Install/Run: - * atest FrameworksServicesTests:LaunchParamsControllerTests + * atest WmTests:LaunchParamsControllerTests */ @MediumTest @Presubmit -@RunWith(AndroidJUnit4.class) public class LaunchParamsControllerTests extends ActivityTestsBase { - private ActivityTaskManagerService mService; private LaunchParamsController mController; @Before - @Override public void setUp() throws Exception { - super.setUp(); mService = createActivityTaskManagerService(); mController = new LaunchParamsController(mService); } @@ -181,8 +175,7 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { mController.registerModifier(positioner1); mController.registerModifier(positioner2); - final LaunchParams - result = new LaunchParams(); + final LaunchParams result = new LaunchParams(); mController.calculate(null /*task*/, null /*layout*/, null /*activity*/, null /*source*/, null /*options*/, result); @@ -253,19 +246,18 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { mController.registerModifier(positioner); final int beforeWindowMode = task.getStack().getWindowingMode(); - assertNotEquals(beforeWindowMode, windowingMode); + assertNotEquals(windowingMode, beforeWindowMode); mController.layoutTask(task, null /* windowLayout */); final int afterWindowMode = task.getStack().getWindowingMode(); - assertEquals(afterWindowMode, windowingMode); + assertEquals(windowingMode, afterWindowMode); } - public static class InstrumentedPositioner implements - LaunchParamsModifier { + public static class InstrumentedPositioner implements LaunchParamsModifier { - final private int mReturnVal; - final private LaunchParams mParams; + private final int mReturnVal; + private final LaunchParams mParams; InstrumentedPositioner(int returnVal, LaunchParams params) { mReturnVal = returnVal; diff --git a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java index 863a0d8d34a4..6b613ed96761 100644 --- a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java @@ -1,20 +1,20 @@ /* - * Copyright 2017, The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; @@ -32,12 +32,25 @@ import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATI import static android.os.Process.SYSTEM_UID; import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; -import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_LOCKED; -import static com.android.server.am.LockTaskController.STATUS_BAR_MASK_PINNED; - -import static org.junit.Assert.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_LOCKED; +import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_PINNED; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.StatusBarManager; import android.app.admin.DevicePolicyManager; @@ -56,7 +69,6 @@ import android.telecom.TelecomManager; import android.testing.DexmakerShareClassLoaderRule; import android.util.Pair; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import com.android.internal.statusbar.IStatusBarService; @@ -77,10 +89,10 @@ import org.mockito.verification.VerificationMode; * Unit tests for {@link LockTaskController}. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.am.LockTaskControllerTest + * atest WmTests:LockTaskControllerTest */ -@Presubmit @SmallTest +@Presubmit public class LockTaskControllerTest { private static final String TEST_PACKAGE_NAME = "com.test.package"; private static final String TEST_PACKAGE_NAME_2 = "com.test.package2"; @@ -109,7 +121,7 @@ public class LockTaskControllerTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mContext = InstrumentationRegistry.getTargetContext(); + mContext = getInstrumentation().getTargetContext(); mLockToAppSetting = Settings.Secure.getString(mContext.getContentResolver(), Settings.Secure.LOCK_TO_APP_EXIT_LOCKED); @@ -183,7 +195,7 @@ public class LockTaskControllerTest { } @Test - public void testStartLockTaskMode_pinningRequest() throws Exception { + public void testStartLockTaskMode_pinningRequest() { // GIVEN a task record that is not whitelisted, i.e. with pinned auth TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_PINNABLE); @@ -214,7 +226,7 @@ public class LockTaskControllerTest { } @Test - public void testLockTaskViolation() throws Exception { + public void testLockTaskViolation() { // GIVEN one task record with whitelisted auth that is in lock task mode TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); mLockTaskController.startLockTaskMode(tr, false, TEST_UID); @@ -240,7 +252,7 @@ public class LockTaskControllerTest { } @Test - public void testLockTaskViolation_emergencyCall() throws Exception { + public void testLockTaskViolation_emergencyCall() { // GIVEN one task record with whitelisted auth that is in lock task mode TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); mLockTaskController.startLockTaskMode(tr, false, TEST_UID); @@ -289,7 +301,7 @@ public class LockTaskControllerTest { } @Test(expected = SecurityException.class) - public void testStopLockTaskMode_differentCaller() throws Exception { + public void testStopLockTaskMode_differentCaller() { // GIVEN one task record with whitelisted auth that is in lock task mode TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); mLockTaskController.startLockTaskMode(tr, false, TEST_UID); @@ -301,7 +313,7 @@ public class LockTaskControllerTest { } @Test - public void testStopLockTaskMode_systemCaller() throws Exception { + public void testStopLockTaskMode_systemCaller() { // GIVEN one task record with whitelisted auth that is in lock task mode TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); mLockTaskController.startLockTaskMode(tr, false, TEST_UID); @@ -404,7 +416,7 @@ public class LockTaskControllerTest { } @Test - public void testUpdateLockTaskPackages() throws Exception { + public void testUpdateLockTaskPackages() { String[] whitelist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2}; String[] whitelist2 = {TEST_PACKAGE_NAME}; @@ -541,7 +553,7 @@ public class LockTaskControllerTest { } @Test - public void testUpdateLockTaskFeatures_keyguard() throws Exception { + public void testUpdateLockTaskFeatures_keyguard() { // GIVEN a locked task TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED); mLockTaskController.startLockTaskMode(tr, false, TEST_UID); diff --git a/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java index 4beebc4dd2f9..efd7d25c586d 100644 --- a/services/tests/servicestests/src/com/android/server/am/PendingRemoteAnimationRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -26,35 +26,31 @@ import android.view.RemoteAnimationAdapter; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.testutils.OffsettableClock; import com.android.server.testutils.TestHandler; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * atest PendingRemoteAnimationRegistryTest + * Build/Install/Run: + * atest WmTests:PendingRemoteAnimationRegistryTest */ @SmallTest -@Presubmit @FlakyTest -@RunWith(AndroidJUnit4.class) +@Presubmit public class PendingRemoteAnimationRegistryTest extends ActivityTestsBase { @Mock RemoteAnimationAdapter mAdapter; private PendingRemoteAnimationRegistry mRegistry; private final OffsettableClock mClock = new OffsettableClock.Stopped(); private TestHandler mHandler; - private ActivityTaskManagerService mService; @Before public void setUp() throws Exception { - super.setUp(); MockitoAnnotations.initMocks(this); mService = createActivityTaskManagerService(); mService.mH.runWithScissors(() -> { diff --git a/services/tests/servicestests/src/com/android/server/am/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java index d7794b04adca..20150b4594cb 100644 --- a/services/tests/servicestests/src/com/android/server/am/PersisterQueueTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java @@ -11,11 +11,12 @@ * 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. - * + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; + +import static com.google.common.truth.Truth.assertWithMessage; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertSame; @@ -27,10 +28,12 @@ import static org.junit.Assert.assertTrue; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.MediumTest; + import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.List; @@ -39,17 +42,13 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; -import androidx.test.filters.FlakyTest; -import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; - /** - * atest PersisterQueueTests + * Build/Install/Run: + * atest WmTests:PersisterQueueTests */ -@RunWith(AndroidJUnit4.class) @MediumTest -@Presubmit @FlakyTest(detail = "Confirm stable in post-submit before removing") +@Presubmit public class PersisterQueueTests implements PersisterQueue.Listener { private static final long INTER_WRITE_DELAY_MS = 50; private static final long PRE_TASK_DELAY_MS = 300; @@ -63,7 +62,8 @@ public class PersisterQueueTests implements PersisterQueue.Listener { private volatile CountDownLatch mLatch; private List<Boolean> mProbablyDoneResults; - private PersisterQueue mTarget; + private final PersisterQueue mTarget = + new PersisterQueue(INTER_WRITE_DELAY_MS, PRE_TASK_DELAY_MS); @Before public void setUp() throws Exception { @@ -71,7 +71,6 @@ public class PersisterQueueTests implements PersisterQueue.Listener { mProbablyDoneResults = new ArrayList<>(); mSetUpLatch = new CountDownLatch(1); - mTarget = new PersisterQueue(INTER_WRITE_DELAY_MS, PRE_TASK_DELAY_MS); mTarget.addListener(this); mTarget.startPersisting(); @@ -82,10 +81,11 @@ public class PersisterQueueTests implements PersisterQueue.Listener { @After public void tearDown() throws Exception { mTarget.stopPersisting(); + mTarget.removeListener(this); } @Test - public void testCallCallbackOnStartUp() throws Exception { + public void testCallCallbackOnStartUp() { // The onPreProcessItem() must be called on start up. assertEquals(1, mProbablyDoneResults.size()); // The last one must be called with probably done being true. @@ -197,7 +197,7 @@ public class PersisterQueueTests implements PersisterQueue.Listener { } @Test - public void testFindLastItemNotReturnDifferentType() throws Exception { + public void testFindLastItemNotReturnDifferentType() { synchronized (mTarget) { mTarget.addItem(new TestItem(), false); assertNull(mTarget.findLastItem(TEST_ITEM_PREDICATE, MatchingTestItem.class)); @@ -205,7 +205,7 @@ public class PersisterQueueTests implements PersisterQueue.Listener { } @Test - public void testFindLastItemNotReturnMismatchItem() throws Exception { + public void testFindLastItemNotReturnMismatchItem() { synchronized (mTarget) { mTarget.addItem(new MatchingTestItem(false), false); assertNull(mTarget.findLastItem(TEST_ITEM_PREDICATE, MatchingTestItem.class)); @@ -213,7 +213,7 @@ public class PersisterQueueTests implements PersisterQueue.Listener { } @Test - public void testFindLastItemReturnMatchedItem() throws Exception { + public void testFindLastItemReturnMatchedItem() { synchronized (mTarget) { final MatchingTestItem item = new MatchingTestItem(true); mTarget.addItem(item, false); @@ -267,8 +267,8 @@ public class PersisterQueueTests implements PersisterQueue.Listener { assertEquals("Flush should wait until all items are processed before return.", 2, mItemCount.get()); final long processTime = SystemClock.uptimeMillis() - dispatchTime; - assertTrue("Flush should trigger immediate flush without delays. processTime: " - + processTime, processTime < TIMEOUT_ALLOWANCE); + assertWithMessage("Flush should trigger immediate flush without delays. processTime: " + + processTime).that(processTime).isLessThan(TIMEOUT_ALLOWANCE); } @Override diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 04fe7873f5b1..26241d2e2e6f 100644 --- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,13 +11,12 @@ * 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. + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; @@ -30,6 +29,9 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.view.Display.DEFAULT_DISPLAY; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -39,6 +41,8 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static java.lang.Integer.MAX_VALUE; + import android.app.ActivityManager.RecentTaskInfo; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; @@ -58,44 +62,37 @@ import android.platform.test.annotations.Presubmit; import android.util.MutableLong; import android.util.SparseBooleanArray; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; -import com.android.server.am.RecentTasks.Callbacks; +import com.android.server.wm.RecentTasks.Callbacks; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; - -import static java.lang.Integer.MAX_VALUE; import java.io.File; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; /** - * atest FrameworksServicesTests:RecentTasksTest + * Build/Install/Run: + * atest WmTests:RecentTasksTest */ @MediumTest @Presubmit -@RunWith(AndroidJUnit4.class) public class RecentTasksTest extends ActivityTestsBase { private static final int TEST_USER_0_ID = 0; private static final int TEST_USER_1_ID = 10; private static final int TEST_QUIET_USER_ID = 20; private static final UserInfo DEFAULT_USER_INFO = new UserInfo(); private static final UserInfo QUIET_USER_INFO = new UserInfo(); - private static int LAST_TASK_ID = 1; - private static int LAST_STACK_ID = 1; - private static int INVALID_STACK_ID = 999; + private static int sLastTaskId = 1; + private static int sLastStackId = 1; + private static final int INVALID_STACK_ID = 999; - private Context mContext = InstrumentationRegistry.getContext(); - private TestActivityTaskManagerService mService; + private TestActivityTaskManagerService mTestService; private ActivityDisplay mDisplay; private ActivityDisplay mOtherDisplay; private ActivityStack mStack; @@ -110,19 +107,16 @@ public class RecentTasksTest extends ActivityTestsBase { private CallbacksRecorder mCallbacksRecorder; @Before - @Override public void setUp() throws Exception { - super.setUp(); - mTaskPersister = new TestTaskPersister(mContext.getFilesDir()); - mService = spy(new MyTestActivityTaskManagerService(mContext)); + mTestService = spy(new MyTestActivityTaskManagerService(mContext)); final TestActivityManagerService am = spy(new MyTestActivityManagerService()); - setupActivityManagerService(am, mService); - mRecentTasks = (TestRecentTasks) mService.getRecentTasks(); + setupActivityManagerService(am, mTestService); + mRecentTasks = (TestRecentTasks) mTestService.getRecentTasks(); mRecentTasks.loadParametersFromResources(mContext.getResources()); - mHomeStack = mService.mStackSupervisor.getDefaultDisplay().getOrCreateStack( + mHomeStack = mTestService.mStackSupervisor.getDefaultDisplay().getOrCreateStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); - mStack = mService.mStackSupervisor.getDefaultDisplay().createStack( + mStack = mTestService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); mCallbacksRecorder = new CallbacksRecorder(); mRecentTasks.registerCallback(mCallbacksRecorder); @@ -141,50 +135,50 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testCallbacks() throws Exception { + public void testCallbacks() { // Add some tasks mRecentTasks.add(mTasks.get(0)); mRecentTasks.add(mTasks.get(1)); - assertTrue(mCallbacksRecorder.added.contains(mTasks.get(0)) - && mCallbacksRecorder.added.contains(mTasks.get(1))); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.isEmpty()); + assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(0)); + assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(1)); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).isEmpty(); mCallbacksRecorder.clear(); // Remove some tasks mRecentTasks.remove(mTasks.get(0)); mRecentTasks.remove(mTasks.get(1)); - assertTrue(mCallbacksRecorder.added.isEmpty()); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.contains(mTasks.get(0))); - assertTrue(mCallbacksRecorder.removed.contains(mTasks.get(1))); + assertThat(mCallbacksRecorder.mAdded).isEmpty(); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(0)); + assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(1)); mCallbacksRecorder.clear(); // Remove the callback, ensure we don't get any calls mRecentTasks.unregisterCallback(mCallbacksRecorder); mRecentTasks.add(mTasks.get(0)); mRecentTasks.remove(mTasks.get(0)); - assertTrue(mCallbacksRecorder.added.isEmpty()); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.isEmpty()); + assertThat(mCallbacksRecorder.mAdded).isEmpty(); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).isEmpty(); } @Test - public void testAddTasksNoMultiple_expectNoTrim() throws Exception { + public void testAddTasksNoMultiple_expectNoTrim() { // Add same non-multiple-task document tasks will remove the task (to re-add it) but not // trim it TaskRecord documentTask1 = createDocumentTask(".DocumentTask1"); TaskRecord documentTask2 = createDocumentTask(".DocumentTask1"); mRecentTasks.add(documentTask1); mRecentTasks.add(documentTask2); - assertTrue(mCallbacksRecorder.added.contains(documentTask1)); - assertTrue(mCallbacksRecorder.added.contains(documentTask2)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.contains(documentTask1)); + assertThat(mCallbacksRecorder.mAdded).contains(documentTask1); + assertThat(mCallbacksRecorder.mAdded).contains(documentTask2); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).contains(documentTask1); } @Test - public void testAddTasksMaxTaskRecents_expectNoTrim() throws Exception { + public void testAddTasksMaxTaskRecents_expectNoTrim() { // Add a task hitting max-recents for that app will remove the task (to add the next one) // but not trim it TaskRecord documentTask1 = createDocumentTask(".DocumentTask1"); @@ -193,27 +187,27 @@ public class RecentTasksTest extends ActivityTestsBase { documentTask2.maxRecents = 1; mRecentTasks.add(documentTask1); mRecentTasks.add(documentTask2); - assertTrue(mCallbacksRecorder.added.contains(documentTask1)); - assertTrue(mCallbacksRecorder.added.contains(documentTask2)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.contains(documentTask1)); + assertThat(mCallbacksRecorder.mAdded).contains(documentTask1); + assertThat(mCallbacksRecorder.mAdded).contains(documentTask2); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).contains(documentTask1); } @Test - public void testAddTasksSameTask_expectNoTrim() throws Exception { + public void testAddTasksSameTask_expectNoTrim() { // Add a task that is already in the task list does not trigger any callbacks, it just // moves in the list TaskRecord documentTask1 = createDocumentTask(".DocumentTask1"); mRecentTasks.add(documentTask1); mRecentTasks.add(documentTask1); - assertTrue(mCallbacksRecorder.added.size() == 1); - assertTrue(mCallbacksRecorder.added.contains(documentTask1)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.isEmpty()); + assertThat(mCallbacksRecorder.mAdded).hasSize(1); + assertThat(mCallbacksRecorder.mAdded).contains(documentTask1); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).isEmpty(); } @Test - public void testAddTasksMultipleDocumentTasks_expectNoTrim() throws Exception { + public void testAddTasksMultipleDocumentTasks_expectNoTrim() { // Add same multiple-task document tasks does not trim the first tasks TaskRecord documentTask1 = createDocumentTask(".DocumentTask1", FLAG_ACTIVITY_MULTIPLE_TASK); @@ -221,15 +215,15 @@ public class RecentTasksTest extends ActivityTestsBase { FLAG_ACTIVITY_MULTIPLE_TASK); mRecentTasks.add(documentTask1); mRecentTasks.add(documentTask2); - assertTrue(mCallbacksRecorder.added.size() == 2); - assertTrue(mCallbacksRecorder.added.contains(documentTask1)); - assertTrue(mCallbacksRecorder.added.contains(documentTask2)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.isEmpty()); + assertThat(mCallbacksRecorder.mAdded).hasSize(2); + assertThat(mCallbacksRecorder.mAdded).contains(documentTask1); + assertThat(mCallbacksRecorder.mAdded).contains(documentTask2); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).isEmpty(); } @Test - public void testAddTasksMultipleTasks_expectRemovedNoTrim() throws Exception { + public void testAddTasksMultipleTasks_expectRemovedNoTrim() { // Add multiple same-affinity non-document tasks, ensure that it removes the other task, // but that it does not trim it TaskRecord task1 = createTaskBuilder(".Task1") @@ -239,21 +233,21 @@ public class RecentTasksTest extends ActivityTestsBase { .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) .build(); mRecentTasks.add(task1); - assertTrue(mCallbacksRecorder.added.size() == 1); - assertTrue(mCallbacksRecorder.added.contains(task1)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.isEmpty()); + assertThat(mCallbacksRecorder.mAdded).hasSize(1); + assertThat(mCallbacksRecorder.mAdded).contains(task1); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).isEmpty(); mCallbacksRecorder.clear(); mRecentTasks.add(task2); - assertTrue(mCallbacksRecorder.added.size() == 1); - assertTrue(mCallbacksRecorder.added.contains(task2)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.size() == 1); - assertTrue(mCallbacksRecorder.removed.contains(task1)); + assertThat(mCallbacksRecorder.mAdded).hasSize(1); + assertThat(mCallbacksRecorder.mAdded).contains(task2); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).hasSize(1); + assertThat(mCallbacksRecorder.mRemoved).contains(task1); } @Test - public void testAddTasksDifferentStacks_expectNoRemove() throws Exception { + public void testAddTasksDifferentStacks_expectNoRemove() { // Adding the same task with different activity types should not trigger removal of the // other task TaskRecord task1 = createTaskBuilder(".Task1") @@ -264,15 +258,15 @@ public class RecentTasksTest extends ActivityTestsBase { .setStack(mStack).build(); mRecentTasks.add(task1); mRecentTasks.add(task2); - assertTrue(mCallbacksRecorder.added.size() == 2); - assertTrue(mCallbacksRecorder.added.contains(task1)); - assertTrue(mCallbacksRecorder.added.contains(task2)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.isEmpty()); + assertThat(mCallbacksRecorder.mAdded).hasSize(2); + assertThat(mCallbacksRecorder.mAdded).contains(task1); + assertThat(mCallbacksRecorder.mAdded).contains(task2); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).isEmpty(); } @Test - public void testAddTaskCompatibleActivityType_expectRemove() throws Exception { + public void testAddTaskCompatibleActivityType_expectRemove() { // Test with undefined activity type since the type is not persisted by the task persister // and we want to ensure that a new task will match a restored task TaskRecord task1 = createTaskBuilder(".Task1") @@ -280,7 +274,7 @@ public class RecentTasksTest extends ActivityTestsBase { .setStack(mStack) .build(); setTaskActivityType(task1, ACTIVITY_TYPE_UNDEFINED); - assertTrue(task1.getActivityType() == ACTIVITY_TYPE_UNDEFINED); + assertThat(task1.getActivityType()).isEqualTo(ACTIVITY_TYPE_UNDEFINED); mRecentTasks.add(task1); mCallbacksRecorder.clear(); @@ -288,24 +282,24 @@ public class RecentTasksTest extends ActivityTestsBase { .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); - assertTrue(task2.getActivityType() == ACTIVITY_TYPE_STANDARD); + assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType()); mRecentTasks.add(task2); - assertTrue(mCallbacksRecorder.added.size() == 1); - assertTrue(mCallbacksRecorder.added.contains(task2)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.size() == 1); - assertTrue(mCallbacksRecorder.removed.contains(task1)); + assertThat(mCallbacksRecorder.mAdded).hasSize(1); + assertThat(mCallbacksRecorder.mAdded).contains(task2); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).hasSize(1); + assertThat(mCallbacksRecorder.mRemoved).contains(task1); } @Test - public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() throws Exception { + public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() { TaskRecord task1 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .setUserId(TEST_USER_0_ID) .build(); setTaskActivityType(task1, ACTIVITY_TYPE_UNDEFINED); - assertTrue(task1.getActivityType() == ACTIVITY_TYPE_UNDEFINED); + assertEquals(ACTIVITY_TYPE_UNDEFINED, task1.getActivityType()); mRecentTasks.add(task1); mCallbacksRecorder.clear(); @@ -314,22 +308,22 @@ public class RecentTasksTest extends ActivityTestsBase { .setStack(mStack) .setUserId(TEST_USER_1_ID) .build(); - assertTrue(task2.getActivityType() == ACTIVITY_TYPE_STANDARD); + assertEquals(ACTIVITY_TYPE_STANDARD, task2.getActivityType()); mRecentTasks.add(task2); - assertTrue(mCallbacksRecorder.added.size() == 1); - assertTrue(mCallbacksRecorder.added.contains(task2)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.isEmpty()); + assertThat(mCallbacksRecorder.mAdded).hasSize(1); + assertThat(mCallbacksRecorder.mAdded).contains(task2); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).isEmpty(); } @Test - public void testAddTaskCompatibleWindowingMode_expectRemove() throws Exception { + public void testAddTaskCompatibleWindowingMode_expectRemove() { TaskRecord task1 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); setTaskWindowingMode(task1, WINDOWING_MODE_UNDEFINED); - assertTrue(task1.getWindowingMode() == WINDOWING_MODE_UNDEFINED); + assertEquals(WINDOWING_MODE_UNDEFINED, task1.getWindowingMode()); mRecentTasks.add(task1); mCallbacksRecorder.clear(); @@ -338,24 +332,24 @@ public class RecentTasksTest extends ActivityTestsBase { .setStack(mStack) .build(); setTaskWindowingMode(task2, WINDOWING_MODE_FULLSCREEN); - assertTrue(task2.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); + assertEquals(WINDOWING_MODE_FULLSCREEN, task2.getWindowingMode()); mRecentTasks.add(task2); - assertTrue(mCallbacksRecorder.added.size() == 1); - assertTrue(mCallbacksRecorder.added.contains(task2)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.size() == 1); - assertTrue(mCallbacksRecorder.removed.contains(task1)); + assertThat(mCallbacksRecorder.mAdded).hasSize(1); + assertThat(mCallbacksRecorder.mAdded).contains(task2); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).hasSize(1); + assertThat(mCallbacksRecorder.mRemoved).contains(task1); } @Test - public void testAddTaskIncompatibleWindowingMode_expectNoRemove() throws Exception { + public void testAddTaskIncompatibleWindowingMode_expectNoRemove() { TaskRecord task1 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK) .setStack(mStack) .build(); setTaskWindowingMode(task1, WINDOWING_MODE_FULLSCREEN); - assertTrue(task1.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); + assertEquals(WINDOWING_MODE_FULLSCREEN, task1.getWindowingMode()); mRecentTasks.add(task1); TaskRecord task2 = createTaskBuilder(".Task1") @@ -363,41 +357,41 @@ public class RecentTasksTest extends ActivityTestsBase { .setStack(mStack) .build(); setTaskWindowingMode(task2, WINDOWING_MODE_PINNED); - assertTrue(task2.getWindowingMode() == WINDOWING_MODE_PINNED); + assertEquals(WINDOWING_MODE_PINNED, task2.getWindowingMode()); mRecentTasks.add(task2); - assertTrue(mCallbacksRecorder.added.size() == 2); - assertTrue(mCallbacksRecorder.added.contains(task1)); - assertTrue(mCallbacksRecorder.added.contains(task2)); - assertTrue(mCallbacksRecorder.trimmed.isEmpty()); - assertTrue(mCallbacksRecorder.removed.isEmpty()); + assertThat(mCallbacksRecorder.mAdded).hasSize(2); + assertThat(mCallbacksRecorder.mAdded).contains(task1); + assertThat(mCallbacksRecorder.mAdded).contains(task2); + assertThat(mCallbacksRecorder.mTrimmed).isEmpty(); + assertThat(mCallbacksRecorder.mRemoved).isEmpty(); } @Test - public void testUsersTasks() throws Exception { + public void testUsersTasks() { mRecentTasks.setOnlyTestVisibleRange(); // Setup some tasks for the users - mTaskPersister.userTaskIdsOverride = new SparseBooleanArray(); - mTaskPersister.userTaskIdsOverride.put(1, true); - mTaskPersister.userTaskIdsOverride.put(2, true); - mTaskPersister.userTasksOverride = new ArrayList<>(); - mTaskPersister.userTasksOverride.add(createTaskBuilder(".UserTask1").build()); - mTaskPersister.userTasksOverride.add(createTaskBuilder(".UserTask2").build()); + mTaskPersister.mUserTaskIdsOverride = new SparseBooleanArray(); + mTaskPersister.mUserTaskIdsOverride.put(1, true); + mTaskPersister.mUserTaskIdsOverride.put(2, true); + mTaskPersister.mUserTasksOverride = new ArrayList<>(); + mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build()); + mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build()); // Assert no user tasks are initially loaded - assertTrue(mRecentTasks.usersWithRecentsLoadedLocked().length == 0); + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0); // Load user 0 tasks mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID); - assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID)); + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID)); assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID)); // Load user 1 tasks mRecentTasks.loadUserRecentsLocked(TEST_USER_1_ID); - assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID)); - assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_1_ID)); + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_1_ID); assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID)); assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID)); assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_1_ID)); @@ -405,19 +399,22 @@ public class RecentTasksTest extends ActivityTestsBase { // Unload user 1 tasks mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_1_ID); - assertTrue(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID)); - assertFalse(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_1_ID)); + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList() + .doesNotContain(TEST_USER_1_ID); assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID)); assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID)); // Unload user 0 tasks mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID); - assertFalse(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_0_ID)); - assertFalse(arrayContainsUser(mRecentTasks.usersWithRecentsLoadedLocked(), TEST_USER_1_ID)); + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList() + .doesNotContain(TEST_USER_0_ID); + assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList() + .doesNotContain(TEST_USER_1_ID); } @Test - public void testOrderedIteration() throws Exception { + public void testOrderedIteration() { mRecentTasks.setOnlyTestVisibleRange(); TaskRecord task1 = createTaskBuilder(".Task1").build(); task1.lastActiveTime = new Random().nextInt(); @@ -436,13 +433,13 @@ public class RecentTasksTest extends ActivityTestsBase { final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks(); for (int i = 0; i < tasks.size(); i++) { final TaskRecord task = tasks.get(i); - assertTrue(task.lastActiveTime >= prevLastActiveTime.value); + assertThat(prevLastActiveTime.value).isLessThan(task.lastActiveTime); prevLastActiveTime.value = task.lastActiveTime; } } @Test - public void testTrimToGlobalMaxNumRecents() throws Exception { + public void testTrimToGlobalMaxNumRecents() { mRecentTasks.setOnlyTestVisibleRange(); // Limit the global maximum number of recent tasks to a fixed size @@ -458,7 +455,7 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testTrimQuietProfileTasks() throws Exception { + public void testTrimQuietProfileTasks() { mRecentTasks.setOnlyTestVisibleRange(); TaskRecord qt1 = createTaskBuilder(".QuietTask1").setUserId(TEST_QUIET_USER_ID).build(); TaskRecord qt2 = createTaskBuilder(".QuietTask2").setUserId(TEST_QUIET_USER_ID).build(); @@ -473,7 +470,7 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testSessionDuration() throws Exception { + public void testSessionDuration() { mRecentTasks.setOnlyTestVisibleRange(); mRecentTasks.setParameters(-1 /* min */, -1 /* max */, 50 /* ms */); @@ -493,7 +490,7 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testVisibleTasks_excludedFromRecents() throws Exception { + public void testVisibleTasks_excludedFromRecents() { mRecentTasks.setOnlyTestVisibleRange(); mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */); @@ -515,7 +512,7 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testVisibleTasks_minNum() throws Exception { + public void testVisibleTasks_minNum() { mRecentTasks.setOnlyTestVisibleRange(); mRecentTasks.setParameters(5 /* min */, -1 /* max */, 25 /* ms */); @@ -536,7 +533,7 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testVisibleTasks_maxNum() throws Exception { + public void testVisibleTasks_maxNum() { mRecentTasks.setOnlyTestVisibleRange(); mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */); @@ -551,11 +548,11 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testBackStackTasks_expectNoTrim() throws Exception { + public void testBackStackTasks_expectNoTrim() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); final MyTestActivityStackSupervisor supervisor = - (MyTestActivityStackSupervisor) mService.mStackSupervisor; + (MyTestActivityStackSupervisor) mTestService.mStackSupervisor; final ActivityStack homeStack = mDisplay.getHomeStack(); final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor); @@ -570,11 +567,11 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testBehindHomeStackTasks_expectTaskTrimmed() throws Exception { + public void testBehindHomeStackTasks_expectTaskTrimmed() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); final MyTestActivityStackSupervisor supervisor = - (MyTestActivityStackSupervisor) mService.mStackSupervisor; + (MyTestActivityStackSupervisor) mTestService.mStackSupervisor; final ActivityStack behindHomeStack = new MyTestActivityStack(mDisplay, supervisor); final ActivityStack homeStack = mDisplay.getHomeStack(); final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor); @@ -592,11 +589,11 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testOtherDisplayTasks_expectNoTrim() throws Exception { + public void testOtherDisplayTasks_expectNoTrim() { mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */); final MyTestActivityStackSupervisor supervisor = - (MyTestActivityStackSupervisor) mService.mStackSupervisor; + (MyTestActivityStackSupervisor) mTestService.mStackSupervisor; final ActivityStack homeStack = mDisplay.getHomeStack(); final ActivityStack otherDisplayStack = new MyTestActivityStack(mOtherDisplay, supervisor); @@ -611,7 +608,7 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testRemovePackageByName() throws Exception { + public void testRemovePackageByName() { // Add a number of tasks with the same package name mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".Task1").build()); mRecentTasks.add(createTaskBuilder("com.android.pkg2", ".Task2").build()); @@ -628,7 +625,7 @@ public class RecentTasksTest extends ActivityTestsBase { } @Test - public void testRemoveAllVisibleTasks() throws Exception { + public void testRemoveAllVisibleTasks() { mRecentTasks.setParameters(-1 /* min */, 3 /* max */, 100 /* ms */); // Create some set of tasks, some of which are visible and some are not @@ -674,16 +671,16 @@ public class RecentTasksTest extends ActivityTestsBase { mStack.remove(); // The following APIs should not restore task from recents to the active list. - assertNotRestoreTask(() -> mService.setFocusedTask(taskId)); - assertNotRestoreTask(() -> mService.startSystemLockTaskMode(taskId)); - assertNotRestoreTask(() -> mService.cancelTaskWindowTransition(taskId)); + assertNotRestoreTask(() -> mTestService.setFocusedTask(taskId)); + assertNotRestoreTask(() -> mTestService.startSystemLockTaskMode(taskId)); + assertNotRestoreTask(() -> mTestService.cancelTaskWindowTransition(taskId)); assertNotRestoreTask( - () -> mService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */)); + () -> mTestService.resizeTask(taskId, null /* bounds */, 0 /* resizeMode */)); assertNotRestoreTask( - () -> mService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN, + () -> mTestService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN, false/* toTop */)); assertNotRestoreTask( - () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId, + () -> mTestService.setTaskWindowingModeSplitScreenPrimary(taskId, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, false /* toTop */, false /* animate */, null /* initialBounds */, true /* showRecents */)); @@ -699,87 +696,90 @@ public class RecentTasksTest extends ActivityTestsBase { @Test public void testNotRecentsComponent_denyApiAccess() throws Exception { - doReturn(PackageManager.PERMISSION_DENIED).when(mService) + doReturn(PackageManager.PERMISSION_DENIED).when(mTestService) .checkGetTasksPermission(anyString(), anyInt(), anyInt()); // Expect the following methods to fail due to recents component not being set mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY_THROW_SECURITY_EXCEPTION); - testRecentTasksApis(false /* expectNoSecurityException */); + doTestRecentTasksApis(false /* expectNoSecurityException */); // Don't throw for the following tests mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.DENY); testGetTasksApis(false /* expectNoSecurityException */); } @Test - public void testRecentsComponent_allowApiAccessWithoutPermissions() throws Exception { - doReturn(PackageManager.PERMISSION_DENIED).when(mService) + public void testRecentsComponent_allowApiAccessWithoutPermissions() { + doReturn(PackageManager.PERMISSION_DENIED).when(mTestService) .checkGetTasksPermission(anyString(), anyInt(), anyInt()); // Set the recents component and ensure that the following calls do not fail mRecentTasks.setIsCallerRecentsOverride(TestRecentTasks.GRANT); - testRecentTasksApis(true /* expectNoSecurityException */); + doTestRecentTasksApis(true /* expectNoSecurityException */); testGetTasksApis(true /* expectNoSecurityException */); } - private void testRecentTasksApis(boolean expectCallable) { - assertSecurityException(expectCallable, () -> mService.removeStack(INVALID_STACK_ID)); + private void doTestRecentTasksApis(boolean expectCallable) { + assertSecurityException(expectCallable, () -> mTestService.removeStack(INVALID_STACK_ID)); assertSecurityException(expectCallable, - () -> mService.removeStacksInWindowingModes(new int[] {WINDOWING_MODE_UNDEFINED})); + () -> mTestService.removeStacksInWindowingModes( + new int[]{WINDOWING_MODE_UNDEFINED})); assertSecurityException(expectCallable, - () -> mService.removeStacksWithActivityTypes(new int[] {ACTIVITY_TYPE_UNDEFINED})); - assertSecurityException(expectCallable, () -> mService.removeTask(0)); + () -> mTestService.removeStacksWithActivityTypes( + new int[]{ACTIVITY_TYPE_UNDEFINED})); + assertSecurityException(expectCallable, () -> mTestService.removeTask(0)); assertSecurityException(expectCallable, - () -> mService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true)); + () -> mTestService.setTaskWindowingMode(0, WINDOWING_MODE_UNDEFINED, true)); assertSecurityException(expectCallable, - () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true)); + () -> mTestService.moveTaskToStack(0, INVALID_STACK_ID, true)); assertSecurityException(expectCallable, - () -> mService.setTaskWindowingModeSplitScreenPrimary(0, + () -> mTestService.setTaskWindowingModeSplitScreenPrimary(0, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true)); - assertSecurityException(expectCallable, () -> mService.dismissSplitScreenMode(true)); - assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0)); + assertSecurityException(expectCallable, () -> mTestService.dismissSplitScreenMode(true)); + assertSecurityException(expectCallable, () -> mTestService.dismissPip(true, 0)); assertSecurityException(expectCallable, - () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect())); + () -> mTestService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect())); assertSecurityException(expectCallable, - () -> mService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0)); + () -> mTestService.resizeStack(INVALID_STACK_ID, new Rect(), true, true, true, 0)); assertSecurityException(expectCallable, - () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(), + () -> mTestService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(), new Rect())); assertSecurityException(expectCallable, - () -> mService.resizePinnedStack(new Rect(), new Rect())); - assertSecurityException(expectCallable, () -> mService.getAllStackInfos()); + () -> mTestService.resizePinnedStack(new Rect(), new Rect())); + assertSecurityException(expectCallable, () -> mTestService.getAllStackInfos()); assertSecurityException(expectCallable, - () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED)); + () -> mTestService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED)); assertSecurityException(expectCallable, () -> { try { - mService.getFocusedStackInfo(); + mTestService.getFocusedStackInfo(); } catch (RemoteException e) { // Ignore } }); assertSecurityException(expectCallable, - () -> mService.moveTasksToFullscreenStack(INVALID_STACK_ID, true)); + () -> mTestService.moveTasksToFullscreenStack(INVALID_STACK_ID, true)); + assertSecurityException(expectCallable, + () -> mTestService.startActivityFromRecents(0, new Bundle())); + assertSecurityException(expectCallable, () -> mTestService.getTaskSnapshot(0, true)); + assertSecurityException(expectCallable, () -> mTestService.registerTaskStackListener(null)); assertSecurityException(expectCallable, - () -> mService.startActivityFromRecents(0, new Bundle())); - assertSecurityException(expectCallable,() -> mService.getTaskSnapshot(0, true)); - assertSecurityException(expectCallable,() -> mService.registerTaskStackListener(null)); - assertSecurityException(expectCallable,() -> mService.unregisterTaskStackListener(null)); - assertSecurityException(expectCallable, () -> mService.getTaskDescription(0)); - assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0)); - assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null, + () -> mTestService.unregisterTaskStackListener(null)); + assertSecurityException(expectCallable, () -> mTestService.getTaskDescription(0)); + assertSecurityException(expectCallable, () -> mTestService.cancelTaskWindowTransition(0)); + assertSecurityException(expectCallable, () -> mTestService.startRecentsActivity(null, null, null)); - assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation(true)); - assertSecurityException(expectCallable, () -> mService.stopAppSwitches()); - assertSecurityException(expectCallable, () -> mService.resumeAppSwitches()); + assertSecurityException(expectCallable, () -> mTestService.cancelRecentsAnimation(true)); + assertSecurityException(expectCallable, () -> mTestService.stopAppSwitches()); + assertSecurityException(expectCallable, () -> mTestService.resumeAppSwitches()); } private void testGetTasksApis(boolean expectCallable) { - mService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID); - mService.getTasks(MAX_VALUE); + mTestService.getRecentTasks(MAX_VALUE, 0, TEST_USER_0_ID); + mTestService.getTasks(MAX_VALUE); if (expectCallable) { - assertTrue(mRecentTasks.lastAllowed); - assertTrue(mRunningTasks.lastAllowed); + assertTrue(mRecentTasks.mLastAllowed); + assertTrue(mRunningTasks.mLastAllowed); } else { - assertFalse(mRecentTasks.lastAllowed); - assertFalse(mRunningTasks.lastAllowed); + assertFalse(mRecentTasks.mLastAllowed); + assertFalse(mRunningTasks.mLastAllowed); } } @@ -788,10 +788,10 @@ public class RecentTasksTest extends ActivityTestsBase { } private TaskBuilder createTaskBuilder(String packageName, String className) { - return new TaskBuilder(mService.mStackSupervisor) + return new TaskBuilder(mTestService.mStackSupervisor) .setComponent(new ComponentName(packageName, className)) .setStack(mStack) - .setTaskId(LAST_TASK_ID++) + .setTaskId(sLastTaskId++) .setUserId(TEST_USER_0_ID); } @@ -824,25 +824,20 @@ public class RecentTasksTest extends ActivityTestsBase { return task; } - private boolean arrayContainsUser(int[] userIds, int targetUserId) { - Arrays.sort(userIds); - return Arrays.binarySearch(userIds, targetUserId) >= 0; - } - private void assertNoTasksTrimmed() { assertTrimmed(); } private void assertTrimmed(TaskRecord... tasks) { - final ArrayList<TaskRecord> trimmed = mCallbacksRecorder.trimmed; - final ArrayList<TaskRecord> removed = mCallbacksRecorder.removed; - assertTrue("Expected " + tasks.length + " trimmed tasks, got " + trimmed.size(), - trimmed.size() == tasks.length); - assertTrue("Expected " + tasks.length + " removed tasks, got " + removed.size(), - removed.size() == tasks.length); + final ArrayList<TaskRecord> trimmed = mCallbacksRecorder.mTrimmed; + final ArrayList<TaskRecord> removed = mCallbacksRecorder.mRemoved; + assertWithMessage("Expected " + tasks.length + " trimmed tasks, got " + trimmed.size()) + .that(trimmed).hasSize(tasks.length); + assertWithMessage("Expected " + tasks.length + " removed tasks, got " + removed.size()) + .that(removed).hasSize(tasks.length); for (TaskRecord task : tasks) { - assertTrue("Expected trimmed task: " + task, trimmed.contains(task)); - assertTrue("Expected removed task: " + task, removed.contains(task)); + assertWithMessage("Expected trimmed task: " + task).that(trimmed).contains(task); + assertWithMessage("Expected removed task: " + task).that(removed).contains(task); } } @@ -853,8 +848,7 @@ public class RecentTasksTest extends ActivityTestsBase { } catch (SecurityException se) { noSecurityException = false; } catch (Exception e) { - // We only care about SecurityExceptions, fall through here - e.printStackTrace(); + // We only care about SecurityExceptions, fall through here. } if (noSecurityException != expectCallable) { fail("Expected callable: " + expectCallable + " but got no security exception: " @@ -891,7 +885,7 @@ public class RecentTasksTest extends ActivityTestsBase { } private class MyTestActivityStackSupervisor extends TestActivityStackSupervisor { - public MyTestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) { + MyTestActivityStackSupervisor(ActivityTaskManagerService service, Looper looper) { super(service, looper); } @@ -911,11 +905,11 @@ public class RecentTasksTest extends ActivityTestsBase { } } - private class MyTestActivityStack extends TestActivityStack { + private static class MyTestActivityStack extends TestActivityStack { private ActivityDisplay mDisplay = null; MyTestActivityStack(ActivityDisplay display, ActivityStackSupervisor supervisor) { - super(display, LAST_STACK_ID++, supervisor, WINDOWING_MODE_FULLSCREEN, + super(display, sLastStackId++, supervisor, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */, false /* createActivity */); mDisplay = display; } @@ -930,33 +924,33 @@ public class RecentTasksTest extends ActivityTestsBase { } private static class CallbacksRecorder implements Callbacks { - ArrayList<TaskRecord> added = new ArrayList<>(); - ArrayList<TaskRecord> trimmed = new ArrayList<>(); - ArrayList<TaskRecord> removed = new ArrayList<>(); + public final ArrayList<TaskRecord> mAdded = new ArrayList<>(); + public final ArrayList<TaskRecord> mTrimmed = new ArrayList<>(); + public final ArrayList<TaskRecord> mRemoved = new ArrayList<>(); void clear() { - added.clear(); - trimmed.clear(); - removed.clear(); + mAdded.clear(); + mTrimmed.clear(); + mRemoved.clear(); } @Override public void onRecentTaskAdded(TaskRecord task) { - added.add(task); + mAdded.add(task); } @Override public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) { if (wasTrimmed) { - trimmed.add(task); + mTrimmed.add(task); } - removed.add(task); + mRemoved.add(task); } } private static class TestTaskPersister extends TaskPersister { - SparseBooleanArray userTaskIdsOverride; - ArrayList<TaskRecord> userTasksOverride; + public SparseBooleanArray mUserTaskIdsOverride; + public ArrayList<TaskRecord> mUserTasksOverride; TestTaskPersister(File workingDir) { super(workingDir); @@ -964,16 +958,16 @@ public class RecentTasksTest extends ActivityTestsBase { @Override SparseBooleanArray loadPersistedTaskIdsForUser(int userId) { - if (userTaskIdsOverride != null) { - return userTaskIdsOverride; + if (mUserTaskIdsOverride != null) { + return mUserTaskIdsOverride; } return super.loadPersistedTaskIdsForUser(userId); } @Override List<TaskRecord> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) { - if (userTasksOverride != null) { - return userTasksOverride; + if (mUserTasksOverride != null) { + return mUserTasksOverride; } return super.restoreTasksForUserLocked(userId, preaddedTasks); } @@ -988,7 +982,7 @@ public class RecentTasksTest extends ActivityTestsBase { private boolean mIsTrimmableOverride; private int mIsCallerRecentsPolicy; - boolean lastAllowed; + public boolean mLastAllowed; TestRecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) { super(service, taskPersister); @@ -1053,7 +1047,7 @@ public class RecentTasksTest extends ActivityTestsBase { ParceledListSlice<RecentTaskInfo> getRecentTasks(int maxNum, int flags, boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) { - lastAllowed = getTasksAllowed; + mLastAllowed = getTasksAllowed; return super.getRecentTasks(maxNum, flags, getTasksAllowed, getDetailedTasks, userId, callingUid); } @@ -1065,13 +1059,13 @@ public class RecentTasksTest extends ActivityTestsBase { } private static class TestRunningTasks extends RunningTasks { - boolean lastAllowed; + public boolean mLastAllowed; @Override void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType, int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays, int callingUid, boolean allowed) { - lastAllowed = allowed; + mLastAllowed = allowed; super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, activityDisplays, callingUid, allowed); } diff --git a/services/tests/servicestests/src/com/android/server/am/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index f15b5f7f04b0..a01a3d90f7c6 100644 --- a/services/tests/servicestests/src/com/android/server/am/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,10 +11,10 @@ * 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. + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; @@ -38,63 +38,60 @@ import android.view.IRecentsAnimationRunner; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; /** - * atest FrameworksServicesTests:RecentsAnimationTest + * Build/Install/Run: + * atest WmTests:RecentsAnimationTest */ @MediumTest @Presubmit -@RunWith(AndroidJUnit4.class) public class RecentsAnimationTest extends ActivityTestsBase { private Context mContext = InstrumentationRegistry.getContext(); - private TestActivityTaskManagerService mService; + private TestActivityTaskManagerService mTestService; private ComponentName mRecentsComponent; @Before - @Override public void setUp() throws Exception { - super.setUp(); - mRecentsComponent = new ComponentName(mContext.getPackageName(), "RecentsActivity"); - mService = spy(new MyTestActivityTaskManagerService(mContext)); - setupActivityManagerService(mService); + mTestService = spy(new MyTestActivityTaskManagerService(mContext)); + setupActivityManagerService(mTestService); } @Test - public void testCancelAnimationOnStackOrderChange() throws Exception { - ActivityStack fullscreenStack = mService.mStackSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - ActivityStack recentsStack = mService.mStackSupervisor.getDefaultDisplay().createStack( + public void testCancelAnimationOnStackOrderChange() { + ActivityStack fullscreenStack = + mTestService.mStackSupervisor.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + ActivityStack recentsStack = mTestService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); - ActivityRecord recentsActivity = new ActivityBuilder(mService) + ActivityRecord recentsActivity = new ActivityBuilder(mTestService) .setComponent(mRecentsComponent) .setCreateTask(true) .setStack(recentsStack) .build(); - ActivityStack fullscreenStack2 = mService.mStackSupervisor.getDefaultDisplay().createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - ActivityRecord fsActivity = new ActivityBuilder(mService) + ActivityStack fullscreenStack2 = + mTestService.mStackSupervisor.getDefaultDisplay().createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + ActivityRecord fsActivity = new ActivityBuilder(mTestService) .setComponent(new ComponentName(mContext.getPackageName(), "App1")) .setCreateTask(true) .setStack(fullscreenStack2) .build(); - doReturn(true).when(mService.mWindowManager).canStartRecentsAnimation(); + doReturn(true).when(mTestService.mWindowManager).canStartRecentsAnimation(); // Start the recents animation Intent recentsIntent = new Intent(); recentsIntent.setComponent(mRecentsComponent); - mService.startRecentsActivity(recentsIntent, null, mock(IRecentsAnimationRunner.class)); + mTestService.startRecentsActivity(recentsIntent, null, mock(IRecentsAnimationRunner.class)); fullscreenStack.moveToFront("Activity start"); // Ensure that the recents animation was canceled - verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously( + verify(mTestService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously( eq(REORDER_KEEP_IN_PLACE), any()); } diff --git a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index 849a41183672..0e1624ebef63 100644 --- a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,57 +11,50 @@ * 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. + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM; +import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM; -import static org.junit.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; import android.app.ActivityManager.RunningTaskInfo; import android.content.ComponentName; -import android.content.Context; import android.platform.test.annotations.Presubmit; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.ArrayList; /** - * atest FrameworksServicesTests:RunningTasksTest + * Build/Install/Run: + * atest WmTests:RunningTasksTest */ @MediumTest @Presubmit -@RunWith(AndroidJUnit4.class) public class RunningTasksTest extends ActivityTestsBase { - private Context mContext = InstrumentationRegistry.getContext(); - private RunningTasks mRunningTasks; @Before - @Override public void setUp() throws Exception { - super.setUp(); - setupActivityTaskManagerService(); mRunningTasks = new RunningTasks(); } @Test - public void testCollectTasksByLastActiveTime() throws Exception { + public void testCollectTasksByLastActiveTime() { // Create a number of stacks with tasks (of incrementing active time) final ArrayList<ActivityDisplay> displays = new ArrayList<>(); final ActivityDisplay display = TestActivityDisplay.create(mSupervisor, DEFAULT_DISPLAY); @@ -86,9 +79,9 @@ public class RunningTasksTest extends ActivityTestsBase { ArrayList<RunningTaskInfo> tasks = new ArrayList<>(); mRunningTasks.getTasks(5, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, displays, -1 /* callingUid */, true /* allowed */); - assertTrue(tasks.size() == numFetchTasks); + assertThat(tasks).hasSize(numFetchTasks); for (int i = 0; i < numFetchTasks; i++) { - assertTrue(tasks.get(i).id == (numTasks - i - 1)); + assertEquals(numTasks - i - 1, tasks.get(i).id); } // Ensure that requesting more than the total number of tasks only returns the subset @@ -96,9 +89,9 @@ public class RunningTasksTest extends ActivityTestsBase { tasks.clear(); mRunningTasks.getTasks(100, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, displays, -1 /* callingUid */, true /* allowed */); - assertTrue(tasks.size() == numTasks); + assertThat(tasks).hasSize(numTasks); for (int i = 0; i < numTasks; i++) { - assertTrue(tasks.get(i).id == (numTasks - i - 1)); + assertEquals(numTasks - i - 1, tasks.get(i).id); } } @@ -119,4 +112,4 @@ public class RunningTasksTest extends ActivityTestsBase { .build(); return task; } -}
\ No newline at end of file +} diff --git a/services/tests/servicestests/src/com/android/server/am/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java index 8e4e7e6b63c3..530fd6d7d70e 100644 --- a/services/tests/servicestests/src/com/android/server/am/SafeActivityOptionsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static org.junit.Assert.assertEquals; @@ -23,15 +23,16 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; +/** + * Build/Install/Run: + * atest WmTests:SafeActivityOptionsTest + */ @MediumTest -@Presubmit @FlakyTest -@RunWith(AndroidJUnit4.class) +@Presubmit public class SafeActivityOptionsTest { @Test diff --git a/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java index ae40f7e7d235..36eccd1892a7 100644 --- a/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -33,6 +33,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import android.app.Activity; @@ -46,6 +48,7 @@ import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.media.ImageReader; import android.os.Handler; +import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.Pair; import android.view.Display; @@ -57,13 +60,10 @@ import android.widget.TextView; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.function.BooleanSupplier; @@ -72,13 +72,12 @@ import java.util.function.BooleanSupplier; * Tests for the {@link android.view.WindowManager.LayoutParams#PRIVATE_FLAG_IS_SCREEN_DECOR} flag. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.wm.ScreenDecorWindowTests + * atest WmTests:ScreenDecorWindowTests */ // TODO: Add test for FLAG_FULLSCREEN which hides the status bar and also other flags. // TODO: Test non-Activity windows. @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class ScreenDecorWindowTests { private final Context mContext = InstrumentationRegistry.getTargetContext(); @@ -120,7 +119,7 @@ public class ScreenDecorWindowTests { } @Test - public void testScreenSides() throws Exception { + public void testScreenSides() { // Decor on top final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness); assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness); @@ -139,7 +138,7 @@ public class ScreenDecorWindowTests { } @Test - public void testMultipleDecors() throws Exception { + public void testMultipleDecors() { // Test 2 decor windows on-top. createDecorWindow(TOP, MATCH_PARENT, mHalfDecorThickness); assertInsetGreaterOrEqual(mTestActivity, TOP, mHalfDecorThickness); @@ -153,7 +152,7 @@ public class ScreenDecorWindowTests { } @Test - public void testFlagChange() throws Exception { + public void testFlagChange() { WindowInsets initialInsets = getInsets(mTestActivity); final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness); @@ -174,7 +173,7 @@ public class ScreenDecorWindowTests { } @Test - public void testRemoval() throws Exception { + public void testRemoval() { WindowInsets initialInsets = getInsets(mTestActivity); final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness); @@ -256,7 +255,7 @@ public class ScreenDecorWindowTests { /** * Asserts the top inset of {@param activity} is equal to {@param expected} waiting as needed. */ - private void assertTopInsetEquals(Activity activity, int expected) throws Exception { + private void assertTopInsetEquals(Activity activity, int expected) { waitForTopInsetEqual(activity, expected); assertEquals(expected, getInsets(activity).getSystemWindowInsetTop()); } @@ -269,16 +268,23 @@ public class ScreenDecorWindowTests { * Asserts the inset at {@param side} of {@param activity} is equal to {@param expected} * waiting as needed. */ - private void assertInsetGreaterOrEqual(Activity activity, int side, int expected) - throws Exception { + private void assertInsetGreaterOrEqual(Activity activity, int side, int expected) { waitForInsetGreaterOrEqual(activity, side, expected); final WindowInsets insets = getInsets(activity); switch (side) { - case TOP: assertGreaterOrEqual(insets.getSystemWindowInsetTop(), expected); break; - case BOTTOM: assertGreaterOrEqual(insets.getSystemWindowInsetBottom(), expected); break; - case LEFT: assertGreaterOrEqual(insets.getSystemWindowInsetLeft(), expected); break; - case RIGHT: assertGreaterOrEqual(insets.getSystemWindowInsetRight(), expected); break; + case TOP: + assertThat(insets.getSystemWindowInsetTop()).isAtLeast(expected); + break; + case BOTTOM: + assertThat(insets.getSystemWindowInsetBottom()).isAtLeast(expected); + break; + case LEFT: + assertThat(insets.getSystemWindowInsetLeft()).isAtLeast(expected); + break; + case RIGHT: + assertThat(insets.getSystemWindowInsetRight()).isAtLeast(expected); + break; } } @@ -295,22 +301,13 @@ public class ScreenDecorWindowTests { }); } - /** Asserts that the first entry is greater than or equal to the second entry. */ - private void assertGreaterOrEqual(int first, int second) throws Exception { - Assert.assertTrue("Excepted " + first + " >= " + second, first >= second); - } - private void waitFor(BooleanSupplier waitCondition) { int retriesLeft = 5; do { if (waitCondition.getAsBoolean()) { break; } - try { - Thread.sleep(500); - } catch (InterruptedException e) { - // Well I guess we are not waiting... - } + SystemClock.sleep(500); } while (retriesLeft-- > 0); } diff --git a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index b7f2b3581fb6..95965c82ad1f 100644 --- a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,10 +11,10 @@ * 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. + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; @@ -22,17 +22,14 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; -import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; -import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -46,15 +43,13 @@ import android.os.Build; import android.platform.test.annotations.Presubmit; import android.view.Gravity; -import androidx.test.filters.SmallTest; import androidx.test.filters.FlakyTest; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.filters.SmallTest; -import com.android.server.am.LaunchParamsController.LaunchParams; +import com.android.server.wm.LaunchParamsController.LaunchParams; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.Locale; @@ -62,12 +57,11 @@ import java.util.Locale; * Tests for default task bounds. * * Build/Install/Run: - * atest FrameworksServicesTests:TaskLaunchParamsModifierTests + * atest WmTests:TaskLaunchParamsModifierTests */ @SmallTest -@Presubmit -@RunWith(AndroidJUnit4.class) @FlakyTest(detail = "Confirm stable in post-submit before removing") +@Presubmit public class TaskLaunchParamsModifierTests extends ActivityTestsBase { private ActivityRecord mActivity; @@ -78,10 +72,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { private LaunchParams mResult; @Before - @Override public void setUp() throws Exception { - super.setUp(); - setupActivityTaskManagerService(); mService.mSupportsFreeformWindowManagement = true; when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod(); @@ -1027,8 +1018,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null, mActivity, /* source */ null, options, mCurrent, mResult)); - assertEquals(new Rect(0, 0, 1680, - 953), mResult.mBounds); + assertEquals(new Rect(0, 0, 1680, 953), mResult.mBounds); } private TestActivityDisplay createNewActivityDisplay(int windowingMode) { diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java index 48bfe1d963af..df7bc11663bc 100644 --- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,59 +11,61 @@ * 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. + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static androidx.test.InstrumentationRegistry.getTargetContext; - +import android.content.Context; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.SparseBooleanArray; +import androidx.test.filters.FlakyTest; + import org.junit.After; import org.junit.Before; import org.junit.Test; -import androidx.test.filters.FlakyTest; - /** * Tests for {@link TaskPersister}. * * Build/Install/Run: - * atest FrameworksServicesTests:TaskPersisterTest + * atest WmTests:TaskPersisterTest */ -@Presubmit @FlakyTest(detail = "Promote to presubmit if stable") +@Presubmit public class TaskPersisterTest { private static final String TEST_USER_NAME = "AM-Test-User"; private TaskPersister mTaskPersister; - private int testUserId; + private int mTestUserId; private UserManager mUserManager; @Before public void setUp() throws Exception { - mUserManager = UserManager.get(getTargetContext()); - mTaskPersister = new TaskPersister(getTargetContext().getFilesDir()); + final Context context = getInstrumentation().getTargetContext(); + mUserManager = UserManager.get(context); + mTaskPersister = new TaskPersister(context.getFilesDir()); // In ARC, the maximum number of supported users is one, which is different from the ones of // most phones (more than 4). This prevents TaskPersisterTest from creating another user for // test. However, since guest users can be added as much as possible, we create guest user // in the test. - testUserId = createUser(TEST_USER_NAME, UserInfo.FLAG_GUEST); + mTestUserId = createUser(TEST_USER_NAME, UserInfo.FLAG_GUEST); } @After public void tearDown() throws Exception { - mTaskPersister.unloadUserDataFromMemory(testUserId); - removeUser(testUserId); + mTaskPersister.unloadUserDataFromMemory(mTestUserId); + removeUser(mTestUserId); } private int getRandomTaskIdForUser(int userId) { @@ -76,11 +78,11 @@ public class TaskPersisterTest { public void testTaskIdsPersistence() { SparseBooleanArray taskIdsOnFile = new SparseBooleanArray(); for (int i = 0; i < 100; i++) { - taskIdsOnFile.put(getRandomTaskIdForUser(testUserId), true); + taskIdsOnFile.put(getRandomTaskIdForUser(mTestUserId), true); } - mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, testUserId); + mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, mTestUserId); SparseBooleanArray newTaskIdsOnFile = mTaskPersister - .loadPersistedTaskIdsForUser(testUserId); + .loadPersistedTaskIdsForUser(mTestUserId); assertEquals("TaskIds written differ from TaskIds read back from file", taskIdsOnFile, newTaskIdsOnFile); } diff --git a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index 27766d3d8d6c..44556305b1e1 100644 --- a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,11 +11,10 @@ * 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. - * + * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; @@ -35,14 +34,12 @@ import android.service.voice.IVoiceInteractionSession; import android.util.Xml; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.app.IVoiceInteractor; -import com.android.server.am.TaskRecord.TaskRecordFactory; +import com.android.server.wm.TaskRecord.TaskRecordFactory; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -60,18 +57,16 @@ import java.util.ArrayList; * Tests for exercising {@link TaskRecord}. * * Build/Install/Run: - * atest FrameworksServicesTests:com.android.server.am.TaskRecordTests + * atest WmTests:TaskRecordTests */ @MediumTest @Presubmit -@RunWith(AndroidJUnit4.class) public class TaskRecordTests extends ActivityTestsBase { private static final String TASK_TAG = "task"; @Before public void setUp() throws Exception { - super.setUp(); TaskRecord.setTaskRecordFactory(null); setupActivityTaskManagerService(); } @@ -124,7 +119,7 @@ public class TaskRecordTests extends ActivityTestsBase { private File serializeToFile(TaskRecord r) throws IOException, XmlPullParserException { final File tmpFile = File.createTempFile(r.taskId + "_task_", "xml"); - try (final OutputStream os = new FileOutputStream(tmpFile)) { + try (OutputStream os = new FileOutputStream(tmpFile)) { final XmlSerializer serializer = Xml.newSerializer(); serializer.setOutput(os, "UTF-8"); serializer.startDocument(null, true); @@ -138,7 +133,7 @@ public class TaskRecordTests extends ActivityTestsBase { } private TaskRecord restoreFromFile(File file) throws IOException, XmlPullParserException { - try (final Reader reader = new BufferedReader(new FileReader(file))) { + try (Reader reader = new BufferedReader(new FileReader(file))) { final XmlPullParser parser = Xml.newPullParser(); parser.setInput(reader); assertEquals(XmlPullParser.START_TAG, parser.next()); diff --git a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 3f7c7148381e..4a734e5256f6 100644 --- a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,9 +14,9 @@ * limitations under the License */ -package com.android.server.am; +package com.android.server.wm; -import static androidx.test.InstrumentationRegistry.getInstrumentation; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -38,23 +38,22 @@ import android.os.RemoteException; import android.support.test.uiautomator.UiDevice; import android.text.TextUtils; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.annotations.GuardedBy; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +/** + * Build/Install/Run: + * atest WmTests:TaskStackChangedListenerTest + */ @MediumTest -@RunWith(AndroidJUnit4.class) public class TaskStackChangedListenerTest { private IActivityManager mService; @@ -87,13 +86,13 @@ public class TaskStackChangedListenerTest { } }); - Context ctx = InstrumentationRegistry.getContext(); - ctx.startActivity(new Intent(ctx, ActivityA.class)); + Context context = getInstrumentation().getContext(); + context.startActivity(new Intent(context, ActivityA.class)); UiDevice.getInstance(getInstrumentation()).waitForIdle(); synchronized (sLock) { - Assert.assertTrue(sTaskStackChangedCalled); + assertTrue(sTaskStackChangedCalled); } - Assert.assertTrue(sActivityBResumed); + assertTrue(sActivityBResumed); } @Test @@ -101,17 +100,17 @@ public class TaskStackChangedListenerTest { final Object[] params = new Object[2]; final CountDownLatch latch = new CountDownLatch(1); registerTaskStackChangedListener(new TaskStackListener() { - int taskId = -1; + int mTaskId = -1; @Override public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException { - this.taskId = taskId; + mTaskId = taskId; } @Override public void onTaskDescriptionChanged(int taskId, TaskDescription td) throws RemoteException { - if (this.taskId == taskId && !TextUtils.isEmpty(td.getLabel())) { + if (mTaskId == taskId && !TextUtils.isEmpty(td.getLabel())) { params[0] = taskId; params[1] = td; latch.countDown(); @@ -204,7 +203,7 @@ public class TaskStackChangedListenerTest { activity.finishAndRemoveTask(); waitForCallback(taskRemovalStartedLatch); // onTaskRemovalStarted happens before the activity's window is removed. - assertFalse(activity.onDetachedFromWindowCalled); + assertFalse(activity.mOnDetachedFromWindowCalled); assertEquals(id, params[0]); // Test for onTaskRemoved. @@ -212,19 +211,18 @@ public class TaskStackChangedListenerTest { waitForCallback(taskRemovedLatch); assertEquals(id, params[0]); waitForCallback(onDetachedFromWindowLatch); - assertTrue(activity.onDetachedFromWindowCalled); + assertTrue(activity.mOnDetachedFromWindowCalled); } /** * Starts the provided activity and returns the started instance. */ private TestActivity startTestActivity(Class<?> activityClass) throws InterruptedException { - final Context context = InstrumentationRegistry.getContext(); - final ActivityMonitor monitor = - new ActivityMonitor(activityClass.getName(), null, false); - InstrumentationRegistry.getInstrumentation().addMonitor(monitor); + final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false); + getInstrumentation().addMonitor(monitor); + final Context context = getInstrumentation().getContext(); context.startActivity(new Intent(context, activityClass)); - final TestActivity activity = (TestActivity)monitor.waitForActivityWithTimeout(1000); + final TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(1000); if (activity == null) { throw new RuntimeException("Timed out waiting for Activity"); } @@ -239,11 +237,12 @@ public class TaskStackChangedListenerTest { private void waitForCallback(CountDownLatch latch) { try { - final boolean result = latch.await(2, TimeUnit.SECONDS); + final boolean result = latch.await(2, TimeUnit.SECONDS); if (!result) { throw new RuntimeException("Timed out waiting for task stack change notification"); } - }catch (InterruptedException e) {} + } catch (InterruptedException e) { + } } public static class TestActivity extends Activity { @@ -271,6 +270,7 @@ public class TaskStackChangedListenerTest { * If isResumed is {@code true}, sleep the thread until the activity is resumed. * if {@code false}, sleep the thread until the activity is paused. */ + @SuppressWarnings("WaitNotInLoop") public void waitForResumeStateChange(boolean isResumed) throws InterruptedException { synchronized (this) { if (mIsResumed == isResumed) { @@ -278,7 +278,7 @@ public class TaskStackChangedListenerTest { } wait(5000); } - assertTrue("The activity resume state change timed out", mIsResumed == isResumed); + assertEquals("The activity resume state change timed out", isResumed, mIsResumed); } } @@ -330,17 +330,17 @@ public class TaskStackChangedListenerTest { } public static class ActivityTaskChangeCallbacks extends TestActivity { - boolean onDetachedFromWindowCalled = false; - CountDownLatch onDetachedFromWindowCountDownLatch; + public boolean mOnDetachedFromWindowCalled = false; + private CountDownLatch mOnDetachedFromWindowCountDownLatch; @Override public void onDetachedFromWindow() { - onDetachedFromWindowCalled = true; - onDetachedFromWindowCountDownLatch.countDown(); + mOnDetachedFromWindowCalled = true; + mOnDetachedFromWindowCountDownLatch.countDown(); } void setDetachedFromWindowLatch(CountDownLatch countDownLatch) { - onDetachedFromWindowCountDownLatch = countDownLatch; + mOnDetachedFromWindowCountDownLatch = countDownLatch; } } } diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java index 827d938aa73e..21e5d991b63b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm; @@ -33,19 +33,17 @@ import android.view.animation.Animation; import android.view.animation.ClipRectAnimation; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; /** * Tests for the {@link WindowAnimationSpec} class. * - * atest FrameworksServicesTests:com.android.server.wm.WindowAnimationSpecTest + * Build/Install/Run: + * atest WmTests:WindowAnimationSpecTest */ @SmallTest @Presubmit -@RunWith(AndroidJUnit4.class) public class WindowAnimationSpecTest { private final SurfaceControl mSurfaceControl = mock(SurfaceControl.class); private final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java new file mode 100644 index 000000000000..115bcb1f44a2 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.anyFloat; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.view.Display; +import android.view.Surface; + +import org.mockito.invocation.InvocationOnMock; + +/** + * A collection of static functions that can be referenced by other test packages to provide access + * to WindowManager related test functionality. + */ +public class WindowTestUtils { + private static int sNextTaskId = 0; + + /** Retrieves an instance of a mock {@link WindowManagerService}. */ + static WindowManagerService getMockWindowManagerService() { + final WindowManagerService service = mock(WindowManagerService.class); + final WindowManagerGlobalLock lock = new WindowManagerGlobalLock(); + doReturn(lock).when(service).getWindowManagerLock(); + return service; + } + + /** An extension of {@link DisplayContent} to gain package scoped access. */ + public static class TestDisplayContent extends DisplayContent { + + private TestDisplayContent(Display display, WindowManagerService service, + WallpaperController wallpaperController, DisplayWindowController controller) { + super(display, service, wallpaperController, controller); + } + + /** Create a mocked default {@link DisplayContent}. */ + public static TestDisplayContent create(Context context) { + final TestDisplayContent displayContent = mock(TestDisplayContent.class); + displayContent.isDefaultDisplay = true; + + final DisplayPolicy displayPolicy = mock(DisplayPolicy.class); + when(displayPolicy.navigationBarCanMove()).thenReturn(true); + when(displayPolicy.hasNavigationBar()).thenReturn(true); + + final DisplayRotation displayRotation = new DisplayRotation( + mock(WindowManagerService.class), displayContent, displayPolicy, + context, new Object()); + displayRotation.mPortraitRotation = Surface.ROTATION_0; + displayRotation.mLandscapeRotation = Surface.ROTATION_90; + displayRotation.mUpsideDownRotation = Surface.ROTATION_180; + displayRotation.mSeascapeRotation = Surface.ROTATION_270; + + when(displayContent.getDisplayRotation()).thenReturn(displayRotation); + + return displayContent; + } + } + + /** + * Creates a mock instance of {@link StackWindowController}. + */ + public static StackWindowController createMockStackWindowContainerController() { + StackWindowController controller = mock(StackWindowController.class); + controller.mContainer = mock(TestTaskStack.class); + + // many components rely on the {@link StackWindowController#adjustConfigurationForBounds} + // to properly set bounds values in the configuration. We must mimick those actions here. + doAnswer((InvocationOnMock invocationOnMock) -> { + final Configuration config = invocationOnMock.<Configuration>getArgument(7); + final Rect bounds = invocationOnMock.<Rect>getArgument(0); + config.windowConfiguration.setBounds(bounds); + return null; + }).when(controller).adjustConfigurationForBounds(any(), any(), any(), any(), + anyBoolean(), anyBoolean(), anyFloat(), any(), any(), anyInt()); + + return controller; + } + + /** + * An extension of {@link TestTaskStack}, which overrides package scoped methods that would not + * normally be mocked out. + */ + public static class TestTaskStack extends TaskStack { + TestTaskStack(WindowManagerService service, int stackId) { + super(service, stackId, null); + } + + @Override + void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) { + // Do nothing. + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java index 01b7c4f650e7..0445ea03da73 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -29,21 +31,21 @@ import static org.mockito.Mockito.verifyZeroInteractions; import android.content.Context; import android.platform.test.annotations.Presubmit; +import android.testing.DexmakerShareClassLoaderRule; import android.util.proto.ProtoOutputStream; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.Preconditions; -import com.android.server.wm.WindowManagerTraceProto; import org.junit.After; import org.junit.Before; import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.io.File; import java.io.FileInputStream; @@ -55,41 +57,44 @@ import java.nio.charset.StandardCharsets; * Test class for {@link WindowTracing}. * * Build/Install/Run: - * bit FrameworksServicesTests:com.android.server.wm.WindowTracingTest + * atest FrameworksServicesTests:WindowTracingTest */ -@SmallTest @FlakyTest(bugId = 74078662) -// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed. -// @Presubmit -@RunWith(AndroidJUnit4.class) -public class WindowTracingTest extends WindowTestsBase { +@SmallTest +@Presubmit +public class WindowTracingTest { - private static final byte[] MAGIC_HEADER = new byte[] { - 0x9, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45, + private static final byte[] MAGIC_HEADER = new byte[]{ + 0x9, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45, }; - private Context mTestContext; - private WindowTracing mWindowTracing; + @Rule + public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = + new DexmakerShareClassLoaderRule(); + + @Mock private WindowManagerService mWmMock; + private WindowTracing mWindowTracing; private File mFile; - @Override @Before public void setUp() throws Exception { - super.setUp(); + MockitoAnnotations.initMocks(this); - mWmMock = mock(WindowManagerService.class); - - mTestContext = InstrumentationRegistry.getContext(); - - mFile = mTestContext.getFileStreamPath("tracing_test.dat"); + final Context testContext = getInstrumentation().getContext(); + mFile = testContext.getFileStreamPath("tracing_test.dat"); mFile.delete(); mWindowTracing = new WindowTracing(mFile); } + @After + public void tearDown() throws Exception { + mFile.delete(); + } + @Test - public void isEnabled_returnsFalseByDefault() throws Exception { + public void isEnabled_returnsFalseByDefault() { assertFalse(mWindowTracing.isEnabled()); } @@ -107,7 +112,7 @@ public class WindowTracingTest extends WindowTestsBase { } @Test - public void trace_discared_whenNotTracing() throws Exception { + public void trace_discared_whenNotTracing() { mWindowTracing.traceStateLocked("where", mWmMock); verifyZeroInteractions(mWmMock); } @@ -132,12 +137,12 @@ public class WindowTracingTest extends WindowTestsBase { } } - @Test @Ignore("Figure out why this test is crashing when setting up mWmMock.") + @Test public void tracing_endsUpInFile() throws Exception { mWindowTracing.startTrace(mock(PrintWriter.class)); - doAnswer((inv) -> { + doAnswer(inv -> { inv.<ProtoOutputStream>getArgument(0).write( WindowManagerTraceProto.WHERE, "TEST_WM_PROTO"); return null; @@ -157,22 +162,14 @@ public class WindowTracingTest extends WindowTestsBase { } } - @Override - @After - public void tearDown() throws Exception { - super.tearDown(); - - mFile.delete(); - } - /** Return true if {@code needle} appears anywhere in {@code haystack[0..length]} */ - boolean containsBytes(byte[] haystack, int haystackLenght, byte[] needle) { - Preconditions.checkArgument(haystackLenght > 0); + private static boolean containsBytes(byte[] haystack, int haystackLength, byte[] needle) { + Preconditions.checkArgument(haystackLength > 0); Preconditions.checkArgument(needle.length > 0); - outer: for (int i = 0; i <= haystackLenght - needle.length; i++) { + outer: for (int i = 0; i <= haystackLength - needle.length; i++) { for (int j = 0; j < needle.length; j++) { - if (haystack[i+j] != needle[j]) { + if (haystack[i + j] != needle[j]) { continue outer; } } diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java index f82b01224f96..649b785c992b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/utils/CoordinateTransformsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/utils/CoordinateTransformsTest.java @@ -23,8 +23,6 @@ import static android.view.Surface.ROTATION_90; import static com.android.server.wm.utils.CoordinateTransforms.transformLogicalToPhysicalCoordinates; import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates; - - import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation; import static org.hamcrest.Matchers.is; @@ -40,6 +38,10 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; +/** + * Build/Install/Run: + * atest WmTests:CoordinateTransformsTest + */ public class CoordinateTransformsTest { private static final int W = 200; @@ -202,4 +204,4 @@ public class CoordinateTransformsTest { public interface TransformPointAssertable { void transformsTo(int x, int y); } -}
\ No newline at end of file +} diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/DisplayRotationUtilTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/DisplayRotationUtilTest.java index ba8869b1692d..926153db58d6 100644 --- a/services/tests/servicestests/src/com/android/server/wm/utils/DisplayRotationUtilTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/utils/DisplayRotationUtilTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm.utils; @@ -24,6 +24,7 @@ import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; + import static com.android.server.wm.utils.DisplayRotationUtil.getBoundIndexFromRotation; import static org.hamcrest.Matchers.equalTo; @@ -32,24 +33,20 @@ import static org.junit.Assert.assertThat; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; -import org.junit.Test; -import org.junit.runner.RunWith; - import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - +import org.junit.Test; /** * Tests for {@link DisplayRotationUtil} * - * Run with: atest DisplayRotationUtilTest + * Build/Install/Run: + * atest WmTests:DisplayRotationUtilTest */ -@RunWith(AndroidJUnit4.class) @SmallTest @Presubmit public class DisplayRotationUtilTest { - private static Rect ZERO_RECT = new Rect(); + private static final Rect ZERO_RECT = new Rect(); @Test public void testGetBoundIndexFromRotation_rot0() { @@ -103,7 +100,7 @@ public class DisplayRotationUtilTest { @Test public void testGetRotatedBounds_top_rot0() { DisplayRotationUtil util = new DisplayRotationUtil(); - Rect[] bounds = new Rect[] { ZERO_RECT, new Rect(50,0,150,10), ZERO_RECT, ZERO_RECT }; + Rect[] bounds = new Rect[] {ZERO_RECT, new Rect(50, 0, 150, 10), ZERO_RECT, ZERO_RECT}; assertThat(util.getRotatedBounds(bounds, ROTATION_0, 200, 300), equalTo(bounds)); } @@ -111,31 +108,31 @@ public class DisplayRotationUtilTest { @Test public void testGetRotatedBounds_top_rot90() { DisplayRotationUtil util = new DisplayRotationUtil(); - Rect[] bounds = new Rect[] { ZERO_RECT, new Rect(50,0,150,10), ZERO_RECT, ZERO_RECT }; + Rect[] bounds = new Rect[] {ZERO_RECT, new Rect(50, 0, 150, 10), ZERO_RECT, ZERO_RECT}; assertThat(util.getRotatedBounds(bounds, ROTATION_90, 200, 300), - equalTo(new Rect[] { new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT })); + equalTo(new Rect[] {new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT})); } @Test public void testGetRotatedBounds_top_rot180() { DisplayRotationUtil util = new DisplayRotationUtil(); - Rect[] bounds = new Rect[] { ZERO_RECT, new Rect(50,0,150,10), ZERO_RECT, ZERO_RECT }; + Rect[] bounds = new Rect[] {ZERO_RECT, new Rect(50, 0, 150, 10), ZERO_RECT, ZERO_RECT}; assertThat(util.getRotatedBounds(bounds, ROTATION_180, 200, 300), - equalTo(new Rect[] { ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(50, 290, 150, 300) })); + equalTo(new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(50, 290, 150, 300)})); } @Test public void testGetRotatedBounds_top_rot270() { DisplayRotationUtil util = new DisplayRotationUtil(); - Rect[] bounds = new Rect[] { ZERO_RECT, new Rect(50,0,150,10), ZERO_RECT, ZERO_RECT }; + Rect[] bounds = new Rect[] {ZERO_RECT, new Rect(50, 0, 150, 10), ZERO_RECT, ZERO_RECT}; assertThat(util.getRotatedBounds(bounds, ROTATION_270, 200, 300), - equalTo(new Rect[] { ZERO_RECT, ZERO_RECT, new Rect(290, 50, 300, 150), ZERO_RECT })); + equalTo(new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(290, 50, 300, 150), ZERO_RECT})); } @Test public void testGetRotatedBounds_left_rot0() { DisplayRotationUtil util = new DisplayRotationUtil(); - Rect[] bounds = new Rect[] { new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT }; + Rect[] bounds = new Rect[] {new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT}; assertThat(util.getRotatedBounds(bounds, ROTATION_0, 300, 200), equalTo(bounds)); } @@ -143,24 +140,24 @@ public class DisplayRotationUtilTest { @Test public void testGetRotatedBounds_left_rot90() { DisplayRotationUtil util = new DisplayRotationUtil(); - Rect[] bounds = new Rect[] { new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT }; + Rect[] bounds = new Rect[] {new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT}; assertThat(util.getRotatedBounds(bounds, ROTATION_90, 300, 200), - equalTo(new Rect[]{ ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(50, 290, 150, 300) })); + equalTo(new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(50, 290, 150, 300)})); } @Test public void testGetRotatedBounds_left_rot180() { DisplayRotationUtil util = new DisplayRotationUtil(); - Rect[] bounds = new Rect[] { new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT }; + Rect[] bounds = new Rect[] {new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT}; assertThat(util.getRotatedBounds(bounds, ROTATION_180, 300, 200), - equalTo(new Rect[]{ ZERO_RECT, ZERO_RECT, new Rect(290, 50, 300, 150), ZERO_RECT })); + equalTo(new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(290, 50, 300, 150), ZERO_RECT})); } @Test public void testGetRotatedBounds_left_rot270() { DisplayRotationUtil util = new DisplayRotationUtil(); - Rect[] bounds = new Rect[] { new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT }; + Rect[] bounds = new Rect[] {new Rect(0, 50, 10, 150), ZERO_RECT, ZERO_RECT, ZERO_RECT}; assertThat(util.getRotatedBounds(bounds, ROTATION_270, 300, 200), - equalTo(new Rect[]{ ZERO_RECT, new Rect(50, 0, 150, 10), ZERO_RECT, ZERO_RECT })); + equalTo(new Rect[] {ZERO_RECT, new Rect(50, 0, 150, 10), ZERO_RECT, ZERO_RECT})); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/InsetUtilsTest.java index 3364aef25bd0..089e908cbd5a 100644 --- a/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/utils/InsetUtilsTest.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.server.wm.utils; @@ -27,18 +27,19 @@ import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +/** + * Build/Install/Run: + * atest WmTests:InsetUtilsTest + */ @SmallTest @Presubmit public class InsetUtilsTest { @Test - public void testAdd() throws Exception { + public void testAdd() { final Rect rect1 = new Rect(10, 20, 30, 40); final Rect rect2 = new Rect(50, 60, 70, 80); InsetUtils.addInsets(rect1, rect2); diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/RotationCacheTest.java index 5d08920b43d0..33f34b465576 100644 --- a/services/tests/servicestests/src/com/android/server/wm/utils/RotationCacheTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/utils/RotationCacheTest.java @@ -28,13 +28,14 @@ import android.util.Pair; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +/** + * Build/Install/Run: + * atest WmTests:RotationCacheTest + */ @SmallTest @FlakyTest(bugId = 74078662) @Presubmit @@ -53,7 +54,7 @@ public class RotationCacheTest { } @Test - public void getOrCompute_computes() throws Exception { + public void getOrCompute_computes() { assertThat(mCache.getOrCompute("hello", 0), equalTo(create("hello", 0))); assertThat(mCache.getOrCompute("hello", 1), equalTo(create("hello", 1))); assertThat(mCache.getOrCompute("hello", 2), equalTo(create("hello", 2))); @@ -61,7 +62,7 @@ public class RotationCacheTest { } @Test - public void getOrCompute_sameParam_sameRot_hitsCache() throws Exception { + public void getOrCompute_sameParam_sameRot_hitsCache() { assertNotNull(mCache.getOrCompute("hello", 1)); mComputationCalled = false; @@ -70,7 +71,7 @@ public class RotationCacheTest { } @Test - public void getOrCompute_sameParam_hitsCache_forAllRots() throws Exception { + public void getOrCompute_sameParam_hitsCache_forAllRots() { assertNotNull(mCache.getOrCompute("hello", 3)); assertNotNull(mCache.getOrCompute("hello", 2)); assertNotNull(mCache.getOrCompute("hello", 1)); @@ -85,14 +86,14 @@ public class RotationCacheTest { } @Test - public void getOrCompute_changingParam_recomputes() throws Exception { + public void getOrCompute_changingParam_recomputes() { assertNotNull(mCache.getOrCompute("hello", 1)); assertThat(mCache.getOrCompute("world", 1), equalTo(create("world", 1))); } @Test - public void getOrCompute_changingParam_clearsCacheForDifferentRots() throws Exception { + public void getOrCompute_changingParam_clearsCacheForDifferentRots() { assertNotNull(mCache.getOrCompute("hello", 1)); assertNotNull(mCache.getOrCompute("world", 2)); diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java index c5e35e7304c4..fb8ba7bffd4c 100644 --- a/services/tests/servicestests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java @@ -16,12 +16,11 @@ package com.android.server.wm.utils; - -import static android.view.DisplayCutout.NO_CUTOUT; import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM; import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; +import static android.view.DisplayCutout.NO_CUTOUT; import static android.view.DisplayCutout.fromBoundingRect; import static org.hamcrest.Matchers.equalTo; @@ -29,7 +28,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; - import android.graphics.Insets; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; @@ -37,24 +35,18 @@ import android.util.Size; import android.view.DisplayCutout; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.Arrays; /** * Tests for {@link WmDisplayCutout} * - * Run with: atest WmDisplayCutoutTest + * Build/Install/Run: + * atest WmTests:WmDisplayCutoutTest */ -@RunWith(AndroidJUnit4.class) @SmallTest @Presubmit public class WmDisplayCutoutTest { - private static final Rect ZERO_RECT = new Rect(); - private final DisplayCutout mCutoutTop = new DisplayCutout( Insets.of(0, 100, 0, 0), null /* boundLeft */, new Rect(50, 0, 75, 100) /* boundTop */, @@ -165,4 +157,4 @@ public class WmDisplayCutoutTest { assertEquals(new WmDisplayCutout(mCutoutTop, new Size(1, 2)).hashCode(), new WmDisplayCutout(mCutoutTop, new Size(1, 2)).hashCode()); } -}
\ No newline at end of file +} diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp index 3681529643bc..c39688cb8f2d 100644 --- a/startop/view_compiler/Android.bp +++ b/startop/view_compiler/Android.bp @@ -16,10 +16,15 @@ cc_defaults { name: "viewcompiler_defaults", + header_libs: [ + "libbase_headers", + ], shared_libs: [ + "libbase", "libdexfile", "slicer", ], + cppflags: ["-std=c++17"], } cc_library_host_static { @@ -30,9 +35,6 @@ cc_library_host_static { "java_lang_builder.cc", "util.cc", ], - static_libs: [ - "libbase", - ], } cc_binary_host { @@ -42,7 +44,6 @@ cc_binary_host { "main.cc", ], static_libs: [ - "libbase", "libtinyxml2", "libgflags", "libviewcompiler", @@ -59,4 +60,5 @@ cc_test_host { static_libs: [ "libviewcompiler", ], + test_suites: ["general-tests"], } diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING deleted file mode 100644 index cc4b17a7a65a..000000000000 --- a/startop/view_compiler/TEST_MAPPING +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presubmit": [ - { - "name": "view-compiler-tests" - } - ] -} diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc index 7a9f41fd8f38..13e7f73e6713 100644 --- a/startop/view_compiler/dex_builder.cc +++ b/startop/view_compiler/dex_builder.cc @@ -22,14 +22,16 @@ #include <fstream> #include <memory> +#define DCHECK_NOT_NULL(p) DCHECK((p) != nullptr) + namespace startop { namespace dex { using std::shared_ptr; using std::string; -using art::Instruction; using ::dex::kAccPublic; +using Op = Instruction::Op; const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; }; const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; }; @@ -43,6 +45,20 @@ constexpr size_t kMaxEncodedStringLength{5}; } // namespace +std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) { + switch (opcode) { + case Instruction::Op::kReturn: + out << "kReturn"; + return out; + case Instruction::Op::kMove: + out << "kMove"; + return out; + case Instruction::Op::kInvokeVirtual: + out << "kInvokeVirtual"; + return out; + } +} + void* TrackingAllocator::Allocate(size_t size) { std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size); void* raw_buffer = buffer.get(); @@ -56,7 +72,7 @@ void TrackingAllocator::Free(void* ptr) { allocations_.erase(allocations_.find(p // // package dextest; // public class DexTest { -// public static int foo() { return 5; } +// public static int foo(String s) { return s.length(); } // } void WriteTestDexFile(const string& filename) { DexBuilder dex_file; @@ -64,11 +80,17 @@ void WriteTestDexFile(const string& filename) { ClassBuilder cbuilder{dex_file.MakeClass("dextest.DexTest")}; cbuilder.set_source_file("dextest.java"); - MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})}; + TypeDescriptor string_type = TypeDescriptor::FromClassname("java.lang.String"); + + MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), string_type})}; + + Value result = method.MakeRegister(); - MethodBuilder::Register r = method.MakeRegister(); - method.BuildConst4(r, 5); - method.BuildReturn(r); + MethodDeclData string_length = + dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()}); + + method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0))); + method.BuildReturn(result); method.Encode(); @@ -78,6 +100,10 @@ void WriteTestDexFile(const string& filename) { out_file.write(image.ptr<const char>(), image.size()); } +TypeDescriptor TypeDescriptor::FromClassname(const std::string& name) { + return TypeDescriptor{art::DotToDescriptor(name.c_str())}; +} + DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} { dex_file_->magic = slicer::MemView{kDexFileMagic, sizeof(kDexFileMagic)}; } @@ -119,10 +145,9 @@ ClassBuilder DexBuilder::MakeClass(const std::string& name) { class_def->type = type_def; class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object")); class_def->access_flags = kAccPublic; - return ClassBuilder{this, class_def}; + return ClassBuilder{this, name, class_def}; } -// TODO(eholk): we probably want GetOrAddString() also ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) { if (types_by_descriptor_.find(descriptor) != types_by_descriptor_.end()) { return types_by_descriptor_[descriptor]; @@ -158,16 +183,11 @@ std::string Prototype::Shorty() const { return shorty; } -ClassBuilder::ClassBuilder(DexBuilder* parent, ir::Class* class_def) - : parent_(parent), class_(class_def) {} +ClassBuilder::ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def) + : parent_(parent), type_descriptor_{TypeDescriptor::FromClassname(name)}, class_(class_def) {} MethodBuilder ClassBuilder::CreateMethod(const std::string& name, Prototype prototype) { - ir::String* dex_name{parent_->GetOrAddString(name)}; - - auto* decl = parent_->Alloc<ir::MethodDecl>(); - decl->name = dex_name; - decl->parent = class_->type; - decl->prototype = prototype.Encode(parent_); + ir::MethodDecl* decl = parent_->GetOrDeclareMethod(type_descriptor_, name, prototype).decl; return MethodBuilder{parent_, class_, decl}; } @@ -187,8 +207,13 @@ ir::EncodedMethod* MethodBuilder::Encode() { method->access_flags = kAccPublic | ::dex::kAccStatic; auto* code = dex_->Alloc<ir::Code>(); - code->registers = num_registers_; - // TODO: support ins and outs + DCHECK_NOT_NULL(decl_->prototype); + size_t const num_args = + decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0; + code->registers = num_registers_ + num_args; + code->ins_count = num_args; + code->outs_count = decl_->prototype->return_type == dex_->GetOrAddType("V") ? 0 : 1; + EncodeInstructions(); code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size()); method->code = code; @@ -197,17 +222,135 @@ ir::EncodedMethod* MethodBuilder::Encode() { return method; } -MethodBuilder::Register MethodBuilder::MakeRegister() { return num_registers_++; } +Value MethodBuilder::MakeRegister() { return Value::Local(num_registers_++); } + +void MethodBuilder::AddInstruction(Instruction instruction) { + instructions_.push_back(instruction); +} -void MethodBuilder::BuildReturn() { buffer_.push_back(Instruction::RETURN_VOID); } +void MethodBuilder::BuildReturn() { AddInstruction(Instruction::OpNoArgs(Op::kReturn)); } -void MethodBuilder::BuildReturn(Register src) { buffer_.push_back(Instruction::RETURN | src << 8); } +void MethodBuilder::BuildReturn(Value src) { + AddInstruction(Instruction::OpWithArgs(Op::kReturn, /*destination=*/{}, src)); +} -void MethodBuilder::BuildConst4(Register target, int value) { +void MethodBuilder::BuildConst4(Value target, int value) { DCHECK_LT(value, 16); - // TODO: support more registers - DCHECK_LT(target, 16); - buffer_.push_back(Instruction::CONST_4 | (value << 12) | (target << 8)); + AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::Immediate(value))); +} + +void MethodBuilder::EncodeInstructions() { + buffer_.clear(); + for (const auto& instruction : instructions_) { + EncodeInstruction(instruction); + } +} + +void MethodBuilder::EncodeInstruction(const Instruction& instruction) { + switch (instruction.opcode()) { + case Instruction::Op::kReturn: + return EncodeReturn(instruction); + case Instruction::Op::kMove: + return EncodeMove(instruction); + case Instruction::Op::kInvokeVirtual: + return EncodeInvokeVirtual(instruction); + } +} + +void MethodBuilder::EncodeReturn(const Instruction& instruction) { + DCHECK_EQ(Instruction::Op::kReturn, instruction.opcode()); + DCHECK(!instruction.dest().has_value()); + if (instruction.args().size() == 0) { + buffer_.push_back(art::Instruction::RETURN_VOID); + } else { + DCHECK(instruction.args().size() == 1); + size_t source = RegisterValue(instruction.args()[0]); + buffer_.push_back(art::Instruction::RETURN | source << 8); + } +} + +void MethodBuilder::EncodeMove(const Instruction& instruction) { + DCHECK_EQ(Instruction::Op::kMove, instruction.opcode()); + DCHECK(instruction.dest().has_value()); + DCHECK(instruction.dest()->is_register() || instruction.dest()->is_parameter()); + DCHECK_EQ(1, instruction.args().size()); + + const Value& source = instruction.args()[0]; + + if (source.is_immediate()) { + // TODO: support more registers + DCHECK_LT(RegisterValue(*instruction.dest()), 16); + DCHECK_LT(source.value(), 16); + buffer_.push_back(art::Instruction::CONST_4 | (source.value() << 12) | + (RegisterValue(*instruction.dest()) << 8)); + } else { + UNIMPLEMENTED(FATAL); + } +} + +void MethodBuilder::EncodeInvokeVirtual(const Instruction& instruction) { + DCHECK_EQ(Instruction::Op::kInvokeVirtual, instruction.opcode()); + + // TODO: support more than one argument (i.e. the this argument) and change this to DCHECK_GE + DCHECK_EQ(1, instruction.args().size()); + + const Value& this_arg = instruction.args()[0]; + + size_t real_reg = RegisterValue(this_arg) & 0xf; + buffer_.push_back(1 << 12 | art::Instruction::INVOKE_VIRTUAL); + buffer_.push_back(instruction.method_id()); + buffer_.push_back(real_reg); + + if (instruction.dest().has_value()) { + real_reg = RegisterValue(*instruction.dest()); + buffer_.push_back(real_reg << 8 | art::Instruction::MOVE_RESULT); + } +} + +size_t MethodBuilder::RegisterValue(Value value) const { + if (value.is_register()) { + return value.value(); + } else if (value.is_parameter()) { + return value.value() + num_registers_; + } + DCHECK(false && "Must be either a parameter or a register"); + return 0; +} + +const MethodDeclData& DexBuilder::GetOrDeclareMethod(TypeDescriptor type, const std::string& name, + Prototype prototype) { + MethodDeclData& entry = method_id_map_[{type, name, prototype}]; + + if (entry.decl == nullptr) { + // This method has not already been declared, so declare it. + ir::MethodDecl* decl = dex_file_->Alloc<ir::MethodDecl>(); + // The method id is the last added method. + size_t id = dex_file_->methods.size() - 1; + + ir::String* dex_name{GetOrAddString(name)}; + decl->name = dex_name; + decl->parent = GetOrAddType(type.descriptor()); + decl->prototype = GetOrEncodeProto(prototype); + + // update the index -> ir node map (see tools/dexter/slicer/dex_ir_builder.cc) + auto new_index = dex_file_->methods_indexes.AllocateIndex(); + auto& ir_node = dex_file_->methods_map[new_index]; + SLICER_CHECK(ir_node == nullptr); + ir_node = decl; + decl->orig_index = new_index; + + entry = {id, decl}; + } + + return entry; +} + +ir::Proto* DexBuilder::GetOrEncodeProto(Prototype prototype) { + ir::Proto*& ir_proto = proto_map_[prototype]; + if (ir_proto == nullptr) { + ir_proto = prototype.Encode(this); + } + return ir_proto; } } // namespace dex diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h index d280abce21f5..e46655e0d429 100644 --- a/startop/view_compiler/dex_builder.h +++ b/startop/view_compiler/dex_builder.h @@ -17,7 +17,9 @@ #define DEX_BUILDER_H_ #include <map> +#include <optional> #include <string> +#include <unordered_map> #include <vector> #include "slicer/dex_ir.h" @@ -45,7 +47,7 @@ class TrackingAllocator : public ::dex::Writer::Allocator { virtual void Free(void* ptr); private: - std::map<void*, std::unique_ptr<uint8_t[]>> allocations_; + std::unordered_map<void*, std::unique_ptr<uint8_t[]>> allocations_; }; // Represents a DEX type descriptor. @@ -57,11 +59,17 @@ class TypeDescriptor { static const TypeDescriptor Int(); static const TypeDescriptor Void(); + // Creates a type descriptor from a fully-qualified class name. For example, it turns the class + // name java.lang.Object into the descriptor Ljava/lang/Object. + static TypeDescriptor FromClassname(const std::string& name); + // Return the full descriptor, such as I or Ljava/lang/Object const std::string& descriptor() const { return descriptor_; } // Return the shorty descriptor, such as I or L std::string short_descriptor() const { return descriptor().substr(0, 1); } + bool operator<(const TypeDescriptor& rhs) const { return descriptor_ < rhs.descriptor_; } + private: TypeDescriptor(std::string descriptor) : descriptor_{descriptor} {} @@ -82,11 +90,98 @@ class Prototype { // Get the shorty descriptor, such as VII for (Int, Int) -> Void std::string Shorty() const; + bool operator<(const Prototype& rhs) const { + return std::make_tuple(return_type_, param_types_) < + std::make_tuple(rhs.return_type_, rhs.param_types_); + } + private: const TypeDescriptor return_type_; const std::vector<TypeDescriptor> param_types_; }; +// Represents a DEX register or constant. We separate regular registers and parameters +// because we will not know the real parameter id until after all instructions +// have been generated. +class Value { + public: + static constexpr Value Local(size_t id) { return Value{id, Kind::kLocalRegister}; } + static constexpr Value Parameter(size_t id) { return Value{id, Kind::kParameter}; } + static constexpr Value Immediate(size_t value) { return Value{value, Kind::kImmediate}; } + + bool is_register() const { return kind_ == Kind::kLocalRegister; } + bool is_parameter() const { return kind_ == Kind::kParameter; } + bool is_immediate() const { return kind_ == Kind::kImmediate; } + + size_t value() const { return value_; } + + private: + enum class Kind { kLocalRegister, kParameter, kImmediate }; + + const size_t value_; + const Kind kind_; + + constexpr Value(size_t value, Kind kind) : value_{value}, kind_{kind} {} +}; + +// A virtual instruction. We convert these to real instructions in MethodBuilder::Encode. +// Virtual instructions are needed to keep track of information that is not known until all of the +// code is generated. This information includes things like how many local registers are created and +// branch target locations. +class Instruction { + public: + // The operation performed by this instruction. These are virtual instructions that do not + // correspond exactly to DEX instructions. + enum class Op { kReturn, kMove, kInvokeVirtual }; + + //////////////////////// + // Named Constructors // + //////////////////////// + + // For instructions with no return value and no arguments. + static inline Instruction OpNoArgs(Op opcode) { + return Instruction{opcode, /*method_id*/ 0, /*dest*/ {}}; + } + // For most instructions, which take some number of arguments and have an optional return value. + template <typename... T> + static inline Instruction OpWithArgs(Op opcode, std::optional<const Value> dest, T... args) { + return Instruction{opcode, /*method_id*/ 0, dest, args...}; + } + // For method calls. + template <typename... T> + static inline Instruction InvokeVirtual(size_t method_id, std::optional<const Value> dest, + Value this_arg, T... args) { + return Instruction{Op::kInvokeVirtual, method_id, dest, this_arg, args...}; + } + + /////////////// + // Accessors // + /////////////// + + Op opcode() const { return opcode_; } + size_t method_id() const { return method_id_; } + const std::optional<const Value>& dest() const { return dest_; } + const std::vector<const Value>& args() const { return args_; } + + private: + inline Instruction(Op opcode, size_t method_id, std::optional<const Value> dest) + : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{} {} + + template <typename... T> + inline constexpr Instruction(Op opcode, size_t method_id, std::optional<const Value> dest, + T... args) + : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{args...} {} + + const Op opcode_; + // The index of the method to invoke, for kInvokeVirtual and similar opcodes. + const size_t method_id_{0}; + const std::optional<const Value> dest_; + const std::vector<const Value> args_; +}; + +// Needed for CHECK_EQ, DCHECK_EQ, etc. +std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode); + // Tools to help build methods and their bodies. class MethodBuilder { public: @@ -95,42 +190,53 @@ class MethodBuilder { // Encode the method into DEX format. ir::EncodedMethod* Encode(); - // Registers are just represented by their number. - using Register = size_t; - // Create a new register to be used to storing values. Note that these are not SSA registers, like // might be expected in similar code generators. This does no liveness tracking or anything, so // it's up to the caller to reuse registers as appropriate. - Register MakeRegister(); + Value MakeRegister(); ///////////////////////////////// // Instruction builder methods // ///////////////////////////////// + void AddInstruction(Instruction instruction); + // return-void void BuildReturn(); - void BuildReturn(Register src); + void BuildReturn(Value src); // const/4 - void BuildConst4(Register target, int value); + void BuildConst4(Value target, int value); // TODO: add builders for more instructions private: + void EncodeInstructions(); + void EncodeInstruction(const Instruction& instruction); + void EncodeReturn(const Instruction& instruction); + void EncodeMove(const Instruction& instruction); + void EncodeInvokeVirtual(const Instruction& instruction); + + // Converts a register or parameter to its DEX register number. + size_t RegisterValue(Value value) const; + DexBuilder* dex_; ir::Class* class_; ir::MethodDecl* decl_; - // A buffer to hold instructions we are generating. + // A list of the instructions we will eventually encode. + std::vector<Instruction> instructions_; + + // A buffer to hold instructions that have been encoded. std::vector<::dex::u2> buffer_; // How many registers we've allocated - size_t num_registers_; + size_t num_registers_{0}; }; // A helper to build class definitions. class ClassBuilder { public: - ClassBuilder(DexBuilder* parent, ir::Class* class_def); + ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def); void set_source_file(const std::string& source); @@ -139,8 +245,15 @@ class ClassBuilder { MethodBuilder CreateMethod(const std::string& name, Prototype prototype); private: - DexBuilder* parent_; - ir::Class* class_; + DexBuilder* const parent_; + const TypeDescriptor type_descriptor_; + ir::Class* const class_; +}; + +// Keeps track of information needed to manipulate or call a method. +struct MethodDeclData { + size_t id; + ir::MethodDecl* decl; }; // Builds Dex files from scratch. @@ -163,10 +276,19 @@ class DexBuilder { ClassBuilder MakeClass(const std::string& name); // Add a type for the given descriptor, or return the existing one if it already exists. - // See the TypeDescriptor class for help generating these. + // See the TypeDescriptor class for help generating these. GetOrAddType can be used to declare + // imported classes. ir::Type* GetOrAddType(const std::string& descriptor); + // Returns the method id for the method, creating it if it has not been created yet. + const MethodDeclData& GetOrDeclareMethod(TypeDescriptor type, const std::string& name, + Prototype prototype); + private: + // Looks up the ir::Proto* corresponding to this given prototype, or creates one if it does not + // exist. + ir::Proto* GetOrEncodeProto(Prototype prototype); + std::shared_ptr<ir::DexFile> dex_file_; // allocator_ is needed to be able to encode the image. @@ -177,10 +299,29 @@ class DexBuilder { std::vector<std::unique_ptr<uint8_t[]>> string_data_; // Keep track of what types we've defined so we can look them up later. - std::map<std::string, ir::Type*> types_by_descriptor_; + std::unordered_map<std::string, ir::Type*> types_by_descriptor_; + + struct MethodDescriptor { + TypeDescriptor type; + std::string name; + Prototype prototype; + + inline bool operator<(const MethodDescriptor& rhs) const { + return std::make_tuple(type, name, prototype) < + std::make_tuple(rhs.type, rhs.name, rhs.prototype); + } + }; + + // Maps method declarations to their method index. This is needed to encode references to them. + // When we go to actually write the DEX file, slicer will re-assign these after correctly sorting + // the methods list. + std::map<MethodDescriptor, MethodDeclData> method_id_map_; // Keep track of what strings we've defined so we can look them up later. - std::map<std::string, ir::String*> strings_; + std::unordered_map<std::string, ir::String*> strings_; + + // Keep track of already-encoded protos. + std::map<Prototype, ir::Proto*> proto_map_; }; } // namespace dex diff --git a/startop/view_compiler/dex_builder_test.cc b/startop/view_compiler/dex_builder_test.cc index 0d8b8541caeb..61c86b4091b3 100644 --- a/startop/view_compiler/dex_builder_test.cc +++ b/startop/view_compiler/dex_builder_test.cc @@ -40,6 +40,12 @@ bool EncodeAndVerify(DexBuilder* dex_file) { return loaded_dex_file != nullptr; } +// Write out and verify a DEX file that corresponds to: +// +// package dextest; +// public class DexTest { +// public static void foo() {} +// } TEST(DexBuilderTest, VerifyDexWithClassMethod) { DexBuilder dex_file; @@ -67,6 +73,12 @@ TEST(DexBuilderTest, VerifyBadDexWithClassMethod) { EXPECT_FALSE(EncodeAndVerify(&dex_file)); } +// Write out and verify a DEX file that corresponds to: +// +// package dextest; +// public class DexTest { +// public static int foo() { return 5; } +// } TEST(DexBuilderTest, VerifyDexReturn5) { DexBuilder dex_file; @@ -80,3 +92,51 @@ TEST(DexBuilderTest, VerifyDexReturn5) { EXPECT_TRUE(EncodeAndVerify(&dex_file)); } + +// Write out and verify a DEX file that corresponds to: +// +// package dextest; +// public class DexTest { +// public static int foo(int x) { return x; } +// } +TEST(DexBuilderTest, VerifyDexReturnIntParam) { + DexBuilder dex_file; + + auto cbuilder{dex_file.MakeClass("dextest.DexTest")}; + + auto method{ + cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})}; + method.BuildReturn(Value::Parameter(0)); + method.Encode(); + + EXPECT_TRUE(EncodeAndVerify(&dex_file)); +} + +// Write out and verify a DEX file that corresponds to: +// +// package dextest; +// public class DexTest { +// public static int foo(String s) { return s.length(); } +// } +TEST(DexBuilderTest, VerifyDexCallStringLength) { + DexBuilder dex_file; + + auto cbuilder{dex_file.MakeClass("dextest.DexTest")}; + + MethodBuilder method{cbuilder.CreateMethod( + "foo", Prototype{TypeDescriptor::Int(), TypeDescriptor::FromClassname("java.lang.String")})}; + + Value result = method.MakeRegister(); + + MethodDeclData string_length = + dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"), + "length", + Prototype{TypeDescriptor::Int()}); + + method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0))); + method.BuildReturn(result); + + method.Encode(); + + EXPECT_TRUE(EncodeAndVerify(&dex_file)); +} diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 3127b3584dd9..fa16bfe8e795 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -15,6 +15,7 @@ package android.telecom; import android.Manifest; +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; import android.annotation.SuppressLint; @@ -175,6 +176,33 @@ public class TelecomManager { "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME"; /** + * Broadcast intent action indicating that the current default call screening app has changed. + * + * The string extra {@link #EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME} will contain the + * name of the Component of the previous or the new call screening app. + * + * The boolean extra {@link #EXTRA_IS_DEFAULT_CALL_SCREENING_APP} will indicate the component + * name in the String extra {@link #EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME} is default + * call screening app or not. + */ + public static final String ACTION_DEFAULT_CALL_SCREENING_APP_CHANGED = + "android.telecom.action.DEFAULT_CALL_SCREENING_APP_CHANGED"; + + /** + * Extra value used with {@link #ACTION_DEFAULT_CALL_SCREENING_APP_CHANGED} broadcast to + * indicate the ComponentName of the call screening app which has changed. + */ + public static final String EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME = + "android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME"; + + /** + * Extra value used with {@link #ACTION_DEFAULT_CALL_SCREENING_APP_CHANGED} broadcast to + * indicate whether an app is the default call screening app. + */ + public static final String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = + "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP"; + + /** * Optional extra for {@link android.content.Intent#ACTION_CALL} containing a boolean that * determines whether the speakerphone should be automatically turned on for an outgoing call. */ @@ -1169,6 +1197,79 @@ public class TelecomManager { } /** + * Used to trigger display of the ChangeDefaultCallScreeningApp activity to prompt the user to + * change the call screening app. + * + * A {@link SecurityException} will be thrown if calling package name doesn't match the package + * of the passed {@link ComponentName} + * + * @param componentName to verify that the calling package name matches the package of the + * passed ComponentName. + */ + public void requestChangeDefaultCallScreeningApp(@NonNull ComponentName componentName) { + try { + if (isServiceConnected()) { + getTelecomService().requestChangeDefaultCallScreeningApp(componentName, mContext + .getOpPackageName()); + } + } catch (RemoteException e) { + Log.e(TAG, + "RemoteException calling ITelecomService#requestChangeDefaultCallScreeningApp.", + e); + } + } + + /** + * Used to verify that the passed ComponentName is default call screening app. + * + * @param componentName to verify that the package of the passed ComponentName matched the default + * call screening packageName. + * + * @return {@code true} if the passed componentName matches the default call screening's, {@code + * false} if the passed componentName is null, or it doesn't match default call screening's. + */ + public boolean isDefaultCallScreeningApp(ComponentName componentName) { + try { + if (isServiceConnected()) { + return getTelecomService().isDefaultCallScreeningApp(componentName); + } + } catch (RemoteException e) { + Log.e(TAG, + "RemoteException calling ITelecomService#isDefaultCallScreeningApp.", + e); + } + return false; + } + + /** + * Used to set the default call screening package. + * + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} Requires + * permission: {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} + * + * A {@link IllegalArgumentException} will be thrown if the specified package and component name + * of {@link ComponentName} does't exist, or the specified component of {@link ComponentName} + * does't have {@link android.Manifest.permission#BIND_SCREENING_SERVICE}. + * + * @param componentName to set the default call screening to. + * @hide + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.MODIFY_PHONE_STATE, + android.Manifest.permission.WRITE_SECURE_SETTINGS + }) + public void setDefaultCallScreeningApp(ComponentName componentName) { + try { + if (isServiceConnected()) { + getTelecomService().setDefaultCallScreeningApp(componentName); + } + } catch (RemoteException e) { + Log.e(TAG, + "RemoteException calling ITelecomService#setDefaultCallScreeningApp.", e); + } + } + + /** * Return whether a given phone number is the configured voicemail number for a * particular phone account. * diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index df7d6832833a..d97f0c5f7684 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -256,6 +256,21 @@ interface ITelecomService { boolean setDefaultDialer(in String packageName); /** + * @see TelecomServiceImpl#requestChangeDefaultCallScreeningApp + */ + void requestChangeDefaultCallScreeningApp(in ComponentName componentNamem, String callingPackage); + + /** + * @see TelecomServiceImpl#isDefaultCallScreeningApp + */ + boolean isDefaultCallScreeningApp(in ComponentName componentName); + + /** + * @see TelecomServiceImpl#setDefaultCallScreeningApp + */ + void setDefaultCallScreeningApp(in ComponentName componentName); + + /** * @see TelecomServiceImpl#createManageBlockedNumbersIntent **/ Intent createManageBlockedNumbersIntent(); diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 52ac32daf565..d7024cfb7e2f 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -16,6 +16,7 @@ package android.provider; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -1271,6 +1272,31 @@ public final class Telephony { */ public static final String EXTRA_IS_INITIAL_CREATE = "android.provider.extra.IS_INITIAL_CREATE"; + + /** + * Broadcast intent action indicating that the telephony provider SMS MMS database is + * corrupted. A boolean is specified in {@link #EXTRA_IS_CORRUPTED} to indicate if the + * database is corrupted. Requires the + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE permission. + * + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public static final String ACTION_SMS_MMS_DB_LOST = + "android.provider.action.SMS_MMS_DB_LOST"; + + /** + * Boolean flag passed as an extra with {@link #ACTION_SMS_MMS_DB_LOST} to indicate + * whether the DB got corrupted or not. + * + * @see #ACTION_SMS_MMS_DB_LOST + * + * @hide + */ + public static final String EXTRA_IS_CORRUPTED = + "android.provider.extra.IS_CORRUPTED"; + /** * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a * {@link #DATA_SMS_RECEIVED_ACTION} intent. diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java index cac9f2b51b73..9c64cf6ddd8f 100644 --- a/telephony/java/android/telephony/AccessNetworkConstants.java +++ b/telephony/java/android/telephony/AccessNetworkConstants.java @@ -32,7 +32,20 @@ public final class AccessNetworkConstants { public static final int IWLAN = 5; /** @hide */ - private AccessNetworkType() {}; + private AccessNetworkType() {} + + /** @hide */ + public static String toString(int type) { + switch (type) { + case UNKNOWN: return "UNKNOWN"; + case GERAN: return "GERAN"; + case UTRAN: return "UTRAN"; + case EUTRAN: return "EUTRAN"; + case CDMA2000: return "CDMA2000"; + case IWLAN: return "IWLAN"; + default: return Integer.toString(type); + } + } } /** @@ -47,7 +60,16 @@ public final class AccessNetworkConstants { public static final int WLAN = 2; /** @hide */ - private TransportType() {}; + private TransportType() {} + + /** @hide */ + public static String toString(int type) { + switch (type) { + case WWAN: return "WWAN"; + case WLAN: return "WLAN"; + default: return Integer.toString(type); + } + } } /** diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 983e766a6a98..99de4cad605a 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1231,6 +1231,47 @@ public class CarrierConfigManager { public static final String KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL = "show_precise_failed_cause_bool"; + /** + * Boolean to decide whether lte is enabled. + * @hide + */ + public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool"; + + /** + * Boolean to decide whether TD-SCDMA is supported. + * @hide + */ + public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool"; + + /** + * A list of mcc/mnc that support TD-SCDMA for device when connect to the roaming network. + * @hide + */ + public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY = + "support_tdscdma_roaming_networks_string_array"; + + /** + * Boolean to decide whether world mode is enabled. + * @hide + */ + public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool"; + + /** + * Package name of the carrier settings activity. + * @see {@link #KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING}. + * @hide + */ + public static final String KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING = + "carrier_settings_activity_package_name_string"; + + /** + * Class name of the carrier settings activity. + * @see {@link #KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING}. + * @hide + */ + public static final String KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING = + "carrier_settings_activity_class_name_string"; + // These variables are used by the MMS service and exposed through another API, // SmsManager. The variable names and string values are copied from there. public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled"; @@ -2570,6 +2611,12 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false); sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false); sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true); + sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true); + sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false); + sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null); + sDefaults.putBoolean(KEY_WORLD_MODE_ENABLED_BOOL, false); + sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_PACKAGE_NAME_STRING, ""); + sDefaults.putString(KEY_CARRIER_SETTINGS_ACTIVITY_CLASS_NAME_STRING, ""); sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false); sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false); sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index d7169b23d94b..c6887ab93109 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -342,6 +342,12 @@ public class DisconnectCause { */ public static final int TOO_MANY_ONGOING_CALLS = 75; + /** + * Indicates that a new outgoing call cannot be placed because OTASP provisioning is currently + * in process. + */ + public static final int OTASP_PROVISIONING_IN_PROCESS = 76; + //********************************************************************************************* // When adding a disconnect type: // 1) Update toString() with the newly added disconnect type. @@ -505,6 +511,8 @@ public class DisconnectCause { return "CALLING_DISABLED"; case TOO_MANY_ONGOING_CALLS: return "TOO_MANY_ONGOING_CALLS"; + case OTASP_PROVISIONING_IN_PROCESS: + return "OTASP_PROVISIONING_IN_PROCESS"; default: return "INVALID: " + cause; } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 0ba18ee54bf4..31770ec1dce2 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -51,6 +51,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.euicc.EuiccManager; +import android.telephony.ims.ImsMmTelManager; import android.util.DisplayMetrics; import android.util.Log; @@ -134,7 +135,7 @@ public class SubscriptionManager { * A content {@link Uri} used to receive updates on wfc enabled user setting. * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the - * subscription wfc enabled {@link SubscriptionManager#WFC_IMS_ENABLED} + * subscription wfc enabled {@link ImsMmTelManager#isVoWiFiSettingEnabled()} * while your app is running. You can also use a {@link JobService} to ensure your app * is notified of changes to the {@link Uri} even when it is not running. * Note, however, that using a {@link JobService} does not guarantee timely delivery of @@ -147,10 +148,28 @@ public class SubscriptionManager { public static final Uri WFC_ENABLED_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc"); /** - * A content {@link Uri} used to receive updates on enhanced 4g user setting. + * A content {@link Uri} used to receive updates on advanced calling user setting. * <p> * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the - * subscription enhanced 4G enabled {@link SubscriptionManager#ENHANCED_4G_MODE_ENABLED} + * subscription advanced calling enabled + * {@link ImsMmTelManager#isAdvancedCallingSettingEnabled()} while your app is running. + * You can also use a {@link JobService} to ensure your app is notified of changes to the + * {@link Uri} even when it is not running. + * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * updates to the {@link Uri}. + * To be notified of changes to a specific subId, append subId to the URI + * {@link Uri#withAppendedPath(Uri, String)}. + * @hide + */ + @SystemApi + public static final Uri ADVANCED_CALLING_ENABLED_CONTENT_URI = Uri.withAppendedPath( + CONTENT_URI, "advanced_calling"); + + /** + * A content {@link Uri} used to receive updates on wfc mode setting. + * <p> + * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the + * subscription wfc mode {@link ImsMmTelManager#getVoWiFiModeSetting()} * while your app is running. You can also use a {@link JobService} to ensure your app * is notified of changes to the {@link Uri} even when it is not running. * Note, however, that using a {@link JobService} does not guarantee timely delivery of @@ -160,9 +179,59 @@ public class SubscriptionManager { * @hide */ @SystemApi - public static final Uri ENHANCED_4G_ENABLED_CONTENT_URI = Uri.withAppendedPath( - CONTENT_URI, "enhanced_4g"); + public static final Uri WFC_MODE_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc_mode"); + /** + * A content {@link Uri} used to receive updates on wfc roaming mode setting. + * <p> + * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the + * subscription wfc roaming mode {@link ImsMmTelManager#getVoWiFiRoamingModeSetting()} + * while your app is running. You can also use a {@link JobService} to ensure your app + * is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * updates to the {@link Uri}. + * To be notified of changes to a specific subId, append subId to the URI + * {@link Uri#withAppendedPath(Uri, String)}. + * @hide + */ + @SystemApi + public static final Uri WFC_ROAMING_MODE_CONTENT_URI = Uri.withAppendedPath( + CONTENT_URI, "wfc_roaming_mode"); + + /** + * A content {@link Uri} used to receive updates on vt(video telephony over IMS) enabled + * setting. + * <p> + * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the + * subscription vt enabled {@link ImsMmTelManager#isVtSettingEnabled()} + * while your app is running. You can also use a {@link JobService} to ensure your app + * is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * updates to the {@link Uri}. + * To be notified of changes to a specific subId, append subId to the URI + * {@link Uri#withAppendedPath(Uri, String)}. + * @hide + */ + @SystemApi + public static final Uri VT_ENABLED_CONTENT_URI = Uri.withAppendedPath( + CONTENT_URI, "vt_enabled"); + + /** + * A content {@link Uri} used to receive updates on wfc roaming enabled setting. + * <p> + * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the + * subscription wfc roaming enabled {@link ImsMmTelManager#isVoWiFiRoamingSettingEnabled()} + * while your app is running. You can also use a {@link JobService} to ensure your app + * is notified of changes to the {@link Uri} even when it is not running. + * Note, however, that using a {@link JobService} does not guarantee timely delivery of + * updates to the {@link Uri}. + * To be notified of changes to a specific subId, append subId to the URI + * {@link Uri#withAppendedPath(Uri, String)}. + * @hide + */ + @SystemApi + public static final Uri WFC_ROAMING_ENABLED_CONTENT_URI = Uri.withAppendedPath( + CONTENT_URI, "wfc_roaming_enabled"); /** * TelephonyProvider unique key column name is the subscription id. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index e5c4ccda422a..1091b5839fe4 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1238,38 +1238,6 @@ public class TelephonyManager { */ public static final String EXTRA_RECOVERY_ACTION = "recoveryAction"; - /** - * Broadcast intent action indicating that the telephony provider DB got lost. - * - * <p> - * The {@link #EXTRA_IS_CORRUPTED} extra indicates whether the database is lost - * due to corruption or not - * - * <p class="note"> - * Requires the MODIFY_PHONE_STATE permission. - * - * <p class="note"> - * This is a protected intent that can only be sent by the system. - * - * @see #EXTRA_IS_CORRUPTED - * - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - public static final String ACTION_MMSSMS_DATABASE_LOST = - "android.intent.action.MMSSMS_DATABASE_LOST"; - - /** - * A boolean extra used with {@link #ACTION_MMSSMS_DATABASE_LOST} to indicate - * whether the database is lost due to corruption or not. - * - * @see #ACTION_MMSSMS_DATABASE_LOST - * - * @hide - */ - public static final String EXTRA_IS_CORRUPTED = "isCorrupted"; - // // // Device Info @@ -1317,9 +1285,10 @@ public class TelephonyManager { * Returns the unique device ID, for example, the IMEI for GSM and the MEID * or ESN for CDMA phones. Return null if device ID is not available. * - * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the - * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app - * that owns a managed profile on the device; for more details see <a + * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or + * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier + * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a + * managed profile on the device; for more details see <a * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner * access is deprecated and will be removed in a future release. * @@ -1327,7 +1296,7 @@ public class TelephonyManager { * MEID for CDMA. */ @Deprecated - @SuppressAutoDoc // No support for device / profile owner. + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceId() { try { @@ -1346,9 +1315,10 @@ public class TelephonyManager { * Returns the unique device ID of a subscription, for example, the IMEI for * GSM and the MEID for CDMA phones. Return null if device ID is not available. * - * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the - * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app - * that owns a managed profile on the device; for more details see <a + * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or + * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier + * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a + * managed profile on the device; for more details see <a * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner * access is deprecated and will be removed in a future release. * @@ -1358,7 +1328,7 @@ public class TelephonyManager { * MEID for CDMA. */ @Deprecated - @SuppressAutoDoc // No support for device / profile owner. + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceId(int slotIndex) { // FIXME this assumes phoneId == slotIndex @@ -1378,13 +1348,14 @@ public class TelephonyManager { * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not * available. * - * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the - * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app - * that owns a managed profile on the device; for more details see <a + * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or + * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier + * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a + * managed profile on the device; for more details see <a * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner * access is deprecated and will be removed in a future release. */ - @SuppressAutoDoc // No support for device / profile owner. + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getImei() { return getImei(getSlotIndex()); @@ -1394,15 +1365,16 @@ public class TelephonyManager { * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not * available. * - * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the - * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app - * that owns a managed profile on the device; for more details see <a + * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or + * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier + * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a + * managed profile on the device; for more details see <a * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner * access is deprecated and will be removed in a future release. * * @param slotIndex of which IMEI is returned */ - @SuppressAutoDoc // No support for device / profile owner. + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getImei(int slotIndex) { ITelephony telephony = getITelephony(); @@ -1447,13 +1419,14 @@ public class TelephonyManager { /** * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available. * - * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the - * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app - * that owns a managed profile on the device; for more details see <a + * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or + * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier + * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a + * managed profile on the device; for more details see <a * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner * access is deprecated and will be removed in a future release. */ - @SuppressAutoDoc // No support for device / profile owner. + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getMeid() { return getMeid(getSlotIndex()); @@ -1462,15 +1435,16 @@ public class TelephonyManager { /** * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available. * - * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the - * device or profile owner and have the READ_PHONE_STATE permission. The profile owner is an app - * that owns a managed profile on the device; for more details see <a + * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or + * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier + * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a + * managed profile on the device; for more details see <a * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner * access is deprecated and will be removed in a future release. * * @param slotIndex of which MEID is returned */ - @SuppressAutoDoc // No support for device / profile owner. + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getMeid(int slotIndex) { ITelephony telephony = getITelephony(); @@ -2968,7 +2942,7 @@ public class TelephonyManager { * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner * access is deprecated and will be removed in a future release. */ - @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getSimSerialNumber() { return getSimSerialNumber(getSubId()); @@ -3130,7 +3104,7 @@ public class TelephonyManager { * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner * access is deprecated and will be removed in a future release. */ - @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getSubscriberId() { return getSubscriberId(getSubId()); diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index aabefe324d82..2e9bffe9e0d9 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -1184,6 +1184,16 @@ public class ApnSetting implements Parcelable { } /** + * @param apnType APN type + * @return APN type in string format + * @hide + */ + public static String getApnTypeString(int apnType) { + String apnTypeString = APN_TYPE_INT_MAP.get(apnType); + return apnTypeString == null ? "Unknown" : apnTypeString; + } + + /** * @param types comma delimited list of APN types. * @return bitmask of APN types. * @hide diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl index e8e1f017789f..32ffdbc2121c 100644 --- a/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl +++ b/telephony/java/android/telephony/data/IQualifiedNetworksServiceCallback.aidl @@ -22,5 +22,5 @@ package android.telephony.data; */ oneway interface IQualifiedNetworksServiceCallback { - void onQualifiedNetworkTypesChanged(int apnType, in int[] qualifiedNetworkTypesList); + void onQualifiedNetworkTypesChanged(int apnTypes, in int[] qualifiedNetworkTypes); } diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java index bb89f193e03a..57d9cced53b1 100644 --- a/telephony/java/android/telephony/data/QualifiedNetworksService.java +++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java @@ -121,27 +121,28 @@ public abstract class QualifiedNetworksService extends Service { /** * Update the qualified networks list. Network availability updater must invoke this method * whenever the qualified networks changes. If this method is never invoked for certain - * APN type, then frameworks will always use the default (i.e. cellular) data and network + * APN types, then frameworks will always use the default (i.e. cellular) data and network * service. * - * @param apnType APN type of the qualified networks + * @param apnTypes APN types of the qualified networks. This must be a bitmask combination + * of {@link ApnSetting.ApnType}. * @param qualifiedNetworkTypes List of network types which are qualified for data * connection setup for {@link @apnType} in the preferred order. Each element in the array * is a {@link AccessNetworkType}. An empty list or null indicates no networks are qualified * for data setup. */ - public final void updateQualifiedNetworkTypes(@ApnType int apnType, + public final void updateQualifiedNetworkTypes(@ApnType int apnTypes, int[] qualifiedNetworkTypes) { - mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnType, + mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnTypes, qualifiedNetworkTypes).sendToTarget(); } - private void onUpdateQualifiedNetworkTypes(@ApnType int apnType, + private void onUpdateQualifiedNetworkTypes(@ApnType int apnTypes, int[] qualifiedNetworkTypes) { - mQualifiedNetworkTypesList.put(apnType, qualifiedNetworkTypes); + mQualifiedNetworkTypesList.put(apnTypes, qualifiedNetworkTypes); if (mCallback != null) { try { - mCallback.onQualifiedNetworkTypesChanged(apnType, qualifiedNetworkTypes); + mCallback.onQualifiedNetworkTypesChanged(apnTypes, qualifiedNetworkTypes); } catch (RemoteException e) { loge("Failed to call onQualifiedNetworksChanged. " + e); } diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java index 11411778a9ab..3b1ef3f45993 100644 --- a/telephony/java/android/telephony/euicc/EuiccCardManager.java +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -15,6 +15,7 @@ */ package android.telephony.euicc; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -50,7 +51,6 @@ import com.android.internal.telephony.euicc.ISwitchToProfileCallback; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import android.annotation.CallbackExecutor; import java.util.concurrent.Executor; /** @@ -119,6 +119,9 @@ public class EuiccCardManager { /** Result code when the eUICC card with the given card Id is not found. */ public static final int RESULT_EUICC_NOT_FOUND = -2; + /** Result code indicating the caller is not the active LPA. */ + public static final int RESULT_CALLER_NOT_ALLOWED = -3; + /** * Callback to receive the result of an eUICC card API. * @@ -152,7 +155,7 @@ public class EuiccCardManager { * Requests all the profiles on eUicc. * * @param cardId The Id of the eUICC. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code and all the profiles. */ public void requestAllProfiles(String cardId, @CallbackExecutor Executor executor, @@ -176,7 +179,7 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code and profile. */ public void requestProfile(String cardId, String iccid, @CallbackExecutor Executor executor, @@ -201,7 +204,7 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile. * @param refresh Whether sending the REFRESH command to modem. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code. */ public void disableProfile(String cardId, String iccid, boolean refresh, @@ -227,7 +230,7 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile to switch to. * @param refresh Whether sending the REFRESH command to modem. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code and the EuiccProfileInfo enabled. */ public void switchToProfile(String cardId, String iccid, boolean refresh, @@ -252,7 +255,7 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile. * @param nickname The nickname of the profile. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code. */ public void setNickname(String cardId, String iccid, String nickname, @@ -276,7 +279,7 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param iccid The iccid of the profile. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code. */ public void deleteProfile(String cardId, String iccid, @CallbackExecutor Executor executor, @@ -301,7 +304,7 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param options Bits of the options of resetting which parts of the eUICC memory. See * EuiccCard for details. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code. */ public void resetMemory(String cardId, @ResetOption int options, @@ -324,7 +327,7 @@ public class EuiccCardManager { * Requests the default SM-DP+ address from eUICC. * * @param cardId The Id of the eUICC. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code and the default SM-DP+ address. */ public void requestDefaultSmdpAddress(String cardId, @CallbackExecutor Executor executor, @@ -347,7 +350,7 @@ public class EuiccCardManager { * Requests the SM-DS address from eUICC. * * @param cardId The Id of the eUICC. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code and the SM-DS address. */ public void requestSmdsAddress(String cardId, @CallbackExecutor Executor executor, @@ -371,7 +374,7 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param defaultSmdpAddress The default SM-DP+ address to set. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback The callback to get the result code. */ public void setDefaultSmdpAddress(String cardId, String defaultSmdpAddress, @@ -395,7 +398,7 @@ public class EuiccCardManager { * Requests Rules Authorisation Table. * * @param cardId The Id of the eUICC. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and the rule authorisation table. */ public void requestRulesAuthTable(String cardId, @CallbackExecutor Executor executor, @@ -418,7 +421,7 @@ public class EuiccCardManager { * Requests the eUICC challenge for new profile downloading. * * @param cardId The Id of the eUICC. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and the challenge. */ public void requestEuiccChallenge(String cardId, @CallbackExecutor Executor executor, @@ -441,7 +444,7 @@ public class EuiccCardManager { * Requests the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading. * * @param cardId The Id of the eUICC. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and the info1. */ public void requestEuiccInfo1(String cardId, @CallbackExecutor Executor executor, @@ -464,7 +467,7 @@ public class EuiccCardManager { * Gets the eUICC info2 defined in GSMA RSP v2.0+ for new profile downloading. * * @param cardId The Id of the eUICC. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and the info2. */ public void requestEuiccInfo2(String cardId, @CallbackExecutor Executor executor, @@ -497,7 +500,7 @@ public class EuiccCardManager { * GSMA RSP v2.0+. * @param serverCertificate ASN.1 data in byte array indicating SM-DP+ Certificate returned by * SM-DP+ server. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and a byte array which represents a * {@code AuthenticateServerResponse} defined in GSMA RSP v2.0+. */ @@ -537,7 +540,7 @@ public class EuiccCardManager { * SM-DP+ server. * @param smdpCertificate ASN.1 data in byte array indicating the SM-DP+ Certificate returned * by SM-DP+ server. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and a byte array which represents a * {@code PrepareDownloadResponse} defined in GSMA RSP v2.0+ */ @@ -569,7 +572,7 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param boundProfilePackage the Bound Profile Package data returned by SM-DP+ server. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and a byte array which represents a * {@code LoadBoundProfilePackageResponse} defined in GSMA RSP v2.0+. */ @@ -598,7 +601,7 @@ public class EuiccCardManager { * @param cardId The Id of the eUICC. * @param transactionId the transaction ID returned by SM-DP+ server. * @param reason the cancel reason. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and an byte[] which represents a * {@code CancelSessionResponse} defined in GSMA RSP v2.0+. */ @@ -627,7 +630,7 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param events bits of the event types ({@link EuiccNotification.Event}) to list. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and the list of notifications. */ public void listNotifications(String cardId, @EuiccNotification.Event int events, @@ -651,7 +654,7 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param events bits of the event types ({@link EuiccNotification.Event}) to list. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and the list of notifications. */ public void retrieveNotificationList(String cardId, @EuiccNotification.Event int events, @@ -675,7 +678,7 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param seqNumber the sequence number of the notification. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code and the notification. */ public void retrieveNotification(String cardId, int seqNumber, @@ -699,7 +702,7 @@ public class EuiccCardManager { * * @param cardId The Id of the eUICC. * @param seqNumber the sequence number of the notification. - * @param executor The executor through which the callback should be invode. + * @param executor The executor through which the callback should be invoke. * @param callback the callback to get the result code. */ public void removeNotificationFromList(String cardId, int seqNumber, diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 89ef33914c12..f73036e88a95 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -16,17 +16,20 @@ package android.telephony.ims; +import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.os.PersistableBundle; import android.telecom.VideoProfile; import android.util.Log; import com.android.internal.telephony.PhoneConstants; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Parcelable object to handle IMS call profile. * It is created from GSMA IR.92/IR.94, 3GPP TS 24.229/TS 26.114/TS26.111. @@ -206,17 +209,36 @@ public final class ImsCallProfile implements Parcelable { public static final int DIALSTRING_USSD = 2; /** - * Values for causes that restrict call types + * Call is not restricted on peer side and High Definition media is supported */ - // Default cause not restricted at peer and HD is supported public static final int CALL_RESTRICT_CAUSE_NONE = 0; - // Service not supported by RAT at peer + + /** + * High Definition media is not supported on the peer side due to the Radio Access Technology + * (RAT) it is are connected to. + */ public static final int CALL_RESTRICT_CAUSE_RAT = 1; - // Service Disabled at peer + + /** + * The service has been disabled on the peer side. + */ public static final int CALL_RESTRICT_CAUSE_DISABLED = 2; - // HD is not supported + + /** + * High definition media is not currently supported. + */ public static final int CALL_RESTRICT_CAUSE_HD = 3; + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "CALL_RESTRICT_CAUSE_", value = { + CALL_RESTRICT_CAUSE_NONE, + CALL_RESTRICT_CAUSE_RAT, + CALL_RESTRICT_CAUSE_DISABLED, + CALL_RESTRICT_CAUSE_HD + }) + public @interface CallRestrictCause {} + /** * String extra properties * oi : Originating identity (number), MT only @@ -270,7 +292,7 @@ public final class ImsCallProfile implements Parcelable { public int mCallType; /** @hide */ @UnsupportedAppUsage - public int mRestrictCause = CALL_RESTRICT_CAUSE_NONE; + public @CallRestrictCause int mRestrictCause = CALL_RESTRICT_CAUSE_NONE; /** * Extras associated with this {@link ImsCallProfile}. @@ -285,7 +307,7 @@ public final class ImsCallProfile implements Parcelable { * <li>{@code long[]}</li> * <li>{@code double[]}</li> * <li>{@code String[]}</li> - * <li>{@link PersistableBundle}</li> + * <li>{@link android.os.PersistableBundle}</li> * <li>{@link Boolean} (and boolean)</li> * <li>{@code boolean[]}</li> * <li>Other {@link Parcelable} classes in the {@code android.*} namespace.</li> @@ -426,6 +448,14 @@ public final class ImsCallProfile implements Parcelable { } } + /** + * Set the call restrict cause, which provides the reason why a call has been restricted from + * using High Definition media. + */ + public void setCallRestrictCause(@CallRestrictCause int cause) { + mRestrictCause = cause; + } + public void updateCallType(ImsCallProfile profile) { mCallType = profile.mCallType; } @@ -494,7 +524,11 @@ public final class ImsCallProfile implements Parcelable { return mCallType; } - public int getRestrictCause() { + /** + * @return The call restrict cause, which provides the reason why a call has been restricted + * from using High Definition media. + */ + public @CallRestrictCause int getRestrictCause() { return mRestrictCause; } diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java index eb6be65104d1..553e3fb9d219 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java @@ -188,6 +188,13 @@ public final class TelephonyPermissions { if (checkReadDeviceIdentifiers(context, pid, uid, callingPackage)) { return true; } + // Calling packages with carrier privileges will also have access to device identifiers, but + // this may be removed in a future release. + if (SubscriptionManager.isValidSubscriptionId(subId) && getCarrierPrivilegeStatus( + TELEPHONY_SUPPLIER, subId, uid) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { + return true; + } // else the calling package is not authorized to access the device identifiers; call // a central method to report the failure based on the target SDK and if the calling package // has the READ_PHONE_STATE permission or carrier privileges that were previously required @@ -279,44 +286,51 @@ public final class TelephonyPermissions { int uid, String callingPackage, String message) { Log.wtf(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message); - // if the device identifier check is relaxed then revert to the READ_PHONE_STATE permission - // check that was previously required to access device identifiers. - boolean relaxDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(), - Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 0; - if (relaxDeviceIdentifierCheck) { - return checkReadPhoneState(context, subId, pid, uid, callingPackage, message); - } else { + // If the device identifier check is enabled then enforce the new access requirements for + // both 1P and 3P apps. + boolean enableDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(), + Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 1; + // Check if the application is a 3P app; if so then a separate setting is required to relax + // the check to begin flagging problems with 3P apps early. + boolean relax3PDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(), + Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED, 0) == 1; + boolean is3PApp = true; + ApplicationInfo callingPackageInfo = null; + try { + callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0); + if (callingPackageInfo.isSystemApp()) { + is3PApp = false; + } + } catch (PackageManager.NameNotFoundException e) { + // If the application info for the calling package could not be found then assume the + // calling app is a 3P app to detect any issues with the check + } + if (enableDeviceIdentifierCheck || (is3PApp && !relax3PDeviceIdentifierCheck)) { boolean targetQBehaviorDisabled = Settings.Global.getInt(context.getContentResolver(), Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, 0) == 0; if (callingPackage != null) { - try { - // if the target SDK is pre-Q or the target Q behavior is disabled then check if - // the calling package would have previously had access to device identifiers. - ApplicationInfo callingPackageInfo = - context.getPackageManager().getApplicationInfo( - callingPackage, 0); - if (callingPackageInfo != null && ( - callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q - || targetQBehaviorDisabled)) { - if (context.checkPermission( - android.Manifest.permission.READ_PHONE_STATE, - pid, - uid) == PackageManager.PERMISSION_GRANTED) { - return false; - } - if (SubscriptionManager.isValidSubscriptionId(subId) - && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid) - == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { - return false; - } + // if the target SDK is pre-Q or the target Q behavior is disabled then check if + // the calling package would have previously had access to device identifiers. + if (callingPackageInfo != null && ( + callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q + || targetQBehaviorDisabled)) { + if (context.checkPermission( + android.Manifest.permission.READ_PHONE_STATE, + pid, + uid) == PackageManager.PERMISSION_GRANTED) { + return false; + } + if (SubscriptionManager.isValidSubscriptionId(subId) + && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { + return false; } - } catch (PackageManager.NameNotFoundException e) { - // If the application info for the calling package could not be found then - // default to throwing the SecurityException. } } throw new SecurityException(message + ": The user " + uid + " does not meet the requirements to access device identifiers."); + } else { + return checkReadPhoneState(context, subId, pid, uid, callingPackage, message); } } diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java index 04266c5b3a0f..b9222a86a092 100644 --- a/tests/net/java/android/net/MacAddressTest.java +++ b/tests/net/java/android/net/MacAddressTest.java @@ -17,8 +17,8 @@ package android.net; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.support.test.filters.SmallTest; @@ -252,6 +252,39 @@ public class MacAddressTest { } } + @Test + public void testMatches() { + // match 4 bytes prefix + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:00:00"), + MacAddress.fromString("ff:ff:ff:ff:00:00"))); + + // match bytes 0,1,2 and 5 + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:00:00:11"), + MacAddress.fromString("ff:ff:ff:00:00:ff"))); + + // match 34 bit prefix + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:c0:00"), + MacAddress.fromString("ff:ff:ff:ff:c0:00"))); + + // fail to match 36 bit prefix + assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:40:00"), + MacAddress.fromString("ff:ff:ff:ff:f0:00"))); + + // match all 6 bytes + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:ee:11"), + MacAddress.fromString("ff:ff:ff:ff:ff:ff"))); + + // match none of 6 bytes + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("00:00:00:00:00:00"), + MacAddress.fromString("00:00:00:00:00:00"))); + } + static byte[] toByteArray(int... in) { byte[] out = new byte[in.length]; for (int i = 0; i < in.length; i++) { diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp index 4be6534ce857..0a9e964d8d8d 100644 --- a/tests/utils/testutils/Android.bp +++ b/tests/utils/testutils/Android.bp @@ -19,7 +19,7 @@ java_library { srcs: ["java/**/*.java"], - static_libs: ["android-support-test"], + static_libs: ["junit"], libs: [ "android.test.runner", diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 0a517ab8a2de..0bc5221245ca 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -306,8 +306,29 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& break; } - if (entry->overlayable) { - printer->Print(" OVERLAYABLE"); + for (size_t i = 0; i < entry->overlayable_declarations.size(); i++) { + printer->Print((i == 0) ? " " : "|"); + printer->Print("OVERLAYABLE"); + + if (entry->overlayable_declarations[i].policy) { + switch (entry->overlayable_declarations[i].policy.value()) { + case Overlayable::Policy::kProduct: + printer->Print("_PRODUCT"); + break; + case Overlayable::Policy::kProductServices: + printer->Print("_PRODUCT_SERVICES"); + break; + case Overlayable::Policy::kSystem: + printer->Print("_SYSTEM"); + break; + case Overlayable::Policy::kVendor: + printer->Print("_VENDOR"); + break; + case Overlayable::Policy::kPublic: + printer->Print("_PUBLIC"); + break; + } + } } printer->Println(); diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 9a3f14c8e08e..4f25e0968c0e 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -99,7 +99,7 @@ struct ParsedResource { ResourceId id; Visibility::Level visibility_level = Visibility::Level::kUndefined; bool allow_new = false; - bool overlayable = false; + std::vector<Overlayable> overlayable_declarations; std::string comment; std::unique_ptr<Value> value; @@ -133,11 +133,8 @@ static bool AddResourcesToTable(ResourceTable* table, IDiagnostics* diag, Parsed } } - if (res->overlayable) { - Overlayable overlayable; - overlayable.source = res->source; - overlayable.comment = res->comment; - if (!table->SetOverlayable(res->name, overlayable, diag)) { + for (auto& overlayable : res->overlayable_declarations) { + if (!table->AddOverlayable(res->name, overlayable, diag)) { return false; } } @@ -673,7 +670,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser, if (can_be_bag) { const auto bag_iter = elToBagMap.find(resource_type); if (bag_iter != elToBagMap.end()) { - // Ensure we have a name (unless this is a <public-group>). + // Ensure we have a name (unless this is a <public-group> or <overlayable>). if (resource_type != "public-group" && resource_type != "overlayable") { if (!maybe_name) { diag_->Error(DiagMessage(out_resource->source) @@ -1062,72 +1059,135 @@ bool ResourceParser::ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource) { if (out_resource->config != ConfigDescription::DefaultConfig()) { diag_->Warn(DiagMessage(out_resource->source) - << "ignoring configuration '" << out_resource->config << "' for <overlayable> tag"); + << "ignoring configuration '" << out_resource->config + << "' for <overlayable> tag"); } - if (Maybe<StringPiece> maybe_policy = xml::FindNonEmptyAttribute(parser, "policy")) { - const StringPiece& policy = maybe_policy.value(); - if (policy != "system") { - diag_->Error(DiagMessage(out_resource->source) - << "<overlayable> has invalid policy '" << policy << "'"); - return false; - } - } + std::string comment; + std::vector<Overlayable::Policy> policies; bool error = false; - const size_t depth = parser->depth(); - while (xml::XmlPullParser::NextChildNode(parser, depth)) { - if (parser->event() != xml::XmlPullParser::Event::kStartElement) { - // Skip text/comments. + const size_t start_depth = parser->depth(); + while (xml::XmlPullParser::IsGoodEvent(parser->Next())) { + xml::XmlPullParser::Event event = parser->event(); + if (event == xml::XmlPullParser::Event::kEndElement && parser->depth() == start_depth) { + // Break the loop when exiting the overyabale element + break; + } else if (event == xml::XmlPullParser::Event::kEndElement + && parser->depth() == start_depth + 1) { + // Clear the current policies when exiting the policy element + policies.clear(); + continue; + } else if (event == xml::XmlPullParser::Event::kComment) { + // Get the comment of individual item elements + comment = parser->comment(); + continue; + } else if (event != xml::XmlPullParser::Event::kStartElement) { + // Skip to the next element continue; } const Source item_source = source_.WithLine(parser->line_number()); - const std::string& element_namespace = parser->element_namespace(); const std::string& element_name = parser->element_name(); + const std::string& element_namespace = parser->element_namespace(); + if (element_namespace.empty() && element_name == "item") { - Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); - if (!maybe_name) { - diag_->Error(DiagMessage(item_source) - << "<item> within an <overlayable> tag must have a 'name' attribute"); + if (!ParseOverlayableItem(parser, policies, comment, out_resource)) { error = true; - continue; } - - Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); - if (!maybe_type) { - diag_->Error(DiagMessage(item_source) - << "<item> within an <overlayable> tag must have a 'type' attribute"); + } else if (element_namespace.empty() && element_name == "policy") { + if (!policies.empty()) { + // If the policy list is not empty, then we are currently inside a policy element + diag_->Error(DiagMessage(item_source) << "<policy> blocks cannot be recursively nested"); error = true; - continue; + break; + } else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) { + // Parse the polices separated by vertical bar characters to allow for specifying multiple + // policies at once + for (StringPiece part : util::Tokenize(maybe_type.value(), '|')) { + StringPiece trimmed_part = util::TrimWhitespace(part); + if (trimmed_part == "public") { + policies.push_back(Overlayable::Policy::kPublic); + } else if (trimmed_part == "product") { + policies.push_back(Overlayable::Policy::kProduct); + } else if (trimmed_part == "product_services") { + policies.push_back(Overlayable::Policy::kProductServices); + } else if (trimmed_part == "system") { + policies.push_back(Overlayable::Policy::kSystem); + } else if (trimmed_part == "vendor") { + policies.push_back(Overlayable::Policy::kVendor); + } else { + diag_->Error(DiagMessage(out_resource->source) + << "<policy> has unsupported type '" << trimmed_part << "'"); + error = true; + continue; + } + } } + } else if (!ShouldIgnoreElement(element_namespace, element_name)) { + diag_->Error(DiagMessage(item_source) << "invalid element <" << element_name << "> in " + << " <overlayable>"); + error = true; + break; + } + } - const ResourceType* type = ParseResourceType(maybe_type.value()); - if (type == nullptr) { - diag_->Error(DiagMessage(out_resource->source) + return !error; +} + +bool ResourceParser::ParseOverlayableItem(xml::XmlPullParser* parser, + const std::vector<Overlayable::Policy>& policies, + const std::string& comment, + ParsedResource* out_resource) { + const Source item_source = source_.WithLine(parser->line_number()); + + Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name"); + if (!maybe_name) { + diag_->Error(DiagMessage(item_source) + << "<item> within an <overlayable> tag must have a 'name' attribute"); + return false; + } + + Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type"); + if (!maybe_type) { + diag_->Error(DiagMessage(item_source) + << "<item> within an <overlayable> tag must have a 'type' attribute"); + return false; + } + + const ResourceType* type = ParseResourceType(maybe_type.value()); + if (type == nullptr) { + diag_->Error(DiagMessage(out_resource->source) << "invalid resource type '" << maybe_type.value() << "' in <item> within an <overlayable>"); - error = true; - continue; - } + return false; + } - ParsedResource child_resource; - child_resource.name.type = *type; - child_resource.name.entry = maybe_name.value().to_string(); - child_resource.source = item_source; - child_resource.overlayable = true; - if (options_.visibility) { - child_resource.visibility_level = options_.visibility.value(); - } - out_resource->child_resources.push_back(std::move(child_resource)); + ParsedResource child_resource; + child_resource.name.type = *type; + child_resource.name.entry = maybe_name.value().to_string(); + child_resource.source = item_source; - xml::XmlPullParser::SkipCurrentElement(parser); - } else if (!ShouldIgnoreElement(element_namespace, element_name)) { - diag_->Error(DiagMessage(item_source) << ":" << element_name << ">"); - error = true; + if (policies.empty()) { + Overlayable overlayable; + overlayable.source = item_source; + overlayable.comment = comment; + child_resource.overlayable_declarations.push_back(overlayable); + } else { + for (Overlayable::Policy policy : policies) { + Overlayable overlayable; + overlayable.policy = policy; + overlayable.source = item_source; + overlayable.comment = comment; + child_resource.overlayable_declarations.push_back(overlayable); } } - return !error; + + if (options_.visibility) { + child_resource.visibility_level = options_.visibility.value(); + } + out_resource->child_resources.push_back(std::move(child_resource)); + return true; } bool ResourceParser::ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource) { diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 06bb0c9cf264..ebacd6f1280e 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -96,6 +96,10 @@ class ResourceParser { bool ParseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource); + bool ParseOverlayableItem(xml::XmlPullParser* parser, + const std::vector<Overlayable::Policy>& policies, + const std::string& comment, + ParsedResource* out_resource); bool ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseAttr(xml::XmlPullParser* parser, ParsedResource* out_resource); bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak); diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 0dff66430532..c6f29ac53ca6 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -891,56 +891,162 @@ TEST_F(ResourceParserTest, ParsePlatformIndependentNewline) { ASSERT_TRUE(TestParse(R"(<string name="foo">%1$s %n %2$s</string>)")); } -TEST_F(ResourceParserTest, ParseOverlayableTagWithSystemPolicy) { - std::string input = R"( - <overlayable policy="illegal_policy"> +TEST_F(ResourceParserTest, ParseOverlayable) { + std::string input = R"(<overlayable />)"; + EXPECT_TRUE(TestParse(input)); + + input = R"( + <overlayable> <item type="string" name="foo" /> + <item type="drawable" name="bar" /> </overlayable>)"; - EXPECT_FALSE(TestParse(input)); + ASSERT_TRUE(TestParse(input)); + + auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy); + + search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy); +} + +TEST_F(ResourceParserTest, ParseOverlayablePolicy) { + std::string input = R"(<overlayable />)"; + EXPECT_TRUE(TestParse(input)); input = R"( - <overlayable policy="system"> - <item name="foo" /> + <overlayable> + <item type="string" name="foo" /> + <policy type="product"> + <item type="string" name="bar" /> + </policy> + <policy type="product_services"> + <item type="string" name="baz" /> + </policy> + <policy type="system"> + <item type="string" name="fiz" /> + </policy> + <policy type="vendor"> + <item type="string" name="fuz" /> + </policy> + <policy type="public"> + <item type="string" name="faz" /> + </policy> </overlayable>)"; - EXPECT_FALSE(TestParse(input)); + ASSERT_TRUE(TestParse(input)); - input = R"( - <overlayable policy="system"> - <item type="attr" /> + auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy); + + search_result = table_.FindResource(test::ParseNameOrDie("string/bar")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kProduct)); + + search_result = table_.FindResource(test::ParseNameOrDie("string/baz")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kProductServices)); + + search_result = table_.FindResource(test::ParseNameOrDie("string/fiz")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kSystem)); + + search_result = table_.FindResource(test::ParseNameOrDie("string/fuz")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kVendor)); + + search_result = table_.FindResource(test::ParseNameOrDie("string/faz")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kPublic)); +} + +TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) { + std::string input = R"( + <overlayable> + <policy type="illegal_policy"> + <item type="string" name="foo" /> + </policy> </overlayable>)"; EXPECT_FALSE(TestParse(input)); input = R"( - <overlayable policy="system"> - <item type="bad_type" name="foo" /> + <overlayable> + <policy type="product"> + <item name="foo" /> + </policy> </overlayable>)"; EXPECT_FALSE(TestParse(input)); - input = R"(<overlayable policy="system" />)"; - EXPECT_TRUE(TestParse(input)); - - input = R"(<overlayable />)"; - EXPECT_TRUE(TestParse(input)); - input = R"( - <overlayable policy="system"> - <item type="string" name="foo" /> - <item type="dimen" name="foo" /> + <overlayable> + <policy type="vendor"> + <item type="string" /> + </policy> </overlayable>)"; - ASSERT_TRUE(TestParse(input)); + EXPECT_FALSE(TestParse(input)); +} - input = R"( +TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) { + std::string input = R"( <overlayable> - <item type="string" name="bar" /> + <policy type="vendor|product_services"> + <item type="string" name="foo" /> + </policy> + <policy type="product|system"> + <item type="string" name="bar" /> + </policy> </overlayable>)"; ASSERT_TRUE(TestParse(input)); - Maybe<ResourceTable::SearchResult> search_result = - table_.FindResource(test::ParseNameOrDie("string/bar")); + auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(2)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kVendor)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations[1].policy, + Eq(Overlayable::Policy::kProductServices)); + + search_result = table_.FindResource(test::ParseNameOrDie("string/bar")); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined)); - EXPECT_TRUE(search_result.value().entry->overlayable); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(2)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kProduct)); + EXPECT_THAT(search_result.value().entry->overlayable_declarations[1].policy, + Eq(Overlayable::Policy::kSystem)); } TEST_F(ResourceParserTest, DuplicateOverlayableIsError) { @@ -950,6 +1056,85 @@ TEST_F(ResourceParserTest, DuplicateOverlayableIsError) { <item type="string" name="foo" /> </overlayable>)"; EXPECT_FALSE(TestParse(input)); + + input = R"( + <overlayable> + <item type="string" name="foo" /> + </overlayable> + <overlayable> + <item type="string" name="foo" /> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); + + input = R"( + <overlayable"> + <policy type="product"> + <item type="string" name="foo" /> + <item type="string" name="foo" /> + </policy> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); + + input = R"( + <overlayable> + <policy type="product"> + <item type="string" name="foo" /> + </policy> + </overlayable> + + <overlayable> + <policy type="product"> + <item type="string" name="foo" /> + </policy> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); +} + +TEST_F(ResourceParserTest, PolicyAndNonPolicyOverlayableError) { + std::string input = R"( + <overlayable policy="product"> + <item type="string" name="foo" /> + </overlayable> + <overlayable policy=""> + <item type="string" name="foo" /> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); + + input = R"( + <overlayable policy=""> + <item type="string" name="foo" /> + </overlayable> + <overlayable policy="product"> + <item type="string" name="foo" /> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); +} + +TEST_F(ResourceParserTest, DuplicateOverlayableMultiplePolicyError) { + std::string input = R"( + <overlayable> + <policy type="vendor|product"> + <item type="string" name="foo" /> + </policy> + </overlayable> + <overlayable> + <policy type="product_services|vendor"> + <item type="string" name="foo" /> + </policy> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); +} + +TEST_F(ResourceParserTest, NestPolicyInOverlayableError) { + std::string input = R"( + <overlayable> + <policy type="vendor|product"> + <policy type="product_services"> + <item type="string" name="foo" /> + </policy> + </policy> + </overlayable>)"; + EXPECT_FALSE(TestParse(input)); } TEST_F(ResourceParserTest, ParseIdItem) { diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp index 056a27bf011d..bc8a4d1f85b8 100644 --- a/tools/aapt2/ResourceTable.cpp +++ b/tools/aapt2/ResourceTable.cpp @@ -625,17 +625,17 @@ bool ResourceTable::SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& return true; } -bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable, +bool ResourceTable::AddOverlayable(const ResourceNameRef& name, const Overlayable& overlayable, IDiagnostics* diag) { - return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag); + return AddOverlayableImpl(name, overlayable, ResourceNameValidator, diag); } -bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name, +bool ResourceTable::AddOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable, IDiagnostics* diag) { - return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag); + return AddOverlayableImpl(name, overlayable, SkipNameValidator, diag); } -bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable, +bool ResourceTable::AddOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable, NameValidator name_validator, IDiagnostics* diag) { CHECK(diag != nullptr); @@ -646,13 +646,28 @@ bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overla ResourceTablePackage* package = FindOrCreatePackage(name.package); ResourceTableType* type = package->FindOrCreateType(name.type); ResourceEntry* entry = type->FindOrCreateEntry(name.entry); - if (entry->overlayable) { - diag->Error(DiagMessage(overlayable.source) - << "duplicate overlayable declaration for resource '" << name << "'"); - diag->Error(DiagMessage(entry->overlayable.value().source) << "previous declaration here"); - return false; + + for (auto& overlayable_declaration : entry->overlayable_declarations) { + // An overlayable resource cannot be declared twice with the same policy + if (overlayable.policy == overlayable_declaration.policy) { + diag->Error(DiagMessage(overlayable.source) + << "duplicate overlayable declaration for resource '" << name << "'"); + diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here"); + return false; + } + + // An overlayable resource cannot be declared once with a policy and without a policy because + // the policy becomes unused + if (!overlayable.policy || !overlayable_declaration.policy) { + diag->Error(DiagMessage(overlayable.source) + << "overlayable resource '" << name << "'" + << " declared once with a policy and once with no policy"); + diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here"); + return false; + } } - entry->overlayable = overlayable; + + entry->overlayable_declarations.push_back(overlayable); return true; } @@ -688,7 +703,7 @@ std::unique_ptr<ResourceTable> ResourceTable::Clone() const { new_entry->id = entry->id; new_entry->visibility = entry->visibility; new_entry->allow_new = entry->allow_new; - new_entry->overlayable = entry->overlayable; + new_entry->overlayable_declarations = entry->overlayable_declarations; for (const auto& config_value : entry->values) { ResourceConfigValue* new_value = diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h index 1917d7e78c4f..3dd0a769d944 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -57,8 +57,27 @@ struct AllowNew { std::string comment; }; -// The policy dictating whether an entry is overlayable at runtime by RROs. +// Represents a declaration that a resource is overayable at runtime. struct Overlayable { + // Represents the types overlays that are allowed to overlay the resource. + enum class Policy { + // The resource can be overlaid by any overlay. + kPublic, + + // The resource can be overlaid by any overlay on the system partition. + kSystem, + + // The resource can be overlaid by any overlay on the vendor partition. + kVendor, + + // The resource can be overlaid by any overlay on the product partition. + kProduct, + + // The resource can be overlaid by any overlay on the product services partition. + kProductServices, + }; + + Maybe<Policy> policy; Source source; std::string comment; }; @@ -96,7 +115,8 @@ class ResourceEntry { Maybe<AllowNew> allow_new; - Maybe<Overlayable> overlayable; + // The declarations of this resource as overlayable for RROs + std::vector<Overlayable> overlayable_declarations; // The resource's values for each configuration. std::vector<std::unique_ptr<ResourceConfigValue>> values; @@ -226,9 +246,9 @@ class ResourceTable { bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility, const ResourceId& res_id, IDiagnostics* diag); - bool SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable, + bool AddOverlayable(const ResourceNameRef& name, const Overlayable& overlayable, IDiagnostics* diag); - bool SetOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable, + bool AddOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable, IDiagnostics* diag); bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag); @@ -303,7 +323,7 @@ class ResourceTable { bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new, NameValidator name_validator, IDiagnostics* diag); - bool SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable, + bool AddOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable, NameValidator name_validator, IDiagnostics* diag); bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id, diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp index 05c6f1531d34..7c28f07d0f66 100644 --- a/tools/aapt2/ResourceTable_test.cpp +++ b/tools/aapt2/ResourceTable_test.cpp @@ -242,21 +242,69 @@ TEST(ResourceTableTest, SetAllowNew) { ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("second")); } -TEST(ResourceTableTest, SetOverlayable) { +TEST(ResourceTableTest, AddOverlayable) { ResourceTable table; const ResourceName name = test::ParseNameOrDie("android:string/foo"); Overlayable overlayable; - + overlayable.policy = Overlayable::Policy::kProduct; overlayable.comment = "first"; - ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics())); + ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics())); Maybe<ResourceTable::SearchResult> result = table.FindResource(name); ASSERT_TRUE(result); - ASSERT_TRUE(result.value().entry->overlayable); - ASSERT_THAT(result.value().entry->overlayable.value().comment, StrEq("first")); + ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1)); + ASSERT_THAT(result.value().entry->overlayable_declarations[0].comment, StrEq("first")); + ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kProduct)); + + Overlayable overlayable2; + overlayable2.comment = "second"; + overlayable2.policy = Overlayable::Policy::kProductServices; + ASSERT_TRUE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics())); + result = table.FindResource(name); + ASSERT_TRUE(result); + ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2)); + ASSERT_THAT(result.value().entry->overlayable_declarations[0].comment, StrEq("first")); + ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kProduct)); + ASSERT_THAT(result.value().entry->overlayable_declarations[1].comment, StrEq("second")); + ASSERT_THAT(result.value().entry->overlayable_declarations[1].policy, + Eq(Overlayable::Policy::kProductServices)); +} + +TEST(ResourceTableTest, AddDuplicateOverlayableFail) { + ResourceTable table; + const ResourceName name = test::ParseNameOrDie("android:string/foo"); + + Overlayable overlayable; + overlayable.policy = Overlayable::Policy::kProduct; + ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics())); + + Overlayable overlayable2; + overlayable2.policy = Overlayable::Policy::kProduct; + ASSERT_FALSE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics())); +} + +TEST(ResourceTableTest, AddOverlayablePolicyAndNoneFirstFail) { + ResourceTable table; + const ResourceName name = test::ParseNameOrDie("android:string/foo"); + + ASSERT_TRUE(table.AddOverlayable(name, {}, test::GetDiagnostics())); + + Overlayable overlayable2; + overlayable2.policy = Overlayable::Policy::kProduct; + ASSERT_FALSE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics())); +} + +TEST(ResourceTableTest, AddOverlayablePolicyAndNoneLastFail) { + ResourceTable table; + const ResourceName name = test::ParseNameOrDie("android:string/foo"); + + Overlayable overlayable; + overlayable.policy = Overlayable::Policy::kProduct; + ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics())); - overlayable.comment = "second"; - ASSERT_FALSE(table.SetOverlayable(name, overlayable, test::GetDiagnostics())); + ASSERT_FALSE(table.AddOverlayable(name, {}, test::GetDiagnostics())); } TEST(ResourceTableTest, AllowDuplictaeResourcesNames) { diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index d7a377176fc5..bf9fe49da2d6 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -133,13 +133,25 @@ message AllowNew { string comment = 2; } -// Whether a resource is overlayable by runtime resource overlays (RRO). +// Represents a declaration that a resource is overayable at runtime. message Overlayable { + enum Policy { + NONE = 0; + PUBLIC = 1; + SYSTEM = 2; + VENDOR = 3; + PRODUCT = 4; + PRODUCT_SERVICES = 5; + } + // Where this declaration was defined in source. Source source = 1; // Any comment associated with the declaration. string comment = 2; + + // The policy of the overlayable declaration + Policy policy = 3; } // An entry ID in the range [0x0000, 0xffff]. @@ -169,7 +181,7 @@ message Entry { AllowNew allow_new = 4; // Whether this resource can be overlaid by a runtime resource overlay (RRO). - Overlayable overlayable = 5; + repeated Overlayable overlayable = 5; // The set of values defined for this entry, each corresponding to a different // configuration/variant. diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index 3a39a6baeeeb..ed70fb3c57d6 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -398,7 +398,7 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package, if (type_spec_flags & ResTable_typeSpec::SPEC_OVERLAYABLE) { Overlayable overlayable; overlayable.source = source_.WithLine(0); - if (!table_->SetOverlayableMangled(name, overlayable, diag_)) { + if (!table_->AddOverlayableMangled(name, overlayable, diag_)) { return false; } } diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index 8641a7c93d19..8a86f63a30c1 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -446,7 +446,7 @@ class PackageFlattener { config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC); } - if (entry->overlayable) { + if (!entry->overlayable_declarations.empty()) { config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_OVERLAYABLE); } diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index af19b98e528b..cd1414c7e628 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -634,7 +634,7 @@ TEST_F(TableFlattenerTest, FlattenOverlayable) { .AddSimple("com.app.test:integer/overlayable", ResourceId(0x7f020000)) .Build(); - ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.test:integer/overlayable"), + ASSERT_TRUE(table->AddOverlayable(test::ParseNameOrDie("com.app.test:integer/overlayable"), Overlayable{}, test::GetDiagnostics())); ResTable res_table; diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index d1b2fdb84afc..f612914269de 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -437,15 +437,37 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr entry->allow_new = std::move(allow_new); } - if (pb_entry.has_overlayable()) { - const pb::Overlayable& pb_overlayable = pb_entry.overlayable(); - + for (const pb::Overlayable& pb_overlayable : pb_entry.overlayable()) { Overlayable overlayable; + switch (pb_overlayable.policy()) { + case pb::Overlayable::NONE: + overlayable.policy = {}; + break; + case pb::Overlayable::PUBLIC: + overlayable.policy = Overlayable::Policy::kPublic; + break; + case pb::Overlayable::PRODUCT: + overlayable.policy = Overlayable::Policy::kProduct; + break; + case pb::Overlayable::PRODUCT_SERVICES: + overlayable.policy = Overlayable::Policy::kProductServices; + break; + case pb::Overlayable::SYSTEM: + overlayable.policy = Overlayable::Policy::kSystem; + break; + case pb::Overlayable::VENDOR: + overlayable.policy = Overlayable::Policy::kVendor; + break; + default: + *out_error = "unknown overlayable policy"; + return false; + } + if (pb_overlayable.has_source()) { DeserializeSourceFromPb(pb_overlayable.source(), src_pool, &overlayable.source); } overlayable.comment = pb_overlayable.comment(); - entry->overlayable = std::move(overlayable); + entry->overlayable_declarations.push_back(overlayable); } ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(), diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index 7e35ea7bb7a3..f1e96d61191b 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -310,11 +310,31 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table pb_allow_new->set_comment(entry->allow_new.value().comment); } - if (entry->overlayable) { - pb::Overlayable* pb_overlayable = pb_entry->mutable_overlayable(); - SerializeSourceToPb(entry->overlayable.value().source, &source_pool, + for (const Overlayable& overlayable : entry->overlayable_declarations) { + pb::Overlayable* pb_overlayable = pb_entry->add_overlayable(); + if (overlayable.policy) { + switch (overlayable.policy.value()) { + case Overlayable::Policy::kPublic: + pb_overlayable->set_policy(pb::Overlayable::PUBLIC); + break; + case Overlayable::Policy::kProduct: + pb_overlayable->set_policy(pb::Overlayable::PRODUCT); + break; + case Overlayable::Policy::kProductServices: + pb_overlayable->set_policy(pb::Overlayable::PRODUCT_SERVICES); + break; + case Overlayable::Policy::kSystem: + pb_overlayable->set_policy(pb::Overlayable::SYSTEM); + break; + case Overlayable::Policy::kVendor: + pb_overlayable->set_policy(pb::Overlayable::VENDOR); + break; + } + } + + SerializeSourceToPb(overlayable.source, &source_pool, pb_overlayable->mutable_source()); - pb_overlayable->set_comment(entry->overlayable.value().comment); + pb_overlayable->set_comment(overlayable.comment); } for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) { diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index 3c4d41ae5d1a..95dbbeb58a5d 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -93,7 +93,7 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) { util::make_unique<Reference>(expected_ref), context->GetDiagnostics())); // Make an overlayable resource. - ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"), + ASSERT_TRUE(table->AddOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"), Overlayable{}, test::GetDiagnostics())); pb::ResourceTable pb_table; @@ -106,7 +106,7 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) { ResourceTable new_table; std::string error; - ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)); + ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error; EXPECT_THAT(error, IsEmpty()); Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo"); @@ -160,7 +160,8 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) { new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable")); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); - EXPECT_TRUE(search_result.value().entry->overlayable); + EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy); } TEST(ProtoSerializeTest, SerializeAndDeserializeXml) { @@ -464,4 +465,59 @@ TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) { "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23"); } +TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .AddOverlayable("com.app.a:bool/foo", Overlayable::Policy::kSystem) + .AddOverlayable("com.app.a:bool/foo", Overlayable::Policy::kProduct) + .AddOverlayable("com.app.a:bool/bar", Overlayable::Policy::kProductServices) + .AddOverlayable("com.app.a:bool/bar", Overlayable::Policy::kVendor) + .AddOverlayable("com.app.a:bool/baz", Overlayable::Policy::kPublic) + .AddOverlayable("com.app.a:bool/biz", {}) + .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true")) + .Build(); + + pb::ResourceTable pb_table; + SerializeTableToPb(*table, &pb_table, context->GetDiagnostics()); + + MockFileCollection files; + ResourceTable new_table; + std::string error; + ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)); + EXPECT_THAT(error, IsEmpty()); + + Maybe<ResourceTable::SearchResult> result = + new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo")); + ASSERT_TRUE(result); + ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2)); + EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kSystem)); + EXPECT_THAT(result.value().entry->overlayable_declarations[1].policy, + Eq(Overlayable::Policy::kProduct)); + + result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar")); + ASSERT_TRUE(result); + ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2)); + EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kProductServices)); + EXPECT_THAT(result.value().entry->overlayable_declarations[1].policy, + Eq(Overlayable::Policy::kVendor)); + + result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz")); + ASSERT_TRUE(result); + ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kPublic)); + + result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz")); + ASSERT_TRUE(result); + ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1)); + EXPECT_FALSE(result.value().entry->overlayable_declarations[0].policy); + + result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz")); + ASSERT_TRUE(result); + EXPECT_THAT(result.value().entry->overlayable_declarations.size(), Eq(0)); +} + } // namespace aapt diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index afb8ae097449..d777e22fa4b7 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -101,7 +101,7 @@ static bool MergeType(IAaptContext* context, const Source& src, ResourceTableTyp return true; } -static bool MergeEntry(IAaptContext* context, const Source& src, bool overlay, +static bool MergeEntry(IAaptContext* context, const Source& src, ResourceEntry* dst_entry, ResourceEntry* src_entry, bool strict_visibility) { if (strict_visibility @@ -134,17 +134,35 @@ static bool MergeEntry(IAaptContext* context, const Source& src, bool overlay, dst_entry->allow_new = std::move(src_entry->allow_new); } - if (src_entry->overlayable) { - if (dst_entry->overlayable && !overlay) { - context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable.value().source) - << "duplicate overlayable declaration for resource '" - << src_entry->name << "'"); - context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable.value().source) - << "previous declaration here"); - return false; + for (auto& src_overlayable : src_entry->overlayable_declarations) { + for (auto& dst_overlayable : dst_entry->overlayable_declarations) { + // An overlayable resource cannot be declared twice with the same policy + if (src_overlayable.policy == dst_overlayable.policy) { + context->GetDiagnostics()->Error(DiagMessage(src_overlayable.source) + << "duplicate overlayable declaration for resource '" + << src_entry->name << "'"); + context->GetDiagnostics()->Error(DiagMessage(dst_overlayable.source) + << "previous declaration here"); + return false; + } + + // An overlayable resource cannot be declared once with a policy and without a policy because + // the policy becomes unused + if (!src_overlayable.policy || !dst_overlayable.policy) { + context->GetDiagnostics()->Error(DiagMessage(src_overlayable.source) + << "overlayable resource '" << src_entry->name + << "' declared once with a policy and once with no " + << "policy"); + context->GetDiagnostics()->Error(DiagMessage(dst_overlayable.source) + << "previous declaration here"); + return false; + } } - dst_entry->overlayable = std::move(src_entry->overlayable); } + + dst_entry->overlayable_declarations.insert(dst_entry->overlayable_declarations.end(), + src_entry->overlayable_declarations.begin(), + src_entry->overlayable_declarations.end()); return true; } @@ -244,7 +262,7 @@ bool TableMerger::DoMerge(const Source& src, ResourceTable* src_table, continue; } - if (!MergeEntry(context_, src, overlay, dst_entry, src_entry.get(), options_.strict_visibility)) { + if (!MergeEntry(context_, src, dst_entry, src_entry.get(), options_.strict_visibility)) { error = true; continue; } diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp index 79a734bffabd..d6579d37b452 100644 --- a/tools/aapt2/link/TableMerger_test.cpp +++ b/tools/aapt2/link/TableMerger_test.cpp @@ -436,4 +436,97 @@ TEST_F(TableMergerTest, OverlaidStyleablesAndStylesShouldBeMerged) { Eq(make_value(Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent"))))); } +TEST_F(TableMergerTest, AddOverlayable) { + std::unique_ptr<ResourceTable> table_a = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .AddOverlayable("bool/foo", Overlayable::Policy::kProduct) + .Build(); + + std::unique_ptr<ResourceTable> table_b = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .AddOverlayable("bool/foo", Overlayable::Policy::kProductServices) + .Build(); + + ResourceTable final_table; + TableMergerOptions options; + options.auto_add_overlay = true; + TableMerger merger(context_.get(), &final_table, options); + ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); + ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/)); + + const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo"); + Maybe<ResourceTable::SearchResult> result = final_table.FindResource(name); + ASSERT_TRUE(result); + ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2)); + ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy, + Eq(Overlayable::Policy::kProduct)); + ASSERT_THAT(result.value().entry->overlayable_declarations[1].policy, + Eq(Overlayable::Policy::kProductServices)); +} + +TEST_F(TableMergerTest, AddDuplicateOverlayableFail) { + std::unique_ptr<ResourceTable> table_a = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .AddOverlayable("bool/foo", Overlayable::Policy::kProduct) + .Build(); + + std::unique_ptr<ResourceTable> table_b = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .AddOverlayable("bool/foo", Overlayable::Policy::kProduct) + .Build(); + + ResourceTable final_table; + TableMergerOptions options; + options.auto_add_overlay = true; + TableMerger merger(context_.get(), &final_table, options); + ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); + ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); +} + +TEST_F(TableMergerTest, AddOverlayablePolicyAndNoneFirstFail) { + std::unique_ptr<ResourceTable> table_a = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .AddOverlayable("bool/foo", {}) + .Build(); + + std::unique_ptr<ResourceTable> table_b = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .AddOverlayable("bool/foo", Overlayable::Policy::kProduct) + .Build(); + + ResourceTable final_table; + TableMergerOptions options; + options.auto_add_overlay = true; + TableMerger merger(context_.get(), &final_table, options); + ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); + ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); +} + +TEST_F(TableMergerTest, AddOverlayablePolicyAndNoneLastFail) { + std::unique_ptr<ResourceTable> table_a = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .AddOverlayable("bool/foo", Overlayable::Policy::kProduct) + .Build(); + + std::unique_ptr<ResourceTable> table_b = + test::ResourceTableBuilder() + .SetPackageId("com.app.a", 0x7f) + .AddOverlayable("bool/foo", {}) + .Build(); + + ResourceTable final_table; + TableMergerOptions options; + options.auto_add_overlay = true; + TableMerger merger(context_.get(), &final_table, options); + ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/)); + ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/)); +} + } // namespace aapt diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp index f33ae3155192..03b59e033402 100644 --- a/tools/aapt2/test/Builders.cpp +++ b/tools/aapt2/test/Builders.cpp @@ -135,6 +135,15 @@ ResourceTableBuilder& ResourceTableBuilder::SetSymbolState(const StringPiece& na return *this; } +ResourceTableBuilder& ResourceTableBuilder::AddOverlayable(const StringPiece& name, + const Maybe<Overlayable::Policy> p) { + ResourceName res_name = ParseNameOrDie(name); + Overlayable overlayable; + overlayable.policy = p; + CHECK(table_->AddOverlayable(res_name, overlayable, GetDiagnostics())); + return *this; +} + StringPool* ResourceTableBuilder::string_pool() { return &table_->string_pool; } diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h index 915959972bed..d68c24ddc665 100644 --- a/tools/aapt2/test/Builders.h +++ b/tools/aapt2/test/Builders.h @@ -73,6 +73,8 @@ class ResourceTableBuilder { const ResourceId& id, std::unique_ptr<Value> value); ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id, Visibility::Level level, bool allow_new = false); + ResourceTableBuilder& AddOverlayable(const android::StringPiece& name, + Maybe<Overlayable::Policy> policy); StringPool* string_pool(); std::unique_ptr<ResourceTable> Build(); diff --git a/services/tests/wmtests/src/com/android/server/am/DummyAmTests.java b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl index 023e4ab6636f..f472a021b031 100644 --- a/services/tests/wmtests/src/com/android/server/am/DummyAmTests.java +++ b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl @@ -14,33 +14,23 @@ * limitations under the License. */ -package com.android.server.am; +package android.net.wifi; -import android.platform.test.annotations.Presubmit; - -import org.junit.Test; - -import androidx.test.filters.FlakyTest; +import android.net.wifi.INetworkRequestUserSelectionCallback; +import android.net.wifi.WifiConfiguration; /** - * Dummy test for com.android.server.am. - * TODO(b/113800711): Remove this class once the actual tests are moved from servicestests. + * Interface for network request match callback. + * + * @hide */ -public class DummyAmTests { - - @Presubmit - @Test - public void preSubmitTest() {} +oneway interface INetworkRequestMatchCallback +{ + void onUserSelectionCallbackRegistration(in INetworkRequestUserSelectionCallback userSelectionCallback); - @FlakyTest - @Presubmit - @Test - public void flakyPreSubmitTest() {} + void onMatch(in List<WifiConfiguration> wificonfigurations); - @Test - public void postSubmitTest() {} + void onUserSelectionConnectSuccess(in WifiConfiguration wificonfiguration); - @FlakyTest - @Test - public void flakyPostSubmitTest() {} + void onUserSelectionConnectFailure(in WifiConfiguration wificonfiguration); } diff --git a/services/tests/wmtests/src/com/android/server/wm/DummyWmTests.java b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl index aecb2783badd..524cefbb295f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DummyWmTests.java +++ b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl @@ -14,33 +14,18 @@ * limitations under the License. */ -package com.android.server.wm; +package android.net.wifi; -import android.platform.test.annotations.Presubmit; - -import org.junit.Test; - -import androidx.test.filters.FlakyTest; +import android.net.wifi.WifiConfiguration; /** - * Dummy test for com.android.server.wm - * TODO(b/113800711): Remove this class once the actual tests are moved from servicestests. + * Interface for providing user selection in response to + * network request match callback. + * @hide */ -public class DummyWmTests { - - @Presubmit - @Test - public void preSubmitTest() {} - - @FlakyTest - @Presubmit - @Test - public void flakyPreSubmitTest() {} - - @Test - public void postSubmitTest() {} +oneway interface INetworkRequestUserSelectionCallback +{ + void select(in WifiConfiguration wificonfiguration); - @FlakyTest - @Test - public void flakyPostSubmitTest() {} + void reject(); } diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 12f50c8af8a9..1fd68ec1df70 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -25,6 +25,7 @@ import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.DhcpInfo; import android.net.Network; +import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.ISoftApCallback; import android.net.wifi.ITrafficStateCallback; import android.net.wifi.PasspointManagementObjectDefinition; @@ -185,5 +186,9 @@ interface IWifiManager void registerTrafficStateCallback(in IBinder binder, in ITrafficStateCallback callback, int callbackIdentifier); void unregisterTrafficStateCallback(int callbackIdentifier); + + void registerNetworkRequestMatchCallback(in IBinder binder, in INetworkRequestMatchCallback callback, int callbackIdentifier); + + void unregisterNetworkRequestMatchCallback(int callbackIdentifier); } diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index 3a4e88b49daf..9b9247dba17c 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -86,9 +86,9 @@ public class ScanResult implements Parcelable { public static final int PROTOCOL_WPA = 1; /** * @hide - * Security protocol type: WPA version 2, also called RSN. + * Security protocol type: RSN, for WPA version 2, and version 3. */ - public static final int PROTOCOL_WPA2 = 2; + public static final int PROTOCOL_RSN = 2; /** * @hide * Security protocol type: @@ -138,7 +138,21 @@ public class ScanResult implements Parcelable { * Used for Hotspot 2.0. */ public static final int KEY_MGMT_OSEN = 7; - + /** + * @hide + * Security key management scheme: SAE. + */ + public static final int KEY_MGMT_SAE = 8; + /** + * @hide + * Security key management scheme: OWE. + */ + public static final int KEY_MGMT_OWE = 9; + /** + * @hide + * Security key management scheme: SUITE_B_192. + */ + public static final int KEY_MGMT_EAP_SUITE_B_192 = 10; /** * @hide * No cipher suite. @@ -159,6 +173,11 @@ public class ScanResult implements Parcelable { * Cipher suite: CCMP */ public static final int CIPHER_CCMP = 3; + /** + * @hide + * Cipher suite: GCMP + */ + public static final int CIPHER_GCMP_256 = 4; /** * The detected signal level in dBm, also known as the RSSI. diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 74722787f441..8fc9b9759469 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -23,6 +23,7 @@ import android.content.pm.PackageManager; import android.net.IpConfiguration; import android.net.IpConfiguration.ProxySettings; import android.net.MacAddress; +import android.net.NetworkSpecifier; import android.net.ProxyInfo; import android.net.StaticIpConfiguration; import android.net.Uri; @@ -47,7 +48,11 @@ import java.util.HashMap; /** * A class representing a configured Wi-Fi network, including the * security configuration. + * + * @deprecated Use {@link WifiNetworkConfigBuilder} to create {@link NetworkSpecifier} and + * {@link WifiNetworkSuggestion}. This will become a system use only object in the future. */ +@Deprecated public class WifiConfiguration implements Parcelable { private static final String TAG = "WifiConfiguration"; /** @@ -125,10 +130,26 @@ public class WifiConfiguration implements Parcelable { */ public static final int FT_EAP = 7; + /** + * Simultaneous Authentication of Equals + */ + public static final int SAE = 8; + + /** + * Opportunististic Wireless Encryption + */ + public static final int OWE = 9; + + /** + * SUITE_B_192 192 bit level + */ + public static final int SUITE_B_192 = 10; + public static final String varName = "key_mgmt"; public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", - "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" }; + "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP", + "SAE", "OWE", "SUITE_B_192"}; } /** @@ -142,7 +163,7 @@ public class WifiConfiguration implements Parcelable { * is discouraged. WPA-2 (RSN) should be used instead. */ @Deprecated public static final int WPA = 0; - /** WPA2/IEEE 802.11i */ + /** RSN WPA2/WPA3/IEEE 802.11i */ public static final int RSN = 1; /** HS2.0 r2 OSEN * @hide @@ -190,10 +211,14 @@ public class WifiConfiguration implements Parcelable { public static final int TKIP = 1; /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */ public static final int CCMP = 2; + /** + * AES in Galois/Counter Mode + */ + public static final int GCMP_256 = 3; public static final String varName = "pairwise"; - public static final String[] strings = { "NONE", "TKIP", "CCMP" }; + public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256" }; } /** @@ -203,6 +228,7 @@ public class WifiConfiguration implements Parcelable { * TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] * WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key * WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) + * GCMP_256 = AES in Galois/Counter Mode * </pre> */ public static class GroupCipher { @@ -226,12 +252,64 @@ public class WifiConfiguration implements Parcelable { * @hide */ public static final int GTK_NOT_USED = 4; + /** + * AES in Galois/Counter Mode + */ + public static final int GCMP_256 = 5; public static final String varName = "group"; public static final String[] strings = { /* deprecated */ "WEP40", /* deprecated */ "WEP104", - "TKIP", "CCMP", "GTK_NOT_USED" }; + "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256" }; + } + + /** + * Recognized group management ciphers. + * <pre> + * BIP_CMAC_256 = Cipher-based Message Authentication Code 256 bits + * BIP_GMAC_128 = Galois Message Authentication Code 128 bits + * BIP_GMAC_256 = Galois Message Authentication Code 256 bits + * </pre> + */ + public static class GroupMgmtCipher { + private GroupMgmtCipher() { } + + /** CMAC-256 = Cipher-based Message Authentication Code */ + public static final int BIP_CMAC_256 = 0; + + /** GMAC-128 = Galois Message Authentication Code */ + public static final int BIP_GMAC_128 = 1; + + /** GMAC-256 = Galois Message Authentication Code */ + public static final int BIP_GMAC_256 = 2; + + private static final String varName = "groupMgmt"; + + private static final String[] strings = { "BIP_CMAC_256", + "BIP_GMAC_128", "BIP_GMAC_256"}; + } + + /** + * Recognized suiteB ciphers. + * <pre> + * ECDHE_ECDSA + * ECDHE_RSA + * </pre> + * @hide + */ + public static class SuiteBCipher { + private SuiteBCipher() { } + + /** Diffie-Hellman with Elliptic Curve_ECDSA signature */ + public static final int ECDHE_ECDSA = 0; + + /** Diffie-Hellman with_RSA signature */ + public static final int ECDHE_RSA = 1; + + private static final String varName = "SuiteB"; + + private static final String[] strings = { "ECDHE_ECDSA", "ECDHE_RSA" }; } /** Possible status of a network configuration. */ @@ -409,6 +487,17 @@ public class WifiConfiguration implements Parcelable { */ public BitSet allowedGroupCiphers; /** + * The set of group management ciphers supported by this configuration. + * See {@link GroupMgmtCipher} for descriptions of the values. + */ + public BitSet allowedGroupMgmtCiphers; + /** + * The set of SuiteB ciphers supported by this configuration. + * To be used for WPA3-Enterprise mode. + * See {@link SuiteBCipher} for descriptions of the values. + */ + public BitSet allowedSuiteBCiphers; + /** * The enterprise configuration details specifying the EAP method, * certificates and other settings associated with the EAP. */ @@ -733,7 +822,8 @@ public class WifiConfiguration implements Parcelable { public boolean isOpenNetwork() { final int cardinality = allowedKeyManagement.cardinality(); final boolean hasNoKeyMgmt = cardinality == 0 - || (cardinality == 1 && allowedKeyManagement.get(KeyMgmt.NONE)); + || (cardinality == 1 && (allowedKeyManagement.get(KeyMgmt.NONE) + || allowedKeyManagement.get(KeyMgmt.OWE))); boolean hasNoWepKeys = true; if (wepKeys != null) { @@ -785,6 +875,23 @@ public class WifiConfiguration implements Parcelable { /** * @hide + * Use factory MAC when connecting to this network + */ + public static final int RANDOMIZATION_NONE = 0; + /** + * @hide + * Generate a randomized MAC once and reuse it for all connections to this network + */ + public static final int RANDOMIZATION_PERSISTENT = 1; + + /** + * @hide + * Level of MAC randomization for this network + */ + public int macRandomizationSetting = RANDOMIZATION_PERSISTENT; + + /** + * @hide * Randomized MAC address to use with this particular network */ @NonNull @@ -1521,6 +1628,8 @@ public class WifiConfiguration implements Parcelable { allowedAuthAlgorithms = new BitSet(); allowedPairwiseCiphers = new BitSet(); allowedGroupCiphers = new BitSet(); + allowedGroupMgmtCiphers = new BitSet(); + allowedSuiteBCiphers = new BitSet(); wepKeys = new String[4]; for (int i = 0; i < wepKeys.length; i++) { wepKeys[i] = null; @@ -1574,7 +1683,8 @@ public class WifiConfiguration implements Parcelable { @UnsupportedAppUsage public boolean isEnterprise() { return (allowedKeyManagement.get(KeyMgmt.WPA_EAP) - || allowedKeyManagement.get(KeyMgmt.IEEE8021X)) + || allowedKeyManagement.get(KeyMgmt.IEEE8021X) + || allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) && enterpriseConfig != null && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE; } @@ -1592,6 +1702,7 @@ public class WifiConfiguration implements Parcelable { append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN) .append(" PRIO: ").append(this.priority) .append(" HIDDEN: ").append(this.hiddenSSID) + .append(" PMF: ").append(this.requirePMF) .append('\n'); @@ -1645,6 +1756,7 @@ public class WifiConfiguration implements Parcelable { if (this.meteredOverride != METERED_OVERRIDE_NONE) { sbuf.append(" meteredOverride ").append(meteredOverride).append("\n"); } + sbuf.append(" macRandomizationSetting ").append(macRandomizationSetting).append("\n"); sbuf.append(" KeyMgmt:"); for (int k = 0; k < this.allowedKeyManagement.size(); k++) { if (this.allowedKeyManagement.get(k)) { @@ -1703,10 +1815,35 @@ public class WifiConfiguration implements Parcelable { } } } - sbuf.append('\n').append(" PSK: "); + sbuf.append('\n'); + sbuf.append(" GroupMgmtCiphers:"); + for (int gmc = 0; gmc < this.allowedGroupMgmtCiphers.size(); gmc++) { + if (this.allowedGroupMgmtCiphers.get(gmc)) { + sbuf.append(" "); + if (gmc < GroupMgmtCipher.strings.length) { + sbuf.append(GroupMgmtCipher.strings[gmc]); + } else { + sbuf.append("??"); + } + } + } + sbuf.append('\n'); + sbuf.append(" SuiteBCiphers:"); + for (int sbc = 0; sbc < this.allowedSuiteBCiphers.size(); sbc++) { + if (this.allowedSuiteBCiphers.get(sbc)) { + sbuf.append(" "); + if (sbc < SuiteBCipher.strings.length) { + sbuf.append(SuiteBCipher.strings[sbc]); + } else { + sbuf.append("??"); + } + } + } + sbuf.append('\n').append(" PSK/SAE: "); if (this.preSharedKey != null) { sbuf.append('*'); } + sbuf.append("\nEnterprise config:\n"); sbuf.append(enterpriseConfig); @@ -1869,6 +2006,12 @@ public class WifiConfiguration implements Parcelable { return KeyMgmt.WPA_EAP; } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { return KeyMgmt.IEEE8021X; + } else if (allowedKeyManagement.get(KeyMgmt.SAE)) { + return KeyMgmt.SAE; + } else if (allowedKeyManagement.get(KeyMgmt.OWE)) { + return KeyMgmt.OWE; + } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) { + return KeyMgmt.SUITE_B_192; } return KeyMgmt.NONE; } @@ -1900,6 +2043,12 @@ public class WifiConfiguration implements Parcelable { key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP]; } else if (wepKeys[0] != null) { key = SSID + "WEP"; + } else if (allowedKeyManagement.get(KeyMgmt.OWE)) { + key = SSID + KeyMgmt.strings[KeyMgmt.OWE]; + } else if (allowedKeyManagement.get(KeyMgmt.SAE)) { + key = SSID + KeyMgmt.strings[KeyMgmt.SAE]; + } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) { + key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192]; } else { key = SSID + KeyMgmt.strings[KeyMgmt.NONE]; } @@ -2068,6 +2217,8 @@ public class WifiConfiguration implements Parcelable { allowedAuthAlgorithms = (BitSet) source.allowedAuthAlgorithms.clone(); allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone(); allowedGroupCiphers = (BitSet) source.allowedGroupCiphers.clone(); + allowedGroupMgmtCiphers = (BitSet) source.allowedGroupMgmtCiphers.clone(); + allowedSuiteBCiphers = (BitSet) source.allowedSuiteBCiphers.clone(); enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig); defaultGwMacAddress = source.defaultGwMacAddress; @@ -2109,6 +2260,8 @@ public class WifiConfiguration implements Parcelable { shared = source.shared; recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus()); mRandomizedMacAddress = source.mRandomizedMacAddress; + macRandomizationSetting = source.macRandomizationSetting; + requirePMF = source.requirePMF; } } @@ -2144,6 +2297,8 @@ public class WifiConfiguration implements Parcelable { writeBitSet(dest, allowedAuthAlgorithms); writeBitSet(dest, allowedPairwiseCiphers); writeBitSet(dest, allowedGroupCiphers); + writeBitSet(dest, allowedGroupMgmtCiphers); + writeBitSet(dest, allowedSuiteBCiphers); dest.writeParcelable(enterpriseConfig, flags); @@ -2173,6 +2328,7 @@ public class WifiConfiguration implements Parcelable { dest.writeString(mPasspointManagementObjectTree); dest.writeInt(recentFailure.getAssociationStatus()); dest.writeParcelable(mRandomizedMacAddress, flags); + dest.writeInt(macRandomizationSetting); } /** Implement the Parcelable interface {@hide} */ @@ -2211,6 +2367,8 @@ public class WifiConfiguration implements Parcelable { config.allowedAuthAlgorithms = readBitSet(in); config.allowedPairwiseCiphers = readBitSet(in); config.allowedGroupCiphers = readBitSet(in); + config.allowedGroupMgmtCiphers = readBitSet(in); + config.allowedSuiteBCiphers = readBitSet(in); config.enterpriseConfig = in.readParcelable(null); config.setIpConfiguration(in.readParcelable(null)); @@ -2239,6 +2397,7 @@ public class WifiConfiguration implements Parcelable { config.mPasspointManagementObjectTree = in.readString(); config.recentFailure.setAssociationStatus(in.readInt()); config.mRandomizedMacAddress = in.readParcelable(null); + config.macRandomizationSetting = in.readInt(); return config; } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 9adbe67c1553..954b51f02820 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -25,19 +25,17 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; +import android.app.PendingIntent; import android.content.Context; import android.content.pm.ParceledListSlice; import android.net.ConnectivityManager; import android.net.DhcpInfo; import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.ProvisioningCallback; import android.os.Binder; -import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -52,7 +50,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; -import com.android.server.net.NetworkPinner; import dalvik.system.CloseGuard; @@ -1035,7 +1032,17 @@ public class WifiManager { * </ul> * @return a list of network configurations in the form of a list * of {@link WifiConfiguration} objects. + * + * @deprecated + * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new + * mechanism to trigger connection to a Wi-Fi network. + * b) See {@link #addNetworkSuggestions(List, PendingIntent)}, + * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration + * when auto-connecting to wifi. + * <b>Compatibility Note:</b> For applications targeting + * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return an empty list. */ + @Deprecated public List<WifiConfiguration> getConfiguredNetworks() { try { ParceledListSlice<WifiConfiguration> parceledList = @@ -1135,7 +1142,17 @@ public class WifiManager { * @return the ID of the newly created network description. This is used in * other operations to specified the network to be acted upon. * Returns {@code -1} on failure. + * + * @deprecated + * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new + * mechanism to trigger connection to a Wi-Fi network. + * b) See {@link #addNetworkSuggestions(List, PendingIntent)}, + * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration + * when auto-connecting to wifi. + * <b>Compatibility Note:</b> For applications targeting + * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}. */ + @Deprecated public int addNetwork(WifiConfiguration config) { if (config == null) { return -1; @@ -1160,7 +1177,17 @@ public class WifiManager { * Returns {@code -1} on failure, including when the {@code networkId} * field of the {@code WifiConfiguration} does not refer to an * existing network. + * + * @deprecated + * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new + * mechanism to trigger connection to a Wi-Fi network. + * b) See {@link #addNetworkSuggestions(List, PendingIntent)}, + * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration + * when auto-connecting to wifi. + * <b>Compatibility Note:</b> For applications targeting + * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}. */ + @Deprecated public int updateNetwork(WifiConfiguration config) { if (config == null || config.networkId < 0) { return -1; @@ -1185,6 +1212,301 @@ public class WifiManager { } /** + * Interface for indicating user selection from the list of networks presented in the + * {@link NetworkRequestMatchCallback#onMatch(List)}. + * + * The platform will implement this callback and pass it along with the + * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration( + * NetworkRequestUserSelectionCallback)}. The UI component handling + * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or + * {@link #reject()} to return the user's selection back to the platform via this callback. + * @hide + */ + @SystemApi + public interface NetworkRequestUserSelectionCallback { + /** + * User selected this network to connect to. + * @param wifiConfiguration WifiConfiguration object corresponding to the network + * user selected. + */ + void select(@NonNull WifiConfiguration wifiConfiguration); + + /** + * User rejected the app's request. + */ + void reject(); + } + + /** + * Interface for network request callback. Should be implemented by applications and passed when + * calling {@link #registerNetworkRequestMatchCallback(NetworkRequestMatchCallback, Handler)}. + * + * This is meant to be implemented by a UI component to present the user with a list of networks + * matching the app's request. The user is allowed to pick one of these networks to connect to + * or reject the request by the app. + * @hide + */ + @SystemApi + public interface NetworkRequestMatchCallback { + /** + * Invoked to register a callback to be invoked to convey user selection. The callback + * object paased in this method is to be invoked by the UI component after the service sends + * a list of matching scan networks using {@link #onMatch(List)} and user picks a network + * from that list. + * + * @param userSelectionCallback Callback object to send back the user selection. + */ + void onUserSelectionCallbackRegistration( + @NonNull NetworkRequestUserSelectionCallback userSelectionCallback); + + /** + * Invoked when a network request initiated by an app matches some networks in scan results. + * This may be invoked multiple times for a single network request as the platform finds new + * networks in scan results. + * + * @param wifiConfigurations List of {@link WifiConfiguration} objects corresponding to the + * networks matching the request. + */ + void onMatch(@NonNull List<WifiConfiguration> wifiConfigurations); + + /** + * Invoked on a successful connection with the network that the user selected + * via {@link NetworkRequestUserSelectionCallback}. + * + * @param wifiConfiguration WifiConfiguration object corresponding to the network that the + * user selected. + */ + void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration); + + /** + * Invoked on failure to establish connection with the network that the user selected + * via {@link NetworkRequestUserSelectionCallback}. + * + * @param wifiConfiguration WifiConfiguration object corresponding to the network + * user selected. + */ + void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration); + } + + /** + * Callback proxy for NetworkRequestUserSelectionCallback objects. + * @hide + */ + private class NetworkRequestUserSelectionCallbackProxy implements + NetworkRequestUserSelectionCallback { + private final INetworkRequestUserSelectionCallback mCallback; + + NetworkRequestUserSelectionCallbackProxy( + INetworkRequestUserSelectionCallback callback) { + mCallback = callback; + } + + @Override + public void select(@NonNull WifiConfiguration wifiConfiguration) { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select " + + "wificonfiguration: " + wifiConfiguration); + } + try { + mCallback.select(wifiConfiguration); + } catch (RemoteException e) { + Log.e(TAG, "Failed to invoke onSelected", e); + throw e.rethrowFromSystemServer(); + } + } + + @Override + public void reject() { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject"); + } + try { + mCallback.reject(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to invoke onRejected", e); + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Callback proxy for NetworkRequestMatchCallback objects. + * @hide + */ + private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub { + private final Handler mHandler; + private final NetworkRequestMatchCallback mCallback; + + NetworkRequestMatchCallbackProxy(Looper looper, NetworkRequestMatchCallback callback) { + mHandler = new Handler(looper); + mCallback = callback; + } + + @Override + public void onUserSelectionCallbackRegistration( + INetworkRequestUserSelectionCallback userSelectionCallback) { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "NetworkRequestMatchCallbackProxy: " + + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback); + } + mHandler.post(() -> { + mCallback.onUserSelectionCallbackRegistration( + new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback)); + }); + } + + @Override + public void onMatch(List<WifiConfiguration> wifiConfigurations) { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch wificonfigurations: " + + wifiConfigurations); + } + mHandler.post(() -> { + mCallback.onMatch(wifiConfigurations); + }); + } + + @Override + public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess " + + " wificonfiguration: " + wifiConfiguration); + } + mHandler.post(() -> { + mCallback.onUserSelectionConnectSuccess(wifiConfiguration); + }); + } + + @Override + public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure" + + " wificonfiguration: " + wifiConfiguration); + } + mHandler.post(() -> { + mCallback.onUserSelectionConnectFailure(wifiConfiguration); + }); + } + } + + /** + * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}. + * Caller can unregister a previously registered callback using + * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)} + * <p> + * Applications should have the + * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers + * without the permission will trigger a {@link java.lang.SecurityException}. + * <p> + * + * @param callback Callback for network match events + * @param handler The Handler on whose thread to execute the callbacks of the {@code callback} + * object. If null, then the application's main thread will be used. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void registerNetworkRequestMatchCallback(@NonNull NetworkRequestMatchCallback callback, + @Nullable Handler handler) { + if (callback == null) throw new IllegalArgumentException("callback cannot be null"); + Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback + + ", handler=" + handler); + + Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); + Binder binder = new Binder(); + try { + mService.registerNetworkRequestMatchCallback( + binder, new NetworkRequestMatchCallbackProxy(looper, callback), + callback.hashCode()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}. + * <p> + * Applications should have the + * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers + * without the permission will trigger a {@link java.lang.SecurityException}. + * <p> + * + * @param callback Callback for network match events + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void unregisterNetworkRequestMatchCallback( + @NonNull NetworkRequestMatchCallback callback) { + if (callback == null) throw new IllegalArgumentException("callback cannot be null"); + Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback); + + try { + mService.unregisterNetworkRequestMatchCallback(callback.hashCode()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion} + * for a detailed explanation of the parameters. + *<p> + * When the device decides to connect to one of the provided network suggestions, platform fires + * the associated {@code pendingIntent} if + * the network was created with {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} + * flag set and the provided {@code pendingIntent} is non-null. + *<p> + * Registration of a non-null pending intent {@code pendingIntent} requires + * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission. + *<p> + * NOTE: + * <li> These networks are just a suggestion to the platform. The platform will ultimately + * decide on which network the device connects to. </li> + * <li> When an app is uninstalled, all its suggested networks are discarded. If the device is + * currently connected to a suggested network which is being removed then the device will + * disconnect from that network.</li> + * <li> No in-place modification of existing suggestions are allowed. Apps are expected to + * remove suggestions using {@link #removeNetworkSuggestions(List)} and then add the modified + * suggestion back using this API.</li> + * + * @param networkSuggestions List of network suggestions provided by the app. + * @param pendingIntent Pending intent to be fired post connection for networks. These will be + * fired only when connecting to a network that was created with + * {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} flag set. + * Pending intent must hold a foreground service, else will be rejected. + * @return true on success, false if any of the suggestions match (See + * {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app. + * @throws {@link SecurityException} if the caller is missing required permissions. + */ + public boolean addNetworkSuggestions( + @NonNull List<WifiNetworkSuggestion> networkSuggestions, + @Nullable PendingIntent pendingIntent) { + // TODO(b/115504887): Implementation + return false; + } + + + /** + * Remove a subset of or all of networks from previously provided suggestions by the app to the + * device. + * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters. + * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used. + * + * @param networkSuggestions List of network suggestions to be removed. Pass an empty list + * to remove all the previous suggestions provided by the app. + * @return true on success, false if any of the suggestions do not match any suggestions + * previously provided by the app. Any matching suggestions are removed from the device and + * will not be considered for any further connection attempts. + */ + public boolean removeNetworkSuggestions( + @NonNull List<WifiNetworkSuggestion> networkSuggestions) { + // TODO(b/115504887): Implementation + return false; + } + + /** * Add or update a Passpoint configuration. The configuration provides a credential * for connecting to Passpoint networks that are operated by the Passpoint * service provider specified in the configuration. @@ -1299,7 +1621,17 @@ public class WifiManager { * @param netId the ID of the network as returned by {@link #addNetwork} or {@link * #getConfiguredNetworks}. * @return {@code true} if the operation succeeded + * + * @deprecated + * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new + * mechanism to trigger connection to a Wi-Fi network. + * b) See {@link #addNetworkSuggestions(List, PendingIntent)}, + * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration + * when auto-connecting to wifi. + * <b>Compatibility Note:</b> For applications targeting + * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false. */ + @Deprecated public boolean removeNetwork(int netId) { try { return mService.removeNetwork(netId, mContext.getOpPackageName()); @@ -1314,10 +1646,8 @@ public class WifiManager { * network is initiated. This may result in the asynchronous delivery * of state change events. * <p> - * <b>Note:</b> If an application's target SDK version is - * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network - * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may - * instead be sent through another network, such as cellular data, + * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected; + * traffic may instead be sent through another network, such as cellular data, * Bluetooth tethering, or Ethernet. For example, traffic will never use a * Wi-Fi network that does not provide Internet access (e.g. a wireless * printer), if another network that does offer Internet access (e.g. @@ -1335,29 +1665,24 @@ public class WifiManager { * @param attemptConnect The way to select a particular network to connect to is specify * {@code true} for this parameter. * @return {@code true} if the operation succeeded + * + * @deprecated + * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new + * mechanism to trigger connection to a Wi-Fi network. + * b) See {@link #addNetworkSuggestions(List, PendingIntent)}, + * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration + * when auto-connecting to wifi. + * <b>Compatibility Note:</b> For applications targeting + * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false. */ + @Deprecated public boolean enableNetwork(int netId, boolean attemptConnect) { - final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP; - if (pin) { - NetworkRequest request = new NetworkRequest.Builder() - .clearCapabilities() - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build(); - NetworkPinner.pin(mContext, request); - } - boolean success; try { success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - - if (pin && !success) { - NetworkPinner.unpin(); - } - return success; } @@ -1372,7 +1697,17 @@ public class WifiManager { * @param netId the ID of the network as returned by {@link #addNetwork} or {@link * #getConfiguredNetworks}. * @return {@code true} if the operation succeeded + * + * @deprecated + * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new + * mechanism to trigger connection to a Wi-Fi network. + * b) See {@link #addNetworkSuggestions(List, PendingIntent)}, + * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration + * when auto-connecting to wifi. + * <b>Compatibility Note:</b> For applications targeting + * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false. */ + @Deprecated public boolean disableNetwork(int netId) { try { return mService.disableNetwork(netId, mContext.getOpPackageName()); @@ -1385,7 +1720,17 @@ public class WifiManager { * Disassociate from the currently active access point. This may result * in the asynchronous delivery of state change events. * @return {@code true} if the operation succeeded + * + * @deprecated + * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new + * mechanism to trigger connection to a Wi-Fi network. + * b) See {@link #addNetworkSuggestions(List, PendingIntent)}, + * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration + * when auto-connecting to wifi. + * <b>Compatibility Note:</b> For applications targeting + * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false. */ + @Deprecated public boolean disconnect() { try { mService.disconnect(mContext.getOpPackageName()); @@ -1400,7 +1745,17 @@ public class WifiManager { * disconnected. This may result in the asynchronous delivery of state * change events. * @return {@code true} if the operation succeeded + * + * @deprecated + * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new + * mechanism to trigger connection to a Wi-Fi network. + * b) See {@link #addNetworkSuggestions(List, PendingIntent)}, + * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration + * when auto-connecting to wifi. + * <b>Compatibility Note:</b> For applications targeting + * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false. */ + @Deprecated public boolean reconnect() { try { mService.reconnect(mContext.getOpPackageName()); @@ -1415,7 +1770,17 @@ public class WifiManager { * connected. This may result in the asynchronous delivery of state * change events. * @return {@code true} if the operation succeeded + * + * @deprecated + * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new + * mechanism to trigger connection to a Wi-Fi network. + * b) See {@link #addNetworkSuggestions(List, PendingIntent)}, + * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration + * when auto-connecting to wifi. + * <b>Compatibility Note:</b> For applications targeting + * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false. */ + @Deprecated public boolean reassociate() { try { mService.reassociate(mContext.getOpPackageName()); @@ -1490,7 +1855,12 @@ public class WifiManager { public static final int WIFI_FEATURE_SCAN_RAND = 0x2000000; // Random MAC & Probe seq /** @hide */ public static final int WIFI_FEATURE_TX_POWER_LIMIT = 0x4000000; // Set Tx power limit - + /** @hide */ + public static final int WIFI_FEATURE_WPA3_SAE = 0x8000000; // WPA3-Personal SAE + /** @hide */ + public static final int WIFI_FEATURE_WPA3_SUITE_B = 0x10000000; // WPA3-Enterprise Suite-B + /** @hide */ + public static final int WIFI_FEATURE_OWE = 0x20000000; // Enhanced Open private int getSupportedFeatures() { try { @@ -1715,7 +2085,10 @@ public class WifiManager { * even when Wi-Fi is turned off. * * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}. + * @deprecated The ability for apps to trigger scan requests will be removed in a future + * release. */ + @Deprecated public boolean isScanAlwaysAvailable() { try { return mService.isScanAlwaysAvailable(); @@ -1821,7 +2194,12 @@ public class WifiManager { * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is * either already in the requested state, or in progress toward the requested state. * @throws {@link java.lang.SecurityException} if the caller is missing required permissions. + * + * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to + * enable/disable Wi-Fi regardless of application's target SDK. This API will have no effect + * and will always return false. */ + @Deprecated public boolean setWifiEnabled(boolean enabled) { try { return mService.setWifiEnabled(mContext.getOpPackageName(), enabled); @@ -3875,4 +4253,31 @@ public class WifiManager { private void updateVerboseLoggingEnabledFromService() { mVerboseLoggingEnabled = getVerboseLoggingLevel() > 0; } + + /** + * @return true if this device supports WPA3-Personal SAE + * @hide + */ + @SystemApi + public boolean isWpa3SaeSupported() { + return isFeatureSupported(WIFI_FEATURE_WPA3_SAE); + } + + /** + * @return true if this device supports WPA3-Enterprise Suite-B-192 + * @hide + */ + @SystemApi + public boolean isWpa3SuiteBSupported() { + return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B); + } + + /** + * @return true if this device supports Wi-Fi Enhanced Open (OWE) + * @hide + */ + @SystemApi + public boolean isOweSupported() { + return isFeatureSupported(WIFI_FEATURE_OWE); + } } diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java new file mode 100644 index 000000000000..55fde4ca335e --- /dev/null +++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.internal.util.Preconditions.checkState; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.MacAddress; +import android.net.MatchAllNetworkSpecifier; +import android.net.NetworkAgent; +import android.net.NetworkRequest; +import android.net.NetworkSpecifier; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Network specifier object used by wifi's {@link android.net.NetworkAgent}. + * @hide + */ +public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements Parcelable { + /** + * Security credentials for the currently connected network. + */ + private final WifiConfiguration mWifiConfiguration; + + /** + * The UID of the app that requested a specific wifi network using {@link WifiNetworkSpecifier}. + * + * Will only be filled when the device connects to a wifi network as a result of a + * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to -1 if the device + * auto-connected to a wifi network. + */ + private final int mOriginalRequestorUid; + + public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration, + int originalRequestorUid) { + checkNotNull(wifiConfiguration); + + mWifiConfiguration = wifiConfiguration; + mOriginalRequestorUid = originalRequestorUid; + } + + /** + * @hide + */ + public static final Creator<WifiNetworkAgentSpecifier> CREATOR = + new Creator<WifiNetworkAgentSpecifier>() { + @Override + public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) { + WifiConfiguration wifiConfiguration = in.readParcelable(null); + int originalRequestorUid = in.readInt(); + return new WifiNetworkAgentSpecifier(wifiConfiguration, originalRequestorUid); + } + + @Override + public WifiNetworkAgentSpecifier[] newArray(int size) { + return new WifiNetworkAgentSpecifier[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeParcelable(mWifiConfiguration, flags); + dest.writeInt(mOriginalRequestorUid); + } + + @Override + public boolean satisfiedBy(@Nullable NetworkSpecifier other) { + if (this == other) { + return true; + } + // Any generic requests should be satisifed by a specific wifi network. + if (other == null || other instanceof MatchAllNetworkSpecifier) { + return true; + } + if (other instanceof WifiNetworkSpecifier) { + return satisfiesNetworkSpecifier((WifiNetworkSpecifier) other); + } + if (other instanceof WifiNetworkAgentSpecifier) { + throw new IllegalStateException("WifiNetworkAgentSpecifier instances should never be " + + "compared"); + } + return false; + } + + /** + * Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the + * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link NetworkAgent}. + */ + public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) { + // None of these should be null by construction. + // {@link WifiNetworkConfigBuilder} enforces non-null in {@link WifiNetworkSpecifier}. + // {@link WifiNetworkFactory} ensures non-null in {@link WifiNetworkAgentSpecifier}. + checkNotNull(ns); + checkNotNull(ns.ssidPatternMatcher); + checkNotNull(ns.bssidPatternMatcher); + checkNotNull(ns.wifiConfiguration.allowedKeyManagement); + checkNotNull(this.mWifiConfiguration.SSID); + checkNotNull(this.mWifiConfiguration.BSSID); + checkNotNull(this.mWifiConfiguration.allowedKeyManagement); + + final String ssidWithQuotes = this.mWifiConfiguration.SSID; + checkState(ssidWithQuotes.startsWith("\"") && ssidWithQuotes.endsWith("\"")); + final String ssidWithoutQuotes = ssidWithQuotes.substring(1, ssidWithQuotes.length() - 1); + if (!ns.ssidPatternMatcher.match(ssidWithoutQuotes)) { + return false; + } + final MacAddress bssid = MacAddress.fromString(this.mWifiConfiguration.BSSID); + final MacAddress matchBaseAddress = ns.bssidPatternMatcher.first; + final MacAddress matchMask = ns.bssidPatternMatcher.second; + if (!bssid.matches(matchBaseAddress, matchMask)) { + return false; + } + if (!ns.wifiConfiguration.allowedKeyManagement.equals( + this.mWifiConfiguration.allowedKeyManagement)) { + return false; + } + if (ns.requestorUid != this.mOriginalRequestorUid) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash( + mWifiConfiguration.SSID, + mWifiConfiguration.BSSID, + mWifiConfiguration.allowedKeyManagement, + mOriginalRequestorUid); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof WifiNetworkAgentSpecifier)) { + return false; + } + WifiNetworkAgentSpecifier lhs = (WifiNetworkAgentSpecifier) obj; + return Objects.equals(this.mWifiConfiguration.SSID, lhs.mWifiConfiguration.SSID) + && Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID) + && Objects.equals(this.mWifiConfiguration.allowedKeyManagement, + lhs.mWifiConfiguration.allowedKeyManagement) + && mOriginalRequestorUid == lhs.mOriginalRequestorUid; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("WifiNetworkAgentSpecifier ["); + sb.append(", WifiConfiguration=").append( + mWifiConfiguration == null ? null : mWifiConfiguration.configKey()) + .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid) + .append("]"); + return sb.toString(); + } + + @Override + public void assertValidFromUid(int requestorUid) { + throw new IllegalStateException("WifiNetworkAgentSpecifier should never be used " + + "for requests."); + } +} diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java new file mode 100644 index 000000000000..67e218972994 --- /dev/null +++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java @@ -0,0 +1,511 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.PendingIntent; +import android.net.MacAddress; +import android.net.NetworkRequest; +import android.net.NetworkSpecifier; +import android.os.PatternMatcher; +import android.os.Process; +import android.text.TextUtils; +import android.util.Pair; + +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * WifiNetworkConfigBuilder to use for creating Wi-Fi network configuration. + * <li>See {@link #buildNetworkSpecifier()} for creating a network specifier to use in + * {@link NetworkRequest}.</li> + * <li>See {@link #buildNetworkSuggestion()} for creating a network suggestion to use in + * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.</li> + */ +public class WifiNetworkConfigBuilder { + private static final String MATCH_ALL_SSID_PATTERN_PATH = ".*"; + private static final String MATCH_EMPTY_SSID_PATTERN_PATH = ""; + private static final Pair<MacAddress, MacAddress> MATCH_NO_BSSID_PATTERN = + new Pair(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS); + private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN = + new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); + private static final MacAddress MATCH_EXACT_BSSID_PATTERN_MASK = + MacAddress.BROADCAST_ADDRESS; + private static final int UNASSIGNED_PRIORITY = -1; + + /** + * SSID pattern match specified by the app. + */ + private @Nullable PatternMatcher mSsidPatternMatcher; + /** + * BSSID pattern match specified by the app. + * Pair of <BaseAddress, Mask>. + */ + private @Nullable Pair<MacAddress, MacAddress> mBssidPatternMatcher; + /** + * Pre-shared key for use with WPA-PSK networks. + */ + private @Nullable String mPskPassphrase; + /** + * The enterprise configuration details specifying the EAP method, + * certificates and other settings associated with the EAP. + */ + private @Nullable WifiEnterpriseConfig mEnterpriseConfig; + /** + * This is a network that does not broadcast its SSID, so an + * SSID-specific probe request must be used for scans. + */ + private boolean mIsHiddenSSID; + /** + * Whether app needs to log in to captive portal to obtain Internet access. + */ + private boolean mIsAppInteractionRequired; + /** + * Whether user needs to log in to captive portal to obtain Internet access. + */ + private boolean mIsUserInteractionRequired; + /** + * Whether this network is metered or not. + */ + private boolean mIsMetered; + /** + * Priority of this network among other network suggestions provided by the app. + * The lower the number, the higher the priority (i.e value of 0 = highest priority). + */ + private int mPriority; + + public WifiNetworkConfigBuilder() { + mSsidPatternMatcher = null; + mBssidPatternMatcher = null; + mPskPassphrase = null; + mEnterpriseConfig = null; + mIsHiddenSSID = false; + mIsAppInteractionRequired = false; + mIsUserInteractionRequired = false; + mIsMetered = false; + mPriority = UNASSIGNED_PRIORITY; + } + + /** + * Set the unicode SSID match pattern to use for filtering networks from scan results. + * <p> + * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li> + * <li>Overrides any previous value set using {@link #setSsid(String)} or + * {@link #setSsidPattern(PatternMatcher)}.</li> + * + * @param ssidPattern Instance of {@link PatternMatcher} containing the UTF-8 encoded + * string pattern to use for matching the network's SSID. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setSsidPattern(@NonNull PatternMatcher ssidPattern) { + checkNotNull(ssidPattern); + mSsidPatternMatcher = ssidPattern; + return this; + } + + /** + * Set the unicode SSID for the network. + * <p> + * <li>For network requests ({@link NetworkSpecifier}), built using + * {@link #buildNetworkSpecifier}, sets the SSID to use for filtering networks from scan + * results. Will only match networks whose SSID is identical to the UTF-8 encoding of the + * specified value.</li> + * <li>For network suggestions ({@link WifiNetworkSuggestion}), built using + * {@link #buildNetworkSuggestion()}, sets the SSID for the network.</li> + * <li>Overrides any previous value set using {@link #setSsid(String)} or + * {@link #setSsidPattern(PatternMatcher)}.</li> + * + * @param ssid The SSID of the network. It must be valid Unicode. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + * @throws IllegalArgumentException if the SSID is not valid unicode. + */ + public WifiNetworkConfigBuilder setSsid(@NonNull String ssid) { + checkNotNull(ssid); + final CharsetEncoder unicodeEncoder = StandardCharsets.UTF_8.newEncoder(); + if (!unicodeEncoder.canEncode(ssid)) { + throw new IllegalArgumentException("SSID is not a valid unicode string"); + } + mSsidPatternMatcher = new PatternMatcher(ssid, PatternMatcher.PATTERN_LITERAL); + return this; + } + + /** + * Set the BSSID match pattern to use for filtering networks from scan results. + * Will match all networks with BSSID which satisfies the following: + * {@code BSSID & mask == baseAddress}. + * <p> + * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li> + * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or + * {@link #setBssidPattern(MacAddress, MacAddress)}.</li> + * + * @param baseAddress Base address for BSSID pattern. + * @param mask Mask for BSSID pattern. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setBssidPattern( + @NonNull MacAddress baseAddress, @NonNull MacAddress mask) { + checkNotNull(baseAddress, mask); + mBssidPatternMatcher = Pair.create(baseAddress, mask); + return this; + } + + /** + * Set the BSSID to use for filtering networks from scan results. Will only match network whose + * BSSID is identical to the specified value. + * <p> + * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li> + * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or + * {@link #setBssidPattern(MacAddress, MacAddress)}.</li> + * + * @param bssid BSSID of the network. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setBssid(@NonNull MacAddress bssid) { + checkNotNull(bssid); + mBssidPatternMatcher = Pair.create(bssid, MATCH_EXACT_BSSID_PATTERN_MASK); + return this; + } + + /** + * Set the ASCII PSK passphrase for this network. Needed for authenticating to + * WPA_PSK networks. + * + * @param pskPassphrase PSK passphrase of the network. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + * @throws IllegalArgumentException if the passphrase is not ASCII encodable. + */ + public WifiNetworkConfigBuilder setPskPassphrase(@NonNull String pskPassphrase) { + checkNotNull(pskPassphrase); + final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); + if (!asciiEncoder.canEncode(pskPassphrase)) { + throw new IllegalArgumentException("passphrase not ASCII encodable"); + } + mPskPassphrase = pskPassphrase; + return this; + } + + /** + * Set the associated enterprise configuration for this network. Needed for authenticating to + * WPA_EAP networks. See {@link WifiEnterpriseConfig} for description. + * + * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setEnterpriseConfig( + @NonNull WifiEnterpriseConfig enterpriseConfig) { + checkNotNull(enterpriseConfig); + mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig); + return this; + } + + /** + * Specifies whether this represents a hidden network. + * <p> + * <li>For network requests (see {@link NetworkSpecifier}), built using + * {@link #buildNetworkSpecifier}, setting this disallows the usage of + * {@link #setSsidPattern(PatternMatcher)} since hidden networks need to be explicitly + * probed for.</li> + * <li>If not set, defaults to false (i.e not a hidden network).</li> + * + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setIsHiddenSsid() { + mIsHiddenSSID = true; + return this; + } + + /** + * Specifies whether the app needs to log in to a captive portal to obtain Internet access. + * <p> + * This will dictate if the associated pending intent in + * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} will be sent after + * successfully connecting to the network. + * Use this for captive portal type networks where the app needs to authenticate the user + * before the device can access the network. + * This setting will be ignored if the {@code PendingIntent} used to add this network + * suggestion is null. + * <p> + * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li> + * <li>If not set, defaults to false (i.e no app interaction required).</li> + * + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setIsAppInteractionRequired() { + mIsAppInteractionRequired = true; + return this; + } + + /** + * Specifies whether the user needs to log in to a captive portal to obtain Internet access. + * <p> + * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li> + * <li>If not set, defaults to false (i.e no user interaction required).</li> + * + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setIsUserInteractionRequired() { + mIsUserInteractionRequired = true; + return this; + } + + /** + * Specify the priority of this network among other network suggestions provided by the same app + * (priorities have no impact on suggestions by different apps). The lower the number, the + * higher the priority (i.e value of 0 = highest priority). + * <p> + * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li> + * <li>If not set, defaults to -1 (i.e unassigned priority).</li> + * + * @param priority Integer number representing the priority among suggestions by the app. + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + * @throws IllegalArgumentException if the priority value is negative. + */ + public WifiNetworkConfigBuilder setPriority(int priority) { + if (priority < 0) { + throw new IllegalArgumentException("Invalid priority value " + priority); + } + mPriority = priority; + return this; + } + + /** + * Specifies whether this network is metered. + * <p> + * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li> + * <li>If not set, defaults to false (i.e not metered).</li> + * + * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder + * method. + */ + public WifiNetworkConfigBuilder setIsMetered() { + mIsMetered = true; + return this; + } + + /** + * Set defaults for the various low level credential type fields in the newly created + * WifiConfiguration object. + * + * See {@link com.android.server.wifi.WifiConfigManager#setDefaultsInWifiConfiguration( + * WifiConfiguration)}. + * + * @param configuration provided WifiConfiguration object. + */ + private static void setDefaultsInWifiConfiguration(@NonNull WifiConfiguration configuration) { + configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); + configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN); + configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); + configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); + configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); + } + + private void setKeyMgmtInWifiConfiguration(@NonNull WifiConfiguration configuration) { + if (!TextUtils.isEmpty(mPskPassphrase)) { + // WPA_PSK network. + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + } else if (mEnterpriseConfig != null) { + // WPA_EAP network + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X); + } else { + // Open network + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + } + } + + /** + * Helper method to build WifiConfiguration object from the builder. + * @return Instance of {@link WifiConfiguration}. + */ + private WifiConfiguration buildWifiConfiguration() { + final WifiConfiguration wifiConfiguration = new WifiConfiguration(); + setDefaultsInWifiConfiguration(wifiConfiguration); + // WifiConfiguration.SSID needs quotes around unicode SSID. + if (mSsidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) { + wifiConfiguration.SSID = "\"" + mSsidPatternMatcher.getPath() + "\""; + } + setKeyMgmtInWifiConfiguration(wifiConfiguration); + // WifiConfiguration.preSharedKey needs quotes around ASCII password. + if (mPskPassphrase != null) { + wifiConfiguration.preSharedKey = "\"" + mPskPassphrase + "\""; + } + wifiConfiguration.enterpriseConfig = mEnterpriseConfig; + wifiConfiguration.hiddenSSID = mIsHiddenSSID; + wifiConfiguration.priority = mPriority; + wifiConfiguration.meteredOverride = + mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED + : WifiConfiguration.METERED_OVERRIDE_NONE; + return wifiConfiguration; + } + + private boolean hasSetAnyPattern() { + return mSsidPatternMatcher != null || mBssidPatternMatcher != null; + } + + private void setMatchAnyPatternIfUnset() { + if (mSsidPatternMatcher == null) { + mSsidPatternMatcher = new PatternMatcher(MATCH_ALL_SSID_PATTERN_PATH, + PatternMatcher.PATTERN_SIMPLE_GLOB); + } + if (mBssidPatternMatcher == null) { + mBssidPatternMatcher = MATCH_ALL_BSSID_PATTERN; + } + } + + private boolean hasSetMatchNonePattern() { + if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_PREFIX + && mSsidPatternMatcher.getPath().equals(MATCH_EMPTY_SSID_PATTERN_PATH)) { + return true; + } + if (mBssidPatternMatcher.equals(MATCH_NO_BSSID_PATTERN)) { + return true; + } + return false; + } + + private boolean hasSetMatchAllPattern() { + if ((mSsidPatternMatcher.match(MATCH_EMPTY_SSID_PATTERN_PATH)) + && mBssidPatternMatcher.equals(MATCH_ALL_BSSID_PATTERN)) { + return true; + } + return false; + } + + /** + * Create a specifier object used to request a Wi-Fi network. The generated + * {@link NetworkSpecifier} should be used in + * {@link NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} when building + * the {@link NetworkRequest}. + *<p> + * Note: Apps can set a combination of network match params: + * <li> SSID Pattern using {@link #setSsidPattern(PatternMatcher)} OR Specific SSID using + * {@link #setSsid(String)}. </li> + * AND/OR + * <li> BSSID Pattern using {@link #setBssidPattern(MacAddress, MacAddress)} OR Specific BSSID + * using {@link #setBssid(MacAddress)} </li> + * to trigger connection to a network that matches the set params. + * The system will find the set of networks matching the request and present the user + * with a system dialog which will allow the user to select a specific Wi-Fi network to connect + * to or to deny the request. + *</p> + * + * For example: + * To connect to an open network with a SSID prefix of "test" and a BSSID OUI of "10:03:23": + * {@code + * final NetworkSpecifier specifier = + * new WifiNetworkConfigBuilder() + * .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX)) + * .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"), + * MacAddress.fromString("ff:ff:ff:00:00:00")) + * .buildNetworkSpecifier() + * final NetworkRequest request = + * new NetworkRequest.Builder() + * .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + * .setNetworkSpecifier(specifier) + * .build(); + * final ConnectivityManager connectivityManager = + * context.getSystemService(Context.CONNECTIVITY_SERVICE); + * final NetworkCallback networkCallback = new NetworkCallback() { + * ... + * {@literal @}Override + * void onAvailable(...) {} + * // etc. + * }; + * connectivityManager.requestNetwork(request, networkCallback); + * } + * + * @return Instance of {@link NetworkSpecifier}. + * @throws IllegalStateException on invalid params set. + */ + public NetworkSpecifier buildNetworkSpecifier() { + if (!hasSetAnyPattern()) { + throw new IllegalStateException("one of setSsidPattern/setSsid/setBssidPattern/setBssid" + + " should be invoked for specifier"); + } + setMatchAnyPatternIfUnset(); + if (hasSetMatchNonePattern()) { + throw new IllegalStateException("cannot set match-none pattern for specifier"); + } + if (hasSetMatchAllPattern()) { + throw new IllegalStateException("cannot set match-all pattern for specifier"); + } + if (mIsHiddenSSID && mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL) { + throw new IllegalStateException("setSsid should also be invoked when " + + "setIsHiddenSsid is invoked for network specifier"); + } + if (mIsAppInteractionRequired || mIsUserInteractionRequired + || mPriority != -1 || mIsMetered) { + throw new IllegalStateException("none of setIsAppInteractionRequired/" + + "setIsUserInteractionRequired/setPriority/setIsMetered are allowed for " + + "specifier"); + } + if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) { + throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can" + + " be invoked for network specifier"); + } + + return new WifiNetworkSpecifier( + mSsidPatternMatcher, + mBssidPatternMatcher, + buildWifiConfiguration(), + Process.myUid()); + } + + /** + * Create a network suggestion object use in + * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}. + * See {@link WifiNetworkSuggestion}. + * + * @return Instance of {@link WifiNetworkSuggestion}. + * @throws IllegalStateException on invalid params set. + */ + public WifiNetworkSuggestion buildNetworkSuggestion() { + if (mSsidPatternMatcher == null) { + throw new IllegalStateException("setSsid should be invoked for suggestion"); + } + if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL + || mBssidPatternMatcher != null) { + throw new IllegalStateException("none of setSsidPattern/setBssidPattern/setBssid are" + + " allowed for suggestion"); + } + if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) { + throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can" + + "be invoked for suggestion"); + } + + return new WifiNetworkSuggestion( + buildWifiConfiguration(), + mIsAppInteractionRequired, + mIsUserInteractionRequired, + Process.myUid()); + + } +} diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java new file mode 100644 index 000000000000..4348399b404b --- /dev/null +++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.NonNull; +import android.net.MacAddress; +import android.net.MatchAllNetworkSpecifier; +import android.net.NetworkSpecifier; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.PatternMatcher; +import android.util.Pair; + +import java.util.Objects; + +/** + * Network specifier object used to request a Wi-Fi network. Apps should use the + * {@link WifiNetworkConfigBuilder} class to create an instance. + * @hide + */ +public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parcelable { + /** + * SSID pattern match specified by the app. + */ + public final PatternMatcher ssidPatternMatcher; + + /** + * BSSID pattern match specified by the app. + * Pair of <BaseAddress, Mask>. + */ + public final Pair<MacAddress, MacAddress> bssidPatternMatcher; + + /** + * Security credentials for the network. + * <p> + * Note: {@link WifiConfiguration#SSID} & {@link WifiConfiguration#BSSID} fields from + * WifiConfiguration are not used. Instead we use the {@link #ssidPatternMatcher} & + * {@link #bssidPatternMatcher} fields embedded directly + * within {@link WifiNetworkSpecifier}. + */ + public final WifiConfiguration wifiConfiguration; + + /** + * The UID of the process initializing this network specifier. Validated by receiver using + * checkUidIfNecessary() and is used by satisfiedBy() to determine whether the specifier + * matches the offered network. + */ + public final int requestorUid; + + public WifiNetworkSpecifier(@NonNull PatternMatcher ssidPatternMatcher, + @NonNull Pair<MacAddress, MacAddress> bssidPatternMatcher, + @NonNull WifiConfiguration wifiConfiguration, + int requestorUid) { + checkNotNull(ssidPatternMatcher); + checkNotNull(bssidPatternMatcher); + checkNotNull(wifiConfiguration); + + this.ssidPatternMatcher = ssidPatternMatcher; + this.bssidPatternMatcher = bssidPatternMatcher; + this.wifiConfiguration = wifiConfiguration; + this.requestorUid = requestorUid; + } + + public static final Creator<WifiNetworkSpecifier> CREATOR = + new Creator<WifiNetworkSpecifier>() { + @Override + public WifiNetworkSpecifier createFromParcel(Parcel in) { + PatternMatcher ssidPatternMatcher = in.readParcelable(/* classLoader */null); + MacAddress baseAddress = in.readParcelable(null); + MacAddress mask = in.readParcelable(null); + Pair<MacAddress, MacAddress> bssidPatternMatcher = + Pair.create(baseAddress, mask); + WifiConfiguration wifiConfiguration = in.readParcelable(null); + int requestorUid = in.readInt(); + return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher, + wifiConfiguration, requestorUid); + } + + @Override + public WifiNetworkSpecifier[] newArray(int size) { + return new WifiNetworkSpecifier[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(ssidPatternMatcher, flags); + dest.writeParcelable(bssidPatternMatcher.first, flags); + dest.writeParcelable(bssidPatternMatcher.second, flags); + dest.writeParcelable(wifiConfiguration, flags); + dest.writeInt(requestorUid); + } + + @Override + public boolean satisfiedBy(NetworkSpecifier other) { + if (this == other) { + return true; + } + // Any generic requests should be satisifed by a specific wifi network. + if (other == null || other instanceof MatchAllNetworkSpecifier) { + return true; + } + if (other instanceof WifiNetworkAgentSpecifier) { + return ((WifiNetworkAgentSpecifier) other).satisfiesNetworkSpecifier(this); + } + // Specific requests are checked for equality although testing for equality of 2 patterns do + // not make much sense! + return equals(other); + } + + @Override + public int hashCode() { + return Objects.hash( + ssidPatternMatcher.getPath(), + ssidPatternMatcher.getType(), + bssidPatternMatcher, + wifiConfiguration.allowedKeyManagement, + requestorUid); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof WifiNetworkSpecifier)) { + return false; + } + WifiNetworkSpecifier lhs = (WifiNetworkSpecifier) obj; + return Objects.equals(this.ssidPatternMatcher.getPath(), + lhs.ssidPatternMatcher.getPath()) + && Objects.equals(this.ssidPatternMatcher.getType(), + lhs.ssidPatternMatcher.getType()) + && Objects.equals(this.bssidPatternMatcher, + lhs.bssidPatternMatcher) + && Objects.equals(this.wifiConfiguration.allowedKeyManagement, + lhs.wifiConfiguration.allowedKeyManagement) + && requestorUid == lhs.requestorUid; + } + + @Override + public String toString() { + return new StringBuilder() + .append("WifiNetworkSpecifierWifiNetworkSpecifier [") + .append(", SSID Match pattern=").append(ssidPatternMatcher) + .append(", BSSID Match pattern=").append(bssidPatternMatcher) + .append(", WifiConfiguration=").append( + wifiConfiguration == null ? null : wifiConfiguration.configKey()) + .append(", requestorUid=").append(requestorUid) + .append("]") + .toString(); + } + + @Override + public void assertValidFromUid(int requestorUid) { + if (this.requestorUid != requestorUid) { + throw new SecurityException("mismatched UIDs"); + } + } +} diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java new file mode 100644 index 000000000000..04b9cb5dfb8d --- /dev/null +++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.app.PendingIntent; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.List; +import java.util.Objects; + +/** + * The Network Suggestion object is used to provide a Wi-Fi network for consideration when + * auto-connecting to networks. Apps cannot directly create this object, they must use + * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} to obtain an instance + * of this object. + *<p> + * Apps can provide a list of such networks to the platform using + * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}. + */ +public final class WifiNetworkSuggestion implements Parcelable { + /** + * Network configuration for the provided network. + * @hide + */ + public final WifiConfiguration wifiConfiguration; + + /** + * Whether app needs to log in to captive portal to obtain Internet access. + * This will dictate if the associated pending intent in + * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} needs to be sent after + * successfully connecting to the network. + * @hide + */ + public final boolean isAppInteractionRequired; + + /** + * Whether user needs to log in to captive portal to obtain Internet access. + * @hide + */ + public final boolean isUserInteractionRequired; + + /** + * The UID of the process initializing this network suggestion. + * @hide + */ + public final int suggestorUid; + + /** @hide */ + public WifiNetworkSuggestion(WifiConfiguration wifiConfiguration, + boolean isAppInteractionRequired, + boolean isUserInteractionRequired, + int suggestorUid) { + checkNotNull(wifiConfiguration); + + this.wifiConfiguration = wifiConfiguration; + this.isAppInteractionRequired = isAppInteractionRequired; + this.isUserInteractionRequired = isUserInteractionRequired; + this.suggestorUid = suggestorUid; + } + + public static final Creator<WifiNetworkSuggestion> CREATOR = + new Creator<WifiNetworkSuggestion>() { + @Override + public WifiNetworkSuggestion createFromParcel(Parcel in) { + return new WifiNetworkSuggestion( + in.readParcelable(null), // wifiConfiguration + in.readBoolean(), // isAppInteractionRequired + in.readBoolean(), // isUserInteractionRequired + in.readInt() // suggestorUid + ); + } + + @Override + public WifiNetworkSuggestion[] newArray(int size) { + return new WifiNetworkSuggestion[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(wifiConfiguration, flags); + dest.writeBoolean(isAppInteractionRequired); + dest.writeBoolean(isUserInteractionRequired); + dest.writeInt(suggestorUid); + } + + @Override + public int hashCode() { + return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.allowedKeyManagement, + suggestorUid); + } + + /** + * Equals for network suggestions. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof WifiNetworkSuggestion)) { + return false; + } + WifiNetworkSuggestion lhs = (WifiNetworkSuggestion) obj; + return Objects.equals(this.wifiConfiguration.SSID, lhs.wifiConfiguration.SSID) + && Objects.equals(this.wifiConfiguration.allowedKeyManagement, + lhs.wifiConfiguration.allowedKeyManagement) + && suggestorUid == lhs.suggestorUid; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [") + .append(", WifiConfiguration=").append(wifiConfiguration) + .append(", isAppInteractionRequired=").append(isAppInteractionRequired) + .append(", isUserInteractionRequired=").append(isUserInteractionRequired) + .append(", suggestorUid=").append(suggestorUid) + .append("]"); + return sb.toString(); + } +} diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java index 045291b4f4d4..529548f1d2b8 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -594,17 +594,17 @@ public class WifiScanner { /** SSID of the network */ public String ssid; /** Bitmask of the FLAG_XXX */ - public byte flags; + public byte flags = 0; /** Bitmask of the ATUH_XXX */ - public byte authBitField; + public byte authBitField = 0; + /** frequencies on which the particular network needs to be scanned for */ + public int[] frequencies = {}; /** * default constructor for PnoNetwork */ public PnoNetwork(String ssid) { this.ssid = ssid; - flags = 0; - authBitField = 0; } } @@ -651,6 +651,7 @@ public class WifiScanner { dest.writeString(networkList[i].ssid); dest.writeByte(networkList[i].flags); dest.writeByte(networkList[i].authBitField); + dest.writeIntArray(networkList[i].frequencies); } } else { dest.writeInt(0); @@ -677,6 +678,7 @@ public class WifiScanner { PnoNetwork network = new PnoNetwork(ssid); network.flags = in.readByte(); network.authBitField = in.readByte(); + network.frequencies = in.createIntArray(); settings.networkList[i] = network; } return settings; diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index 3b9f93e503be..5f3e1b27672e 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -155,7 +155,10 @@ public class WifiConfigurationTest { @Test public void testIsOpenNetwork_NotOpen_HasAuthType() { for (int keyMgmt = 0; keyMgmt < WifiConfiguration.KeyMgmt.strings.length; keyMgmt++) { - if (keyMgmt == WifiConfiguration.KeyMgmt.NONE) continue; + if (keyMgmt == WifiConfiguration.KeyMgmt.NONE + || keyMgmt == WifiConfiguration.KeyMgmt.OWE) { + continue; + } WifiConfiguration config = new WifiConfiguration(); config.allowedKeyManagement.clear(); config.allowedKeyManagement.set(keyMgmt); diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index e40b657aded0..ea41bb39c4d5 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -43,6 +43,8 @@ import android.net.wifi.WifiManager.LocalOnlyHotspotCallback; import android.net.wifi.WifiManager.LocalOnlyHotspotObserver; import android.net.wifi.WifiManager.LocalOnlyHotspotReservation; import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription; +import android.net.wifi.WifiManager.NetworkRequestMatchCallback; +import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback; import android.net.wifi.WifiManager.SoftApCallback; import android.net.wifi.WifiManager.TrafficStateCallback; import android.os.Handler; @@ -59,6 +61,8 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; + /** * Unit tests for {@link android.net.wifi.WifiManager}. */ @@ -67,16 +71,19 @@ public class WifiManagerTest { private static final int ERROR_NOT_SET = -1; private static final int ERROR_TEST_REASON = 5; + private static final int TEST_UID = 14553; private static final String TEST_PACKAGE_NAME = "TestPackage"; private static final String TEST_COUNTRY_CODE = "US"; @Mock Context mContext; - @Mock IWifiManager mWifiService; + @Mock + android.net.wifi.IWifiManager mWifiService; @Mock ApplicationInfo mApplicationInfo; @Mock WifiConfiguration mApConfig; @Mock IBinder mAppBinder; @Mock SoftApCallback mSoftApCallback; @Mock TrafficStateCallback mTrafficStateCallback; + @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback; private Handler mHandler; private TestLooper mLooper; @@ -1163,4 +1170,84 @@ i * Verify that a call to cancel WPS immediately returns a failure. assertEquals(1, altLooper.dispatchAll()); verify(mTrafficStateCallback).onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT); } + + /** + * Verify the call to registerNetworkRequestMatchCallback goes to WifiServiceImpl. + */ + @Test + public void registerNetworkRequestMatchCallbackCallGoesToWifiServiceImpl() + throws Exception { + when(mContext.getMainLooper()).thenReturn(mLooper.getLooper()); + ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor = + ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class); + mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null); + verify(mWifiService).registerNetworkRequestMatchCallback( + any(IBinder.class), callbackCaptor.capture(), anyInt()); + + INetworkRequestUserSelectionCallback iUserSelectionCallback = + mock(INetworkRequestUserSelectionCallback.class); + + assertEquals(0, mLooper.dispatchAll()); + callbackCaptor.getValue().onMatch(new ArrayList<WifiConfiguration>()); + assertEquals(1, mLooper.dispatchAll()); + verify(mNetworkRequestMatchCallback).onMatch(anyList()); + + callbackCaptor.getValue().onUserSelectionConnectSuccess(new WifiConfiguration()); + assertEquals(1, mLooper.dispatchAll()); + verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess( + any(WifiConfiguration.class)); + + callbackCaptor.getValue().onUserSelectionConnectFailure(new WifiConfiguration()); + assertEquals(1, mLooper.dispatchAll()); + verify(mNetworkRequestMatchCallback).onUserSelectionConnectFailure( + any(WifiConfiguration.class)); + } + + /** + * Verify the call to unregisterNetworkRequestMatchCallback goes to WifiServiceImpl. + */ + @Test + public void unregisterNetworkRequestMatchCallbackCallGoesToWifiServiceImpl() throws Exception { + ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class); + mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, mHandler); + verify(mWifiService).registerNetworkRequestMatchCallback( + any(IBinder.class), any(INetworkRequestMatchCallback.class), + callbackIdentifier.capture()); + + mWifiManager.unregisterNetworkRequestMatchCallback(mNetworkRequestMatchCallback); + verify(mWifiService).unregisterNetworkRequestMatchCallback( + eq((int) callbackIdentifier.getValue())); + } + + /** + * Verify the call to NetworkRequestUserSelectionCallback goes to + * WifiServiceImpl. + */ + @Test + public void networkRequestUserSelectionCallbackCallGoesToWifiServiceImpl() + throws Exception { + when(mContext.getMainLooper()).thenReturn(mLooper.getLooper()); + ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor = + ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class); + mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null); + verify(mWifiService).registerNetworkRequestMatchCallback( + any(IBinder.class), callbackCaptor.capture(), anyInt()); + + INetworkRequestUserSelectionCallback iUserSelectionCallback = + mock(INetworkRequestUserSelectionCallback.class); + ArgumentCaptor<NetworkRequestUserSelectionCallback> userSelectionCallbackCaptor = + ArgumentCaptor.forClass(NetworkRequestUserSelectionCallback.class); + callbackCaptor.getValue().onUserSelectionCallbackRegistration( + iUserSelectionCallback); + assertEquals(1, mLooper.dispatchAll()); + verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration( + userSelectionCallbackCaptor.capture()); + + WifiConfiguration selected = new WifiConfiguration(); + userSelectionCallbackCaptor.getValue().select(selected); + verify(iUserSelectionCallback).select(selected); + + userSelectionCallbackCaptor.getValue().reject(); + verify(iUserSelectionCallback).reject(); + } } diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java new file mode 100644 index 000000000000..1b0007c9e732 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.MacAddress; +import android.net.MatchAllNetworkSpecifier; +import android.net.NetworkRequest; +import android.net.NetworkSpecifier; +import android.os.Parcel; +import android.os.PatternMatcher; +import android.support.test.filters.SmallTest; +import android.util.Pair; + +import org.junit.Test; + +/** + * Unit tests for {@link android.net.wifi.WifiNetworkAgentSpecifier}. + */ +@SmallTest +public class WifiNetworkAgentSpecifierTest { + private static final int TEST_UID = 5; + private static final int TEST_UID_1 = 8; + private static final String TEST_SSID = "Test123"; + private static final String TEST_SSID_PATTERN = "Test"; + private static final String TEST_SSID_1 = "456test"; + private static final String TEST_BSSID = "12:12:12:aa:0b:c0"; + private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00"; + private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00"; + private static final String TEST_BSSID_1 = "aa:cc:12:aa:0b:c0"; + private static final String TEST_PRESHARED_KEY = "\"Test123\""; + + /** + * Validate that parcel marshalling/unmarshalling works + */ + @Test + public void testWifiNetworkAgentSpecifierParcel() { + WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier(); + + Parcel parcelW = Parcel.obtain(); + specifier.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + WifiNetworkAgentSpecifier parcelSpecifier = + WifiNetworkAgentSpecifier.CREATOR.createFromParcel(parcelR); + + assertEquals(specifier, parcelSpecifier); + } + + /** + * Validate that the NetworkAgentSpecifier cannot be used in a {@link NetworkRequest} by apps. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkAgentSpecifierNotUsedInNetworkRequest() { + WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier(); + + specifier.assertValidFromUid(TEST_UID); + } + + /** + * Validate NetworkAgentSpecifier equals with itself. + * a) Create network agent specifier 1 for WPA_PSK network + * b) Create network agent specifier 2 with the same params as specifier 1. + * c) Ensure that the specifier 2 equals specifier 1. + */ + @Test + public void testWifiNetworkAgentSpecifierEqualsSame() { + WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier(); + WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier(); + + assertTrue(specifier2.equals(specifier1)); + } + + /** + * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}. + * a) Create network agent specifier 1 for WPA_PSK network + * b) Create network agent specifier 2 with different key mgmt params. + * c) Ensure that the specifier 2 does not equal specifier 1. + */ + @Test + public void testWifiNetworkAgentSpecifierDoesNotEqualsWhenKeyMgmtDifferent() { + WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration(); + WifiNetworkAgentSpecifier specifier1 = + new WifiNetworkAgentSpecifier( + wifiConfiguration1, + TEST_UID); + + WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1); + wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + WifiNetworkAgentSpecifier specifier2 = + new WifiNetworkAgentSpecifier( + wifiConfiguration2, + TEST_UID); + + assertFalse(specifier2.equals(specifier1)); + } + + /** + * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}. + * a) Create network agent specifier 1 for WPA_PSK network + * b) Create network agent specifier 2 with different SSID. + * c) Ensure that the specifier 2 does not equal specifier 1. + */ + @Test + public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenSsidDifferent() { + WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration(); + WifiNetworkAgentSpecifier specifier1 = + new WifiNetworkAgentSpecifier( + wifiConfiguration1, + TEST_UID); + + WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1); + wifiConfiguration2.SSID = TEST_SSID_1; + WifiNetworkAgentSpecifier specifier2 = + new WifiNetworkAgentSpecifier( + wifiConfiguration2, + TEST_UID); + + assertFalse(specifier2.equals(specifier1)); + } + + /** + * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}. + * a) Create network agent specifier 1 for WPA_PSK network + * b) Create network agent specifier 2 with different BSSID. + * c) Ensure that the specifier 2 does not equal specifier 1. + */ + @Test + public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenBssidDifferent() { + WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration(); + WifiNetworkAgentSpecifier specifier1 = + new WifiNetworkAgentSpecifier( + wifiConfiguration1, + TEST_UID); + + WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1); + wifiConfiguration2.BSSID = TEST_BSSID_1; + WifiNetworkAgentSpecifier specifier2 = + new WifiNetworkAgentSpecifier( + wifiConfiguration2, + TEST_UID); + + assertFalse(specifier2.equals(specifier1)); + } + + /** + * Validate NetworkAgentSpecifier matching. + * a) Create a network agent specifier for WPA_PSK network + * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier} + * specifiers. + */ + @Test + public void testWifiNetworkAgentSpecifierSatisifiesNullAndAllMatch() { + WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier(); + + assertTrue(specifier.satisfiedBy(null)); + assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier())); + } + + /** + * Validate NetworkAgentSpecifier matching with itself. + * a) Create network agent specifier 1 for WPA_PSK network + * b) Create network agent specifier 2 with the same params as specifier 1. + * c) Ensure that invoking {@link NetworkSpecifier#satisfiedBy(NetworkSpecifier)} on 2 + * {@link WifiNetworkAgentSpecifier} throws an exception. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkAgentSpecifierDoesNotSatisifySame() { + WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier(); + WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier(); + + assertTrue(specifier2.satisfiedBy(specifier1)); + } + + /** + * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching. + * a) Create network agent specifier for WPA_PSK network + * b) Create network specifier with matching SSID pattern. + * c) Ensure that the agent specifier is satisfied by specifier. + */ + @Test + public void + testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidPattern() { + WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier(); + + PatternMatcher ssidPattern = + new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX); + Pair<MacAddress, MacAddress> bssidPattern = + Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); + WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration(); + wificonfigurationNetworkSpecifier.allowedKeyManagement + .set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier( + ssidPattern, + bssidPattern, + wificonfigurationNetworkSpecifier, + TEST_UID); + + assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier)); + assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier)); + } + + /** + * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching. + * a) Create network agent specifier for WPA_PSK network + * b) Create network specifier with matching BSSID pattern. + * c) Ensure that the agent specifier is satisfied by specifier. + */ + @Test + public void + testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithBssidPattern() { + WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier(); + + PatternMatcher ssidPattern = + new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB); + Pair<MacAddress, MacAddress> bssidPattern = + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)); + WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration(); + wificonfigurationNetworkSpecifier.allowedKeyManagement + .set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier( + ssidPattern, + bssidPattern, + wificonfigurationNetworkSpecifier, + TEST_UID); + + assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier)); + assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier)); + } + + /** + * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching. + * a) Create network agent specifier for WPA_PSK network + * b) Create network specifier with matching SSID & BSSID pattern. + * c) Ensure that the agent specifier is satisfied by specifier. + */ + @Test + public void + testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidAndBssidPattern() { + WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier(); + + PatternMatcher ssidPattern = + new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX); + Pair<MacAddress, MacAddress> bssidPattern = + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)); + WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration(); + wificonfigurationNetworkSpecifier.allowedKeyManagement + .set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier( + ssidPattern, + bssidPattern, + wificonfigurationNetworkSpecifier, + TEST_UID); + + assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier)); + assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier)); + } + + /** + * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching. + * a) Create network agent specifier for WPA_PSK network + * b) Create network specifier with non-matching SSID pattern. + * c) Ensure that the agent specifier is not satisfied by specifier. + */ + @Test + public void + testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidPattern() { + WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration(); + wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID_1 + "\""; + WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = + new WifiNetworkAgentSpecifier( + wifiConfigurationNetworkAgent, + TEST_UID); + + PatternMatcher ssidPattern = + new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX); + Pair<MacAddress, MacAddress> bssidPattern = + Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS); + WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration(); + wificonfigurationNetworkSpecifier.allowedKeyManagement + .set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier( + ssidPattern, + bssidPattern, + wificonfigurationNetworkSpecifier, + TEST_UID); + + assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier)); + assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier)); + } + + /** + * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching. + * a) Create network agent specifier for WPA_PSK network + * b) Create network specifier with non-matching BSSID pattern. + * c) Ensure that the agent specifier is not satisfied by specifier. + */ + @Test + public void + testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithBssidPattern() { + WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration(); + wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1; + WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = + new WifiNetworkAgentSpecifier( + wifiConfigurationNetworkAgent, + TEST_UID); + + PatternMatcher ssidPattern = + new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB); + Pair<MacAddress, MacAddress> bssidPattern = + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)); + WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration(); + wificonfigurationNetworkSpecifier.allowedKeyManagement + .set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier( + ssidPattern, + bssidPattern, + wificonfigurationNetworkSpecifier, + TEST_UID); + + assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier)); + assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier)); + } + + /** + * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching. + * a) Create network agent specifier for WPA_PSK network + * b) Create network specifier with non-matching SSID and BSSID pattern. + * c) Ensure that the agent specifier is not satisfied by specifier. + */ + @Test + public void + testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidAndBssidPattern() { + WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration(); + wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1; + WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = + new WifiNetworkAgentSpecifier( + wifiConfigurationNetworkAgent, + TEST_UID); + + PatternMatcher ssidPattern = + new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX); + Pair<MacAddress, MacAddress> bssidPattern = + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)); + WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration(); + wificonfigurationNetworkSpecifier.allowedKeyManagement + .set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier( + ssidPattern, + bssidPattern, + wificonfigurationNetworkSpecifier, + TEST_UID); + + assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier)); + assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier)); + } + + /** + * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching. + * a) Create network agent specifier for WPA_PSK network + * b) Create network specifier with matching SSID and BSSID pattern, but different key mgmt. + * c) Ensure that the agent specifier is not satisfied by specifier. + */ + @Test + public void + testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentKeyMgmt() { + WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier(); + + PatternMatcher ssidPattern = + new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX); + Pair<MacAddress, MacAddress> bssidPattern = + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)); + WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration(); + wificonfigurationNetworkSpecifier.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier( + ssidPattern, + bssidPattern, + wificonfigurationNetworkSpecifier, + TEST_UID); + + assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier)); + assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier)); + } + + /** + * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching. + * a) Create network agent specifier for WPA_PSK network + * b) Create network specifier with matching SSID and BSSID pattern, but different UID. + * c) Ensure that the agent specifier is not satisfied by specifier. + */ + @Test + public void + testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentUid() { + WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier(); + + PatternMatcher ssidPattern = + new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX); + Pair<MacAddress, MacAddress> bssidPattern = + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)); + WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration(); + wificonfigurationNetworkSpecifier.allowedKeyManagement + .set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier( + ssidPattern, + bssidPattern, + wificonfigurationNetworkSpecifier, + TEST_UID_1); + + assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier)); + assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier)); + } + + private WifiConfiguration createDefaultWifiConfiguration() { + WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.SSID = "\"" + TEST_SSID + "\""; + wifiConfiguration.BSSID = TEST_BSSID; + wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY; + return wifiConfiguration; + } + + private WifiNetworkAgentSpecifier createDefaultNetworkAgentSpecifier() { + return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(), TEST_UID); + } + +} diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java new file mode 100644 index 000000000000..8980ddba238b --- /dev/null +++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java @@ -0,0 +1,481 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static android.os.PatternMatcher.PATTERN_LITERAL; +import static android.os.PatternMatcher.PATTERN_PREFIX; +import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.MacAddress; +import android.net.NetworkSpecifier; +import android.os.PatternMatcher; +import android.os.Process; +import android.support.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit tests for {@link android.net.wifi.WifiNetworkConfigBuilder}. + */ +@SmallTest +public class WifiNetworkConfigBuilderTest { + private static final String TEST_SSID = "Test123"; + private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00"; + private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00"; + private static final String TEST_BSSID = "12:12:12:12:12:12"; + private static final String TEST_PRESHARED_KEY = "Test123"; + + /** + * Validate correctness of WifiNetworkSpecifier object created by + * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for open network with SSID pattern. + */ + @Test + public void testWifiNetworkSpecifierBuilderForOpenNetworkWithSsidPattern() { + NetworkSpecifier specifier = new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX)) + .buildNetworkSpecifier(); + + assertTrue(specifier instanceof WifiNetworkSpecifier); + WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier; + + assertEquals(Process.myUid(), wifiNetworkSpecifier.requestorUid); + assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath()); + assertEquals(PATTERN_PREFIX, wifiNetworkSpecifier.ssidPatternMatcher.getType()); + assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.first); + assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.second); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.NONE)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols + .get(WifiConfiguration.Protocol.RSN)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms + .get(WifiConfiguration.AuthAlgorithm.OPEN)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers + .get(WifiConfiguration.PairwiseCipher.CCMP)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers + .get(WifiConfiguration.GroupCipher.CCMP)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers + .get(WifiConfiguration.GroupCipher.TKIP)); + } + + /** + * Validate correctness of WifiNetworkSpecifier object created by + * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_PSK network with BSSID + * pattern. + */ + @Test + public void testWifiNetworkSpecifierBuilderForWpaPskNetworkWithBssidPattern() { + NetworkSpecifier specifier = new WifiNetworkConfigBuilder() + .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)) + .setPskPassphrase(TEST_PRESHARED_KEY) + .buildNetworkSpecifier(); + + assertTrue(specifier instanceof WifiNetworkSpecifier); + WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier; + + assertEquals(".*", wifiNetworkSpecifier.ssidPatternMatcher.getPath()); + assertEquals(PATTERN_SIMPLE_GLOB, wifiNetworkSpecifier.ssidPatternMatcher.getType()); + assertEquals(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + wifiNetworkSpecifier.bssidPatternMatcher.first); + assertEquals(MacAddress.fromString(TEST_BSSID_OUI_MASK), + wifiNetworkSpecifier.bssidPatternMatcher.second); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.WPA_PSK)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols + .get(WifiConfiguration.Protocol.RSN)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms + .get(WifiConfiguration.AuthAlgorithm.OPEN)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers + .get(WifiConfiguration.PairwiseCipher.CCMP)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers + .get(WifiConfiguration.GroupCipher.CCMP)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers + .get(WifiConfiguration.GroupCipher.TKIP)); + assertEquals("\"" + TEST_PRESHARED_KEY + "\"", + wifiNetworkSpecifier.wifiConfiguration.preSharedKey); + } + + /** + * Validate correctness of WifiNetworkSpecifier object created by + * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_EAP network with + * SSID and BSSID pattern. + */ + @Test + public void testWifiNetworkSpecifierBuilderForEnterpriseHiddenNetworkWithSsidAndBssid() { + WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); + enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS); + enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC); + + NetworkSpecifier specifier = new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setBssid(MacAddress.fromString(TEST_BSSID)) + .setEnterpriseConfig(enterpriseConfig) + .setIsHiddenSsid() + .buildNetworkSpecifier(); + + assertTrue(specifier instanceof WifiNetworkSpecifier); + WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier; + + assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath()); + assertEquals(PATTERN_LITERAL, wifiNetworkSpecifier.ssidPatternMatcher.getType()); + assertEquals(MacAddress.fromString(TEST_BSSID), + wifiNetworkSpecifier.bssidPatternMatcher.first); + assertEquals(MacAddress.BROADCAST_ADDRESS, + wifiNetworkSpecifier.bssidPatternMatcher.second); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.WPA_EAP)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.IEEE8021X)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols + .get(WifiConfiguration.Protocol.RSN)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms + .get(WifiConfiguration.AuthAlgorithm.OPEN)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers + .get(WifiConfiguration.PairwiseCipher.CCMP)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers + .get(WifiConfiguration.GroupCipher.CCMP)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers + .get(WifiConfiguration.GroupCipher.TKIP)); + assertTrue(wifiNetworkSpecifier.wifiConfiguration.hiddenSSID); + assertEquals(enterpriseConfig.getEapMethod(), + wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getEapMethod()); + assertEquals(enterpriseConfig.getPhase2Method(), + wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getPhase2Method()); + } + + + /** + * Ensure {@link WifiNetworkConfigBuilder#setSsid(String)} throws an exception + * when the string is not Unicode. + */ + @Test(expected = IllegalArgumentException.class) + public void testSetSsidWithNonUnicodeString() { + new WifiNetworkConfigBuilder() + .setSsid("\ud800") + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} throws an exception + * when the string is not ASCII encodable. + */ + @Test(expected = IllegalArgumentException.class) + public void testSetPskPassphraseWithNonAsciiString() { + new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setPskPassphrase("salvē") + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when neither SSID nor BSSID patterns were set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithNoSsidAndBssidPattern() { + new WifiNetworkConfigBuilder().buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when match-all SSID pattern is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern1() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB)) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when match-all SSID pattern is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern2() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_ADVANCED_GLOB)) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when match-all SSID pattern is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern3() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_PREFIX)) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when match-all BSSID pattern is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithMatchAllBssidPattern() { + new WifiNetworkConfigBuilder() + .setBssidPattern(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when match-none SSID pattern is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithMatchNoneSsidPattern() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_LITERAL)) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when match-none BSSID pattern is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithMatchNoneBssidPattern() { + new WifiNetworkConfigBuilder() + .setBssidPattern(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when SSID pattern is set for hidden network. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithBssidMatchPatternForHiddenNetwork() { + new WifiNetworkConfigBuilder() + .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)) + .setIsHiddenSsid() + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when both {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} and + * {@link WifiNetworkConfigBuilder#setEnterpriseConfig(WifiEnterpriseConfig)} are invoked. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithBothPskPassphraseAndEnterpriseConfig() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL)) + .setPskPassphrase(TEST_PRESHARED_KEY) + .setEnterpriseConfig(new WifiEnterpriseConfig()) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when SSID pattern is set for hidden network. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithSsidMatchPatternForHiddenNetwork() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_PREFIX)) + .setIsHiddenSsid() + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithRequiredAppInteraction() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL)) + .setIsAppInteractionRequired() + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when {@link WifiNetworkConfigBuilder#setIsUserInteractionRequired()} is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithRequiredUserInteraction() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL)) + .setIsUserInteractionRequired() + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when {@link WifiNetworkConfigBuilder#setPriority(int)} is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithSetPriority() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL)) + .setPriority(4) + .buildNetworkSpecifier(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception + * when {@link WifiNetworkConfigBuilder#setIsMetered()} is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSpecifierBuilderWithMetered() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL)) + .setIsMetered() + .buildNetworkSpecifier(); + } + + /** + * Validate correctness of WifiNetworkSuggestion object created by + * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for Open network which requires + * app interaction. + */ + @Test + public void testWifiNetworkSuggestionBuilderForOpenNetworkWithReqAppInteraction() { + WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setIsAppInteractionRequired() + .buildNetworkSuggestion(); + + assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID); + assertTrue(suggestion.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.NONE)); + assertTrue(suggestion.isAppInteractionRequired); + assertFalse(suggestion.isUserInteractionRequired); + assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE, + suggestion.wifiConfiguration.meteredOverride); + assertEquals(-1, suggestion.wifiConfiguration.priority); + } + + /** + * Validate correctness of WifiNetworkSuggestion object created by + * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_EAP network which requires + * app interaction and has a priority of zero set. + */ + @Test + public void testWifiNetworkSuggestionBuilderForWpaEapNetworkWithPriorityAndReqAppInteraction() { + WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setPskPassphrase(TEST_PRESHARED_KEY) + .setIsAppInteractionRequired() + .setPriority(0) + .buildNetworkSuggestion(); + + assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID); + assertTrue(suggestion.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.WPA_PSK)); + assertEquals("\"" + TEST_PRESHARED_KEY + "\"", + suggestion.wifiConfiguration.preSharedKey); + assertTrue(suggestion.isAppInteractionRequired); + assertFalse(suggestion.isUserInteractionRequired); + assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE, + suggestion.wifiConfiguration.meteredOverride); + assertEquals(0, suggestion.wifiConfiguration.priority); + } + + /** + * Validate correctness of WifiNetworkSuggestion object created by + * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_PSK network which requires + * user interaction and is metered. + */ + @Test + public void testWifiNetworkSuggestionBuilderForWpaPskNetworkWithMeteredAndReqUserInteraction() { + WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setPskPassphrase(TEST_PRESHARED_KEY) + .setIsUserInteractionRequired() + .setIsMetered() + .buildNetworkSuggestion(); + + assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID); + assertTrue(suggestion.wifiConfiguration.allowedKeyManagement + .get(WifiConfiguration.KeyMgmt.WPA_PSK)); + assertEquals("\"" + TEST_PRESHARED_KEY + "\"", + suggestion.wifiConfiguration.preSharedKey); + assertFalse(suggestion.isAppInteractionRequired); + assertTrue(suggestion.isUserInteractionRequired); + assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED, + suggestion.wifiConfiguration.meteredOverride); + assertEquals(-1, suggestion.wifiConfiguration.priority); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception + * when {@link WifiNetworkConfigBuilder#setSsidPattern(PatternMatcher)} is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSuggestionBuilderWithSsidPattern() { + new WifiNetworkConfigBuilder() + .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX)) + .buildNetworkSuggestion(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception + * when {@link WifiNetworkConfigBuilder#setBssid(MacAddress)} is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSuggestionBuilderWithBssidPattern() { + new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setBssidPattern(MacAddress.fromString(TEST_BSSID), + MacAddress.fromString(TEST_BSSID)) + .buildNetworkSuggestion(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception + * when {@link WifiNetworkConfigBuilder#setBssidPattern(MacAddress, MacAddress)} is set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSuggestionBuilderWithBssid() { + new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setBssid(MacAddress.fromString(TEST_BSSID)) + .buildNetworkSuggestion(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception + * when {@link WifiNetworkConfigBuilder#setSsid(String)} is not set. + */ + @Test(expected = IllegalStateException.class) + public void testWifiNetworkSuggestionBuilderWithNoSsid() { + new WifiNetworkConfigBuilder() + .buildNetworkSuggestion(); + } + + /** + * Ensure {@link WifiNetworkConfigBuilder#setPriority(int)} throws an exception + * when the value is negative. + */ + @Test(expected = IllegalArgumentException.class) + public void testWifiNetworkSuggestionBuilderWithInvalidPriority() { + new WifiNetworkConfigBuilder() + .setSsid(TEST_SSID) + .setPriority(-1) + .buildNetworkSuggestion(); + } +} diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java new file mode 100644 index 000000000000..856f0c79a2e7 --- /dev/null +++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static android.os.PatternMatcher.PATTERN_LITERAL; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.MacAddress; +import android.net.MatchAllNetworkSpecifier; +import android.os.Parcel; +import android.os.PatternMatcher; +import android.support.test.filters.SmallTest; +import android.util.Pair; + +import org.junit.Test; + +/** + * Unit tests for {@link android.net.wifi.WifiNetworkSpecifier}. + */ +@SmallTest +public class WifiNetworkSpecifierTest { + private static final int TEST_UID = 5; + private static final String TEST_SSID = "Test123"; + private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00"; + private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00"; + private static final String TEST_PRESHARED_KEY = "\"Test123\""; + + /** + * Validate that parcel marshalling/unmarshalling works + */ + @Test + public void testWifiNetworkSpecifierParcel() { + WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY; + WifiNetworkSpecifier specifier = + new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL), + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)), + wifiConfiguration, + TEST_UID); + + Parcel parcelW = Parcel.obtain(); + specifier.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + WifiNetworkSpecifier parcelSpecifier = + WifiNetworkSpecifier.CREATOR.createFromParcel(parcelR); + + assertEquals(specifier, parcelSpecifier); + } + + /** + * Validate NetworkSpecifier matching. + * a) Create a network specifier for WPA_PSK network + * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier} + * specifiers. + */ + @Test + public void testWifiNetworkSpecifierSatisfiesNullAndAllMatch() { + WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY; + WifiNetworkSpecifier specifier = + new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL), + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)), + wifiConfiguration, + TEST_UID); + + assertTrue(specifier.satisfiedBy(null)); + assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier())); + } + + /** + * Validate NetworkSpecifier matching. + * a) Create network specifier 1 for WPA_PSK network + * b) Create network specifier 2 with the same params as specifier 1. + * c) Ensure that the specifier 2 is satisfied by specifier 1. + */ + @Test + public void testWifiNetworkSpecifierSatisfiesSame() { + WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY; + + WifiNetworkSpecifier specifier1 = + new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL), + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)), + wifiConfiguration, + TEST_UID); + + WifiNetworkSpecifier specifier2 = + new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL), + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)), + wifiConfiguration, + TEST_UID); + + assertTrue(specifier2.satisfiedBy(specifier1)); + } + + /** + * Validate NetworkSpecifier matching. + * a) Create network specifier 1 for WPA_PSK network + * b) Create network specifier 2 with different key mgmt params. + * c) Ensure that the specifier 2 is not satisfied by specifier 1. + */ + @Test + public void testWifiNetworkSpecifierDoesNotSatisfyWhenKeyMgmtDifferent() { + WifiConfiguration wifiConfiguration1 = new WifiConfiguration(); + wifiConfiguration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + wifiConfiguration1.preSharedKey = TEST_PRESHARED_KEY; + + WifiNetworkSpecifier specifier1 = + new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL), + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)), + wifiConfiguration1, + TEST_UID); + + WifiConfiguration wifiConfiguration2 = new WifiConfiguration(); + wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + WifiNetworkSpecifier specifier2 = + new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL), + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)), + wifiConfiguration2, + TEST_UID); + + assertFalse(specifier2.satisfiedBy(specifier1)); + } + + /** + * Validate NetworkSpecifier matching. + * a) Create network specifier 1 for WPA_PSK network + * b) Create network specifier 2 with different SSID pattern. + * c) Ensure that the specifier 2 is not satisfied by specifier 1. + */ + @Test + public void testWifiNetworkSpecifierDoesNotSatisfyWhenSsidDifferent() { + WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY; + + WifiNetworkSpecifier specifier1 = + new WifiNetworkSpecifier(new PatternMatcher("", PATTERN_LITERAL), + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)), + wifiConfiguration, + TEST_UID); + + WifiNetworkSpecifier specifier2 = + new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL), + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)), + wifiConfiguration, + TEST_UID); + + assertFalse(specifier2.satisfiedBy(specifier1)); + } + + /** + * Validate NetworkSpecifier matching. + * a) Create network specifier 1 for WPA_PSK network + * b) Create network specifier 2 with different BSSID pattern. + * c) Ensure that the specifier 2 is not satisfied by specifier 1. + */ + @Test + public void testWifiNetworkSpecifierDoesNotSatisfyWhenBssidDifferent() { + WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY; + + WifiNetworkSpecifier specifier1 = + new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL), + Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS), + MacAddress.fromString(TEST_BSSID_OUI_MASK)), + wifiConfiguration, + TEST_UID); + + WifiNetworkSpecifier specifier2 = + new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL), + Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS), + wifiConfiguration, + TEST_UID); + + assertFalse(specifier2.satisfiedBy(specifier1)); + } +} diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java new file mode 100644 index 000000000000..6bab60dd480b --- /dev/null +++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import static org.junit.Assert.*; + +import android.os.Parcel; +import android.support.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit tests for {@link android.net.wifi.WifiNetworkSuggestion}. + */ +@SmallTest +public class WifiNetworkSuggestionTest { + private static final String TEST_SSID = "\"Test123\""; + private static final String TEST_SSID_1 = "\"Test1234\""; + + /** + * Check that parcel marshalling/unmarshalling works + */ + @Test + public void testWifiNetworkSuggestionParcel() { + WifiConfiguration configuration = new WifiConfiguration(); + configuration.SSID = TEST_SSID; + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + WifiNetworkSuggestion suggestion = + new WifiNetworkSuggestion(configuration, false, true, 0); + + Parcel parcelW = Parcel.obtain(); + suggestion.writeToParcel(parcelW, 0); + byte[] bytes = parcelW.marshall(); + parcelW.recycle(); + + Parcel parcelR = Parcel.obtain(); + parcelR.unmarshall(bytes, 0, bytes.length); + parcelR.setDataPosition(0); + WifiNetworkSuggestion parcelSuggestion = + WifiNetworkSuggestion.CREATOR.createFromParcel(parcelR); + + // Two suggestion objects are considered equal if they point to the same network (i.e same + // SSID + keyMgmt + same UID). |isAppInteractionRequired| & |isUserInteractionRequired| are + // not considered for equality and hence needs to be checked for explicitly below. + assertEquals(suggestion, parcelSuggestion); + assertEquals(suggestion.isAppInteractionRequired, + parcelSuggestion.isAppInteractionRequired); + assertEquals(suggestion.isUserInteractionRequired, + parcelSuggestion.isUserInteractionRequired); + } + + /** + * Check NetworkSuggestion equals returns {@code true} for 2 network suggestions with the same + * SSID, key mgmt and UID. + */ + @Test + public void testWifiNetworkSuggestionEqualsSame() { + WifiConfiguration configuration = new WifiConfiguration(); + configuration.SSID = TEST_SSID; + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSuggestion suggestion = + new WifiNetworkSuggestion(configuration, true, false, 0); + + WifiConfiguration configuration1 = new WifiConfiguration(); + configuration1.SSID = TEST_SSID; + configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSuggestion suggestion1 = + new WifiNetworkSuggestion(configuration1, false, true, 0); + + assertEquals(suggestion, suggestion1); + } + + /** + * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same + * key mgmt and UID, but different SSID. + */ + @Test + public void testWifiNetworkSuggestionEqualsFailsWhenSsidIsDifferent() { + WifiConfiguration configuration = new WifiConfiguration(); + configuration.SSID = TEST_SSID; + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + WifiNetworkSuggestion suggestion = + new WifiNetworkSuggestion(configuration, false, false, 0); + + WifiConfiguration configuration1 = new WifiConfiguration(); + configuration1.SSID = TEST_SSID_1; + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + WifiNetworkSuggestion suggestion1 = + new WifiNetworkSuggestion(configuration1, false, false, 0); + + assertNotEquals(suggestion, suggestion1); + } + + /** + * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same + * SSID and UID, but different key mgmt. + */ + @Test + public void testWifiNetworkSuggestionEqualsFailsWhenKeyMgmtIsDifferent() { + WifiConfiguration configuration = new WifiConfiguration(); + configuration.SSID = TEST_SSID; + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + WifiNetworkSuggestion suggestion = + new WifiNetworkSuggestion(configuration, false, false, 0); + + WifiConfiguration configuration1 = new WifiConfiguration(); + configuration1.SSID = TEST_SSID; + configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + WifiNetworkSuggestion suggestion1 = + new WifiNetworkSuggestion(configuration1, false, false, 0); + + assertNotEquals(suggestion, suggestion1); + } + + /** + * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same + * SSID and key mgmt, but different UID. + */ + @Test + public void testWifiNetworkSuggestionEqualsFailsWhenUidIsDifferent() { + WifiConfiguration configuration = new WifiConfiguration(); + configuration.SSID = TEST_SSID; + configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + WifiNetworkSuggestion suggestion = + new WifiNetworkSuggestion(configuration, false, false, 0); + + WifiNetworkSuggestion suggestion1 = + new WifiNetworkSuggestion(configuration, false, false, 1); + + assertNotEquals(suggestion, suggestion1); + } +} diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java index 96d5a5167480..da42dcf623c2 100644 --- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java @@ -17,16 +17,20 @@ package android.net.wifi; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.validateMockitoUsage; import static org.mockito.Mockito.when; import android.content.Context; +import android.net.wifi.WifiScanner.PnoSettings; +import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork; +import android.net.wifi.WifiScanner.ScanSettings; import android.os.Handler; import android.os.Parcel; import android.os.test.TestLooper; import android.support.test.filters.SmallTest; -import android.net.wifi.WifiScanner.ScanSettings; import com.android.internal.util.test.BidirectionalAsyncChannelServer; @@ -36,6 +40,8 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Arrays; + /** * Unit tests for {@link android.net.wifi.WifiScanner}. @@ -47,6 +53,19 @@ public class WifiScannerTest { @Mock private IWifiScanner mService; + private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false; + private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60; + private static final int TEST_PNOSETTINGS_MIN_2GHZ_RSSI = -70; + private static final int TEST_PNOSETTINGS_INITIAL_SCORE_MAX = 50; + private static final int TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS = 10; + private static final int TEST_PNOSETTINGS_SAME_NETWORK_BONUS = 11; + private static final int TEST_PNOSETTINGS_SECURE_BONUS = 12; + private static final int TEST_PNOSETTINGS_BAND_5GHZ_BONUS = 13; + private static final String TEST_SSID_1 = "TEST1"; + private static final String TEST_SSID_2 = "TEST2"; + private static final int[] TEST_FREQUENCIES_1 = {}; + private static final int[] TEST_FREQUENCIES_2 = {2500, 5124}; + private WifiScanner mWifiScanner; private TestLooper mLooper; private Handler mHandler; @@ -120,4 +139,68 @@ public class WifiScannerTest { return ScanSettings.CREATOR.createFromParcel(parcel); } + /** + * PnoSettings object can be serialized and deserialized, while keeping the + * values unchanged. + */ + @Test + public void canSerializeAndDeserializePnoSettings() throws Exception { + + PnoSettings pnoSettings = new PnoSettings(); + + PnoNetwork pnoNetwork1 = new PnoNetwork(TEST_SSID_1); + PnoNetwork pnoNetwork2 = new PnoNetwork(TEST_SSID_2); + pnoNetwork1.frequencies = TEST_FREQUENCIES_1; + pnoNetwork2.frequencies = TEST_FREQUENCIES_2; + + pnoSettings.networkList = new PnoNetwork[]{pnoNetwork1, pnoNetwork2}; + pnoSettings.isConnected = TEST_PNOSETTINGS_IS_CONNECTED; + pnoSettings.min5GHzRssi = TEST_PNOSETTINGS_MIN_5GHZ_RSSI; + pnoSettings.min24GHzRssi = TEST_PNOSETTINGS_MIN_2GHZ_RSSI; + pnoSettings.initialScoreMax = TEST_PNOSETTINGS_INITIAL_SCORE_MAX; + pnoSettings.currentConnectionBonus = TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS; + pnoSettings.sameNetworkBonus = TEST_PNOSETTINGS_SAME_NETWORK_BONUS; + pnoSettings.secureBonus = TEST_PNOSETTINGS_SECURE_BONUS; + pnoSettings.band5GHzBonus = TEST_PNOSETTINGS_BAND_5GHZ_BONUS; + + Parcel parcel = Parcel.obtain(); + pnoSettings.writeToParcel(parcel, 0); + // Rewind the pointer to the head of the parcel. + parcel.setDataPosition(0); + PnoSettings pnoSettingsDeserialized = + pnoSettings.CREATOR.createFromParcel(parcel); + + assertNotNull(pnoSettingsDeserialized); + assertEquals(TEST_PNOSETTINGS_IS_CONNECTED, pnoSettingsDeserialized.isConnected); + assertEquals(TEST_PNOSETTINGS_MIN_5GHZ_RSSI, pnoSettingsDeserialized.min5GHzRssi); + assertEquals(TEST_PNOSETTINGS_MIN_2GHZ_RSSI, pnoSettingsDeserialized.min24GHzRssi); + assertEquals(TEST_PNOSETTINGS_INITIAL_SCORE_MAX, pnoSettingsDeserialized.initialScoreMax); + assertEquals(TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS, + pnoSettingsDeserialized.currentConnectionBonus); + assertEquals(TEST_PNOSETTINGS_SAME_NETWORK_BONUS, + pnoSettingsDeserialized.sameNetworkBonus); + assertEquals(TEST_PNOSETTINGS_SECURE_BONUS, pnoSettingsDeserialized.secureBonus); + assertEquals(TEST_PNOSETTINGS_BAND_5GHZ_BONUS, pnoSettingsDeserialized.band5GHzBonus); + + // Test parsing of PnoNetwork + assertEquals(pnoSettings.networkList.length, pnoSettingsDeserialized.networkList.length); + for (int i = 0; i < pnoSettings.networkList.length; i++) { + PnoNetwork expected = pnoSettings.networkList[i]; + PnoNetwork actual = pnoSettingsDeserialized.networkList[i]; + assertEquals(expected.ssid, actual.ssid); + assertEquals(expected.flags, actual.flags); + assertEquals(expected.authBitField, actual.authBitField); + assertTrue(Arrays.equals(expected.frequencies, actual.frequencies)); + } + } + + /** + * Make sure that frequencies is not null by default. + */ + @Test + public void pnoNetworkFrequencyIsNotNull() throws Exception { + PnoNetwork pnoNetwork = new PnoNetwork(TEST_SSID_1); + assertNotNull(pnoNetwork.frequencies); + } + } |