diff options
550 files changed, 16427 insertions, 7274 deletions
diff --git a/Android.bp b/Android.bp index eb9cbbb136f9..15befaef84ae 100644 --- a/Android.bp +++ b/Android.bp @@ -739,6 +739,7 @@ java_defaults { "android.hardware.vibrator-V1.0-java", "android.hardware.vibrator-V1.1-java", "android.hardware.vibrator-V1.2-java", + "android.hardware.vibrator-V1.3-java", "android.hardware.wifi-V1.0-java-constants", "android.hardware.radio-V1.0-java", "android.hardware.radio-V1.3-java", @@ -872,6 +873,10 @@ aidl_interface { local_include_dir: "core/java", srcs: [ "core/java/android/net/INetworkStackConnector.aidl", + "core/java/android/net/INetworkStackStatusCallback.aidl", + "core/java/android/net/dhcp/DhcpServingParamsParcel.aidl", + "core/java/android/net/dhcp/IDhcpServer.aidl", + "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl", ], api_dir: "aidl/networkstack", } diff --git a/CleanSpec.mk b/CleanSpec.mk index d01e183df84d..30c2c69e8572 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -252,6 +252,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/overlay/ExperimentNavigation $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/vendor/overlay/ExperimentNavigationBarSlim) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/overlay/ExperimentNavigationBarSlim) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/SystemUI) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio) # ****************************************************************** # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER # ****************************************************************** diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk index 77bacbe4213d..3f87a1c8b598 100644 --- a/apct-tests/perftests/core/Android.mk +++ b/apct-tests/perftests/core/Android.mk @@ -9,7 +9,7 @@ LOCAL_SRC_FILES := \ src/android/os/ISomeService.aidl LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-test \ + androidx.test.rules \ androidx.annotation_annotation \ apct-perftests-utils \ guava diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml index 13c24d9b478d..a564a4d27fb3 100644 --- a/apct-tests/perftests/core/AndroidManifest.xml +++ b/apct-tests/perftests/core/AndroidManifest.xml @@ -28,7 +28,7 @@ </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.perftests.core"/> </manifest> diff --git a/apct-tests/perftests/core/src/android/accounts/AccountManagerPerfTest.java b/apct-tests/perftests/core/src/android/accounts/AccountManagerPerfTest.java index b9411fa463d5..e455e6a0574d 100644 --- a/apct-tests/perftests/core/src/android/accounts/AccountManagerPerfTest.java +++ b/apct-tests/perftests/core/src/android/accounts/AccountManagerPerfTest.java @@ -23,10 +23,10 @@ import android.content.Context; import android.content.pm.PackageManager; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; -import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java index f8fd51d7b0b6..b3f83596e8a1 100644 --- a/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java +++ b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java @@ -21,9 +21,10 @@ import android.content.Intent; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Rule; @@ -33,7 +34,6 @@ import org.junit.runner.RunWith; // Due to b/71353150, you might get "java.lang.AssertionError: Binder ProxyMap has too many // entries", but it's flaky. Adding "Runtime.getRuntime().gc()" between each iteration solves // the problem, but it doesn't seem like it's currently needed. - @RunWith(AndroidJUnit4.class) @LargeTest public class PendingIntentPerfTest { diff --git a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java index 9cdeb489722a..c3e43ee07453 100644 --- a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java +++ b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java @@ -23,7 +23,8 @@ import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; + +import androidx.test.filters.LargeTest; import org.junit.After; import org.junit.Before; diff --git a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java index bb0627e562b4..1b07572fd3f8 100644 --- a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java +++ b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java @@ -19,8 +19,9 @@ import android.content.Context; import android.content.res.Resources; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; import org.junit.Before; import org.junit.Rule; diff --git a/apct-tests/perftests/core/src/android/database/CursorWindowPerfTest.java b/apct-tests/perftests/core/src/android/database/CursorWindowPerfTest.java index 897d0aeed4f8..c5ef80d455f7 100644 --- a/apct-tests/perftests/core/src/android/database/CursorWindowPerfTest.java +++ b/apct-tests/perftests/core/src/android/database/CursorWindowPerfTest.java @@ -23,9 +23,10 @@ import android.database.sqlite.SQLiteCursor; import android.database.sqlite.SQLiteDatabase; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java index 7c5316d233a7..830302e229a8 100644 --- a/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java +++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java @@ -16,17 +16,20 @@ package android.database; +import static org.junit.Assert.assertEquals; + import android.app.Activity; import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; import android.util.ArrayMap; import android.util.Log; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + import com.android.internal.util.Preconditions; import org.junit.After; @@ -40,8 +43,6 @@ import java.nio.file.Files; import java.util.List; import java.util.Map; -import static org.junit.Assert.assertEquals; - /** * Performance tests for measuring amount of data written during typical DB operations * diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java index e2b75c3f5746..973e996a17c3 100644 --- a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java +++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java @@ -16,14 +16,18 @@ package android.database; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.After; import org.junit.Before; @@ -33,9 +37,6 @@ import org.junit.runner.RunWith; import java.util.Random; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - /** * Performance tests for typical CRUD operations and loading rows into the Cursor * diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java index c742df3b882b..9f093052ebb2 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java @@ -24,7 +24,8 @@ import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; + +import androidx.test.filters.LargeTest; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java index f9c375804599..10a51280ac86 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java @@ -19,7 +19,8 @@ package android.graphics.perftests; import android.graphics.Outline; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; + +import androidx.test.filters.LargeTest; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java index 26b830919b65..3a8002003299 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java @@ -20,17 +20,18 @@ import android.graphics.Paint; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; -import java.util.Arrays; -import java.util.Collection; +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized.Parameters; import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import java.util.Arrays; +import java.util.Collection; @LargeTest @RunWith(Parameterized.class) diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java index b9ee613315af..fc8c673d591c 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java @@ -19,9 +19,10 @@ package android.graphics.perftests; import android.graphics.Canvas; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; import android.text.TextPaint; +import androidx.test.filters.LargeTest; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java index 7a49b4f456b1..c6de9ec6c2e0 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java @@ -20,7 +20,8 @@ import android.graphics.Path; import android.graphics.RectF; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; + +import androidx.test.filters.LargeTest; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java index 62dd124beb86..e7fe235e0ea8 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java @@ -20,7 +20,8 @@ import android.graphics.Outline; import android.graphics.RenderNode; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; + +import androidx.test.filters.LargeTest; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java index 11ee59939601..d6e8ab2516a8 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java @@ -21,9 +21,14 @@ import android.content.res.AssetManager; import android.graphics.Typeface; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; import java.io.File; import java.io.FileOutputStream; @@ -31,10 +36,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - @LargeTest @RunWith(AndroidJUnit4.class) public class TypefaceCreatePerfTest { diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java index 5533782ca84d..3b2b8a94f610 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java @@ -16,6 +16,8 @@ package android.graphics.perftests; +import static junit.framework.Assert.assertTrue; + import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -25,21 +27,17 @@ import android.perftests.utils.BenchmarkState; import android.perftests.utils.BitmapUtils; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.InstrumentationRegistry; -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.LargeTest; +import androidx.test.rule.ActivityTestRule; +import androidx.test.runner.AndroidJUnit4; + import com.android.perftests.core.R; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import java.io.IOException; - -import static junit.framework.Assert.assertTrue; - @RunWith(AndroidJUnit4.class) @LargeTest public class VectorDrawablePerfTest { diff --git a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java index 99e4ba1bb804..12e49e36e8cb 100644 --- a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java @@ -18,8 +18,9 @@ package android.os; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderInternal.CallSession; @@ -31,7 +32,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; - /** * Performance tests for {@link BinderCallsStats} */ diff --git a/apct-tests/perftests/core/src/android/os/CpuUsageTrackingPerfTest.java b/apct-tests/perftests/core/src/android/os/CpuUsageTrackingPerfTest.java index 4961b4f94057..0d7b7cae3b0e 100644 --- a/apct-tests/perftests/core/src/android/os/CpuUsageTrackingPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/CpuUsageTrackingPerfTest.java @@ -18,8 +18,9 @@ package android.os; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; @@ -28,7 +29,6 @@ import org.junit.runner.RunWith; import java.nio.file.Files; import java.nio.file.Paths; - /** * Performance tests collecting CPU data different mechanisms. */ diff --git a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java index 9034034539e9..11c7599a508a 100644 --- a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java @@ -20,8 +20,9 @@ import static org.junit.Assert.assertNotNull; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import com.android.internal.os.KernelCpuThreadReader; @@ -29,7 +30,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; - /** * Performance tests collecting per-thread CPU data. */ diff --git a/apct-tests/perftests/core/src/android/os/LooperStatsPerfTest.java b/apct-tests/perftests/core/src/android/os/LooperStatsPerfTest.java index 0f880b71c7b1..162167deb75d 100644 --- a/apct-tests/perftests/core/src/android/os/LooperStatsPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/LooperStatsPerfTest.java @@ -19,8 +19,9 @@ package android.os; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import com.android.internal.os.CachedDeviceState; import com.android.internal.os.LooperStats; @@ -31,7 +32,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; - /** * Performance tests for {@link LooperStats}. */ diff --git a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java index 145fbcd2d5d7..3aa6749502bc 100644 --- a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java @@ -16,20 +16,16 @@ package android.os; -import static android.content.pm.PackageManager.PERMISSION_DENIED; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; - import android.content.ComponentName; -import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; -import org.junit.Assert; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/apct-tests/perftests/core/src/android/os/ParcelArrayPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelArrayPerfTest.java index a67aeca95540..af6d6b03d0a3 100644 --- a/apct-tests/perftests/core/src/android/os/ParcelArrayPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/ParcelArrayPerfTest.java @@ -18,7 +18,8 @@ package android.os; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; + +import androidx.test.filters.LargeTest; import org.junit.After; import org.junit.Before; diff --git a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java index 6e4c9c54a2f3..4db9262f7fe3 100644 --- a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java @@ -16,10 +16,15 @@ package android.os; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.After; import org.junit.Before; @@ -27,10 +32,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - @RunWith(AndroidJUnit4.class) @LargeTest public class ParcelPerfTest { diff --git a/apct-tests/perftests/core/src/android/os/PssPerfTest.java b/apct-tests/perftests/core/src/android/os/PssPerfTest.java index 400115deeeb8..2cc294f40e9c 100644 --- a/apct-tests/perftests/core/src/android/os/PssPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/PssPerfTest.java @@ -18,8 +18,9 @@ package android.os; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java b/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java index 099134f35303..dd479acdeee0 100644 --- a/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java +++ b/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java @@ -20,9 +20,10 @@ import android.content.Context; import android.content.SharedPreferences; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/os/StrictModeTest.java b/apct-tests/perftests/core/src/android/os/StrictModeTest.java index d973c204f89e..60678e954038 100644 --- a/apct-tests/perftests/core/src/android/os/StrictModeTest.java +++ b/apct-tests/perftests/core/src/android/os/StrictModeTest.java @@ -23,17 +23,21 @@ import android.content.ServiceConnection; import android.net.Uri; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + import com.google.common.util.concurrent.SettableFuture; -import java.io.File; -import java.io.IOException; -import java.util.concurrent.ExecutionException; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + @RunWith(AndroidJUnit4.class) @LargeTest public class StrictModeTest { diff --git a/apct-tests/perftests/core/src/android/os/TracePerfTest.java b/apct-tests/perftests/core/src/android/os/TracePerfTest.java index 8e5cfaafde52..0d64c390f4c2 100644 --- a/apct-tests/perftests/core/src/android/os/TracePerfTest.java +++ b/apct-tests/perftests/core/src/android/os/TracePerfTest.java @@ -20,7 +20,8 @@ package android.os; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.ShellHelper; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.runner.AndroidJUnit4; import org.junit.AfterClass; import org.junit.Assert; diff --git a/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java index 95a714486062..4f0d1084b767 100644 --- a/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java +++ b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java @@ -18,8 +18,9 @@ package android.perftests; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import dalvik.annotation.optimization.FastNative; diff --git a/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java index 9245c1ba59e4..c8121c52dda0 100644 --- a/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java @@ -22,9 +22,10 @@ import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; import android.text.NonEditableTextGenerator.TextType; +import androidx.test.filters.LargeTest; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java b/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java index 194a88c36bba..ad1327cbbd1c 100644 --- a/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java @@ -18,9 +18,10 @@ package android.text; import android.graphics.Canvas; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; import android.text.NonEditableTextGenerator.TextType; +import androidx.test.filters.LargeTest; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java index ad9fb5f5e99f..bb6b691226d6 100644 --- a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java +++ b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java @@ -19,8 +19,9 @@ import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Rule; diff --git a/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java index b4c7f543946a..5be99d9d779e 100644 --- a/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java @@ -24,11 +24,12 @@ import android.graphics.Paint.FontMetricsInt; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; import android.text.style.ReplacementSpan; import android.util.ArraySet; +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java index a7972f59f382..bbe75b762bdd 100644 --- a/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java @@ -21,7 +21,8 @@ import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; + +import androidx.test.filters.LargeTest; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java b/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java index 00a626750c79..4ae2b9395d6d 100644 --- a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java +++ b/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java @@ -18,9 +18,10 @@ package android.text; import android.app.Activity; import android.os.Bundle; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java index 33b1a47413c8..3be9114269f1 100644 --- a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java @@ -18,8 +18,9 @@ package android.text; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Rule; diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java index b40dd6b9dbb7..6c9222909f88 100644 --- a/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java @@ -22,9 +22,10 @@ import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; import android.text.NonEditableTextGenerator.TextType; +import androidx.test.filters.LargeTest; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutGetOffsetForHorizontalPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutGetOffsetForHorizontalPerfTest.java index 2768a7d89e16..47e04ef5ab3f 100644 --- a/apct-tests/perftests/core/src/android/text/StaticLayoutGetOffsetForHorizontalPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/StaticLayoutGetOffsetForHorizontalPerfTest.java @@ -19,8 +19,8 @@ package android.text; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Rule; diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java index 60c6d89b39ce..0b79834bb54c 100644 --- a/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java @@ -19,17 +19,16 @@ package android.text; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.Random; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; @LargeTest @RunWith(AndroidJUnit4.class) diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java index f60cbee62c54..bd7522d0359e 100644 --- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java @@ -21,8 +21,9 @@ import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Rule; diff --git a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java index 25cc7078762a..10bfa4247159 100644 --- a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java +++ b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java @@ -23,11 +23,12 @@ import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; import android.text.NonEditableTextGenerator.TextType; import android.widget.TextView; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java index a482c4a6c2f7..a7a81f2d20bb 100644 --- a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java +++ b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java @@ -18,13 +18,14 @@ package android.textclassifier; import android.content.Context; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; import android.view.textclassifier.ConversationActions; import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassifier; import android.view.textclassifier.TextLanguage; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java b/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java index 0c1f2899690d..b24bf42be632 100644 --- a/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java +++ b/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java @@ -18,8 +18,9 @@ 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 androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java b/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java index 07cd33f09294..26cec952a0e5 100644 --- a/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java +++ b/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java @@ -18,11 +18,11 @@ package android.util.perftests; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; - import android.util.Log; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java index 990be24bc805..a1f8608e197a 100644 --- a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java +++ b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java @@ -17,13 +17,13 @@ package android.view; import android.content.Context; -import android.content.res.Resources; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; import android.widget.FrameLayout; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + import com.android.perftests.core.R; import org.junit.Rule; diff --git a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java index dc4d4bd782fb..b34001dcf6b5 100644 --- a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java +++ b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java @@ -24,14 +24,15 @@ import android.graphics.drawable.ColorDrawable; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; import android.view.View.MeasureSpec; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java index d219d3a28189..b3ea62aa7da0 100644 --- a/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java @@ -19,14 +19,15 @@ package android.widget; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; import android.text.Selection; import android.view.KeyEvent; import android.view.View.MeasureSpec; import android.view.ViewGroup; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; + import org.junit.Assert; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java index b6cf7d3f49c2..aa47d5bdd998 100644 --- a/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java @@ -19,14 +19,15 @@ package android.widget; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; import android.text.Selection; import android.view.KeyEvent; import android.view.View.MeasureSpec; import android.view.ViewGroup; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; + import org.junit.Assert; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java index ce0c35747b3f..e50016c45008 100644 --- a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java @@ -16,10 +16,16 @@ package android.widget; -import java.util.Arrays; -import java.util.Collection; -import java.util.Locale; -import java.util.Random; +import android.app.Activity; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.perftests.utils.StubActivity; +import android.view.KeyEvent; +import android.view.View.MeasureSpec; +import android.view.ViewGroup; + +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; import org.junit.Rule; import org.junit.Test; @@ -27,22 +33,9 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import android.app.Activity; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.util.Log; -import android.view.KeyEvent; -import android.view.RenderNodeAnimator; -import android.view.ViewGroup; -import android.view.View.MeasureSpec; - -import android.perftests.utils.BenchmarkState; -import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; -import android.support.test.rule.ActivityTestRule; -import android.support.test.InstrumentationRegistry; +import java.util.Arrays; +import java.util.Collection; +import java.util.Random; @LargeTest @RunWith(Parameterized.class) diff --git a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java index d570ef3b2de6..644095b36206 100644 --- a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java @@ -16,17 +16,26 @@ package android.widget; +import static android.perftests.utils.LayoutUtils.gatherViewTree; +import static android.perftests.utils.LayoutUtils.requestLayoutForAllNodes; +import static android.view.View.MeasureSpec.AT_MOST; +import static android.view.View.MeasureSpec.EXACTLY; +import static android.view.View.MeasureSpec.UNSPECIFIED; + +import static org.junit.Assert.assertTrue; + import android.app.Activity; import android.os.Looper; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.annotation.UiThreadTest; -import android.support.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; import android.view.View; import android.view.ViewGroup; +import androidx.test.annotation.UiThreadTest; +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; + import com.android.perftests.core.R; import org.junit.Rule; @@ -38,13 +47,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import static android.perftests.utils.LayoutUtils.gatherViewTree; -import static android.perftests.utils.LayoutUtils.requestLayoutForAllNodes; -import static android.view.View.MeasureSpec.AT_MOST; -import static android.view.View.MeasureSpec.EXACTLY; -import static android.view.View.MeasureSpec.UNSPECIFIED; -import static org.junit.Assert.assertTrue; - @LargeTest @RunWith(Parameterized.class) public class LayoutPerfTest { diff --git a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java index c3101664d1ff..bed173bd269a 100644 --- a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java @@ -16,33 +16,27 @@ package android.widget; +import static org.junit.Assert.assertTrue; + import android.app.Activity; import android.os.Looper; -import android.os.Bundle; -import android.perftests.utils.PerfStatusReporter; -import android.util.Log; -import android.view.View; - import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; -import android.support.test.rule.ActivityTestRule; -import android.support.test.InstrumentationRegistry; -import com.android.perftests.core.R; +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; -import java.util.Locale; -import java.util.Collection; -import java.util.Arrays; +import com.android.perftests.core.R; -import org.junit.Test; import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import org.junit.runner.RunWith; -import static org.junit.Assert.assertTrue; +import java.util.Arrays; +import java.util.Collection; @LargeTest @RunWith(Parameterized.class) diff --git a/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java index 4b6da6ba345a..1f008382ae74 100644 --- a/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java @@ -19,23 +19,21 @@ package android.widget; import android.content.Context; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; import android.view.LayoutInflater; -import com.android.perftests.core.R; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; -import java.util.Collection; -import java.util.Arrays; +import com.android.perftests.core.R; -import org.junit.Test; import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import org.junit.runner.RunWith; -import static org.junit.Assert.assertTrue; +import java.util.Arrays; +import java.util.Collection; @LargeTest @RunWith(Parameterized.class) diff --git a/apct-tests/perftests/core/src/android/widget/TextViewOnMeasurePerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewOnMeasurePerfTest.java index a14dd25c4446..88acbba62d40 100644 --- a/apct-tests/perftests/core/src/android/widget/TextViewOnMeasurePerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/TextViewOnMeasurePerfTest.java @@ -25,24 +25,20 @@ import android.content.res.ColorStateList; import android.graphics.Typeface; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.TextAppearanceSpan; -import android.view.LayoutInflater; -import com.android.perftests.core.R; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; -import java.util.Random; -import java.util.Locale; - -import org.junit.Test; import org.junit.Rule; +import org.junit.Test; import org.junit.runner.RunWith; -import static org.junit.Assert.assertTrue; +import java.util.Locale; +import java.util.Random; @LargeTest @RunWith(AndroidJUnit4.class) diff --git a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java index bd9111228eac..0bc9ee4e53ab 100644 --- a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java @@ -24,9 +24,6 @@ import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.runner.AndroidJUnit4; import android.text.BoringLayout; import android.text.Layout; import android.text.PrecomputedText; @@ -34,6 +31,10 @@ import android.text.TextPaint; import android.text.TextPerfUtils; import android.view.View.MeasureSpec; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java index e95676b272fd..00bd8db7f5a3 100644 --- a/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java @@ -19,8 +19,9 @@ package android.widget; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.StubActivity; -import android.support.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; + +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; import org.junit.Rule; import org.junit.Test; diff --git a/api/current.txt b/api/current.txt index 13311d4980da..7e0c33cfb657 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5385,11 +5385,11 @@ package android.app { method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); method public int getSemanticAction(); + method public boolean isContextual(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR; field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5 field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa - field public static final int SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION = 11; // 0xb field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4 field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2 field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3 @@ -5414,6 +5414,7 @@ package android.app { method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method public android.os.Bundle getExtras(); method public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); + method public android.app.Notification.Action.Builder setContextual(boolean); method public android.app.Notification.Action.Builder setSemanticAction(int); } @@ -8531,42 +8532,44 @@ package android.bluetooth { field public static final java.lang.String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY = "android.bluetooth.headset.intent.category.companyid"; } - public final class BluetoothHealth implements android.bluetooth.BluetoothProfile { - method public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration); - method public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int); + public final deprecated class BluetoothHealth implements android.bluetooth.BluetoothProfile { + ctor public BluetoothHealth(); + method public deprecated boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration); + method public deprecated boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int); method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); method public int getConnectionState(android.bluetooth.BluetoothDevice); method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]); - method public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration); - method public boolean registerSinkAppConfiguration(java.lang.String, int, android.bluetooth.BluetoothHealthCallback); - method public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration); - field public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1 - field public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0 - field public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3 - field public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; // 0x2 - field public static final int CHANNEL_TYPE_RELIABLE = 10; // 0xa - field public static final int CHANNEL_TYPE_STREAMING = 11; // 0xb - field public static final int SINK_ROLE = 2; // 0x2 - field public static final int SOURCE_ROLE = 1; // 0x1 - field public static final int STATE_CHANNEL_CONNECTED = 2; // 0x2 - field public static final int STATE_CHANNEL_CONNECTING = 1; // 0x1 - field public static final int STATE_CHANNEL_DISCONNECTED = 0; // 0x0 - field public static final int STATE_CHANNEL_DISCONNECTING = 3; // 0x3 - } - - public final class BluetoothHealthAppConfiguration implements android.os.Parcelable { + method public deprecated android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration); + method public deprecated boolean registerSinkAppConfiguration(java.lang.String, int, android.bluetooth.BluetoothHealthCallback); + method public deprecated boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration); + field public static final deprecated int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1 + field public static final deprecated int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0 + field public static final deprecated int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3 + field public static final deprecated int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; // 0x2 + field public static final deprecated int CHANNEL_TYPE_RELIABLE = 10; // 0xa + field public static final deprecated int CHANNEL_TYPE_STREAMING = 11; // 0xb + field public static final deprecated int SINK_ROLE = 2; // 0x2 + field public static final deprecated int SOURCE_ROLE = 1; // 0x1 + field public static final deprecated int STATE_CHANNEL_CONNECTED = 2; // 0x2 + field public static final deprecated int STATE_CHANNEL_CONNECTING = 1; // 0x1 + field public static final deprecated int STATE_CHANNEL_DISCONNECTED = 0; // 0x0 + field public static final deprecated int STATE_CHANNEL_DISCONNECTING = 3; // 0x3 + } + + public final deprecated class BluetoothHealthAppConfiguration implements android.os.Parcelable { + ctor public BluetoothHealthAppConfiguration(); method public int describeContents(); - method public int getDataType(); - method public java.lang.String getName(); - method public int getRole(); + method public deprecated int getDataType(); + method public deprecated java.lang.String getName(); + method public deprecated int getRole(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHealthAppConfiguration> CREATOR; + field public static final deprecated android.os.Parcelable.Creator<android.bluetooth.BluetoothHealthAppConfiguration> CREATOR; } - public abstract class BluetoothHealthCallback { + public abstract deprecated class BluetoothHealthCallback { ctor public BluetoothHealthCallback(); - method public void onHealthAppConfigurationStatusChange(android.bluetooth.BluetoothHealthAppConfiguration, int); - method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int); + method public deprecated void onHealthAppConfigurationStatusChange(android.bluetooth.BluetoothHealthAppConfiguration, int); + method public deprecated void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int); } public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile { @@ -8663,7 +8666,7 @@ package android.bluetooth { field public static final int GATT = 7; // 0x7 field public static final int GATT_SERVER = 8; // 0x8 field public static final int HEADSET = 1; // 0x1 - field public static final int HEALTH = 3; // 0x3 + field public static final deprecated int HEALTH = 3; // 0x3 field public static final int HID_DEVICE = 19; // 0x13 field public static final int SAP = 10; // 0xa field public static final int STATE_CONNECTED = 2; // 0x2 @@ -10199,6 +10202,7 @@ package android.content { field public static final java.lang.String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED"; field public static final java.lang.String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED"; field public static final java.lang.String ACTION_PASTE = "android.intent.action.PASTE"; + field public static final java.lang.String ACTION_PERMISSION_USAGE_DETAILS = "android.intent.action.PERMISSION_USAGE_DETAILS"; field public static final java.lang.String ACTION_PICK = "android.intent.action.PICK"; field public static final java.lang.String ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY"; field public static final java.lang.String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED"; @@ -10323,6 +10327,7 @@ package android.content { field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE"; field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI"; field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME"; + field public static final java.lang.String EXTRA_PERMISSION_USAGE_PERMISSIONS = "android.intent.extra.PERMISSION_USAGE_PERMISSIONS"; field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"; field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT"; field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY"; @@ -25359,12 +25364,15 @@ package android.media { method public java.lang.Object clearNextDataSources(); method public void clearPendingCommands(); method public void close(); + method public java.lang.Object deselectTrack(int); method public java.lang.Object deselectTrack(android.media.DataSourceDesc, int); method public android.media.AudioAttributes getAudioAttributes(); method public int getAudioSessionId(); + method public long getBufferedPosition(); method public long getBufferedPosition(android.media.DataSourceDesc); method public android.media.DataSourceDesc getCurrentDataSource(); method public long getCurrentPosition(); + method public long getDuration(); method public long getDuration(android.media.DataSourceDesc); method public float getMaxPlayerVolume(); method public android.os.PersistableBundle getMetrics(); @@ -25372,10 +25380,12 @@ package android.media { method public float getPlayerVolume(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); + method public int getSelectedTrack(int); method public int getSelectedTrack(android.media.DataSourceDesc, int); method public int getState(); method public android.media.SyncParams getSyncParams(); method public android.media.MediaTimestamp getTimestamp(); + method public java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo(); method public java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo(android.media.DataSourceDesc); method public android.media.VideoSize getVideoSize(); method public boolean isLooping(); @@ -25389,6 +25399,7 @@ package android.media { method public void reset(); method public java.lang.Object seekTo(long); method public java.lang.Object seekTo(long, int); + method public java.lang.Object selectTrack(int); method public java.lang.Object selectTrack(android.media.DataSourceDesc, int); method public java.lang.Object setAudioAttributes(android.media.AudioAttributes); method public java.lang.Object setAudioSessionId(int); @@ -27145,12 +27156,15 @@ package android.media.session { method public void onSessionEvent(java.lang.String, android.os.Bundle); } - public static final class MediaController.PlaybackInfo { + public static final class MediaController.PlaybackInfo implements android.os.Parcelable { + method public int describeContents(); method public android.media.AudioAttributes getAudioAttributes(); method public int getCurrentVolume(); method public int getMaxVolume(); method public int getPlaybackType(); method public int getVolumeControl(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.media.session.MediaController.PlaybackInfo> CREATOR; field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1 field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2 } @@ -33695,6 +33709,7 @@ package android.os { method public static final void flushPendingCommands(); method public static final int getCallingPid(); method public static final int getCallingUid(); + method public static final int getCallingUidOrThrow(); method public static final android.os.UserHandle getCallingUserHandle(); method public java.lang.String getInterfaceDescriptor(); method public boolean isBinderAlive(); @@ -42758,10 +42773,10 @@ package android.telecom { ctor public CallRedirectionService(); method public final void cancelCall(); method public final android.os.IBinder onBind(android.content.Intent); - method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle); + method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean); method public final boolean onUnbind(android.content.Intent); method public final void placeCallUnmodified(); - method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle); + method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean); field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallRedirectionService"; } @@ -44603,6 +44618,7 @@ package android.telephony { field public static final int DATA_CONNECTING = 1; // 0x1 field public static final int DATA_DISCONNECTED = 0; // 0x0 field public static final int DATA_SUSPENDED = 3; // 0x3 + field public static final int DATA_UNKNOWN = -1; // 0xffffffff field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT"; field public static final java.lang.String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID"; field public static final java.lang.String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME"; @@ -44832,6 +44848,7 @@ package android.telephony.emergency { method public int compareTo(android.telephony.emergency.EmergencyNumber); method public int describeContents(); method public java.lang.String getCountryIso(); + method public int getEmergencyCallRouting(); method public int getEmergencyNumberSourceBitmask(); method public java.util.List<java.lang.Integer> getEmergencyNumberSources(); method public java.util.List<java.lang.Integer> getEmergencyServiceCategories(); @@ -44842,6 +44859,9 @@ package android.telephony.emergency { method public boolean isInEmergencyServiceCategories(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.telephony.emergency.EmergencyNumber> CREATOR; + field public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1; // 0x1 + field public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2; // 0x2 + field public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0; // 0x0 field public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 16; // 0x10 field public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = 8; // 0x8 field public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 4; // 0x4 @@ -53111,6 +53131,7 @@ package android.view.textclassifier { field public static final int CATEGORY_SELECTION = 1; // 0x1 field public static final int CATEGORY_UNDEFINED = 0; // 0x0 field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent> CREATOR; + field public static final int TYPE_ACTIONS_GENERATED = 20; // 0x14 field public static final int TYPE_ACTIONS_SHOWN = 6; // 0x6 field public static final int TYPE_AUTO_SELECTION = 5; // 0x5 field public static final int TYPE_COPY_ACTION = 9; // 0x9 @@ -55425,7 +55446,7 @@ package android.widget { method public int getSourceWidth(); method public int getWidth(); method public float getZoom(); - method public boolean isForcePositionWithinWindowSystemInsetsBounds(); + method public boolean isClippingEnabled(); method public void setZoom(float); method public void show(float, float); method public void show(float, float, float, float); @@ -55438,10 +55459,10 @@ package android.widget { public static class Magnifier.Builder { ctor public Magnifier.Builder(android.view.View); method public android.widget.Magnifier build(); + method public android.widget.Magnifier.Builder setClippingEnabled(boolean); method public android.widget.Magnifier.Builder setCornerRadius(float); method public android.widget.Magnifier.Builder setDefaultSourceToMagnifierOffset(int, int); method public android.widget.Magnifier.Builder setElevation(float); - method public android.widget.Magnifier.Builder setForcePositionWithinWindowSystemInsetsBounds(boolean); method public android.widget.Magnifier.Builder setOverlay(android.graphics.drawable.Drawable); method public android.widget.Magnifier.Builder setSize(int, int); method public android.widget.Magnifier.Builder setSourceBounds(int, int, int, int); diff --git a/api/system-current.txt b/api/system-current.txt index e79ede8dc9b7..cb1e96a2bc82 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -927,6 +927,9 @@ package android.app.usage { method public java.util.Map<java.lang.String, java.lang.Integer> getAppStandbyBuckets(); method public void registerAppUsageObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, android.app.PendingIntent); method public void registerUsageSessionObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit, android.app.PendingIntent, android.app.PendingIntent); + method public void reportUsageStart(android.app.Activity, java.lang.String); + method public void reportUsageStart(android.app.Activity, java.lang.String, long); + method public void reportUsageStop(android.app.Activity, java.lang.String); method public void setAppStandbyBucket(java.lang.String, int); method public void setAppStandbyBuckets(java.util.Map<java.lang.String, java.lang.Integer>); method public void unregisterAppUsageObserver(int); @@ -1071,6 +1074,7 @@ package android.content { field public static final java.lang.String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS"; field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS"; field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS"; + field public static final java.lang.String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES"; field public static final java.lang.String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION"; field public static final java.lang.String ACTION_PACKAGE_ROLLBACK_EXECUTED = "android.intent.action.PACKAGE_ROLLBACK_EXECUTED"; field public static final java.lang.String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED"; @@ -1512,6 +1516,8 @@ package android.hardware.display { public final class BrightnessConfiguration implements android.os.Parcelable { method public int describeContents(); + method public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int); + method public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(java.lang.String); method public android.util.Pair<float[], float[]> getCurve(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR; @@ -1519,10 +1525,22 @@ package android.hardware.display { public static class BrightnessConfiguration.Builder { ctor public BrightnessConfiguration.Builder(float[], float[]); + method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection); + method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(java.lang.String, android.hardware.display.BrightnessCorrection); method public android.hardware.display.BrightnessConfiguration build(); + method public int getMaxCorrectionsByCategory(); + method public int getMaxCorrectionsByPackageName(); method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String); } + public final class BrightnessCorrection implements android.os.Parcelable { + method public float apply(float); + method public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float); + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR; + } + public final class DisplayManager { method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats(); method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration(); @@ -3895,7 +3913,6 @@ package android.net.wifi { method public void disable(int, android.net.wifi.WifiManager.ActionListener); method public void disableEphemeralNetwork(java.lang.String); method public void forget(int, android.net.wifi.WifiManager.ActionListener); - method public java.util.List<android.net.wifi.WifiConfiguration> getAllMatchingWifiConfigs(java.util.List<android.net.wifi.ScanResult>); method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks(); method public android.net.wifi.WifiConfiguration getWifiApConfiguration(); method public int getWifiApState(); @@ -4492,6 +4509,7 @@ package android.os { field public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; // 0xa field public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; // 0x6 field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb + field public static final int PAYLOAD_TIMESTAMP_ERROR = 51; // 0x33 field public static final int POST_INSTALL_RUNNER_ERROR = 5; // 0x5 field public static final int SUCCESS = 0; // 0x0 field public static final int UPDATED_BUT_NOT_ACTIVE = 52; // 0x34 @@ -4596,6 +4614,17 @@ package android.os.storage { package android.permission { + public final class PermissionControllerManager { + method public void revokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.util.concurrent.Executor, android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback); + field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2 + field public static final int REASON_MALWARE = 1; // 0x1 + } + + public static abstract class PermissionControllerManager.OnRevokeRuntimePermissionsCallback { + ctor public PermissionControllerManager.OnRevokeRuntimePermissionsCallback(); + method public abstract void onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>); + } + public abstract class PermissionControllerService extends android.app.Service { ctor public PermissionControllerService(); method public final void attachBaseContext(android.content.Context); @@ -4603,6 +4632,7 @@ package android.permission { method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean); method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String); method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String); + method public abstract java.util.Map<java.lang.String, java.util.List<java.lang.String>> onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.lang.String); field public static final java.lang.String SERVICE_INTERFACE = "android.permission.PermissionControllerService"; } @@ -5128,6 +5158,8 @@ package android.service.autofill.augmented { public abstract class AugmentedAutofillService extends android.app.Service { ctor public AugmentedAutofillService(); + method protected final void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); + method protected void dump(java.io.PrintWriter, java.lang.String[]); method public void onFillRequest(android.service.autofill.augmented.FillRequest, android.os.CancellationSignal, android.service.autofill.augmented.FillController, android.service.autofill.augmented.FillCallback); field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.augmented.AugmentedAutofillService"; } @@ -5398,7 +5430,7 @@ package android.service.notification { method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); method public void onActionClicked(java.lang.String, android.app.Notification.Action, int); method public final android.os.IBinder onBind(android.content.Intent); - method public void onNotificationDirectReply(java.lang.String); + method public void onNotificationDirectReplied(java.lang.String); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel); method public void onNotificationExpansionChanged(java.lang.String, boolean, boolean); @@ -5920,6 +5952,87 @@ package android.telephony { field public static final java.lang.String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string"; } + public final class DataFailCause { + field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e + field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f + field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41 + field public static final int APN_TYPE_CONFLICT = 112; // 0x70 + field public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 122; // 0x7a + field public static final int COMPANION_IFACE_IN_USE = 118; // 0x76 + field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64 + field public static final int EMERGENCY_IFACE_ONLY = 116; // 0x74 + field public static final int EMM_ACCESS_BARRED = 115; // 0x73 + field public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 121; // 0x79 + field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff + field public static final int ESM_INFO_NOT_RECEIVED = 53; // 0x35 + field public static final int FEATURE_NOT_SUPP = 40; // 0x28 + field public static final int FILTER_SEMANTIC_ERROR = 44; // 0x2c + field public static final int FILTER_SYTAX_ERROR = 45; // 0x2d + field public static final int GPRS_REGISTRATION_FAIL = -2; // 0xfffffffe + field public static final int IFACE_AND_POL_FAMILY_MISMATCH = 120; // 0x78 + field public static final int IFACE_MISMATCH = 117; // 0x75 + field public static final int INSUFFICIENT_RESOURCES = 26; // 0x1a + field public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 114; // 0x72 + field public static final int INVALID_MANDATORY_INFO = 96; // 0x60 + field public static final int INVALID_PCSCF_ADDR = 113; // 0x71 + field public static final int INVALID_TRANSACTION_ID = 81; // 0x51 + field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77 + field public static final int LLC_SNDCP = 25; // 0x19 + field public static final int LOST_CONNECTION = 65540; // 0x10004 + field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f + field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61 + field public static final int MISSING_UNKNOWN_APN = 27; // 0x1b + field public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; // 0x65 + field public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 98; // 0x62 + field public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 55; // 0x37 + field public static final int NAS_SIGNALLING = 14; // 0xe + field public static final int NETWORK_FAILURE = 38; // 0x26 + field public static final int NONE = 0; // 0x0 + field public static final int NSAPI_IN_USE = 35; // 0x23 + field public static final int OEM_DCFAILCAUSE_1 = 4097; // 0x1001 + field public static final int OEM_DCFAILCAUSE_10 = 4106; // 0x100a + field public static final int OEM_DCFAILCAUSE_11 = 4107; // 0x100b + field public static final int OEM_DCFAILCAUSE_12 = 4108; // 0x100c + field public static final int OEM_DCFAILCAUSE_13 = 4109; // 0x100d + field public static final int OEM_DCFAILCAUSE_14 = 4110; // 0x100e + field public static final int OEM_DCFAILCAUSE_15 = 4111; // 0x100f + field public static final int OEM_DCFAILCAUSE_2 = 4098; // 0x1002 + field public static final int OEM_DCFAILCAUSE_3 = 4099; // 0x1003 + field public static final int OEM_DCFAILCAUSE_4 = 4100; // 0x1004 + field public static final int OEM_DCFAILCAUSE_5 = 4101; // 0x1005 + field public static final int OEM_DCFAILCAUSE_6 = 4102; // 0x1006 + field public static final int OEM_DCFAILCAUSE_7 = 4103; // 0x1007 + field public static final int OEM_DCFAILCAUSE_8 = 4104; // 0x1008 + field public static final int OEM_DCFAILCAUSE_9 = 4105; // 0x1009 + field public static final int ONLY_IPV4_ALLOWED = 50; // 0x32 + field public static final int ONLY_IPV6_ALLOWED = 51; // 0x33 + field public static final int ONLY_SINGLE_BEARER_ALLOWED = 52; // 0x34 + field public static final int OPERATOR_BARRED = 8; // 0x8 + field public static final int PDN_CONN_DOES_NOT_EXIST = 54; // 0x36 + field public static final int PDP_WITHOUT_ACTIVE_TFT = 46; // 0x2e + field public static final int PREF_RADIO_TECH_CHANGED = -4; // 0xfffffffc + field public static final int PROTOCOL_ERRORS = 111; // 0x6f + field public static final int QOS_NOT_ACCEPTED = 37; // 0x25 + field public static final int RADIO_NOT_AVAILABLE = 65537; // 0x10001 + field public static final int RADIO_POWER_OFF = -5; // 0xfffffffb + field public static final int REGISTRATION_FAIL = -1; // 0xffffffff + field public static final int REGULAR_DEACTIVATION = 36; // 0x24 + field public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 33; // 0x21 + field public static final int SERVICE_OPTION_NOT_SUPPORTED = 32; // 0x20 + field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22 + field public static final int SIGNAL_LOST = -3; // 0xfffffffd + field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa + field public static final int TFT_SEMANTIC_ERROR = 41; // 0x29 + field public static final int TFT_SYTAX_ERROR = 42; // 0x2a + field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27 + field public static final int UNKNOWN = 65536; // 0x10000 + field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63 + field public static final int UNKNOWN_PDP_ADDRESS_TYPE = 28; // 0x1c + field public static final int UNKNOWN_PDP_CONTEXT = 43; // 0x2b + field public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 66; // 0x42 + field public static final int USER_AUTHENTICATION = 29; // 0x1d + } + public class DisconnectCause { field public static final int ALREADY_DIALING = 72; // 0x48 field public static final int ANSWERED_ELSEWHERE = 52; // 0x34 @@ -6087,11 +6200,13 @@ package android.telephony { public class PhoneStateListener { method public void onCallDisconnectCauseChanged(int, int); method public void onPreciseCallStateChanged(android.telephony.PreciseCallState); + method public void onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState); method public void onRadioPowerStateChanged(int); method public void onSrvccStateChanged(int); method public void onVoiceActivationStateChanged(int); field public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000 field public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800 + field public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000 field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000 field public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000 field public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000 @@ -6116,6 +6231,16 @@ package android.telephony { field public static final int PRECISE_CALL_STATE_WAITING = 6; // 0x6 } + public final class PreciseDataConnectionState implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.String getDataConnectionApn(); + method public int getDataConnectionApnTypeBitMask(); + method public int getDataConnectionFailCause(); + method public int getDataConnectionState(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.PreciseDataConnectionState> CREATOR; + } + public class PreciseDisconnectCause { field public static final int ACCESS_CLASS_BLOCKED = 260; // 0x104 field public static final int ACCESS_INFORMATION_DISCARDED = 43; // 0x2b @@ -6318,6 +6443,7 @@ package android.telephony { method public deprecated boolean getDataEnabled(int); method public boolean getEmergencyCallbackMode(); method public java.lang.String getIsimDomain(); + method public java.lang.String getIsimIst(); method public int getPreferredNetworkTypeBitmap(); method public int getRadioPowerState(); method public int getSimApplicationState(); @@ -6718,6 +6844,7 @@ package android.telephony.ims { method public android.os.Bundle getCallExtras(); method public int getCallType(); method public static int getCallTypeFromVideoState(int); + method public int getEmergencyCallRouting(); method public int getEmergencyServiceCategories(); method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile(); method public int getRestrictCause(); @@ -6731,6 +6858,7 @@ package android.telephony.ims { method public void setCallExtraBoolean(java.lang.String, boolean); method public void setCallExtraInt(java.lang.String, int); method public void setCallRestrictCause(int); + method public void setEmergencyCallRouting(int); method public void setEmergencyServiceCategories(int); method public void updateCallExtras(android.telephony.ims.ImsCallProfile); method public void updateCallType(android.telephony.ims.ImsCallProfile); @@ -6860,6 +6988,7 @@ package android.telephony.ims { public class ImsMmTelManager { method public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(android.content.Context, int); method public int getVoWiFiModeSetting(); + method public int getVoWiFiRoamingModeSetting(); method public boolean isAdvancedCallingSettingEnabled(); method public boolean isAvailable(int, int); method public boolean isCapable(int, int); diff --git a/api/test-current.txt b/api/test-current.txt index 1401cbb4211e..ae3c1e027f51 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -394,6 +394,7 @@ package android.content.pm { package android.content.res { public final class Configuration implements java.lang.Comparable android.os.Parcelable { + field public int assetsSeq; field public final android.app.WindowConfiguration windowConfiguration; } @@ -985,6 +986,21 @@ package android.os.strictmode { } +package android.permission { + + public final class PermissionControllerManager { + method public void revokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.util.concurrent.Executor, android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback); + field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2 + field public static final int REASON_MALWARE = 1; // 0x1 + } + + public static abstract class PermissionControllerManager.OnRevokeRuntimePermissionsCallback { + ctor public PermissionControllerManager.OnRevokeRuntimePermissionsCallback(); + method public abstract void onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>); + } + +} + package android.print { public final class PrintJobInfo implements android.os.Parcelable { @@ -1221,7 +1237,7 @@ package android.service.notification { method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); method public void onActionClicked(java.lang.String, android.app.Notification.Action, int); method public final android.os.IBinder onBind(android.content.Intent); - method public void onNotificationDirectReply(java.lang.String); + method public void onNotificationDirectReplied(java.lang.String); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification); method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel); method public void onNotificationExpansionChanged(java.lang.String, boolean, boolean); diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java index 74edffb4738d..0c861cfd3e63 100644 --- a/cmds/input/src/com/android/commands/input/Input.java +++ b/cmds/input/src/com/android/commands/input/Input.java @@ -16,15 +16,20 @@ package com.android.commands.input; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; + import android.hardware.input.InputManager; import android.os.SystemClock; -import android.util.Log; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.ViewConfiguration; +import com.android.internal.os.BaseCommand; + +import java.io.PrintStream; import java.util.HashMap; import java.util.Map; @@ -33,9 +38,14 @@ import java.util.Map; * desired character output. */ -public class Input { +public class Input extends BaseCommand { private static final String TAG = "Input"; private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: "; + private static final String INVALID_DISPLAY_ARGUMENTS = + "Error: Invalid arguments for display ID."; + + private static final float DEFAULT_PRESSURE = 1.0f; + private static final float NO_PRESSURE = 0.0f; private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{ put("keyboard", InputDevice.SOURCE_KEYBOARD); @@ -50,6 +60,7 @@ public class Input { put("joystick", InputDevice.SOURCE_JOYSTICK); }}; + private static final Map<String, InputCmd> COMMANDS = new HashMap<String, InputCmd>(); /** * Command-line entry point. @@ -60,217 +71,292 @@ public class Input { (new Input()).run(args); } - private void run(String[] args) { - if (args.length < 1) { - showUsage(); - return; - } + Input() { + COMMANDS.put("text", new InputText()); + COMMANDS.put("keyevent", new InputKeyEvent()); + COMMANDS.put("tap", new InputTap()); + COMMANDS.put("swipe", new InputSwipe()); + COMMANDS.put("draganddrop", new InputDragAndDrop()); + COMMANDS.put("press", new InputPress()); + COMMANDS.put("roll", new InputRoll()); + COMMANDS.put("motionevent", new InputMotionEvent()); + } - int index = 0; - String command = args[index]; + @Override + public void onRun() throws Exception { + String arg = nextArgRequired(); int inputSource = InputDevice.SOURCE_UNKNOWN; - if (SOURCES.containsKey(command)) { - inputSource = SOURCES.get(command); - index++; - command = args[index]; + + // Get source (optional). + if (SOURCES.containsKey(arg)) { + inputSource = SOURCES.get(arg); + arg = nextArgRequired(); } - final int length = args.length - index; - - try { - if (command.equals("text")) { - if (length == 2) { - inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD); - sendText(inputSource, args[index+1]); - return; - } - } else if (command.equals("keyevent")) { - if (length >= 2) { - final boolean longpress = "--longpress".equals(args[index + 1]); - final int start = longpress ? index + 2 : index + 1; - inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD); - if (args.length > start) { - for (int i = start; i < args.length; i++) { - int keyCode = KeyEvent.keyCodeFromString(args[i]); - sendKeyEvent(inputSource, keyCode, longpress); - } - return; - } - } - } else if (command.equals("tap")) { - if (length == 3) { - inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); - sendTap(inputSource, Float.parseFloat(args[index+1]), - Float.parseFloat(args[index+2])); - return; - } - } else if (command.equals("swipe")) { - int duration = -1; - inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); - switch (length) { - case 6: - duration = Integer.parseInt(args[index+5]); - case 5: - sendSwipe(inputSource, - Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]), - Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]), - duration); - return; - } - } else if (command.equals("draganddrop")) { - int duration = -1; - inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); - switch (length) { - case 6: - duration = Integer.parseInt(args[index+5]); - case 5: - sendDragAndDrop(inputSource, - Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]), - Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]), - duration); - return; - } - } else if (command.equals("press")) { - inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL); - if (length == 1) { - sendTap(inputSource, 0.0f, 0.0f); - return; - } - } else if (command.equals("roll")) { - inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL); - if (length == 3) { - sendMove(inputSource, Float.parseFloat(args[index+1]), - Float.parseFloat(args[index+2])); - return; - } - } else { - System.err.println("Error: Unknown command: " + command); - showUsage(); + + // Get displayId (optional). + int displayId = INVALID_DISPLAY; + if ("-d".equals(arg)) { + displayId = getDisplayId(); + arg = nextArgRequired(); + } + + // Get command and run. + InputCmd cmd = COMMANDS.get(arg); + if (cmd != null) { + try { + cmd.run(inputSource, displayId); return; + } catch (NumberFormatException ex) { + throw new IllegalArgumentException(INVALID_ARGUMENTS + arg); } - } catch (NumberFormatException ex) { } - System.err.println(INVALID_ARGUMENTS + command); - showUsage(); + + throw new IllegalArgumentException("Error: Unknown command: " + arg); } - /** - * Convert the characters of string text into key event's and send to - * device. - * - * @param text is a string of characters you want to input to the device. - */ - private void sendText(int source, String text) { + private int getDisplayId() { + String displayArg = nextArgRequired(); + if ("INVALID_DISPLAY".equalsIgnoreCase(displayArg)) { + return INVALID_DISPLAY; + } else if ("DEFAULT_DISPLAY".equalsIgnoreCase(displayArg)) { + return DEFAULT_DISPLAY; + } else { + try { + final int displayId = Integer.parseInt(displayArg); + if (displayId == INVALID_DISPLAY) { + return INVALID_DISPLAY; + } + return Math.max(displayId, 0); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(INVALID_DISPLAY_ARGUMENTS); + } + } + } - StringBuffer buff = new StringBuffer(text); + class InputText implements InputCmd { + @Override + public void run(int inputSource, int displayId) { + inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD); + sendText(inputSource, nextArgRequired(), displayId); + } - boolean escapeFlag = false; - for (int i=0; i<buff.length(); i++) { - if (escapeFlag) { - escapeFlag = false; - if (buff.charAt(i) == 's') { - buff.setCharAt(i, ' '); - buff.deleteCharAt(--i); + /** + * Convert the characters of string text into key event's and send to + * device. + * + * @param text is a string of characters you want to input to the device. + */ + private void sendText(int source, final String text, int displayId) { + final StringBuffer buff = new StringBuffer(text); + boolean escapeFlag = false; + for (int i = 0; i < buff.length(); i++) { + if (escapeFlag) { + escapeFlag = false; + if (buff.charAt(i) == 's') { + buff.setCharAt(i, ' '); + buff.deleteCharAt(--i); + } + } + if (buff.charAt(i) == '%') { + escapeFlag = true; } } - if (buff.charAt(i) == '%') { - escapeFlag = true; + + final char[] chars = buff.toString().toCharArray(); + final KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); + final KeyEvent[] events = kcm.getEvents(chars); + for (int i = 0; i < events.length; i++) { + KeyEvent e = events[i]; + if (source != e.getSource()) { + e.setSource(source); + } + e.setDisplayId(displayId); + injectKeyEvent(e); } } + } + + class InputKeyEvent implements InputCmd { + @Override + public void run(int inputSource, int displayId) { + String arg = nextArgRequired(); + final boolean longpress = "--longpress".equals(arg); + if (longpress) { + arg = nextArgRequired(); + } + + do { + final int keycode = KeyEvent.keyCodeFromString(arg); + sendKeyEvent(inputSource, keycode, longpress, displayId); + } while ((arg = nextArg()) != null); + } + + private void sendKeyEvent(int inputSource, int keyCode, boolean longpress, int displayId) { + final long now = SystemClock.uptimeMillis(); + int repeatCount = 0; - char[] chars = buff.toString().toCharArray(); + KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, repeatCount, + 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0/*flags*/, + inputSource); + event.setDisplayId(displayId); - KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); - KeyEvent[] events = kcm.getEvents(chars); - for(int i = 0; i < events.length; i++) { - KeyEvent e = events[i]; - if (source != e.getSource()) { - e.setSource(source); + injectKeyEvent(event); + if (longpress) { + repeatCount++; + injectKeyEvent(KeyEvent.changeTimeRepeat(event, now, repeatCount, + KeyEvent.FLAG_LONG_PRESS)); } - injectKeyEvent(e); + injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP)); } } - private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) { - long now = SystemClock.uptimeMillis(); - injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource)); - if (longpress) { - injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS, - inputSource)); + class InputTap implements InputCmd { + @Override + public void run(int inputSource, int displayId) { + inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); + sendTap(inputSource, Float.parseFloat(nextArgRequired()), + Float.parseFloat(nextArgRequired()), displayId); + } + + void sendTap(int inputSource, float x, float y, int displayId) { + final long now = SystemClock.uptimeMillis(); + injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, now, x, y, 1.0f, + displayId); + injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, now, x, y, 0.0f, displayId); } - injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0, - KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource)); } - private void sendTap(int inputSource, float x, float y) { - long now = SystemClock.uptimeMillis(); - injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f); - injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f); + class InputPress extends InputTap { + @Override + public void run(int inputSource, int displayId) { + inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL); + sendTap(inputSource, 0.0f, 0.0f, displayId); + } } - private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2, int duration) { - if (duration < 0) { - duration = 300; + class InputSwipe implements InputCmd { + @Override + public void run(int inputSource, int displayId) { + inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); + sendSwipe(inputSource, displayId, false); } - long now = SystemClock.uptimeMillis(); - injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f); - long startTime = now; - long endTime = startTime + duration; - while (now < endTime) { - long elapsedTime = now - startTime; - float alpha = (float) elapsedTime / duration; - injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha), - lerp(y1, y2, alpha), 1.0f); - now = SystemClock.uptimeMillis(); + + void sendSwipe(int inputSource, int displayId, boolean isDragDrop) { + // Parse two points and duration. + final float x1 = Float.parseFloat(nextArgRequired()); + final float y1 = Float.parseFloat(nextArgRequired()); + final float x2 = Float.parseFloat(nextArgRequired()); + final float y2 = Float.parseFloat(nextArgRequired()); + String durationArg = nextArg(); + int duration = durationArg != null ? Integer.parseInt(durationArg) : -1; + if (duration < 0) { + duration = 300; + } + + final long down = SystemClock.uptimeMillis(); + injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, down, down, x1, y1, 1.0f, + displayId); + if (isDragDrop) { + // long press until drag start. + try { + Thread.sleep(ViewConfiguration.getLongPressTimeout()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + long now = SystemClock.uptimeMillis(); + final long endTime = down + duration; + while (now < endTime) { + final long elapsedTime = now - down; + final float alpha = (float) elapsedTime / duration; + injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, down, now, + lerp(x1, x2, alpha), lerp(y1, y2, alpha), 1.0f, displayId); + now = SystemClock.uptimeMillis(); + } + injectMotionEvent(inputSource, MotionEvent.ACTION_UP, down, now, x2, y2, 0.0f, + displayId); } - injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f); } - private void sendDragAndDrop(int inputSource, float x1, float y1, float x2, float y2, - int dragDuration) { - if (dragDuration < 0) { - dragDuration = 300; + class InputDragAndDrop extends InputSwipe { + @Override + public void run(int inputSource, int displayId) { + inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); + sendSwipe(inputSource, displayId, true); } - long now = SystemClock.uptimeMillis(); - injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f); - try { - Thread.sleep(ViewConfiguration.getLongPressTimeout()); - } catch (InterruptedException e) { - throw new RuntimeException(e); + } + + class InputRoll implements InputCmd { + @Override + public void run(int inputSource, int displayId) { + inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL); + sendMove(inputSource, Float.parseFloat(nextArgRequired()), + Float.parseFloat(nextArgRequired()), displayId); + } + + /** + * Sends a simple zero-pressure move event. + * + * @param inputSource the InputDevice.SOURCE_* sending the input event + * @param dx change in x coordinate due to move + * @param dy change in y coordinate due to move + */ + private void sendMove(int inputSource, float dx, float dy, int displayId) { + final long now = SystemClock.uptimeMillis(); + injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, now, dx, dy, 0.0f, + displayId); + } + } + + class InputMotionEvent implements InputCmd { + @Override + public void run(int inputSource, int displayId) { + inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN); + sendMotionEvent(inputSource, nextArgRequired(), Float.parseFloat(nextArgRequired()), + Float.parseFloat(nextArgRequired()), displayId); } - now = SystemClock.uptimeMillis(); - long startTime = now; - long endTime = startTime + dragDuration; - while (now < endTime) { - long elapsedTime = now - startTime; - float alpha = (float) elapsedTime / dragDuration; - injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha), - lerp(y1, y2, alpha), 1.0f); - now = SystemClock.uptimeMillis(); + + private void sendMotionEvent(int inputSource, String motionEventType, float x, float y, + int displayId) { + final int action; + final float pressure; + + switch (motionEventType.toUpperCase()) { + case "DOWN": + action = MotionEvent.ACTION_DOWN; + pressure = DEFAULT_PRESSURE; + break; + case "UP": + action = MotionEvent.ACTION_UP; + pressure = NO_PRESSURE; + break; + case "MOVE": + action = MotionEvent.ACTION_MOVE; + pressure = DEFAULT_PRESSURE; + break; + default: + throw new IllegalArgumentException("Unknown motionevent " + motionEventType); + } + + final long now = SystemClock.uptimeMillis(); + injectMotionEvent(inputSource, action, now, now, x, y, pressure, displayId); } - injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f); } /** - * Sends a simple zero-pressure move event. - * - * @param inputSource the InputDevice.SOURCE_* sending the input event - * @param dx change in x coordinate due to move - * @param dy change in y coordinate due to move + * Abstract class for command + * use nextArgRequired or nextArg to check next argument if necessary. */ - private void sendMove(int inputSource, float dx, float dy) { - long now = SystemClock.uptimeMillis(); - injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f); + private interface InputCmd { + void run(int inputSource, int displayId); } - private void injectKeyEvent(KeyEvent event) { - Log.i(TAG, "injectKeyEvent: " + event); + private static void injectKeyEvent(KeyEvent event) { InputManager.getInstance().injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); } - private int getInputDeviceId(int inputSource) { + private static int getInputDeviceId(int inputSource) { final int DEFAULT_DEVICE_ID = 0; int[] devIds = InputDevice.getDeviceIds(); for (int devId : devIds) { @@ -287,22 +373,27 @@ public class Input { * * @param inputSource the InputDevice.SOURCE_* sending the input event * @param action the MotionEvent.ACTION_* for the event + * @param downTime the value of the ACTION_DOWN event happened * @param when the value of SystemClock.uptimeMillis() at which the event happened * @param x x coordinate of event * @param y y coordinate of event * @param pressure pressure of event */ - private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) { + private static void injectMotionEvent(int inputSource, int action, long downTime, long when, + float x, float y, float pressure, int displayId) { final float DEFAULT_SIZE = 1.0f; final int DEFAULT_META_STATE = 0; final float DEFAULT_PRECISION_X = 1.0f; final float DEFAULT_PRECISION_Y = 1.0f; final int DEFAULT_EDGE_FLAGS = 0; - MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE, + MotionEvent event = MotionEvent.obtain(downTime, when, action, x, y, pressure, DEFAULT_SIZE, DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, getInputDeviceId(inputSource), DEFAULT_EDGE_FLAGS); event.setSource(inputSource); - Log.i(TAG, "injectMotionEvent: " + event); + if (displayId == INVALID_DISPLAY && (inputSource & InputDevice.SOURCE_CLASS_POINTER) != 0) { + displayId = DEFAULT_DISPLAY; + } + event.setDisplayId(displayId); InputManager.getInstance().injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); } @@ -315,24 +406,30 @@ public class Input { return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource; } - private void showUsage() { - System.err.println("Usage: input [<source>] <command> [<arg>...]"); - System.err.println(); - System.err.println("The sources are: "); + @Override + public void onShowUsage(PrintStream out) { + out.println("Usage: input [<source>] [-d DISPLAY_ID] <command> [<arg>...]"); + out.println(); + out.println("The sources are: "); for (String src : SOURCES.keySet()) { - System.err.println(" " + src); + out.println(" " + src); } - System.err.println(); - System.err.println("The commands and default sources are:"); - System.err.println(" text <string> (Default: touchscreen)"); - System.err.println(" keyevent [--longpress] <key code number or name> ..." + out.println(); + out.printf("-d: specify the display ID.\n" + + " (Default: %d for key event, %d for motion event if not specified.)", + INVALID_DISPLAY, DEFAULT_DISPLAY); + out.println(); + out.println("The commands and default sources are:"); + out.println(" text <string> (Default: touchscreen)"); + out.println(" keyevent [--longpress] <key code number or name> ..." + " (Default: keyboard)"); - System.err.println(" tap <x> <y> (Default: touchscreen)"); - System.err.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]" + out.println(" tap <x> <y> (Default: touchscreen)"); + out.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]" + " (Default: touchscreen)"); - System.err.println(" draganddrop <x1> <y1> <x2> <y2> [duration(ms)]" + out.println(" draganddrop <x1> <y1> <x2> <y2> [duration(ms)]" + " (Default: touchscreen)"); - System.err.println(" press (Default: trackball)"); - System.err.println(" roll <dx> <dy> (Default: trackball)"); + out.println(" press (Default: trackball)"); + out.println(" roll <dx> <dy> (Default: trackball)"); + out.println(" event <DOWN|UP|MOVE> <x> <y> (Default: touchscreen)"); } } diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java index c6d2bc891b18..6788f7d45071 100644 --- a/cmds/media/src/com/android/commands/media/Media.java +++ b/cmds/media/src/com/android/commands/media/Media.java @@ -24,7 +24,7 @@ import android.media.MediaMetadata; import android.media.session.ISessionController; import android.media.session.ISessionControllerCallback; import android.media.session.ISessionManager; -import android.media.session.ParcelableVolumeInfo; +import android.media.session.MediaController.PlaybackInfo; import android.media.session.PlaybackState; import android.os.Bundle; import android.os.HandlerThread; @@ -224,7 +224,7 @@ public class Media extends BaseCommand { } @Override - public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException { + public void onVolumeInfoChanged(PlaybackInfo info) throws RemoteException { System.out.println("onVolumeInfoChanged " + info); } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 5c53a3a585f8..fa3be26a96f7 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -173,6 +173,10 @@ message Atom { WifiRunningStateChanged wifi_running_state_changed = 114; AppCompacted app_compacted = 115; NetworkDnsEventReported network_dns_event_Reported = 116; + DocsUIPickerLaunchedFromReported docs_ui_picker_launched_from_reported = 117; + DocsUIPickResultReported docs_ui_pick_result_reported = 118; + DocsUISearchModeReported docs_ui_search_mode_reported = 119; + DocsUISearchTypeReported docs_ui_search_type_reported = 120; } // Pulled events will start at field 10000. @@ -3656,6 +3660,52 @@ message DocsUIInvalidScopedAccessRequestReported { } /** + * Logs the package name that launches docsui picker mode. + * + * Logged from: + * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java + */ +message DocsUIPickerLaunchedFromReported { + optional string package_name = 1; +} + +/** + * Logs the search type. + * + * Logged from: + * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java + */ +message DocsUISearchTypeReported { + optional android.stats.docsui.SearchType search_type = 1; +} + +/** + * Logs the search mode. + * + * Logged from: + * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java + */ +message DocsUISearchModeReported { + optional android.stats.docsui.SearchMode search_mode = 1; +} + +/** + * Logs the pick result information. + * + * Logged from: + * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java + */ +message DocsUIPickResultReported { + optional int32 total_action_count = 1; + optional int64 duration_millis = 2; + optional int32 file_count= 3; + optional bool is_searching = 4; + optional android.stats.docsui.Root picked_from = 5; + optional android.stats.docsui.MimeType mime_type = 6; + optional int32 repeatedly_pick_times = 7; +} + +/** * Logs when an app's memory is compacted. * * Logged from: diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index 041fbfaff23d..e0e1b7202347 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -56,7 +56,6 @@ Landroid/app/IActivityManager$Stub$Proxy;->getConfiguration()Landroid/content/re Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinder;)I Landroid/app/IActivityManager$Stub$Proxy;->getProcessLimit()I Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J -Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder; Landroid/app/IActivityManager$Stub$Proxy;->setActivityController(Landroid/app/IActivityController;Z)V Landroid/app/IActivityManager$Stub$Proxy;->updatePersistentConfiguration(Landroid/content/res/Configuration;)V @@ -2768,92 +2767,6 @@ 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;->mConnectionParams:Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams; -Lcom/android/internal/telephony/dataconnection/DataConnection;->mDataRegState:I -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;->notifyAllOfConnected(Ljava/lang/String;)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/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;->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;->onActionIntentDataStallAlarm(Landroid/content/Intent;)V -Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentProvisioningApnAlarm(Landroid/content/Intent;)V -Lcom/android/internal/telephony/dataconnection/DcTracker;->onRecordsLoadedOrSubIdChanged()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;->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;->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/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; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 5b8261e38f1e..fdb71bbb93d7 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2158,6 +2158,7 @@ public class Activity extends ContextThemeWrapper * for helping activities determine the proper time to cancel a notification. * * @see #onUserInteraction() + * @see android.content.Intent#FLAG_ACTIVITY_NO_USER_ACTION */ protected void onUserLeaveHint() { } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 0b509169010c..9d44e58112c5 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -314,4 +314,7 @@ public abstract class ActivityManagerInternal { /** Returns mount mode for process running with given pid */ public abstract int getStorageMountMode(int pid, int uid); + + /** Returns true if the given uid is the app in the foreground. */ + public abstract boolean isAppForeground(int uid); } diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 0b5776e89524..57132a72700d 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -37,6 +37,7 @@ import android.view.SurfaceControl; import android.view.SurfaceHolder; import android.view.SurfaceSession; import android.view.SurfaceView; +import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -320,7 +321,7 @@ public class ActivityView extends ViewGroup { public void surfaceCreated(SurfaceHolder surfaceHolder) { mTmpSurface = new Surface(); if (mVirtualDisplay == null) { - initVirtualDisplay(new SurfaceSession(surfaceHolder.getSurface())); + initVirtualDisplay(new SurfaceSession()); if (mVirtualDisplay != null && mActivityViewCallback != null) { mActivityViewCallback.onActivityViewReady(ActivityView.this); } @@ -354,6 +355,12 @@ public class ActivityView extends ViewGroup { } } + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + mSurfaceView.setVisibility(visibility); + } + private void initVirtualDisplay(SurfaceSession surfaceSession) { if (mVirtualDisplay != null) { throw new IllegalStateException("Trying to initialize for the second time."); @@ -382,6 +389,7 @@ public class ActivityView extends ViewGroup { mRootSurfaceControl = new SurfaceControl.Builder(surfaceSession) .setContainerLayer(true) + .setParent(mSurfaceView.getSurfaceControl()) .setName(DISPLAY_NAME) .build(); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index fb519b625012..347973ea3387 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -421,7 +421,6 @@ interface IActivityManager { void resizeDockedStack(in Rect dockedBounds, in Rect tempDockedTaskBounds, in Rect tempDockedTaskInsetBounds, in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds); - boolean isAppForeground(int uid); void removeStack(int stackId); void makePackageIdle(String packageName, int userId); int getMemoryTrimLevel(); diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 3a2038d40952..666f7218a4f2 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -142,19 +142,20 @@ interface IWallpaperManager { * * @param which either {@link WallpaperManager#FLAG_LOCK} * or {@link WallpaperManager#FLAG_SYSTEM} + * @param displayId Which display is interested * @return colors of chosen wallpaper */ - WallpaperColors getWallpaperColors(int which, int userId); + WallpaperColors getWallpaperColors(int which, int userId, int displayId); /** - * Register a callback to receive color updates + * Register a callback to receive color updates from a display */ - void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId); + void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId); /** - * Unregister a callback that was receiving color updates + * Unregister a callback that was receiving color updates from a display */ - void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId); + void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId); /** * Called from SystemUI when it shows the AoD UI. diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index e066f06542c3..b657a916604b 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1427,18 +1427,13 @@ public class Notification implements Parcelable */ public static final int SEMANTIC_ACTION_CALL = 10; - /** - * {@code SemanticAction}: Contextual action - dependent on the current notification. E.g. - * open a Map application with an address shown in the notification. - */ - public static final int SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION = 11; - private final Bundle mExtras; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Icon mIcon; private final RemoteInput[] mRemoteInputs; private boolean mAllowGeneratedReplies = true; private final @SemanticAction int mSemanticAction; + private final boolean mIsContextual; /** * Small icon representing the action. @@ -1474,6 +1469,7 @@ public class Notification implements Parcelable mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR); mAllowGeneratedReplies = in.readInt() == 1; mSemanticAction = in.readInt(); + mIsContextual = in.readInt() == 1; } /** @@ -1482,13 +1478,13 @@ public class Notification implements Parcelable @Deprecated public Action(int icon, CharSequence title, PendingIntent intent) { this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true, - SEMANTIC_ACTION_NONE); + SEMANTIC_ACTION_NONE, false /* isContextual */); } /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */ private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, RemoteInput[] remoteInputs, boolean allowGeneratedReplies, - @SemanticAction int semanticAction) { + @SemanticAction int semanticAction, boolean isContextual) { this.mIcon = icon; if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) { this.icon = icon.getResId(); @@ -1499,6 +1495,7 @@ public class Notification implements Parcelable this.mRemoteInputs = remoteInputs; this.mAllowGeneratedReplies = allowGeneratedReplies; this.mSemanticAction = semanticAction; + this.mIsContextual = isContextual; } /** @@ -1546,6 +1543,15 @@ public class Notification implements Parcelable } /** + * Returns whether this is a contextual Action, i.e. whether the action is dependent on the + * notification message body. An example of a contextual action could be an action opening a + * map application with an address shown in the notification. + */ + public boolean isContextual() { + return mIsContextual; + } + + /** * Get the list of inputs to be collected from the user that ONLY accept data when this * action is sent. These remote inputs are guaranteed to return true on a call to * {@link RemoteInput#isDataOnly}. @@ -1570,6 +1576,7 @@ public class Notification implements Parcelable private final Bundle mExtras; private ArrayList<RemoteInput> mRemoteInputs; private @SemanticAction int mSemanticAction; + private boolean mIsContextual; /** * Construct a new builder for {@link Action} object. @@ -1684,6 +1691,16 @@ public class Notification implements Parcelable } /** + * Sets whether this {@link Action} is a contextual action, i.e. whether the action is + * dependent on the notification message body. An example of a contextual action could + * be an action opening a map application with an address shown in the notification. + */ + public Builder setContextual(boolean isContextual) { + mIsContextual = isContextual; + return this; + } + + /** * Apply an extender to this action builder. Extenders may be used to add * metadata or change options on this builder. */ @@ -1697,7 +1714,7 @@ public class Notification implements Parcelable * necessary to display the action. */ private void checkContextualActionNullFields() { - if (mSemanticAction != SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) return; + if (!mIsContextual) return; if (mIcon == null) { throw new NullPointerException("Contextual Actions must contain a valid icon"); @@ -1743,7 +1760,7 @@ public class Notification implements Parcelable RemoteInput[] textInputsArr = textInputs.isEmpty() ? null : textInputs.toArray(new RemoteInput[textInputs.size()]); return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr, - mAllowGeneratedReplies, mSemanticAction); + mAllowGeneratedReplies, mSemanticAction, mIsContextual); } } @@ -1756,7 +1773,8 @@ public class Notification implements Parcelable mExtras == null ? new Bundle() : new Bundle(mExtras), getRemoteInputs(), getAllowGeneratedReplies(), - getSemanticAction()); + getSemanticAction(), + isContextual()); } @Override @@ -1784,6 +1802,7 @@ public class Notification implements Parcelable out.writeTypedArray(mRemoteInputs, flags); out.writeInt(mAllowGeneratedReplies ? 1 : 0); out.writeInt(mSemanticAction); + out.writeInt(mIsContextual ? 1 : 0); } public static final Parcelable.Creator<Action> CREATOR = @@ -2073,8 +2092,7 @@ public class Notification implements Parcelable SEMANTIC_ACTION_UNMUTE, SEMANTIC_ACTION_THUMBS_UP, SEMANTIC_ACTION_THUMBS_DOWN, - SEMANTIC_ACTION_CALL, - SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION + SEMANTIC_ACTION_CALL }) @Retention(RetentionPolicy.SOURCE) public @interface SemanticAction {} @@ -3230,8 +3248,7 @@ public class Notification implements Parcelable } /** - * Returns the actions that are contextual (marked as SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) out - * of the actions in this notification. + * Returns the actions that are contextual out of the actions in this notification. * * @hide */ @@ -3240,8 +3257,7 @@ public class Notification implements Parcelable List<Notification.Action> contextualActions = new ArrayList<>(); for (Notification.Action action : actions) { - if (action.getSemanticAction() - == Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) { + if (action.isContextual()) { contextualActions.add(action); } } @@ -5062,8 +5078,7 @@ public class Notification implements Parcelable List<Notification.Action> actions) { List<Notification.Action> nonContextualActions = new ArrayList<>(); for (Notification.Action action : actions) { - if (action.getSemanticAction() - != Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) { + if (!action.isContextual()) { nonContextualActions.add(action); } } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 27ae0b0314d0..a929fe0f688e 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -307,13 +307,14 @@ public class WallpaperManager { * @param callback Listener * @param handler Thread to call it from. Main thread if null. * @param userId Owner of the wallpaper or UserHandle.USER_ALL + * @param displayId Caller comes from which display */ public void addOnColorsChangedListener(@NonNull OnColorsChangedListener callback, - @Nullable Handler handler, int userId) { + @Nullable Handler handler, int userId, int displayId) { synchronized (this) { if (!mColorCallbackRegistered) { try { - mService.registerWallpaperColorsCallback(this, userId); + mService.registerWallpaperColorsCallback(this, userId, displayId); mColorCallbackRegistered = true; } catch (RemoteException e) { // Failed, service is gone @@ -329,16 +330,17 @@ public class WallpaperManager { * * @param callback listener * @param userId Owner of the wallpaper or UserHandle.USER_ALL + * @param displayId Which display is interested */ public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback, - int userId) { + int userId, int displayId) { synchronized (this) { mColorListeners.removeIf(pair -> pair.first == callback); if (mColorListeners.size() == 0 && mColorCallbackRegistered) { mColorCallbackRegistered = false; try { - mService.unregisterWallpaperColorsCallback(this, userId); + mService.unregisterWallpaperColorsCallback(this, userId, displayId); } catch (RemoteException e) { // Failed, service is gone Log.w(TAG, "Can't unregister color updates", e); @@ -370,14 +372,14 @@ public class WallpaperManager { } } - WallpaperColors getWallpaperColors(int which, int userId) { + WallpaperColors getWallpaperColors(int which, int userId, int displayId) { if (which != FLAG_LOCK && which != FLAG_SYSTEM) { throw new IllegalArgumentException( "Must request colors for exactly one kind of wallpaper"); } try { - return mService.getWallpaperColors(which, userId); + return mService.getWallpaperColors(which, userId, displayId); } catch (RemoteException e) { // Can't get colors, connection lost. } @@ -894,7 +896,7 @@ public class WallpaperManager { @UnsupportedAppUsage public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener, @NonNull Handler handler, int userId) { - sGlobals.addOnColorsChangedListener(listener, handler, userId); + sGlobals.addOnColorsChangedListener(listener, handler, userId, mContext.getDisplayId()); } /** @@ -913,7 +915,7 @@ public class WallpaperManager { */ public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback, int userId) { - sGlobals.removeOnColorsChangedListener(callback, userId); + sGlobals.removeOnColorsChangedListener(callback, userId, mContext.getDisplayId()); } /** @@ -947,7 +949,7 @@ public class WallpaperManager { */ @UnsupportedAppUsage public @Nullable WallpaperColors getWallpaperColors(int which, int userId) { - return sGlobals.getWallpaperColors(which, userId); + return sGlobals.getWallpaperColors(which, userId, mContext.getDisplayId()); } /** diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 4d52263c1d78..bbae7d3463ae 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -55,4 +55,8 @@ interface IUsageStatsManager { long sessionThresholdTimeMs, in PendingIntent limitReachedCallbackIntent, in PendingIntent sessionEndCallbackIntent, String callingPackage); void unregisterUsageSessionObserver(int sessionObserverId, String callingPackage); + void reportUsageStart(in IBinder activity, String token, String callingPackage); + void reportPastUsageStart(in IBinder activity, String token, long timeAgoMs, + String callingPackage); + void reportUsageStop(in IBinder activity, String token, String callingPackage); } diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 26beb45be13f..605deac80994 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -23,6 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; +import android.app.Activity; import android.app.PendingIntent; import android.content.Context; import android.content.pm.ParceledListSlice; @@ -579,15 +580,18 @@ public final class UsageStatsManager { /** * @hide * Register an app usage limit observer that receives a callback on the provided intent when - * the sum of usages of apps in the packages array exceeds the {@code timeLimit} specified. The - * observer will automatically be unregistered when the time limit is reached and the intent - * is delivered. Registering an {@code observerId} that was already registered will override - * the previous one. No more than 1000 unique {@code observerId} may be registered by a single - * uid at any one time. + * the sum of usages of apps and tokens in the {@code observed} array exceeds the + * {@code timeLimit} specified. The structure of a token is a String with the reporting + * package's name and a token the reporting app will use, separated by the forward slash + * character. Example: com.reporting.package/5OM3*0P4QU3-7OK3N + * The observer will automatically be unregistered when the time limit is reached and the + * intent is delivered. Registering an {@code observerId} that was already registered will + * override the previous one. No more than 1000 unique {@code observerId} may be registered by + * a single uid at any one time. * @param observerId A unique id associated with the group of apps to be monitored. There can * be multiple groups with common packages and different time limits. - * @param packages The list of packages to observe for foreground activity time. Cannot be null - * and must include at least one package. + * @param observedEntities The list of packages and token to observe for usage time. Cannot be + * null and must include at least one package or token. * @param timeLimit The total time the set of apps can be in the foreground before the * callbackIntent is delivered. Must be at least one minute. * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null. @@ -600,11 +604,11 @@ public final class UsageStatsManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) - public void registerAppUsageObserver(int observerId, @NonNull String[] packages, long timeLimit, - @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) { + public void registerAppUsageObserver(int observerId, @NonNull String[] observedEntities, + long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) { try { - mService.registerAppUsageObserver(observerId, packages, timeUnit.toMillis(timeLimit), - callbackIntent, mContext.getOpPackageName()); + mService.registerAppUsageObserver(observerId, observedEntities, + timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -631,18 +635,21 @@ public final class UsageStatsManager { /** * Register a usage session observer that receives a callback on the provided {@code - * limitReachedCallbackIntent} when the sum of usages of apps in the packages array exceeds - * the {@code timeLimit} specified within a usage session. After the {@code timeLimit} has - * been reached, the usage session observer will receive a callback on the provided {@code - * sessionEndCallbackIntent} when the usage session ends. Registering another session - * observer against a {@code sessionObserverId} that has already been registered will - * override the previous session observer. + * limitReachedCallbackIntent} when the sum of usages of apps and tokens in the {@code + * observed} array exceeds the {@code timeLimit} specified within a usage session. The + * structure of a token is a String with the reporting packages' name and a token the + * reporting app will use, separated by the forward slash character. + * Example: com.reporting.package/5OM3*0P4QU3-7OK3N + * After the {@code timeLimit} has been reached, the usage session observer will receive a + * callback on the provided {@code sessionEndCallbackIntent} when the usage session ends. + * Registering another session observer against a {@code sessionObserverId} that has already + * been registered will override the previous session observer. * * @param sessionObserverId A unique id associated with the group of apps to be * monitored. There can be multiple groups with common * packages and different time limits. - * @param packages The list of packages to observe for foreground activity time. Cannot be null - * and must include at least one package. + * @param observedEntities The list of packages and token to observe for usage time. Cannot be + * null and must include at least one package or token. * @param timeLimit The total time the set of apps can be used continuously before the {@code * limitReachedCallbackIntent} is delivered. Must be at least one minute. * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null. @@ -668,13 +675,13 @@ public final class UsageStatsManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) - public void registerUsageSessionObserver(int sessionObserverId, @NonNull String[] packages, - long timeLimit, @NonNull TimeUnit timeUnit, long sessionThresholdTime, - @NonNull TimeUnit sessionThresholdTimeUnit, + public void registerUsageSessionObserver(int sessionObserverId, + @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit, + long sessionThresholdTime, @NonNull TimeUnit sessionThresholdTimeUnit, @NonNull PendingIntent limitReachedCallbackIntent, @Nullable PendingIntent sessionEndCallbackIntent) { try { - mService.registerUsageSessionObserver(sessionObserverId, packages, + mService.registerUsageSessionObserver(sessionObserverId, observedEntities, timeUnit.toMillis(timeLimit), sessionThresholdTimeUnit.toMillis(sessionThresholdTime), limitReachedCallbackIntent, sessionEndCallbackIntent, @@ -704,6 +711,71 @@ public final class UsageStatsManager { } } + /** + * Report usage associated with a particular {@code token} has started. Tokens are app defined + * strings used to represent usage of in-app features. Apps with the {@link + * android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time limit observers + * to monitor the usage of a token. In app usage can only associated with an {@code activity} + * and usage will be considered stopped if the activity stops or crashes. + * @see #registerAppUsageObserver + * @see #registerUsageSessionObserver + * + * @param activity The activity {@code token} is associated with. + * @param token The token to report usage against. + * @hide + */ + @SystemApi + public void reportUsageStart(@NonNull Activity activity, @NonNull String token) { + try { + mService.reportUsageStart(activity.getActivityToken(), token, + mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Report usage associated with a particular {@code token} had started some amount of time in + * the past. Tokens are app defined strings used to represent usage of in-app features. Apps + * with the {@link android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time + * limit observers to monitor the usage of a token. In app usage can only associated with an + * {@code activity} and usage will be considered stopped if the activity stops or crashes. + * @see #registerAppUsageObserver + * @see #registerUsageSessionObserver + * + * @param activity The activity {@code token} is associated with. + * @param token The token to report usage against. + * @param timeAgoMs How long ago the start of usage took place + * @hide + */ + @SystemApi + public void reportUsageStart(@NonNull Activity activity, @NonNull String token, + long timeAgoMs) { + try { + mService.reportPastUsageStart(activity.getActivityToken(), token, timeAgoMs, + mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Report the usage associated with a particular {@code token} has stopped. + * + * @param activity The activity {@code token} is associated with. + * @param token The token to report usage against. + * @hide + */ + @SystemApi + public void reportUsageStop(@NonNull Activity activity, @NonNull String token) { + try { + mService.reportUsageStop(activity.getActivityToken(), token, + mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** @hide */ public static String reasonToString(int standbyReason) { StringBuilder sb = new StringBuilder(); diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index c740c42c9c0d..3e9dd2882600 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -375,12 +375,12 @@ public class AppWidgetHostView extends FrameLayout { } /** - * Sets whether the widget should is being displayed on a light/white background and use an + * Sets whether the widget is being displayed on a light/white background and use an * alternate UI if available. * @see RemoteViews#setLightBackgroundLayoutId(int) */ - public void setOnLightBackground(boolean useDarkTextLayout) { - mOnLightBackground = useDarkTextLayout; + public void setOnLightBackground(boolean onLightBackground) { + mOnLightBackground = onLightBackground; } /** diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 87b64797f3c6..1945b2fd51de 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -2066,8 +2066,7 @@ public final class BluetoothAdapter { * Get the current connection state of a profile. * This function can be used to check whether the local Bluetooth adapter * is connected to any remote device for a specific profile. - * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, - * {@link BluetoothProfile#A2DP}. + * Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. * * <p> Return value can be one of * {@link BluetoothProfile#STATE_DISCONNECTED}, @@ -2441,16 +2440,15 @@ public final class BluetoothAdapter { /** * Get the profile proxy object associated with the profile. * - * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, - * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or - * {@link BluetoothProfile#GATT_SERVER}. Clients must implement - * {@link BluetoothProfile.ServiceListener} to get notified of - * the connection status and to get the proxy object. + * <p>Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}, + * {@link BluetoothProfile#GATT}, or {@link BluetoothProfile#GATT_SERVER}. Clients must + * implement {@link BluetoothProfile.ServiceListener} to get notified of the connection status + * and to get the proxy object. * * @param context Context of the application * @param listener The service Listener for connection callbacks. - * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, {@link - * BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. {@link BluetoothProfile#GATT} or + * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET}, + * {@link BluetoothProfile#A2DP}. {@link BluetoothProfile#GATT} or * {@link BluetoothProfile#GATT_SERVER}. * @return true on success, false on error */ @@ -2479,8 +2477,8 @@ public final class BluetoothAdapter { BluetoothPan pan = new BluetoothPan(context, listener); return true; } else if (profile == BluetoothProfile.HEALTH) { - BluetoothHealth health = new BluetoothHealth(context, listener); - return true; + Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated"); + return false; } else if (profile == BluetoothProfile.MAP) { BluetoothMap map = new BluetoothMap(context, listener); return true; @@ -2512,8 +2510,7 @@ public final class BluetoothAdapter { * * <p> Clients should call this when they are no longer using * the proxy obtained from {@link #getProfileProxy}. - * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or - * {@link BluetoothProfile#A2DP} + * Profile can be one of {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP} * * @param profile * @param proxy Profile proxy object @@ -2548,10 +2545,6 @@ public final class BluetoothAdapter { BluetoothPan pan = (BluetoothPan) proxy; pan.close(); break; - case BluetoothProfile.HEALTH: - BluetoothHealth health = (BluetoothHealth) proxy; - health.close(); - break; case BluetoothProfile.GATT: BluetoothGatt gatt = (BluetoothGatt) proxy; gatt.close(); diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java index 22d41d9c896e..e2e56fd02ab7 100644 --- a/core/java/android/bluetooth/BluetoothHealth.java +++ b/core/java/android/bluetooth/BluetoothHealth.java @@ -16,15 +16,7 @@ package android.bluetooth; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Binder; -import android.os.IBinder; import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.os.UserHandle; import android.util.Log; import java.util.ArrayList; @@ -54,79 +46,59 @@ import java.util.List; * <li> When done, close the health channel by calling {@link #disconnectChannel} * and unregister the application configuration calling * {@link #unregisterAppConfiguration} + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New apps + * should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ +@Deprecated public final class BluetoothHealth implements BluetoothProfile { private static final String TAG = "BluetoothHealth"; - private static final boolean DBG = true; - private static final boolean VDBG = false; - /** * Health Profile Source Role - the health device. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public static final int SOURCE_ROLE = 1 << 0; /** * Health Profile Sink Role the device talking to the health device. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public static final int SINK_ROLE = 1 << 1; /** * Health Profile - Channel Type used - Reliable + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public static final int CHANNEL_TYPE_RELIABLE = 10; /** * Health Profile - Channel Type used - Streaming + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public static final int CHANNEL_TYPE_STREAMING = 11; - /** - * @hide - */ - public static final int CHANNEL_TYPE_ANY = 12; - - /** @hide */ - public static final int HEALTH_OPERATION_SUCCESS = 6000; - /** @hide */ - public static final int HEALTH_OPERATION_ERROR = 6001; - /** @hide */ - public static final int HEALTH_OPERATION_INVALID_ARGS = 6002; - /** @hide */ - public static final int HEALTH_OPERATION_GENERIC_FAILURE = 6003; - /** @hide */ - public static final int HEALTH_OPERATION_NOT_FOUND = 6004; - /** @hide */ - public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005; - - private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = - new IBluetoothStateChangeCallback.Stub() { - public void onBluetoothStateChange(boolean up) { - if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); - if (!up) { - if (VDBG) Log.d(TAG, "Unbinding service..."); - synchronized (mConnection) { - try { - mService = null; - mContext.unbindService(mConnection); - } catch (Exception re) { - Log.e(TAG, "", re); - } - } - } else { - synchronized (mConnection) { - try { - if (mService == null) { - if (VDBG) Log.d(TAG, "Binding service..."); - doBind(); - } - } catch (Exception re) { - Log.e(TAG, "", re); - } - } - } - } - }; - /** * Register an application configuration that acts as a Health SINK. @@ -142,53 +114,17 @@ public final class BluetoothHealth implements BluetoothProfile { * @param callback A callback to indicate success or failure of the registration and all * operations done on this application configuration. * @return If true, callback will be called. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public boolean registerSinkAppConfiguration(String name, int dataType, BluetoothHealthCallback callback) { - if (!isEnabled() || name == null) return false; - - if (VDBG) log("registerSinkApplication(" + name + ":" + dataType + ")"); - return registerAppConfiguration(name, dataType, SINK_ROLE, - CHANNEL_TYPE_ANY, callback); - } - - /** - * Register an application configuration that acts as a Health SINK or in a Health - * SOURCE role.This is an asynchronous call and so - * the callback is used to notify success or failure if the function returns true. - * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param name The friendly name associated with the application or configuration. - * @param dataType The dataType of the Source role of Health Profile. - * @param channelType The channel type. Will be one of {@link #CHANNEL_TYPE_RELIABLE} or {@link - * #CHANNEL_TYPE_STREAMING} - * @param callback - A callback to indicate success or failure. - * @return If true, callback will be called. - * @hide - */ - public boolean registerAppConfiguration(String name, int dataType, int role, - int channelType, BluetoothHealthCallback callback) { - boolean result = false; - if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result; - - if (VDBG) log("registerApplication(" + name + ":" + dataType + ")"); - BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback); - BluetoothHealthAppConfiguration config = - new BluetoothHealthAppConfiguration(name, dataType, role, channelType); - - final IBluetoothHealth service = mService; - if (service != null) { - try { - result = service.registerAppConfiguration(config, wrapper); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } - return result; + Log.e(TAG, "registerSinkAppConfiguration(): BluetoothHealth is deprecated"); + return false; } /** @@ -199,22 +135,16 @@ public final class BluetoothHealth implements BluetoothProfile { * * @param config The health app configuration * @return Success or failure. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) { - boolean result = false; - final IBluetoothHealth service = mService; - if (service != null && isEnabled() && config != null) { - try { - result = service.unregisterAppConfiguration(config); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } - - return result; + Log.e(TAG, "unregisterAppConfiguration(): BluetoothHealth is deprecated"); + return false; } /** @@ -228,49 +158,16 @@ public final class BluetoothHealth implements BluetoothProfile { * @param config The application configuration which has been registered using {@link * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) } * @return If true, the callback associated with the application config will be called. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public boolean connectChannelToSource(BluetoothDevice device, BluetoothHealthAppConfiguration config) { - final IBluetoothHealth service = mService; - if (service != null && isEnabled() && isValidDevice(device) && config != null) { - try { - return service.connectChannelToSource(device, config); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } - return false; - } - - /** - * Connect to a health device which has the {@link #SINK_ROLE}. - * This is an asynchronous call. If this function returns true, the callback - * associated with the application configuration will be called. - * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param device The remote Bluetooth device. - * @param config The application configuration which has been registered using {@link - * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) } - * @return If true, the callback associated with the application config will be called. - * @hide - */ - public boolean connectChannelToSink(BluetoothDevice device, - BluetoothHealthAppConfiguration config, int channelType) { - final IBluetoothHealth service = mService; - if (service != null && isEnabled() && isValidDevice(device) && config != null) { - try { - return service.connectChannelToSink(device, config, channelType); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } + Log.e(TAG, "connectChannelToSource(): BluetoothHealth is deprecated"); return false; } @@ -286,20 +183,16 @@ public final class BluetoothHealth implements BluetoothProfile { * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) } * @param channelId The channel id associated with the channel * @return If true, the callback associated with the application config will be called. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public boolean disconnectChannel(BluetoothDevice device, BluetoothHealthAppConfiguration config, int channelId) { - final IBluetoothHealth service = mService; - if (service != null && isEnabled() && isValidDevice(device) && config != null) { - try { - return service.disconnectChannel(device, config, channelId); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } + Log.e(TAG, "disconnectChannel(): BluetoothHealth is deprecated"); return false; } @@ -315,20 +208,16 @@ public final class BluetoothHealth implements BluetoothProfile { * @param device The remote Bluetooth health device * @param config The application configuration * @return null on failure, ParcelFileDescriptor on success. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device, BluetoothHealthAppConfiguration config) { - final IBluetoothHealth service = mService; - if (service != null && isEnabled() && isValidDevice(device) && config != null) { - try { - return service.getMainChannelFd(device, config); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } + Log.e(TAG, "getMainChannelFd(): BluetoothHealth is deprecated"); return null; } @@ -348,17 +237,7 @@ public final class BluetoothHealth implements BluetoothProfile { */ @Override public int getConnectionState(BluetoothDevice device) { - final IBluetoothHealth service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { - try { - return service.getHealthDeviceConnectionState(device); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); - } + Log.e(TAG, "getConnectionState(): BluetoothHealth is deprecated"); return STATE_DISCONNECTED; } @@ -378,17 +257,8 @@ public final class BluetoothHealth implements BluetoothProfile { */ @Override public List<BluetoothDevice> getConnectedDevices() { - final IBluetoothHealth service = mService; - if (service != null && isEnabled()) { - try { - return service.getConnectedHealthDevices(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); - } - } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + Log.e(TAG, "getConnectedDevices(): BluetoothHealth is deprecated"); + return new ArrayList<>(); } /** @@ -410,163 +280,81 @@ public final class BluetoothHealth implements BluetoothProfile { */ @Override public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { - final IBluetoothHealth service = mService; - if (service != null && isEnabled()) { - try { - return service.getHealthDevicesMatchingConnectionStates(states); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); - } - } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + Log.e(TAG, "getDevicesMatchingConnectionStates(): BluetoothHealth is deprecated"); + return new ArrayList<>(); } - private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub { - private BluetoothHealthCallback mCallback; - - public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) { - mCallback = callback; - } - - @Override - public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config, - int status) { - mCallback.onHealthAppConfigurationStatusChange(config, status); - } - - @Override - public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config, - BluetoothDevice device, int prevState, int newState, - ParcelFileDescriptor fd, int channelId) { - mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd, - channelId); - } - } - - /** Health Channel Connection State - Disconnected */ + /** Health Channel Connection State - Disconnected + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} + */ + @Deprecated public static final int STATE_CHANNEL_DISCONNECTED = 0; - /** Health Channel Connection State - Connecting */ + /** Health Channel Connection State - Connecting + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} + */ + @Deprecated public static final int STATE_CHANNEL_CONNECTING = 1; - /** Health Channel Connection State - Connected */ + /** Health Channel Connection State - Connected + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} + */ + @Deprecated public static final int STATE_CHANNEL_CONNECTED = 2; - /** Health Channel Connection State - Disconnecting */ + /** Health Channel Connection State - Disconnecting + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} + */ + @Deprecated public static final int STATE_CHANNEL_DISCONNECTING = 3; - /** Health App Configuration registration success */ + /** Health App Configuration registration success + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} + */ + @Deprecated public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; - /** Health App Configuration registration failure */ + /** Health App Configuration registration failure + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} + */ + @Deprecated public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; - /** Health App Configuration un-registration success */ + /** Health App Configuration un-registration success + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} + */ + @Deprecated public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; - /** Health App Configuration un-registration failure */ - public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; - - private Context mContext; - private ServiceListener mServiceListener; - private volatile IBluetoothHealth mService; - BluetoothAdapter mAdapter; - - /** - * Create a BluetoothHealth proxy object. + /** Health App Configuration un-registration failure + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ - /*package*/ BluetoothHealth(Context context, ServiceListener l) { - mContext = context; - mServiceListener = l; - mAdapter = BluetoothAdapter.getDefaultAdapter(); - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - } - - doBind(); - } - - boolean doBind() { - Intent intent = new Intent(IBluetoothHealth.class.getName()); - ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); - intent.setComponent(comp); - if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, - UserHandle.CURRENT_OR_SELF)) { - Log.e(TAG, "Could not bind to Bluetooth Health Service with " + intent); - return false; - } - return true; - } - - /*package*/ void close() { - if (VDBG) log("close()"); - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); - } catch (Exception e) { - Log.e(TAG, "", e); - } - } - - synchronized (mConnection) { - if (mService != null) { - try { - mService = null; - mContext.unbindService(mConnection); - } catch (Exception re) { - Log.e(TAG, "", re); - } - } - } - mServiceListener = null; - } - - private final ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothHealth.Stub.asInterface(Binder.allowBlocking(service)); - - if (mServiceListener != null) { - mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this); - } - } - - public void onServiceDisconnected(ComponentName className) { - if (DBG) Log.d(TAG, "Proxy object disconnected"); - mService = null; - if (mServiceListener != null) { - mServiceListener.onServiceDisconnected(BluetoothProfile.HEALTH); - } - } - }; - - private boolean isEnabled() { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - - if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true; - log("Bluetooth is Not enabled"); - return false; - } - - private static boolean isValidDevice(BluetoothDevice device) { - return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); - } - - private boolean checkAppParam(String name, int role, int channelType, - BluetoothHealthCallback callback) { - if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE) - || (channelType != CHANNEL_TYPE_RELIABLE && channelType != CHANNEL_TYPE_STREAMING - && channelType != CHANNEL_TYPE_ANY) - || callback == null) { - return false; - } - if (role == SOURCE_ROLE && channelType == CHANNEL_TYPE_ANY) return false; - return true; - } - - private static void log(String msg) { - Log.d(TAG, msg); - } + @Deprecated + public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; } diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java index 7c9db6f7213c..9788bbf74e3e 100644 --- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java +++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java @@ -25,72 +25,14 @@ import android.os.Parcelable; * the {@link BluetoothHealth} class. This class represents an application configuration * that the Bluetooth Health third party application will register to communicate with the * remote Bluetooth health device. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ +@Deprecated public final class BluetoothHealthAppConfiguration implements Parcelable { - private final String mName; - private final int mDataType; - private final int mRole; - private final int mChannelType; - - /** - * Constructor to register the SINK role - * - * @param name Friendly name associated with the application configuration - * @param dataType Data Type of the remote Bluetooth Health device - * @hide - */ - BluetoothHealthAppConfiguration(String name, int dataType) { - mName = name; - mDataType = dataType; - mRole = BluetoothHealth.SINK_ROLE; - mChannelType = BluetoothHealth.CHANNEL_TYPE_ANY; - } - - /** - * Constructor to register the application configuration. - * - * @param name Friendly name associated with the application configuration - * @param dataType Data Type of the remote Bluetooth Health device - * @param role {@link BluetoothHealth#SOURCE_ROLE} or {@link BluetoothHealth#SINK_ROLE} - * @hide - */ - BluetoothHealthAppConfiguration(String name, int dataType, int role, int - channelType) { - mName = name; - mDataType = dataType; - mRole = role; - mChannelType = channelType; - } - - @Override - public boolean equals(Object o) { - if (o instanceof BluetoothHealthAppConfiguration) { - BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o; - - if (mName == null) return false; - - return mName.equals(config.getName()) && mDataType == config.getDataType() - && mRole == config.getRole() && mChannelType == config.getChannelType(); - } - return false; - } - - @Override - public int hashCode() { - int result = 17; - result = 31 * result + (mName != null ? mName.hashCode() : 0); - result = 31 * result + mDataType; - result = 31 * result + mRole; - result = 31 * result + mChannelType; - return result; - } - - @Override - public String toString() { - return "BluetoothHealthAppConfiguration [mName = " + mName + ",mDataType = " + mDataType - + ", mRole = " + mRole + ",mChannelType = " + mChannelType + "]"; - } - @Override public int describeContents() { return 0; @@ -100,50 +42,59 @@ public final class BluetoothHealthAppConfiguration implements Parcelable { * Return the data type associated with this application configuration. * * @return dataType + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public int getDataType() { - return mDataType; + return 0; } /** * Return the name of the application configuration. * * @return String name + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public String getName() { - return mName; + return null; } /** * Return the role associated with this application configuration. * * @return One of {@link BluetoothHealth#SOURCE_ROLE} or {@link BluetoothHealth#SINK_ROLE} + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated public int getRole() { - return mRole; + return 0; } /** - * Return the channel type associated with this application configuration. - * - * @return One of {@link BluetoothHealth#CHANNEL_TYPE_RELIABLE} or {@link - * BluetoothHealth#CHANNEL_TYPE_STREAMING} or {@link BluetoothHealth#CHANNEL_TYPE_ANY}. - * @hide + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ - public int getChannelType() { - return mChannelType; - } - + @Deprecated public static final Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR = new Parcelable.Creator<BluetoothHealthAppConfiguration>() { @Override public BluetoothHealthAppConfiguration createFromParcel(Parcel in) { - String name = in.readString(); - int type = in.readInt(); - int role = in.readInt(); - int channelType = in.readInt(); - return new BluetoothHealthAppConfiguration(name, type, role, - channelType); + return new BluetoothHealthAppConfiguration(); } @Override @@ -153,10 +104,5 @@ public final class BluetoothHealthAppConfiguration implements Parcelable { }; @Override - public void writeToParcel(Parcel out, int flags) { - out.writeString(mName); - out.writeInt(mDataType); - out.writeInt(mRole); - out.writeInt(mChannelType); - } + public void writeToParcel(Parcel out, int flags) {} } diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java index 40234856b8ad..4769212c5361 100644 --- a/core/java/android/bluetooth/BluetoothHealthCallback.java +++ b/core/java/android/bluetooth/BluetoothHealthCallback.java @@ -23,7 +23,13 @@ import android.util.Log; /** * This abstract class is used to implement {@link BluetoothHealth} callbacks. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ +@Deprecated public abstract class BluetoothHealthCallback { private static final String TAG = "BluetoothHealthCallback"; @@ -38,8 +44,14 @@ public abstract class BluetoothHealthCallback { * BluetoothHealth#APP_CONFIG_REGISTRATION_FAILURE} or * {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_SUCCESS} * or {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_FAILURE} + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ @BinderThread + @Deprecated public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config, int status) { Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + "Status: " + status); @@ -58,8 +70,14 @@ public abstract class BluetoothHealthCallback { * @param fd The Parcel File Descriptor when the channel state is connected. * @param channelId The id associated with the channel. This id will be used in future calls * like when disconnecting the channel. + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ @BinderThread + @Deprecated public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config, BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd, int channelId) { diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 3c3a01b191e6..3c87c739e1f6 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -72,7 +72,13 @@ public interface BluetoothProfile { /** * Health Profile + * + * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New + * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt}, + * {@link BluetoothAdapter#listenUsingL2capChannel()}, or + * {@link BluetoothDevice#createL2capChannel(int)} */ + @Deprecated int HEALTH = 3; /** @@ -269,9 +275,8 @@ public interface BluetoothProfile { * Called to notify the client when the proxy object has been * connected to the service. * - * @param profile - One of {@link #HEALTH}, {@link #HEADSET} or {@link #A2DP} - * @param proxy - One of {@link BluetoothHealth}, {@link BluetoothHeadset} or {@link - * BluetoothA2dp} + * @param profile - One of {@link #HEADSET} or {@link #A2DP} + * @param proxy - One of {@link BluetoothHeadset} or {@link BluetoothA2dp} */ public void onServiceConnected(int profile, BluetoothProfile proxy); @@ -279,7 +284,7 @@ public interface BluetoothProfile { * Called to notify the client that this proxy object has been * disconnected from the service. * - * @param profile - One of {@link #HEALTH}, {@link #HEADSET} or {@link #A2DP} + * @param profile - One of {@link #HEADSET} or {@link #A2DP} */ public void onServiceDisconnected(int profile); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 7b3497b8b483..de810e8a02e7 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -816,6 +816,28 @@ public class Intent implements Parcelable, Cloneable { = "android.intent.action.SHOW_APP_INFO"; /** + * Activity Action: Start an activity to show the app's detailed usage information for + * permission protected data. + * + * The Intent contains an extra {@link #EXTRA_PERMISSION_USAGE_PERMISSIONS} that is of + * type {@code String[]} and contains the specific permissions to show information for. + * + * Apps should handle this intent if they want to provide more information about permission + * usage to users beyond the information provided in the manifest. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_PERMISSION_USAGE_DETAILS = + "android.intent.action.PERMISSION_USAGE_DETAILS"; + + /** + * The name of the extra used to contain the permissions in + * {@link #ACTION_PERMISSION_USAGE_DETAILS}. + * @see #ACTION_PERMISSION_USAGE_DETAILS + */ + public static final String EXTRA_PERMISSION_USAGE_PERMISSIONS = + "android.intent.extra.PERMISSION_USAGE_PERMISSIONS"; + + /** * Represents a shortcut/live folder icon resource. * * @see Intent#ACTION_CREATE_SHORTCUT @@ -1811,6 +1833,23 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.REVIEW_PERMISSIONS"; /** + * Activity action: Launch UI to manage special app accesses. + * <p> + * Input: Nothing. + * </p> + * <p> + * Output: Nothing. + * </p> + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + @SystemApi + public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES = + "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES"; + + /** * Intent extra: A callback for reporting remote result as a bundle. * <p> * Type: IRemoteCallback diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 799f8e55cd18..536a1b7ab6e5 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -794,6 +794,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * {@link ActivityInfo#CONFIG_ASSETS_PATHS}. * @hide */ + @TestApi public int assetsSeq; /** diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java index 7e52ca331f9f..be054297c769 100644 --- a/core/java/android/hardware/display/BrightnessConfiguration.java +++ b/core/java/android/hardware/display/BrightnessConfiguration.java @@ -19,26 +19,54 @@ package android.hardware.display; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.content.pm.ApplicationInfo; import android.os.Parcel; import android.os.Parcelable; import android.util.Pair; import com.android.internal.util.Preconditions; +import com.android.internal.util.XmlUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; /** @hide */ @SystemApi @TestApi public final class BrightnessConfiguration implements Parcelable { + private static final String TAG_BRIGHTNESS_CURVE = "brightness-curve"; + private static final String TAG_BRIGHTNESS_POINT = "brightness-point"; + private static final String TAG_BRIGHTNESS_CORRECTIONS = "brightness-corrections"; + private static final String TAG_BRIGHTNESS_CORRECTION = "brightness-correction"; + private static final String ATTR_LUX = "lux"; + private static final String ATTR_NITS = "nits"; + private static final String ATTR_DESCRIPTION = "description"; + private static final String ATTR_PACKAGE_NAME = "package-name"; + private static final String ATTR_CATEGORY = "category"; + private final float[] mLux; private final float[] mNits; + private final Map<String, BrightnessCorrection> mCorrectionsByPackageName; + private final Map<Integer, BrightnessCorrection> mCorrectionsByCategory; private final String mDescription; - private BrightnessConfiguration(float[] lux, float[] nits, String description) { + private BrightnessConfiguration(float[] lux, float[] nits, + Map<String, BrightnessCorrection> correctionsByPackageName, + Map<Integer, BrightnessCorrection> correctionsByCategory, String description) { mLux = lux; mNits = nits; + mCorrectionsByPackageName = correctionsByPackageName; + mCorrectionsByCategory = correctionsByCategory; mDescription = description; } @@ -56,6 +84,38 @@ public final class BrightnessConfiguration implements Parcelable { } /** + * Returns a brightness correction by app, or null. + * + * @param packageName + * The app's package name. + * + * @return The matching brightness correction, or null. + * + * @hide + */ + @SystemApi + @Nullable + public BrightnessCorrection getCorrectionByPackageName(String packageName) { + return mCorrectionsByPackageName.get(packageName); + } + + /** + * Returns a brightness correction by app category, or null. + * + * @param category + * The app category. + * + * @return The matching brightness correction, or null. + * + * @hide + */ + @SystemApi + @Nullable + public BrightnessCorrection getCorrectionByCategory(int category) { + return mCorrectionsByCategory.get(category); + } + + /** * Returns description string. * @hide */ @@ -67,6 +127,20 @@ public final class BrightnessConfiguration implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeFloatArray(mLux); dest.writeFloatArray(mNits); + dest.writeInt(mCorrectionsByPackageName.size()); + for (Entry<String, BrightnessCorrection> entry : mCorrectionsByPackageName.entrySet()) { + final String packageName = entry.getKey(); + final BrightnessCorrection correction = entry.getValue(); + dest.writeString(packageName); + correction.writeToParcel(dest, flags); + } + dest.writeInt(mCorrectionsByCategory.size()); + for (Entry<Integer, BrightnessCorrection> entry : mCorrectionsByCategory.entrySet()) { + final int category = entry.getKey(); + final BrightnessCorrection correction = entry.getValue(); + dest.writeInt(category); + correction.writeToParcel(dest, flags); + } dest.writeString(mDescription); } @@ -85,7 +159,14 @@ public final class BrightnessConfiguration implements Parcelable { } sb.append("(").append(mLux[i]).append(", ").append(mNits[i]).append(")"); } - sb.append("], '"); + sb.append("], {"); + for (Entry<String, BrightnessCorrection> entry : mCorrectionsByPackageName.entrySet()) { + sb.append("'" + entry.getKey() + "': " + entry.getValue() + ", "); + } + for (Entry<Integer, BrightnessCorrection> entry : mCorrectionsByCategory.entrySet()) { + sb.append(entry.getKey() + ": " + entry.getValue() + ", "); + } + sb.append("}, '"); if (mDescription != null) { sb.append(mDescription); } @@ -98,6 +179,8 @@ public final class BrightnessConfiguration implements Parcelable { int result = 1; result = result * 31 + Arrays.hashCode(mLux); result = result * 31 + Arrays.hashCode(mNits); + result = result * 31 + mCorrectionsByPackageName.hashCode(); + result = result * 31 + mCorrectionsByCategory.hashCode(); if (mDescription != null) { result = result * 31 + mDescription.hashCode(); } @@ -114,6 +197,8 @@ public final class BrightnessConfiguration implements Parcelable { } final BrightnessConfiguration other = (BrightnessConfiguration) o; return Arrays.equals(mLux, other.mLux) && Arrays.equals(mNits, other.mNits) + && mCorrectionsByPackageName.equals(other.mCorrectionsByPackageName) + && mCorrectionsByCategory.equals(other.mCorrectionsByCategory) && Objects.equals(mDescription, other.mDescription); } @@ -123,7 +208,25 @@ public final class BrightnessConfiguration implements Parcelable { float[] lux = in.createFloatArray(); float[] nits = in.createFloatArray(); Builder builder = new Builder(lux, nits); - builder.setDescription(in.readString()); + + int n = in.readInt(); + for (int i = 0; i < n; i++) { + final String packageName = in.readString(); + final BrightnessCorrection correction = + BrightnessCorrection.CREATOR.createFromParcel(in); + builder.addCorrectionByPackageName(packageName, correction); + } + + n = in.readInt(); + for (int i = 0; i < n; i++) { + final int category = in.readInt(); + final BrightnessCorrection correction = + BrightnessCorrection.CREATOR.createFromParcel(in); + builder.addCorrectionByCategory(category, correction); + } + + final String description = in.readString(); + builder.setDescription(description); return builder.build(); } @@ -133,11 +236,146 @@ public final class BrightnessConfiguration implements Parcelable { }; /** + * Writes the configuration to an XML serializer. + * + * @param serializer + * The XML serializer. + * + * @hide + */ + public void saveToXml(XmlSerializer serializer) throws IOException { + serializer.startTag(null, TAG_BRIGHTNESS_CURVE); + if (mDescription != null) { + serializer.attribute(null, ATTR_DESCRIPTION, mDescription); + } + for (int i = 0; i < mLux.length; i++) { + serializer.startTag(null, TAG_BRIGHTNESS_POINT); + serializer.attribute(null, ATTR_LUX, Float.toString(mLux[i])); + serializer.attribute(null, ATTR_NITS, Float.toString(mNits[i])); + serializer.endTag(null, TAG_BRIGHTNESS_POINT); + } + serializer.endTag(null, TAG_BRIGHTNESS_CURVE); + serializer.startTag(null, TAG_BRIGHTNESS_CORRECTIONS); + for (Map.Entry<String, BrightnessCorrection> entry : + mCorrectionsByPackageName.entrySet()) { + final String packageName = entry.getKey(); + final BrightnessCorrection correction = entry.getValue(); + serializer.startTag(null, TAG_BRIGHTNESS_CORRECTION); + serializer.attribute(null, ATTR_PACKAGE_NAME, packageName); + correction.saveToXml(serializer); + serializer.endTag(null, TAG_BRIGHTNESS_CORRECTION); + } + for (Map.Entry<Integer, BrightnessCorrection> entry : mCorrectionsByCategory.entrySet()) { + final int category = entry.getKey(); + final BrightnessCorrection correction = entry.getValue(); + serializer.startTag(null, TAG_BRIGHTNESS_CORRECTION); + serializer.attribute(null, ATTR_CATEGORY, Integer.toString(category)); + correction.saveToXml(serializer); + serializer.endTag(null, TAG_BRIGHTNESS_CORRECTION); + } + serializer.endTag(null, TAG_BRIGHTNESS_CORRECTIONS); + } + + /** + * Read a configuration from an XML parser. + * + * @param parser + * The XML parser. + * + * @throws IOException + * The parser failed to read the XML file. + * @throws XmlPullParserException + * The parser failed to parse the XML file. + * + * @hide + */ + public static BrightnessConfiguration loadFromXml(XmlPullParser parser) + throws IOException, XmlPullParserException { + String description = null; + List<Float> luxList = new ArrayList<>(); + List<Float> nitsList = new ArrayList<>(); + Map<String, BrightnessCorrection> correctionsByPackageName = new HashMap<>(); + Map<Integer, BrightnessCorrection> correctionsByCategory = new HashMap<>(); + final int configDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, configDepth)) { + if (TAG_BRIGHTNESS_CURVE.equals(parser.getName())) { + description = parser.getAttributeValue(null, ATTR_DESCRIPTION); + final int curveDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, curveDepth)) { + if (!TAG_BRIGHTNESS_POINT.equals(parser.getName())) { + continue; + } + final float lux = loadFloatFromXml(parser, ATTR_LUX); + final float nits = loadFloatFromXml(parser, ATTR_NITS); + luxList.add(lux); + nitsList.add(nits); + } + } + if (TAG_BRIGHTNESS_CORRECTIONS.equals(parser.getName())) { + final int correctionsDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, correctionsDepth)) { + if (!TAG_BRIGHTNESS_CORRECTION.equals(parser.getName())) { + continue; + } + final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); + final String categoryText = parser.getAttributeValue(null, ATTR_CATEGORY); + BrightnessCorrection correction = BrightnessCorrection.loadFromXml(parser); + if (packageName != null) { + correctionsByPackageName.put(packageName, correction); + } else if (categoryText != null) { + try { + final int category = Integer.parseInt(categoryText); + correctionsByCategory.put(category, correction); + } catch (NullPointerException | NumberFormatException e) { + continue; + } + } + } + } + } + final int n = luxList.size(); + float[] lux = new float[n]; + float[] nits = new float[n]; + for (int i = 0; i < n; i++) { + lux[i] = luxList.get(i); + nits[i] = nitsList.get(i); + } + final BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(lux, + nits); + builder.setDescription(description); + for (Map.Entry<String, BrightnessCorrection> entry : correctionsByPackageName.entrySet()) { + final String packageName = entry.getKey(); + final BrightnessCorrection correction = entry.getValue(); + builder.addCorrectionByPackageName(packageName, correction); + } + for (Map.Entry<Integer, BrightnessCorrection> entry : correctionsByCategory.entrySet()) { + final int category = entry.getKey(); + final BrightnessCorrection correction = entry.getValue(); + builder.addCorrectionByCategory(category, correction); + } + return builder.build(); + } + + private static float loadFloatFromXml(XmlPullParser parser, String attribute) { + final String string = parser.getAttributeValue(null, attribute); + try { + return Float.parseFloat(string); + } catch (NullPointerException | NumberFormatException e) { + return Float.NaN; + } + } + + /** * A builder class for {@link BrightnessConfiguration}s. */ public static class Builder { + private static final int MAX_CORRECTIONS_BY_PACKAGE_NAME = 20; + private static final int MAX_CORRECTIONS_BY_CATEGORY = 20; + private float[] mCurveLux; private float[] mCurveNits; + private Map<String, BrightnessCorrection> mCorrectionsByPackageName; + private Map<Integer, BrightnessCorrection> mCorrectionsByCategory; private String mDescription; /** @@ -169,6 +407,88 @@ public final class BrightnessConfiguration implements Parcelable { checkMonotonic(nits, false /*strictly increasing*/, "nits"); mCurveLux = lux; mCurveNits = nits; + mCorrectionsByPackageName = new HashMap<>(); + mCorrectionsByCategory = new HashMap<>(); + } + + /** + * Returns the maximum number of corrections by package name allowed. + * + * @return The maximum number of corrections by package name allowed. + * + * @hide + */ + @SystemApi + public int getMaxCorrectionsByPackageName() { + return MAX_CORRECTIONS_BY_PACKAGE_NAME; + } + + /** + * Returns the maximum number of corrections by category allowed. + * + * @return The maximum number of corrections by category allowed. + * + * @hide + */ + @SystemApi + public int getMaxCorrectionsByCategory() { + return MAX_CORRECTIONS_BY_CATEGORY; + } + + /** + * Add a brightness correction by app package name. + * This correction is applied whenever an app with this package name has the top activity + * of the focused stack. + * + * @param packageName + * The app's package name. + * @param correction + * The brightness correction. + * + * @return The builder. + * + * @throws IllegalArgumentExceptions + * Maximum number of corrections by package name exceeded (see + * {@link #getMaxCorrectionsByPackageName}). + * + * @hide + */ + @SystemApi + public Builder addCorrectionByPackageName(String packageName, + BrightnessCorrection correction) { + if (mCorrectionsByPackageName.size() >= getMaxCorrectionsByPackageName()) { + throw new IllegalArgumentException("Too many corrections by package name"); + } + mCorrectionsByPackageName.put(packageName, correction); + return this; + } + + /** + * Add a brightness correction by app category. + * This correction is applied whenever an app with this category has the top activity of + * the focused stack, and only if a correction by package name has not been applied. + * + * @param category + * The {@link android.content.pm.ApplicationInfo#category app category}. + * @param correction + * The brightness correction. + * + * @return The builder. + * + * @throws IllegalArgumentException + * Maximum number of corrections by category exceeded (see + * {@link #getMaxCorrectionsByCategory}). + * + * @hide + */ + @SystemApi + public Builder addCorrectionByCategory(@ApplicationInfo.Category int category, + BrightnessCorrection correction) { + if (mCorrectionsByCategory.size() >= getMaxCorrectionsByCategory()) { + throw new IllegalArgumentException("Too many corrections by category"); + } + mCorrectionsByCategory.put(category, correction); + return this; } /** @@ -191,7 +511,8 @@ public final class BrightnessConfiguration implements Parcelable { if (mCurveLux == null || mCurveNits == null) { throw new IllegalStateException("A curve must be set!"); } - return new BrightnessConfiguration(mCurveLux, mCurveNits, mDescription); + return new BrightnessConfiguration(mCurveLux, mCurveNits, mCorrectionsByPackageName, + mCorrectionsByCategory, mDescription); } private static void checkMonotonic(float[] vals, boolean strictlyIncreasing, String name) { diff --git a/core/java/android/hardware/display/BrightnessCorrection.aidl b/core/java/android/hardware/display/BrightnessCorrection.aidl new file mode 100644 index 000000000000..3abe29cc0076 --- /dev/null +++ b/core/java/android/hardware/display/BrightnessCorrection.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.hardware.display; + +parcelable BrightnessCorrection; diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java new file mode 100644 index 000000000000..c4e0e3b723cd --- /dev/null +++ b/core/java/android/hardware/display/BrightnessCorrection.java @@ -0,0 +1,245 @@ +/* + * 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.display; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.MathUtils; + +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; + +/** + * BrightnessCorrection encapsulates a correction to the brightness, without comitting to the + * actual correction scheme. + * It is used by the BrightnessConfiguration, which maps context (e.g. the foreground app's package + * name and category) to corrections that need to be applied to the brightness within that context. + * Corrections are currently done by the app that has the top activity of the focused stack, either + * by its package name, or (if its package name is not mapped to any correction) by its category. + * + * @hide + */ +@SystemApi +public final class BrightnessCorrection implements Parcelable { + + private static final int SCALE_AND_TRANSLATE_LOG = 1; + + private static final String TAG_SCALE_AND_TRANSLATE_LOG = "scale-and-translate-log"; + + private BrightnessCorrectionImplementation mImplementation; + + // Parcelable classes must be final, and protected methods are not allowed in APIs, so we can't + // make this class abstract and use composition instead of inheritence. + private BrightnessCorrection(BrightnessCorrectionImplementation implementation) { + mImplementation = implementation; + } + + /** + * Creates a BrightnessCorrection that given {@code brightness}, corrects it to be + * {@code exp(scale * log(brightness) + translate)}. + * + * @param scale + * How much to scale the log brightness. + * @param translate + * How much to translate the log brightness. + * + * @return A BrightnessCorrection that given {@code brightness}, corrects it to be + * {@code exp(scale * log(brightness) + translate)}. + * + * @throws IllegalArgumentException + * - scale or translate are NaN. + */ + @NonNull + public static BrightnessCorrection createScaleAndTranslateLog(float scale, float translate) { + BrightnessCorrectionImplementation implementation = + new ScaleAndTranslateLog(scale, translate); + return new BrightnessCorrection(implementation); + } + + /** + * Applies the brightness correction to a given brightness. + * + * @param brightness + * The brightness. + * + * @return The corrected brightness. + */ + public float apply(float brightness) { + return mImplementation.apply(brightness); + } + + /** + * Returns a string representation. + * + * @return A string representation. + */ + public String toString() { + return mImplementation.toString(); + } + + public static final Creator<BrightnessCorrection> CREATOR = + new Creator<BrightnessCorrection>() { + public BrightnessCorrection createFromParcel(Parcel in) { + final int type = in.readInt(); + switch (type) { + case SCALE_AND_TRANSLATE_LOG: + return ScaleAndTranslateLog.readFromParcel(in); + } + return null; + } + + public BrightnessCorrection[] newArray(int size) { + return new BrightnessCorrection[size]; + } + }; + + @Override + public void writeToParcel(Parcel dest, int flags) { + mImplementation.writeToParcel(dest); + } + + @Override + public int describeContents() { + return 0; + } + + /** + * Writes the correction to an XML serializer. + * + * @param serializer + * The XML serializer. + * + * @hide + */ + public void saveToXml(XmlSerializer serializer) throws IOException { + mImplementation.saveToXml(serializer); + } + + /** + * Read a correction from an XML parser. + * + * @param parser + * The XML parser. + * + * @throws IOException + * The parser failed to read the XML file. + * @throws XmlPullParserException + * The parser failed to parse the XML file. + * + * @hide + */ + public static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException, + XmlPullParserException { + final int depth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, depth)) { + if (TAG_SCALE_AND_TRANSLATE_LOG.equals(parser.getName())) { + return ScaleAndTranslateLog.loadFromXml(parser); + } + } + return null; + } + + private static float loadFloatFromXml(XmlPullParser parser, String attribute) { + final String string = parser.getAttributeValue(null, attribute); + try { + return Float.parseFloat(string); + } catch (NullPointerException | NumberFormatException e) { + return Float.NaN; + } + } + + private interface BrightnessCorrectionImplementation { + float apply(float brightness); + String toString(); + void writeToParcel(Parcel dest); + void saveToXml(XmlSerializer serializer) throws IOException; + // Package-private static methods: + // static BrightnessCorrection readFromParcel(Parcel in); + // static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException, + // XmlPullParserException; + } + + /** + * A BrightnessCorrection that given {@code brightness}, corrects it to be + * {@code exp(scale * log(brightness) + translate)}. + */ + private static class ScaleAndTranslateLog implements BrightnessCorrectionImplementation { + private static final float MIN_SCALE = 0.5f; + private static final float MAX_SCALE = 2.0f; + private static final float MIN_TRANSLATE = -0.6f; + private static final float MAX_TRANSLATE = 0.7f; + + private static final String ATTR_SCALE = "scale"; + private static final String ATTR_TRANSLATE = "translate"; + + private final float mScale; + private final float mTranslate; + + ScaleAndTranslateLog(float scale, float translate) { + if (Float.isNaN(scale) || Float.isNaN(translate)) { + throw new IllegalArgumentException("scale and translate must be numbers"); + } + mScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE); + mTranslate = MathUtils.constrain(translate, MIN_TRANSLATE, MAX_TRANSLATE); + } + + @Override + public float apply(float brightness) { + return MathUtils.exp(mScale * MathUtils.log(brightness) + mTranslate); + } + + @Override + public String toString() { + return "ScaleAndTranslateLog(" + mScale + ", " + mTranslate + ")"; + } + + @Override + public void writeToParcel(Parcel dest) { + dest.writeInt(SCALE_AND_TRANSLATE_LOG); + dest.writeFloat(mScale); + dest.writeFloat(mTranslate); + } + + @Override + public void saveToXml(XmlSerializer serializer) throws IOException { + serializer.startTag(null, TAG_SCALE_AND_TRANSLATE_LOG); + serializer.attribute(null, ATTR_SCALE, Float.toString(mScale)); + serializer.attribute(null, ATTR_TRANSLATE, Float.toString(mTranslate)); + serializer.endTag(null, TAG_SCALE_AND_TRANSLATE_LOG); + } + + static BrightnessCorrection readFromParcel(Parcel in) { + float scale = in.readFloat(); + float translate = in.readFloat(); + return BrightnessCorrection.createScaleAndTranslateLog(scale, translate); + } + + static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException, + XmlPullParserException { + final float scale = loadFloatFromXml(parser, ATTR_SCALE); + final float translate = loadFloatFromXml(parser, ATTR_TRANSLATE); + return BrightnessCorrection.createScaleAndTranslateLog(scale, translate); + } + } +} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 61d5a9127743..436b4a15e7c1 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -16,6 +16,7 @@ package android.net; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; @@ -909,6 +910,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @Nullable public NetworkInfo getActiveNetworkInfo() { try { return mService.getActiveNetworkInfo(); @@ -928,6 +930,7 @@ public class ConnectivityManager { * {@code null} if no default network is currently active */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @Nullable public Network getActiveNetwork() { try { return mService.getActiveNetwork(); @@ -949,6 +952,7 @@ public class ConnectivityManager { * @hide */ @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) + @Nullable public Network getActiveNetworkForUid(int uid) { return getActiveNetworkForUid(uid, false); } @@ -1074,6 +1078,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @Nullable public NetworkInfo getNetworkInfo(int networkType) { try { return mService.getNetworkInfo(networkType); @@ -1095,7 +1100,8 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public NetworkInfo getNetworkInfo(Network network) { + @Nullable + public NetworkInfo getNetworkInfo(@Nullable Network network) { return getNetworkInfoForUid(network, Process.myUid(), false); } @@ -1121,6 +1127,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @NonNull public NetworkInfo[] getAllNetworkInfo() { try { return mService.getAllNetworkInfo(); @@ -1156,6 +1163,7 @@ public class ConnectivityManager { * @return an array of {@link Network} objects. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @NonNull public Network[] getAllNetworks() { try { return mService.getAllNetworks(); @@ -1230,7 +1238,8 @@ public class ConnectivityManager { * @return The {@link LinkProperties} for the network, or {@code null}. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public LinkProperties getLinkProperties(Network network) { + @Nullable + public LinkProperties getLinkProperties(@Nullable Network network) { try { return mService.getLinkProperties(network); } catch (RemoteException e) { @@ -1246,7 +1255,8 @@ public class ConnectivityManager { * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public NetworkCapabilities getNetworkCapabilities(Network network) { + @Nullable + public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) { try { return mService.getNetworkCapabilities(network); } catch (RemoteException e) { @@ -2000,7 +2010,7 @@ public class ConnectivityManager { * * @param l Previously registered listener. */ - public void removeDefaultNetworkActiveListener(OnNetworkActiveListener l) { + public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) { INetworkActivityListener rl = mNetworkActivityListeners.get(l); Preconditions.checkArgument(rl != null, "Listener was not registered."); try { @@ -2475,6 +2485,8 @@ public class ConnectivityManager { public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; /** {@hide} */ public static final int TETHER_ERROR_PROVISION_FAILED = 11; + /** {@hide} */ + public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; /** * Get a more detailed error code after a Tethering or Untethering @@ -2528,7 +2540,7 @@ public class ConnectivityManager { * working and non-working connectivity. */ @Deprecated - public void reportBadNetwork(Network network) { + public void reportBadNetwork(@Nullable Network network) { printStackTrace(); try { // One of these will be ignored because it matches system's current state. @@ -2551,7 +2563,7 @@ public class ConnectivityManager { * @param hasConnectivity {@code true} if the application was able to successfully access the * Internet using {@code network} or {@code false} if not. */ - public void reportNetworkConnectivity(Network network, boolean hasConnectivity) { + public void reportNetworkConnectivity(@Nullable Network network, boolean hasConnectivity) { printStackTrace(); try { mService.reportNetworkConnectivity(network, hasConnectivity); @@ -2625,6 +2637,7 @@ public class ConnectivityManager { * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no * HTTP proxy is active. */ + @Nullable public ProxyInfo getDefaultProxy() { return getProxyForNetwork(getBoundNetworkForProcess()); } @@ -3156,8 +3169,9 @@ public class ConnectivityManager { * * @hide */ - public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback, - int timeoutMs, int legacyType, Handler handler) { + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, int timeoutMs, int legacyType, + @NonNull Handler handler) { CallbackHandler cbHandler = new CallbackHandler(handler); NetworkCapabilities nc = request.networkCapabilities; sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler); @@ -3194,7 +3208,8 @@ public class ConnectivityManager { * @throws IllegalArgumentException if {@code request} specifies any mutable * {@code NetworkCapabilities}. */ - public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) { + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback) { requestNetwork(request, networkCallback, getDefaultHandler()); } @@ -3229,8 +3244,8 @@ public class ConnectivityManager { * @throws IllegalArgumentException if {@code request} specifies any mutable * {@code NetworkCapabilities}. */ - public void requestNetwork( - NetworkRequest request, NetworkCallback networkCallback, Handler handler) { + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities); CallbackHandler cbHandler = new CallbackHandler(handler); requestNetwork(request, networkCallback, 0, legacyType, cbHandler); @@ -3264,8 +3279,8 @@ public class ConnectivityManager { * before {@link NetworkCallback#onUnavailable()} is called. The timeout must * be a positive value (i.e. >0). */ - public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback, - int timeoutMs) { + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, int timeoutMs) { checkTimeout(timeoutMs); int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities); requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler()); @@ -3298,8 +3313,8 @@ public class ConnectivityManager { * @param timeoutMs The time in milliseconds to attempt looking for a suitable network * before {@link NetworkCallback#onUnavailable} is called. */ - public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback, - Handler handler, int timeoutMs) { + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) { checkTimeout(timeoutMs); int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities); CallbackHandler cbHandler = new CallbackHandler(handler); @@ -3371,7 +3386,8 @@ public class ConnectivityManager { * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}. */ - public void requestNetwork(NetworkRequest request, PendingIntent operation) { + public void requestNetwork(@NonNull NetworkRequest request, + @NonNull PendingIntent operation) { printStackTrace(); checkPendingIntentNotNull(operation); try { @@ -3395,7 +3411,7 @@ public class ConnectivityManager { * {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} with the * corresponding NetworkRequest you'd like to remove. Cannot be null. */ - public void releaseNetworkRequest(PendingIntent operation) { + public void releaseNetworkRequest(@NonNull PendingIntent operation) { printStackTrace(); checkPendingIntentNotNull(operation); try { @@ -3428,7 +3444,8 @@ public class ConnectivityManager { * The callback is invoked on the default internal Handler. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) { + public void registerNetworkCallback(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback) { registerNetworkCallback(request, networkCallback, getDefaultHandler()); } @@ -3443,8 +3460,8 @@ public class ConnectivityManager { * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerNetworkCallback( - NetworkRequest request, NetworkCallback networkCallback, Handler handler) { + public void registerNetworkCallback(@NonNull NetworkRequest request, + @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { CallbackHandler cbHandler = new CallbackHandler(handler); NetworkCapabilities nc = request.networkCapabilities; sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler); @@ -3480,7 +3497,8 @@ public class ConnectivityManager { * comes from {@link PendingIntent#getBroadcast}. Cannot be null. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerNetworkCallback(NetworkRequest request, PendingIntent operation) { + public void registerNetworkCallback(@NonNull NetworkRequest request, + @NonNull PendingIntent operation) { printStackTrace(); checkPendingIntentNotNull(operation); try { @@ -3502,7 +3520,7 @@ public class ConnectivityManager { * The callback is invoked on the default internal Handler. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerDefaultNetworkCallback(NetworkCallback networkCallback) { + public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback) { registerDefaultNetworkCallback(networkCallback, getDefaultHandler()); } @@ -3516,7 +3534,8 @@ public class ConnectivityManager { * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void registerDefaultNetworkCallback(NetworkCallback networkCallback, Handler handler) { + public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback, + @NonNull Handler handler) { // This works because if the NetworkCapabilities are null, // ConnectivityService takes them from the default request. // @@ -3541,7 +3560,7 @@ public class ConnectivityManager { * @param network {@link Network} specifying which network you're interested. * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. */ - public boolean requestBandwidthUpdate(Network network) { + public boolean requestBandwidthUpdate(@NonNull Network network) { try { return mService.requestBandwidthUpdate(network); } catch (RemoteException e) { @@ -3562,7 +3581,7 @@ public class ConnectivityManager { * * @param networkCallback The {@link NetworkCallback} used when making the request. */ - public void unregisterNetworkCallback(NetworkCallback networkCallback) { + public void unregisterNetworkCallback(@NonNull NetworkCallback networkCallback) { printStackTrace(); checkCallbackNotNull(networkCallback); final List<NetworkRequest> reqs = new ArrayList<>(); @@ -3601,7 +3620,7 @@ public class ConnectivityManager { * {@link #registerNetworkCallback(NetworkRequest, android.app.PendingIntent)}. * Cannot be null. */ - public void unregisterNetworkCallback(PendingIntent operation) { + public void unregisterNetworkCallback(@NonNull PendingIntent operation) { checkPendingIntentNotNull(operation); releaseNetworkRequest(operation); } @@ -3723,7 +3742,7 @@ public class ConnectivityManager { * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public @MultipathPreference int getMultipathPreference(Network network) { + public @MultipathPreference int getMultipathPreference(@Nullable Network network) { try { return mService.getMultipathPreference(network); } catch (RemoteException e) { @@ -3761,7 +3780,7 @@ public class ConnectivityManager { * the current binding. * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. */ - public boolean bindProcessToNetwork(Network network) { + public boolean bindProcessToNetwork(@Nullable Network network) { // Forcing callers to call through non-static function ensures ConnectivityManager // instantiated. return setProcessDefaultNetwork(network); @@ -3789,7 +3808,7 @@ public class ConnectivityManager { * is a direct replacement. */ @Deprecated - public static boolean setProcessDefaultNetwork(Network network) { + public static boolean setProcessDefaultNetwork(@Nullable Network network) { int netId = (network == null) ? NETID_UNSET : network.netId; if (netId == NetworkUtils.getBoundNetworkForProcess()) { return true; @@ -3820,6 +3839,7 @@ public class ConnectivityManager { * * @return {@code Network} to which this process is bound, or {@code null}. */ + @Nullable public Network getBoundNetworkForProcess() { // Forcing callers to call thru non-static function ensures ConnectivityManager // instantiated. @@ -3836,6 +3856,7 @@ public class ConnectivityManager { * {@code getBoundNetworkForProcess} is a direct replacement. */ @Deprecated + @Nullable public static Network getProcessDefaultNetwork() { int netId = NetworkUtils.getBoundNetworkForProcess(); if (netId == NETID_UNSET) return null; @@ -3962,6 +3983,7 @@ public class ConnectivityManager { * * @return Hash of network watchlist config file. Null if config does not exist. */ + @Nullable public byte[] getNetworkWatchlistConfigHash() { try { return mService.getNetworkWatchlistConfigHash(); @@ -3983,8 +4005,8 @@ public class ConnectivityManager { * (e.g., if it is associated with the calling VPN app's tunnel) or * {@link android.os.Process#INVALID_UID} if the connection is not found. */ - public int getConnectionOwnerUid(int protocol, InetSocketAddress local, - InetSocketAddress remote) { + public int getConnectionOwnerUid(int protocol, @NonNull InetSocketAddress local, + @NonNull InetSocketAddress remote) { ConnectionInfo connectionInfo = new ConnectionInfo(protocol, local, remote); try { return mService.getConnectionOwnerUid(connectionInfo); diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl index 29f882858c05..be0dc07f4b23 100644 --- a/core/java/android/net/INetworkStackConnector.aidl +++ b/core/java/android/net/INetworkStackConnector.aidl @@ -15,7 +15,11 @@ */ package android.net; +import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.IDhcpServerCallbacks; + /** @hide */ oneway interface INetworkStackConnector { - // TODO: requestDhcpServer(), etc. will go here + void makeDhcpServer(in String ifName, in DhcpServingParamsParcel params, + in IDhcpServerCallbacks cb); }
\ No newline at end of file diff --git a/core/java/android/net/INetworkStackStatusCallback.aidl b/core/java/android/net/INetworkStackStatusCallback.aidl new file mode 100644 index 000000000000..51032d80a172 --- /dev/null +++ b/core/java/android/net/INetworkStackStatusCallback.aidl @@ -0,0 +1,22 @@ +/* + * 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; + +/** @hide */ +oneway interface INetworkStackStatusCallback { + void onStatusAvailable(int statusCode); +}
\ No newline at end of file diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 3a792065155e..4a466f300718 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -55,6 +55,8 @@ public final class LinkProperties implements Parcelable { private String mIfaceName; private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>(); private ArrayList<InetAddress> mDnses = new ArrayList<>(); + // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service. + private ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>(); private ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>(); private boolean mUsePrivateDns; private String mPrivateDnsServerName; @@ -179,6 +181,7 @@ public final class LinkProperties implements Parcelable { mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses); mUsePrivateDns = source.mUsePrivateDns; mPrivateDnsServerName = source.mPrivateDnsServerName; + mPcscfs.addAll(source.mPcscfs); mDomains = source.mDomains; mRoutes.addAll(source.mRoutes); mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy); @@ -525,6 +528,60 @@ public final class LinkProperties implements Parcelable { } /** + * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present. + * + * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers. + * @return true if the PCSCF server was added, false otherwise. + * @hide + */ + public boolean addPcscfServer(InetAddress pcscfServer) { + if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) { + mPcscfs.add(pcscfServer); + return true; + } + return false; + } + + /** + * Removes the given {@link InetAddress} from the list of PCSCF servers. + * + * @param pcscf Server The {@link InetAddress} to remove from the list of PCSCF servers. + * @return true if the PCSCF server was removed, false otherwise. + * @hide + */ + public boolean removePcscfServer(InetAddress pcscfServer) { + if (pcscfServer != null) { + return mPcscfs.remove(pcscfServer); + } + return false; + } + + /** + * Replaces the PCSCF servers in this {@code LinkProperties} with + * the given {@link Collection} of {@link InetAddress} objects. + * + * @param addresses The {@link Collection} of PCSCF servers to set in this object. + * @hide + */ + public void setPcscfServers(Collection<InetAddress> pcscfServers) { + mPcscfs.clear(); + for (InetAddress pcscfServer: pcscfServers) { + addPcscfServer(pcscfServer); + } + } + + /** + * Returns all the {@link InetAddress} for PCSCF servers on this link. + * + * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on + * this link. + * @hide + */ + public List<InetAddress> getPcscfServers() { + return Collections.unmodifiableList(mPcscfs); + } + + /** * Sets the DNS domain search path used on this link. * * @param domains A {@link String} listing in priority order the comma separated @@ -767,6 +824,7 @@ public final class LinkProperties implements Parcelable { mDnses.clear(); mUsePrivateDns = false; mPrivateDnsServerName = null; + mPcscfs.clear(); mDomains = null; mRoutes.clear(); mHttpProxy = null; @@ -813,6 +871,12 @@ public final class LinkProperties implements Parcelable { resultJoiner.add(mPrivateDnsServerName); } + if (!mPcscfs.isEmpty()) { + resultJoiner.add("PcscfAddresses: ["); + resultJoiner.add(TextUtils.join(",", mPcscfs)); + resultJoiner.add("]"); + } + if (!mValidatedPrivateDnses.isEmpty()) { final StringJoiner validatedPrivateDnsesJoiner = new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]"); @@ -965,6 +1029,36 @@ public final class LinkProperties implements Parcelable { } /** + * Returns true if this link has an IPv4 PCSCF server. + * + * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise. + * @hide + */ + public boolean hasIPv4PcscfServer() { + for (InetAddress ia : mPcscfs) { + if (ia instanceof Inet4Address) { + return true; + } + } + return false; + } + + /** + * Returns true if this link has an IPv6 PCSCF server. + * + * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise. + * @hide + */ + public boolean hasIPv6PcscfServer() { + for (InetAddress ia : mPcscfs) { + if (ia instanceof Inet6Address) { + return true; + } + } + return false; + } + + /** * Returns true if this link is provisioned for global IPv4 connectivity. * This requires an IP address, default route, and DNS server. * @@ -1117,6 +1211,19 @@ public final class LinkProperties implements Parcelable { } /** + * Compares this {@code LinkProperties} PCSCF addresses against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + * @hide + */ + public boolean isIdenticalPcscfs(LinkProperties target) { + Collection<InetAddress> targetPcscfs = target.getPcscfServers(); + return (mPcscfs.size() == targetPcscfs.size()) ? + mPcscfs.containsAll(targetPcscfs) : false; + } + + /** * Compares this {@code LinkProperties} Routes against the target * * @param target LinkProperties to compare. @@ -1218,6 +1325,7 @@ public final class LinkProperties implements Parcelable { && isIdenticalDnses(target) && isIdenticalPrivateDns(target) && isIdenticalValidatedPrivateDnses(target) + && isIdenticalPcscfs(target) && isIdenticalRoutes(target) && isIdenticalHttpProxy(target) && isIdenticalStackedLinks(target) @@ -1334,6 +1442,7 @@ public final class LinkProperties implements Parcelable { + mMtu * 51 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode()) + (mUsePrivateDns ? 57 : 0) + + mPcscfs.size() * 67 + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode()); } @@ -1357,6 +1466,10 @@ public final class LinkProperties implements Parcelable { } dest.writeBoolean(mUsePrivateDns); dest.writeString(mPrivateDnsServerName); + dest.writeInt(mPcscfs.size()); + for (InetAddress d : mPcscfs) { + dest.writeByteArray(d.getAddress()); + } dest.writeString(mDomains); dest.writeInt(mMtu); dest.writeString(mTcpBufferSizes); @@ -1406,6 +1519,12 @@ public final class LinkProperties implements Parcelable { } netProp.setUsePrivateDns(in.readBoolean()); netProp.setPrivateDnsServerName(in.readString()); + addressCount = in.readInt(); + for (int i = 0; i < addressCount; i++) { + try { + netProp.addPcscfServer(InetAddress.getByAddress(in.createByteArray())); + } catch (UnknownHostException e) { } + } netProp.setDomains(in.readString()); netProp.setMtu(in.readInt()); netProp.setTcpBufferSizes(in.readString()); diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java index 82a4e31a81dd..d4a0ec632383 100644 --- a/core/java/android/net/NetworkStack.java +++ b/core/java/android/net/NetworkStack.java @@ -25,9 +25,12 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.IDhcpServerCallbacks; import android.os.Binder; import android.os.IBinder; import android.os.Process; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.util.Slog; @@ -58,6 +61,22 @@ public class NetworkStack { public NetworkStack() { } + /** + * Create a DHCP server according to the specified parameters. + * + * <p>The server will be returned asynchronously through the provided callbacks. + */ + public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params, + final IDhcpServerCallbacks cb) { + requestConnector(connector -> { + try { + connector.makeDhcpServer(ifName, params, cb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + }); + } + private class NetworkStackConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java b/core/java/android/net/dhcp/DhcpServerCallbacks.java index 343d35959df4..bb56876c77f5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java +++ b/core/java/android/net/dhcp/DhcpServerCallbacks.java @@ -14,31 +14,20 @@ * limitations under the License. */ -package com.android.server.wm; - -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; - -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; - -import org.junit.Rule; -import org.junit.Test; +package android.net.dhcp; /** - * Build/InstallRun: - * atest FrameworksServicesTests:WindowManagerServiceRuleTest + * Convenience wrapper around IDhcpServerCallbacks.Stub that implements getInterfaceVersion(). + * @hide */ -@Presubmit -@SmallTest -public class WindowManagerServiceRuleTest { - - @Rule - public final WindowManagerServiceRule mRule = new WindowManagerServiceRule(); - - @Test - public void testWindowManagerSetUp() { - assertThat(mRule.getWindowManagerService(), notNullValue()); +public abstract class DhcpServerCallbacks extends IDhcpServerCallbacks.Stub { + // TODO: add @Override here once the API is versioned + + /** + * Get the version of the aidl interface implemented by the callbacks. + */ + public int getInterfaceVersion() { + // TODO: return IDhcpServerCallbacks.VERSION; + return 0; } } diff --git a/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl b/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl new file mode 100644 index 000000000000..7b8b9ee324bc --- /dev/null +++ b/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl @@ -0,0 +1,30 @@ +/** + * + * 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.dhcp; + +parcelable DhcpServingParamsParcel { + int serverAddr; + int serverAddrPrefixLength; + int[] defaultRouters; + int[] dnsServers; + int[] excludedAddrs; + long dhcpLeaseTimeSecs; + int linkMtu; + boolean metered; +} + diff --git a/core/java/android/net/dhcp/IDhcpServer.aidl b/core/java/android/net/dhcp/IDhcpServer.aidl new file mode 100644 index 000000000000..559433b13962 --- /dev/null +++ b/core/java/android/net/dhcp/IDhcpServer.aidl @@ -0,0 +1,32 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ + +package android.net.dhcp; + +import android.net.INetworkStackStatusCallback; +import android.net.dhcp.DhcpServingParamsParcel; + +/** @hide */ +oneway interface IDhcpServer { + const int STATUS_UNKNOWN = 0; + const int STATUS_SUCCESS = 1; + const int STATUS_INVALID_ARGUMENT = 2; + const int STATUS_UNKNOWN_ERROR = 3; + + void start(in INetworkStackStatusCallback cb); + void updateParams(in DhcpServingParamsParcel params, in INetworkStackStatusCallback cb); + void stop(in INetworkStackStatusCallback cb); +} diff --git a/core/java/android/net/dhcp/IDhcpServerCallbacks.aidl b/core/java/android/net/dhcp/IDhcpServerCallbacks.aidl new file mode 100644 index 000000000000..7ab4dcdbe584 --- /dev/null +++ b/core/java/android/net/dhcp/IDhcpServerCallbacks.aidl @@ -0,0 +1,24 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ + +package android.net.dhcp; + +import android.net.dhcp.IDhcpServer; + +/** @hide */ +oneway interface IDhcpServerCallbacks { + void onDhcpServerCreated(int statusCode, in IDhcpServer server); +} diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java new file mode 100644 index 000000000000..40cbaf75c02d --- /dev/null +++ b/core/java/android/os/AppZygote.java @@ -0,0 +1,119 @@ +/* + * 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.os; + +import android.content.pm.ApplicationInfo; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; + +/** + * AppZygote is responsible for interfacing with an application-specific zygote. + * + * Application zygotes can pre-load app-specific code and data, and this interface can + * be used to spawn isolated services from such an application zygote. + * + * Note that we'll have only one instance of this per application / uid combination. + * + * @hide + */ +public class AppZygote { + private static final String LOG_TAG = "AppZygote"; + + private final int mZygoteUid; + + private final Object mLock = new Object(); + + /** + * Instance that maintains the socket connection to the zygote. This is {@code null} if the + * zygote is not running or is not connected. + */ + @GuardedBy("mLock") + private ChildZygoteProcess mZygote; + + private final ApplicationInfo mAppInfo; + + public AppZygote(ApplicationInfo appInfo, int zygoteUid) { + mAppInfo = appInfo; + mZygoteUid = zygoteUid; + } + + /** + * Returns the zygote process associated with this app zygote. + * Creates the process if it's not already running. + */ + public ChildZygoteProcess getProcess() { + synchronized (mLock) { + if (mZygote != null) return mZygote; + + connectToZygoteIfNeededLocked(); + return mZygote; + } + } + + /** + * Stops the Zygote and kills the zygote process. + */ + public void stopZygote() { + synchronized (mLock) { + stopZygoteLocked(); + } + } + + public ApplicationInfo getAppInfo() { + return mAppInfo; + } + + @GuardedBy("mLock") + private void stopZygoteLocked() { + if (mZygote != null) { + // Close the connection and kill the zygote process. This will not cause + // child processes to be killed by itself. + mZygote.close(); + Process.killProcess(mZygote.getPid()); + mZygote = null; + } + } + + @GuardedBy("mLock") + private void connectToZygoteIfNeededLocked() { + String abi = mAppInfo.primaryCpuAbi != null ? mAppInfo.primaryCpuAbi : + Build.SUPPORTED_ABIS[0]; + try { + mZygote = Process.zygoteProcess.startChildZygote( + "com.android.internal.os.AppZygoteInit", + mAppInfo.processName + "_zygote", + mZygoteUid, + mZygoteUid, + null, // gids + 0, // runtimeFlags + "app_zygote", // seInfo + abi, // abi + abi, // acceptedAbiList + null); // instructionSet + + ZygoteProcess.waitForConnectionToZygote(mZygote.getPrimarySocketAddress()); + // preload application code in the zygote + Log.i(LOG_TAG, "Starting application preload."); + mZygote.preloadApp(mAppInfo, abi); + Log.i(LOG_TAG, "Application preload done."); + } catch (Exception e) { + Log.e(LOG_TAG, "Error connecting to app zygote", e); + stopZygoteLocked(); + } + } +} diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 9939a3c8f36d..1ebb551df961 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -273,6 +273,30 @@ public class Binder implements IBinder { public static final native int getCallingUid(); /** + * Returns {@code true} if the current thread is currently executing an + * incoming transaction. + * + * @hide + */ + @CriticalNative + public static final native boolean isHandlingTransaction(); + + /** + * Return the Linux uid assigned to the process that sent the transaction + * currently being processed. + * + * @throws IllegalStateException if the current thread is not currently + * executing an incoming transaction. + */ + public static final int getCallingUidOrThrow() { + if (!isHandlingTransaction()) { + throw new IllegalStateException( + "Thread is not in a binder transcation"); + } + return getCallingUid(); + } + + /** * Return the UserHandle assigned to the process that sent you the * current transaction that is being processed. This is the user * of the caller. It is distinct from {@link #getCallingUid()} in that a diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index d9793097fc3a..b0b8f493e98a 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -480,14 +480,19 @@ public class GraphicsEnvironment { return; } - String applicationPackageName = context.getPackageName(); - String devOptInApplicationName = coreSettings.getString( - Settings.Global.GUP_DEV_OPT_IN_APPS); - boolean devOptIn = applicationPackageName.equals(devOptInApplicationName); - boolean whitelisted = onWhitelist(context, driverPackageName, ai.packageName); - if (!devOptIn && !whitelisted) { + if (getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_OUT_APPS) + .contains(ai.packageName)) { if (DEBUG) { - Log.w(TAG, applicationPackageName + " is not on the whitelist."); + Log.w(TAG, ai.packageName + " opts out from GUP."); + } + return; + } + + if (!getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_IN_APPS) + .contains(ai.packageName) + && !onWhitelist(context, driverPackageName, ai.packageName)) { + if (DEBUG) { + Log.w(TAG, ai.packageName + " is not on the whitelist."); } return; } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 938b23ca733f..ee56e3d0ad16 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -205,6 +205,24 @@ public class Process { public static final int LAST_APPLICATION_UID = 19999; /** + * First uid used for fully isolated sandboxed processes spawned from an app zygote + * @hide + */ + public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; + + /** + * Number of UIDs we allocate per application zygote + * @hide + */ + public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; + + /** + * Last uid used for fully isolated sandboxed processes spawned from an app zygote + * @hide + */ + public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; + + /** * First uid used for fully isolated sandboxed processes (with no permissions of their own) * @hide */ @@ -650,7 +668,8 @@ public class Process { /** {@hide} */ public static final boolean isIsolated(int uid) { uid = UserHandle.getAppId(uid); - return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID; + return (uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID) + || (uid >= FIRST_APP_ZYGOTE_ISOLATED_UID && uid <= LAST_APP_ZYGOTE_ISOLATED_UID); } /** diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 6ea155fe70f8..980140675959 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -95,6 +95,8 @@ public final class Trace { public static final long TRACE_TAG_AIDL = 1L << 24; /** @hide */ public static final long TRACE_TAG_NNAPI = 1L << 25; + /** @hide */ + public static final long TRACE_TAG_RRO = 1L << 26; private static final long TRACE_TAG_NOT_READY = 1L << 63; private static final int MAX_SECTION_NAME_LEN = 127; diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java index 8f2826c16b63..1df3dad9530b 100644 --- a/core/java/android/os/UpdateEngine.java +++ b/core/java/android/os/UpdateEngine.java @@ -66,6 +66,7 @@ public class UpdateEngine { public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12; + public static final int PAYLOAD_TIMESTAMP_ERROR = 51; public static final int UPDATED_BUT_NOT_ACTIVE = 52; } diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index f8feb7b4a693..ad8a4d5645bc 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -138,8 +138,7 @@ public final class UserHandle implements Parcelable { */ public static boolean isIsolated(int uid) { if (uid > 0) { - final int appId = getAppId(uid); - return appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID; + return Process.isIsolated(uid); } else { return false; } @@ -294,9 +293,14 @@ public final class UserHandle implements Parcelable { sb.append('u'); sb.append(getUserId(uid)); final int appId = getAppId(uid); - if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) { - sb.append('i'); - sb.append(appId - Process.FIRST_ISOLATED_UID); + if (isIsolated(appId)) { + if (appId > Process.FIRST_ISOLATED_UID) { + sb.append('i'); + sb.append(appId - Process.FIRST_ISOLATED_UID); + } else { + sb.append("ai"); + sb.append(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID); + } } else if (appId >= Process.FIRST_APPLICATION_UID) { sb.append('a'); sb.append(appId - Process.FIRST_APPLICATION_UID); @@ -330,9 +334,14 @@ public final class UserHandle implements Parcelable { pw.print('u'); pw.print(getUserId(uid)); final int appId = getAppId(uid); - if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) { - pw.print('i'); - pw.print(appId - Process.FIRST_ISOLATED_UID); + if (isIsolated(appId)) { + if (appId > Process.FIRST_ISOLATED_UID) { + pw.print('i'); + pw.print(appId - Process.FIRST_ISOLATED_UID); + } else { + pw.print("ai"); + pw.print(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID); + } } else if (appId >= Process.FIRST_APPLICATION_UID) { pw.print('a'); pw.print(appId - Process.FIRST_APPLICATION_UID); diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index f136cd6699a7..251c5eebadc4 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -18,6 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.ApplicationInfo; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.util.Log; @@ -34,6 +35,7 @@ import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -673,6 +675,36 @@ public class ZygoteProcess { } /** + * Instructs the zygote to pre-load the application code for the given Application. + * Only the app zygote supports this function. + * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead. + */ + public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx, + IOException { + synchronized (mLock) { + ZygoteState state = openZygoteSocketIfNeeded(abi); + state.writer.write("2"); + state.writer.newLine(); + + state.writer.write("--preload-app"); + state.writer.newLine(); + + // Zygote args needs to be strings, so in order to pass ApplicationInfo, + // write it to a Parcel, and base64 the raw Parcel bytes to the other side. + Parcel parcel = Parcel.obtain(); + appInfo.writeToParcel(parcel, 0 /* flags */); + String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall()); + parcel.recycle(); + state.writer.write(encodedParcelData); + state.writer.newLine(); + + state.writer.flush(); + + return (state.inputStream.readInt() == 0); + } + } + + /** * Instructs the zygote to pre-load the classes and native libraries at the given paths * for the specified abi. Not all zygotes support this function. */ @@ -763,6 +795,20 @@ public class ZygoteProcess { * secondary zygotes that inherit data from the zygote that this object * communicates with. This returns a new ZygoteProcess representing a connection * to the newly created zygote. Throws an exception if the zygote cannot be started. + * + * @param processClass The class to use as the child zygote's main entry + * point. + * @param niceName A more readable name to use for the process. + * @param uid The user-id under which the child zygote will run. + * @param gid The group-id under which the child zygote will run. + * @param gids Additional group-ids associated with the child zygote process. + * @param runtimeFlags Additional flags. + * @param seInfo null-ok SELinux information for the child zygote process. + * @param abi non-null the ABI of the child zygote + * @param acceptedAbiList ABIs this child zygote will accept connections for; this + * may be different from <code>abi</code> in case the children + * spawned from this Zygote only communicate using ABI-safe methods. + * @param instructionSet null-ok the instruction set to use. */ public ChildZygoteProcess startChildZygote(final String processClass, final String niceName, @@ -770,12 +816,14 @@ public class ZygoteProcess { int runtimeFlags, String seInfo, String abi, + String acceptedAbiList, String instructionSet) { // Create an unguessable address in the global abstract namespace. final LocalSocketAddress serverAddress = new LocalSocketAddress( processClass + "/" + UUID.randomUUID().toString()); - final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName()}; + final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(), + Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList}; Process.ProcessStartResult result; try { diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl index 38951d5466c7..0e18b445fd01 100644 --- a/core/java/android/permission/IPermissionController.aidl +++ b/core/java/android/permission/IPermissionController.aidl @@ -17,6 +17,7 @@ package android.permission; import android.os.RemoteCallback; +import android.os.Bundle; /** * Interface for system apps to communication with the permission controller. @@ -24,6 +25,8 @@ import android.os.RemoteCallback; * @hide */ oneway interface IPermissionController { + void revokeRuntimePermissions(in Bundle request, boolean doDryRun, int reason, + String callerPackageName, in RemoteCallback callback); void getAppPermissions(String packageName, in RemoteCallback callback); void revokeRuntimePermission(String packageName, String permissionName); void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted, diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java index 66e8666a8a70..e21a6608bee0 100644 --- a/core/java/android/permission/PermissionControllerManager.java +++ b/core/java/android/permission/PermissionControllerManager.java @@ -22,46 +22,97 @@ import static com.android.internal.util.Preconditions.checkCollectionElementsNot import static com.android.internal.util.Preconditions.checkNotNull; import android.Manifest; +import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.Binder; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.Log; import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; import com.android.internal.infra.AbstractRemoteService; +import com.android.internal.util.Preconditions; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; /** - * Interface for communicating with the permission controller from system apps. All UI operations - * regarding permissions and any changes to the permission state should flow through this - * interface. + * Interface for communicating with the permission controller. * * @hide */ +@TestApi +@SystemApi @SystemService(Context.PERMISSION_CONTROLLER_SERVICE) public final class PermissionControllerManager { private static final String TAG = PermissionControllerManager.class.getSimpleName(); /** * The key for retrieving the result from the returned bundle. + * + * @hide */ public static final String KEY_RESULT = "android.permission.PermissionControllerManager.key.result"; + /** @hide */ + @IntDef(prefix = { "REASON_" }, value = { + REASON_MALWARE, + REASON_INSTALLER_POLICY_VIOLATION, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Reason {} + + /** The permissions are revoked because the apps holding the permissions are malware */ + public static final int REASON_MALWARE = 1; + + /** + * The permissions are revoked because the apps holding the permissions violate a policy of the + * app that installed it. + * + * <p>If this reason is used only permissions of apps that are installed by the caller of the + * API can be revoked. + */ + public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; + + /** + * Callback for delivering the result of {@link #revokeRuntimePermissions}. + */ + public abstract static class OnRevokeRuntimePermissionsCallback { + /** + * The result for {@link #revokeRuntimePermissions}. + * + * @param revoked The actually revoked permissions as + * {@code Map<packageName, List<permission>>} + */ + public abstract void onRevokeRuntimePermissions(@NonNull Map<String, List<String>> revoked); + } + /** * Callback for delivering the result of {@link #getAppPermissions}. + * + * @hide */ public interface OnGetAppPermissionResultCallback { /** @@ -75,6 +126,8 @@ public final class PermissionControllerManager { /** * Callback for delivering the result of {@link #countPermissionApps}. + * + * @hide */ public interface OnCountPermissionAppsResultCallback { /** @@ -86,23 +139,61 @@ public final class PermissionControllerManager { void onCountPermissionApps(int numApps); } + private final @NonNull Context mContext; private final RemoteService mRemoteService; + /** @hide */ public PermissionControllerManager(@NonNull Context context) { Intent intent = new Intent(SERVICE_INTERFACE); intent.setPackage(context.getPackageManager().getPermissionControllerPackageName()); ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0); + mContext = context; mRemoteService = new RemoteService(context, serviceInfo.getComponentInfo().getComponentName()); } /** + * Revoke a set of runtime permissions for various apps. + * + * @param request The permissions to revoke as {@code Map<packageName, List<permission>>} + * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them + * @param reason Why the permission should be revoked + * @param executor Executor on which to invoke the callback + * @param callback Callback to receive the result + */ + @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) + public void revokeRuntimePermissions(@NonNull Map<String, List<String>> request, + boolean doDryRun, @Reason int reason, @NonNull @CallbackExecutor Executor executor, + @NonNull OnRevokeRuntimePermissionsCallback callback) { + // Check input to fail immediately instead of inside the async request + checkNotNull(executor); + checkNotNull(callback); + checkNotNull(request); + for (Map.Entry<String, List<String>> appRequest : request.entrySet()) { + checkNotNull(appRequest.getKey()); + checkCollectionElementsNotNull(appRequest.getValue(), "permissions"); + } + + // Check required permission to fail immediately instead of inside the oneway binder call + if (mContext.checkSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS + + " required"); + } + + mRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(mRemoteService, + request, doDryRun, reason, mContext.getPackageName(), executor, callback)); + } + + /** * Gets the runtime permissions for an app. * * @param packageName The package for which to query. * @param callback Callback to receive the result. * @param handler Handler on which to invoke the callback. + * + * @hide */ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getAppPermissions(@NonNull String packageName, @@ -119,6 +210,8 @@ public final class PermissionControllerManager { * * @param packageName The package for which to revoke * @param permissionName The permission to revoke + * + * @hide */ @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String packageName, @@ -138,6 +231,8 @@ public final class PermissionControllerManager { * @param countSystem Also count system apps * @param callback Callback to receive the result * @param handler Handler on which to invoke the callback + * + * @hide */ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS) public void countPermissionApps(@NonNull List<String> permissionNames, @@ -206,6 +301,84 @@ public final class PermissionControllerManager { } /** + * Request for {@link #revokeRuntimePermissions} + */ + private static final class PendingRevokeRuntimePermissionRequest extends + AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> { + private final @NonNull Map<String, List<String>> mRequest; + private final boolean mDoDryRun; + private final int mReason; + private final @NonNull String mCallingPackage; + private final @NonNull OnRevokeRuntimePermissionsCallback mCallback; + + private final @NonNull RemoteCallback mRemoteCallback; + + private PendingRevokeRuntimePermissionRequest(@NonNull RemoteService service, + @NonNull Map<String, List<String>> request, boolean doDryRun, + @Reason int reason, @NonNull String callingPackage, + @NonNull @CallbackExecutor Executor executor, + @NonNull OnRevokeRuntimePermissionsCallback callback) { + super(service); + + mRequest = request; + mDoDryRun = doDryRun; + mReason = reason; + mCallingPackage = callingPackage; + mCallback = callback; + + mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> { + long token = Binder.clearCallingIdentity(); + try { + Map<String, List<String>> revoked = new ArrayMap<>(); + try { + Bundle bundleizedRevoked = result.getBundle(KEY_RESULT); + + for (String packageName : bundleizedRevoked.keySet()) { + Preconditions.checkNotNull(packageName); + + ArrayList<String> permissions = + bundleizedRevoked.getStringArrayList(packageName); + Preconditions.checkCollectionElementsNotNull(permissions, + "permissions"); + + revoked.put(packageName, permissions); + } + } catch (Exception e) { + Log.e(TAG, "Could not read result when revoking runtime permissions", e); + } + + callback.onRevokeRuntimePermissions(revoked); + } finally { + Binder.restoreCallingIdentity(token); + + finish(); + } + }), null); + } + + @Override + protected void onTimeout(RemoteService remoteService) { + mCallback.onRevokeRuntimePermissions(Collections.emptyMap()); + } + + @Override + public void run() { + Bundle bundledizedRequest = new Bundle(); + for (Map.Entry<String, List<String>> appRequest : mRequest.entrySet()) { + bundledizedRequest.putStringArrayList(appRequest.getKey(), + new ArrayList<>(appRequest.getValue())); + } + + try { + getService().getServiceInterface().revokeRuntimePermissions(bundledizedRequest, + mDoDryRun, mReason, mCallingPackage, mRemoteCallback); + } catch (RemoteException e) { + Log.e(TAG, "Error revoking runtime permission", e); + } + } + } + + /** * Request for {@link #getAppPermissions} */ private static final class PendingGetAppPermissionRequest extends diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java index 5dad07178e53..f621737e5ed4 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -16,6 +16,7 @@ package android.permission; +import static com.android.internal.util.Preconditions.checkArgument; import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; @@ -26,12 +27,19 @@ import android.annotation.SystemApi; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteCallback; +import android.util.ArrayMap; +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * This service is meant to be implemented by the app controlling permissions. @@ -60,6 +68,20 @@ public abstract class PermissionControllerService extends Service { } /** + * Revoke a set of runtime permissions for various apps. + * + * @param requests The permissions to revoke as {@code Map<packageName, List<permission>>} + * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them + * @param reason Why the permission should be revoked + * @param callerPackageName The package name of the calling app + * + * @return the actually removed permissions as {@code Map<packageName, List<permission>>} + */ + public abstract @NonNull Map<String, List<String>> onRevokeRuntimePermissions( + @NonNull Map<String, List<String>> requests, boolean doDryRun, + @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName); + + /** * Gets the runtime permissions for an app. * * @param packageName The package for which to query. @@ -94,6 +116,41 @@ public abstract class PermissionControllerService extends Service { public final IBinder onBind(Intent intent) { return new IPermissionController.Stub() { @Override + public void revokeRuntimePermissions( + Bundle bundleizedRequest, boolean doDryRun, int reason, + String callerPackageName, RemoteCallback callback) { + checkNotNull(bundleizedRequest, "bundleizedRequest"); + checkNotNull(callerPackageName); + checkNotNull(callback); + + Map<String, List<String>> request = new ArrayMap<>(); + for (String packageName : bundleizedRequest.keySet()) { + Preconditions.checkNotNull(packageName); + + ArrayList<String> permissions = + bundleizedRequest.getStringArrayList(packageName); + Preconditions.checkCollectionElementsNotNull(permissions, "permissions"); + + request.put(packageName, permissions); + } + + enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null); + + // Verify callerPackageName + try { + PackageInfo pkgInfo = getPackageManager().getPackageInfo(callerPackageName, 0); + checkArgument(getCallingUid() == pkgInfo.applicationInfo.uid); + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException(e); + } + + mHandler.sendMessage(obtainMessage( + PermissionControllerService::revokeRuntimePermissions, + PermissionControllerService.this, request, doDryRun, reason, + callerPackageName, callback)); + } + + @Override public void getAppPermissions(String packageName, RemoteCallback callback) { checkNotNull(packageName, "packageName"); checkNotNull(callback, "callback"); @@ -133,6 +190,27 @@ public abstract class PermissionControllerService extends Service { }; } + private void revokeRuntimePermissions(@NonNull Map<String, List<String>> requests, + boolean doDryRun, @PermissionControllerManager.Reason int reason, + @NonNull String callerPackageName, @NonNull RemoteCallback callback) { + Map<String, List<String>> revoked = onRevokeRuntimePermissions(requests, + doDryRun, reason, callerPackageName); + + checkNotNull(revoked); + Bundle bundledizedRevoked = new Bundle(); + for (Map.Entry<String, List<String>> appRevocation : revoked.entrySet()) { + checkNotNull(appRevocation.getKey()); + checkCollectionElementsNotNull(appRevocation.getValue(), "permissions"); + + bundledizedRevoked.putStringArrayList(appRevocation.getKey(), + new ArrayList<>(appRevocation.getValue())); + } + + Bundle result = new Bundle(); + result.putBundle(PermissionControllerManager.KEY_RESULT, bundledizedRevoked); + callback.sendResult(result); + } + private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) { List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName); if (permissions != null && !permissions.isEmpty()) { diff --git a/core/java/android/permission/TEST_MAPPING b/core/java/android/permission/TEST_MAPPING new file mode 100644 index 000000000000..ba9f36a31f2e --- /dev/null +++ b/core/java/android/permission/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "CtsPermissionTestCases", + "options": [ + { + "include-filter": "android.permission.cts.PermissionControllerTest" + } + ] + } + ] +}
\ No newline at end of file diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index bb1784af6c85..16f9a43de28d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6207,7 +6207,7 @@ public final class Settings { public static final String CHARGING_SOUNDS_ENABLED = "charging_sounds_enabled"; /** - * Whether to vibrate for wireless charging events. + * Whether to vibrate for charging events. * @hide */ public static final String CHARGING_VIBRATION_ENABLED = "charging_vibration_enabled"; @@ -8882,6 +8882,14 @@ public final class Settings { public static final String ADD_USERS_WHEN_LOCKED = "add_users_when_locked"; /** + * Whether applying ramping ringer on incoming phone call ringtone. + * <p>1 = apply ramping ringer + * <p>0 = do not apply ramping ringer + * @hide + */ + public static final String APPLY_RAMPING_RINGER = "apply_ramping_ringer"; + + /** * Setting whether the global gesture for enabling accessibility is enabled. * If this gesture is enabled the user will be able to perfrom it to enable * the accessibility state without visiting the settings app. @@ -9415,7 +9423,8 @@ public final class Settings { "hdmi_control_auto_wakeup_enabled"; /** - * Whether TV will also turn off other CEC devices when it goes to standby mode. + * Whether TV or Audio System will also turn off other CEC devices when it goes to standby + * mode. * (0 = false, 1 = true) * * @hide @@ -9424,6 +9433,15 @@ public final class Settings { "hdmi_control_auto_device_off_enabled"; /** + * Whether Audio System will also turn off TV when it goes to standby mode. + * (0 = false, 1 = true) + * + * @hide + */ + public static final String HDMI_CONTROL_AUTO_TV_OFF_ENABLED = + "hdmi_control_auto_tv_off_enabled"; + + /** * If <b>true</b>, enables out-of-the-box execution for priv apps. * Default: false * Values: 0 = false, 1 = true @@ -11982,12 +12000,18 @@ public final class Settings { "angle_gl_driver_selection_values"; /** - * Apps that are selected to use Game Update Package. + * List of Apps selected to use Game Update Packages. * @hide */ public static final String GUP_DEV_OPT_IN_APPS = "gup_dev_opt_in_apps"; /** + * List of Apps selected not to use Game Update Packages. + * @hide + */ + public static final String GUP_DEV_OPT_OUT_APPS = "gup_dev_opt_out_apps"; + + /** * Apps on the black list that are forbidden to useGame Update Package. * @hide */ diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index 7683b8ae08b2..a9f4034c37af 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -214,7 +214,7 @@ public abstract class AugmentedAutofillService extends Service { } @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + protected final void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mAutofillProxies != null) { final int size = mAutofillProxies.size(); pw.print("Number proxies: "); pw.println(size); @@ -225,6 +225,15 @@ public abstract class AugmentedAutofillService extends Service { proxy.dump(" ", pw); } } + dump(pw, args); + } + + /** + * Implementation specific {@code dump}. + */ + protected void dump(@NonNull PrintWriter pw, + @SuppressWarnings("unused") @NonNull String[] args) { + pw.print(getClass().getName()); pw.println(": nothing to dump"); } /** @hide */ diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java index 784e71993815..db242a2e265e 100644 --- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java +++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java @@ -34,7 +34,7 @@ import java.util.List; @SystemApi @Deprecated public final class ContentCaptureEventsRequest implements Parcelable { -// TODO(b/121033016): remove .java and .aidl once service implementation doesn't use it anymore +// TODO(b/121051220): remove .java and .aidl once service implementation doesn't use it anymore private final ContentCaptureEvent mEvent; diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index c9d46dd701b5..26bf361a8acc 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -123,12 +123,12 @@ public abstract class ContentCaptureService extends Service { }; /** - * List of sessions per UID. + * UIDs associated with each session. * * <p>This map is populated when an session is started, which is called by the system server * and can be trusted. Then subsequent calls made by the app are verified against this map. */ - private final ArrayMap<String, Integer> mSessionsByUid = new ArrayMap<>(); + private final ArrayMap<String, Integer> mSessionUids = new ArrayMap<>(); @CallSuper @Override @@ -285,13 +285,13 @@ public abstract class ContentCaptureService extends Service { @Override @CallSuper protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - final int size = mSessionsByUid.size(); + final int size = mSessionUids.size(); pw.print("Number sessions: "); pw.println(size); if (size > 0) { final String prefix = " "; for (int i = 0; i < size; i++) { - pw.print(prefix); pw.print(mSessionsByUid.keyAt(i)); - pw.print(": uid="); pw.println(mSessionsByUid.valueAt(i)); + pw.print(prefix); pw.print(mSessionUids.keyAt(i)); + pw.print(": uid="); pw.println(mSessionUids.valueAt(i)); } } } @@ -309,7 +309,7 @@ public abstract class ContentCaptureService extends Service { private void handleOnCreateSession(@NonNull ContentCaptureContext context, @NonNull String sessionId, int uid, IResultReceiver clientReceiver) { - mSessionsByUid.put(sessionId, uid); + mSessionUids.put(sessionId, uid); onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId)); setClientState(clientReceiver, ContentCaptureSession.STATE_ACTIVE, mClientInterface.asBinder()); @@ -336,11 +336,11 @@ public abstract class ContentCaptureService extends Service { case ContentCaptureEvent.TYPE_SESSION_STARTED: final ContentCaptureContext clientContext = event.getClientContext(); clientContext.setParentSessionId(event.getParentSessionId()); - mSessionsByUid.put(sessionIdString, uid); + mSessionUids.put(sessionIdString, uid); onCreateContentCaptureSession(clientContext, sessionId); break; case ContentCaptureEvent.TYPE_SESSION_FINISHED: - mSessionsByUid.remove(sessionIdString); + mSessionUids.remove(sessionIdString); onDestroyContentCaptureSession(sessionId); break; default: @@ -355,7 +355,7 @@ public abstract class ContentCaptureService extends Service { } private void handleFinishSession(@NonNull String sessionId) { - mSessionsByUid.remove(sessionId); + mSessionUids.remove(sessionId); onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId)); } @@ -372,10 +372,13 @@ public abstract class ContentCaptureService extends Service { default: sessionId = event.getSessionId(); } - final Integer rightUid = mSessionsByUid.get(sessionId); + final Integer rightUid = mSessionUids.get(sessionId); if (rightUid == null) { - if (VERBOSE) Log.v(TAG, "No session for " + sessionId); - // Just ignore, as the session could have finished + if (DEBUG) { + Log.d(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId + + ": " + mSessionUids); + } + // Just ignore, as the session could have been finished already return false; } if (rightUid != uid) { diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl index be3f3b345824..b84e6c9bc962 100644 --- a/core/java/android/service/dreams/IDreamManager.aidl +++ b/core/java/android/service/dreams/IDreamManager.aidl @@ -33,4 +33,5 @@ interface IDreamManager { void finishSelf(in IBinder token, boolean immediate); void startDozing(in IBinder token, int screenState, int screenBrightness); void stopDozing(in IBinder token); + void forceAmbientDisplayEnabled(boolean enabled); } diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index dd0242ae2dc8..fd2b0fae6afb 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -185,7 +185,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS * Implement this to know when a direct reply is sent from a notification. * @param key the notification key */ - public void onNotificationDirectReply(@NonNull String key) {} + public void onNotificationDirectReplied(@NonNull String key) {} /** * Implement this to know when a suggested reply is sent. @@ -407,7 +407,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS SomeArgs args = (SomeArgs) msg.obj; String key = (String) args.arg1; args.recycle(); - onNotificationDirectReply(key); + onNotificationDirectReplied(key); break; } case MSG_ON_SUGGESTED_REPLY_SENT: { diff --git a/core/java/android/service/wallpaper/IWallpaperConnection.aidl b/core/java/android/service/wallpaper/IWallpaperConnection.aidl index a976d0e40423..f334d9d3e874 100644 --- a/core/java/android/service/wallpaper/IWallpaperConnection.aidl +++ b/core/java/android/service/wallpaper/IWallpaperConnection.aidl @@ -27,5 +27,5 @@ interface IWallpaperConnection { void attachEngine(IWallpaperEngine engine, int displayId); void engineShown(IWallpaperEngine engine); ParcelFileDescriptor setWallpaper(String name); - void onWallpaperColorsChanged(in WallpaperColors colors); + void onWallpaperColorsChanged(in WallpaperColors colors, int displayId); } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index a011d677fc6a..0d7223d67907 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -56,6 +56,7 @@ import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.InsetsState; import android.view.MotionEvent; +import android.view.SurfaceControl; import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; @@ -217,6 +218,8 @@ public abstract class WallpaperService extends Service { private Context mDisplayContext; private int mDisplayState; + SurfaceControl mSurfaceControl = new SurfaceControl(); + final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() { { mRequestedFormat = PixelFormat.RGBX_8888; @@ -642,7 +645,7 @@ public abstract class WallpaperService extends Service { try { final WallpaperColors newColors = onComputeColors(); if (mConnection != null) { - mConnection.onWallpaperColorsChanged(newColors); + mConnection.onWallpaperColorsChanged(newColors, mDisplay.getDisplayId()); } else { Log.w(TAG, "Can't notify system because wallpaper connection " + "was not established."); @@ -843,8 +846,12 @@ public abstract class WallpaperService extends Service { mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, View.VISIBLE, 0, -1, mWinFrame, mOverscanInsets, mContentInsets, mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame, - mDisplayCutout, mMergedConfiguration, mSurfaceHolder.mSurface, + mDisplayCutout, mMergedConfiguration, mSurfaceControl, mInsetsState); + if (mSurfaceControl.isValid()) { + mSurfaceHolder.mSurface.copyFrom(mSurfaceControl); + mSurfaceControl.release(); + } if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface + ", frame=" + mWinFrame); @@ -963,7 +970,7 @@ public abstract class WallpaperService extends Service { mFinalSystemInsets.set(mDispatchedOverscanInsets); mFinalStableInsets.set(mDispatchedStableInsets); WindowInsets insets = new WindowInsets(mFinalSystemInsets, - null, mFinalStableInsets, + mFinalStableInsets, getResources().getConfiguration().isScreenRound(), false, mDispatchedDisplayCutout); if (DEBUG) { @@ -1466,7 +1473,7 @@ public abstract class WallpaperService extends Service { break; } try { - mConnection.onWallpaperColorsChanged(mEngine.onComputeColors()); + mConnection.onWallpaperColorsChanged(mEngine.onComputeColors(), mDisplayId); } catch (RemoteException e) { // Connection went away, nothing to do in here. } diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 3d0c6622d8af..24d746e0dfe2 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -376,9 +376,13 @@ public class StaticLayout extends Layout { * Set paragraph justification mode. The default value is * {@link Layout#JUSTIFICATION_MODE_NONE}. If the last line is too short for justification, * the last line will be displayed with the alignment set by {@link #setAlignment}. + * When Justification mode is JUSTIFICATION_MODE_INTER_WORD, wordSpacing on the given + * {@link Paint} will be ignored. This behavior also affects Spans which change the + * wordSpacing. * * @param justificationMode justification mode for the paragraph. * @return this builder, useful for chaining. + * @see Paint#setWordSpacing(float) */ @NonNull public Builder setJustificationMode(@JustificationMode int justificationMode) { diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 6eb433abf16c..949328fd3a99 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -75,8 +75,9 @@ public class TextLine { private int mEllipsisEnd; // Additional width of whitespace for justification. This value is per whitespace, thus - // the line width will increase by mAddedWidth x (number of stretchable whitespaces). - private float mAddedWidth; + // the line width will increase by mAddedWidthForJustify x (number of stretchable whitespaces). + private float mAddedWidthForJustify; + private boolean mIsJustifying; private final TextPaint mWorkPaint = new TextPaint(); private final TextPaint mActivePaint = new TextPaint(); @@ -229,7 +230,8 @@ public class TextLine { } } mTabs = tabStops; - mAddedWidth = 0; + mAddedWidthForJustify = 0; + mIsJustifying = false; mEllipsisStart = ellipsisStart != ellipsisEnd ? ellipsisStart : 0; mEllipsisEnd = ellipsisStart != ellipsisEnd ? ellipsisEnd : 0; @@ -255,7 +257,8 @@ public class TextLine { return; } final float width = Math.abs(measure(end, false, null)); - mAddedWidth = (justifyWidth - width) / spaces; + mAddedWidthForJustify = (justifyWidth - width) / spaces; + mIsJustifying = true; } /** @@ -713,7 +716,9 @@ public class TextLine { TextPaint wp = mWorkPaint; wp.set(mPaint); - wp.setWordSpacing(mAddedWidth); + if (mIsJustifying) { + wp.setWordSpacing(mAddedWidthForJustify); + } int spanStart = runStart; int spanLimit; @@ -849,7 +854,9 @@ public class TextLine { FontMetricsInt fmi, boolean needWidth, int offset, @Nullable ArrayList<DecorationInfo> decorations) { - wp.setWordSpacing(mAddedWidth); + if (mIsJustifying) { + wp.setWordSpacing(mAddedWidthForJustify); + } // Get metrics first (even for empty strings or "0" width runs) if (fmi != null) { expandMetricsFromPaint(fmi, wp); diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java index 7eef63efd14d..d051ed84dd7c 100644 --- a/core/java/android/util/KeyValueListParser.java +++ b/core/java/android/util/KeyValueListParser.java @@ -16,7 +16,9 @@ package android.util; import android.text.TextUtils; +import android.util.proto.ProtoOutputStream; +import java.io.PrintWriter; import java.time.Duration; import java.time.format.DateTimeParseException; @@ -212,4 +214,163 @@ public class KeyValueListParser { } return def; } + + /** Represents an integer config value. */ + public static class IntValue { + private final String mKey; + private final int mDefaultValue; + private int mValue; + + /** Constructor, initialize with a config key and a default value. */ + public IntValue(String key, int defaultValue) { + mKey = key; + mDefaultValue = defaultValue; + mValue = mDefaultValue; + } + + /** Read a value from {@link KeyValueListParser} */ + public void parse(KeyValueListParser parser) { + mValue = parser.getInt(mKey, mDefaultValue); + } + + /** Return the config key. */ + public String getKey() { + return mKey; + } + + /** Return the default value. */ + public int getDefaultValue() { + return mDefaultValue; + } + + /** Return the actual config value. */ + public int getValue() { + return mValue; + } + + /** Overwrites with a value. */ + public void setValue(int value) { + mValue = value; + } + + /** Used for dumpsys */ + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); + pw.print(mKey); + pw.print("="); + pw.print(mValue); + pw.println(); + } + + /** Used for proto dumpsys */ + public void dumpProto(ProtoOutputStream proto, long tag) { + proto.write(tag, mValue); + } + } + + /** Represents an long config value. */ + public static class LongValue { + private final String mKey; + private final long mDefaultValue; + private long mValue; + + /** Constructor, initialize with a config key and a default value. */ + public LongValue(String key, long defaultValue) { + mKey = key; + mDefaultValue = defaultValue; + mValue = mDefaultValue; + } + + /** Read a value from {@link KeyValueListParser} */ + public void parse(KeyValueListParser parser) { + mValue = parser.getLong(mKey, mDefaultValue); + } + + /** Return the config key. */ + public String getKey() { + return mKey; + } + + /** Return the default value. */ + public long getDefaultValue() { + return mDefaultValue; + } + + /** Return the actual config value. */ + public long getValue() { + return mValue; + } + + /** Overwrites with a value. */ + public void setValue(long value) { + mValue = value; + } + + /** Used for dumpsys */ + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); + pw.print(mKey); + pw.print("="); + pw.print(mValue); + pw.println(); + } + + /** Used for proto dumpsys */ + public void dumpProto(ProtoOutputStream proto, long tag) { + proto.write(tag, mValue); + } + } + + /** Represents an string config value. */ + public static class StringValue { + private final String mKey; + private final String mDefaultValue; + private String mValue; + + /** Constructor, initialize with a config key and a default value. */ + public StringValue(String key, String defaultValue) { + mKey = key; + mDefaultValue = defaultValue; + mValue = mDefaultValue; + } + + /** Read a value from {@link KeyValueListParser} */ + public void parse(KeyValueListParser parser) { + mValue = parser.getString(mKey, mDefaultValue); + } + + /** Return the config key. */ + public String getKey() { + return mKey; + } + + /** Return the default value. */ + public String getDefaultValue() { + return mDefaultValue; + } + + /** Return the actual config value. */ + public String getValue() { + return mValue; + } + + /** Overwrites with a value. */ + public void setValue(String value) { + mValue = value; + } + + /** Used for dumpsys */ + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); + pw.print(mKey); + pw.print("="); + pw.print(mValue); + pw.println(); + } + + /** Used for proto dumpsys */ + public void dumpProto(ProtoOutputStream proto, long tag) { + proto.write(tag, mValue); + } + } } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index d1115c7b4d1d..658f06ad21f9 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -99,7 +99,7 @@ interface IWindowSession { out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets, out Rect outOutsets, out Rect outBackdropFrame, out DisplayCutout.ParcelableWrapper displayCutout, - out MergedConfiguration outMergedConfiguration, out Surface outSurface, + out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl, out InsetsState insetsState); /* diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 885b3e94c593..093191499921 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -16,6 +16,8 @@ package android.view; +import static android.view.WindowInsets.Type.indexOf; + import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Insets; @@ -114,8 +116,8 @@ public class InsetsState implements Parcelable { public WindowInsets calculateInsets(Rect frame, boolean isScreenRound, boolean alwaysConsumeNavBar, DisplayCutout cutout, @Nullable @InsetSide SparseIntArray typeSideMap) { - Insets systemInsets = Insets.NONE; - Insets maxInsets = Insets.NONE; + Insets[] typeInsetsMap = new Insets[Type.SIZE]; + Insets[] typeMaxInsetsMap = new Insets[Type.SIZE]; final Rect relativeFrame = new Rect(frame); final Rect relativeFrameMax = new Rect(frame); for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) { @@ -123,32 +125,38 @@ public class InsetsState implements Parcelable { if (source == null) { continue; } - systemInsets = processSource(source, systemInsets, relativeFrame, - false /* ignoreVisibility */, typeSideMap); + processSource(source, relativeFrame, false /* ignoreVisibility */, typeInsetsMap, + typeSideMap); // IME won't be reported in max insets as the size depends on the EditorInfo of the IME // target. if (source.getType() != TYPE_IME) { - maxInsets = processSource(source, maxInsets, relativeFrameMax, - true /* ignoreVisibility */, null /* typeSideMap */); + processSource(source, relativeFrameMax, true /* ignoreVisibility */, + typeMaxInsetsMap, null /* typeSideMap */); } } - return new WindowInsets(new Rect(systemInsets), null, new Rect(maxInsets), isScreenRound, + return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, isScreenRound, alwaysConsumeNavBar, cutout); } - private Insets processSource(InsetsSource source, Insets insets, Rect relativeFrame, - boolean ignoreVisibility, @Nullable @InsetSide SparseIntArray typeSideMap) { - Insets currentInsets = source.calculateInsets(relativeFrame, ignoreVisibility); - insets = Insets.add(currentInsets, insets); - relativeFrame.inset(insets); - if (typeSideMap != null && !Insets.NONE.equals(currentInsets)) { - @InsetSide int insetSide = getInsetSide(currentInsets); + private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility, + Insets[] typeInsetsMap, @Nullable @InsetSide SparseIntArray typeSideMap) { + Insets insets = source.calculateInsets(relativeFrame, ignoreVisibility); + + int index = indexOf(toPublicType(source.getType())); + Insets existing = typeInsetsMap[index]; + if (existing == null) { + typeInsetsMap[index] = insets; + } else { + typeInsetsMap[index] = Insets.max(existing, insets); + } + + if (typeSideMap != null && !Insets.NONE.equals(insets)) { + @InsetSide int insetSide = getInsetSide(insets); if (insetSide != INSET_SIDE_UNKNWON) { - typeSideMap.put(source.getType(), getInsetSide(currentInsets)); + typeSideMap.put(source.getType(), getInsetSide(insets)); } } - return insets; } /** @@ -229,6 +237,21 @@ public class InsetsState implements Parcelable { return result; } + static @InsetType int toPublicType(@InternalInsetType int type) { + switch (type) { + case TYPE_TOP_BAR: + return Type.TOP_BAR; + case TYPE_SIDE_BAR_1: + case TYPE_SIDE_BAR_2: + case TYPE_SIDE_BAR_3: + return Type.SIDE_BARS; + case TYPE_IME: + return Type.IME; + default: + throw new IllegalArgumentException("Unknown type: " + type); + } + } + public static boolean getDefaultVisibly(@InsetType int type) { switch (type) { case TYPE_TOP_BAR: diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 1a708e8e30ec..acad5d76f0b5 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -67,6 +67,7 @@ public class SurfaceControl implements Parcelable { int w, int h, int format, int flags, long parentObject, int windowType, int ownerUid) throws OutOfResourcesException; private static native long nativeReadFromParcel(Parcel in); + private static native long nativeCopyFromSurfaceControl(long nativeObject); private static native void nativeWriteToParcel(long nativeObject, Parcel out); private static native void nativeRelease(long nativeObject); private static native void nativeDestroy(long nativeObject); @@ -157,7 +158,6 @@ public class SurfaceControl implements Parcelable { private static native void nativeSeverChildren(long transactionObj, long nativeObject); private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject, int scalingMode); - private static native void nativeDestroy(long transactionObj, long nativeObject); private static native IBinder nativeGetHandle(long nativeObject); private static native boolean nativeGetTransformToDisplayInverse(long nativeObject); @@ -169,7 +169,7 @@ public class SurfaceControl implements Parcelable { IBinder toToken); private final CloseGuard mCloseGuard = CloseGuard.get(); - private final String mName; + private String mName; long mNativeObject; // package visibility only for Surface.java access // TODO: Move this to native. @@ -359,6 +359,20 @@ public class SurfaceControl implements Parcelable { */ public static final int WINDOW_TYPE_DONT_SCREENSHOT = 441731; + private void assignNativeObject(long nativeObject) { + if (mNativeObject != 0) { + release(); + } + mNativeObject = nativeObject; + } + + public void copyFrom(SurfaceControl other) { + mName = other.mName; + mWidth = other.mWidth; + mHeight = other.mHeight; + assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject)); + } + /** * Builder class for {@link SurfaceControl} objects. */ @@ -660,14 +674,28 @@ public class SurfaceControl implements Parcelable { } private SurfaceControl(Parcel in) { + readFromParcel(in); + mCloseGuard.open("release"); + } + + public SurfaceControl() { + mCloseGuard.open("release"); + } + + public void readFromParcel(Parcel in) { + if (in == null) { + throw new IllegalArgumentException("source must not be null"); + } + mName = in.readString(); mWidth = in.readInt(); mHeight = in.readInt(); - mNativeObject = nativeReadFromParcel(in); - if (mNativeObject == 0) { - throw new IllegalArgumentException("Couldn't read SurfaceControl from parcel=" + in); + + long object = 0; + if (in.readInt() != 0) { + object = nativeReadFromParcel(in); } - mCloseGuard.open("release"); + assignNativeObject(object); } @Override @@ -680,7 +708,16 @@ public class SurfaceControl implements Parcelable { dest.writeString(mName); dest.writeInt(mWidth); dest.writeInt(mHeight); + if (mNativeObject == 0) { + dest.writeInt(0); + } else { + dest.writeInt(1); + } nativeWriteToParcel(mNativeObject, dest); + + if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { + release(); + } } /** @@ -763,6 +800,10 @@ public class SurfaceControl implements Parcelable { "mNativeObject is null. Have you called release() already?"); } + public boolean isValid() { + return mNativeObject != 0; + } + /* * set surface parameters. * needs to be inside open/closeTransaction block @@ -1729,30 +1770,6 @@ public class SurfaceControl implements Parcelable { return this; } - /** - * Same as {@link #destroy()} except this is invoked in a transaction instead of - * immediately. - */ - public Transaction destroy(SurfaceControl sc) { - sc.checkNotReleased(); - - /** - * Perhaps it's safer to transfer the close guard to the Transaction - * but then we have a whole wonky scenario regarding merging, multiple - * close-guards per transaction etc...the whole scenario is kind of wonky - * and it seems really we'd like to just be able to call release here - * but the WindowManager has some code that looks like - * --- destroyInTransaction(a) - * --- reparentChildrenInTransaction(a) - * so we need to ensure the SC remains valid until the transaction - * is applied. - */ - sc.mCloseGuard.close(); - - nativeDestroy(mNativeObject, sc.mNativeObject); - return this; - } - public Transaction setDisplaySurface(IBinder displayToken, Surface surface) { if (displayToken == null) { throw new IllegalArgumentException("displayToken must not be null"); diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java index a4fa12a57e93..361ac932758e 100644 --- a/core/java/android/view/SurfaceSession.java +++ b/core/java/android/view/SurfaceSession.java @@ -30,7 +30,6 @@ public final class SurfaceSession { private long mNativeClient; // SurfaceComposerClient* private static native long nativeCreate(); - private static native long nativeCreateScoped(long surfacePtr); private static native void nativeDestroy(long ptr); private static native void nativeKill(long ptr); @@ -40,15 +39,6 @@ public final class SurfaceSession { mNativeClient = nativeCreate(); } - public SurfaceSession(Surface root) { - synchronized (root.mLock) { - if (root.mNativeObject == 0) { - throw new IllegalStateException("Surface is not initialized or has been released"); - } - mNativeClient = nativeCreateScoped(root.mNativeObject); - } - } - /* no user serviceable parts here ... */ @Override protected void finalize() throws Throwable { diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index a0af83d17abd..61fb00d3fe59 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -547,7 +547,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb if (creating) { viewRoot.createBoundsSurface(mSubLayer); - mSurfaceSession = new SurfaceSession(viewRoot.mBoundsSurface); + mSurfaceSession = new SurfaceSession(); mDeferredDestroySurfaceControl = mSurfaceControl; updateOpaqueFlag(); @@ -559,6 +559,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb new SurfaceControl.Builder(mSurfaceSession) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) + .setParent(viewRoot.getSurfaceControl()) .setFlags(mSurfaceFlags)); } else if (mSurfaceControl == null) { return; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 6b07efc0b448..cb2c40e6197e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -939,6 +939,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static boolean sAcceptZeroSizeDragShadow; + /** + * Prior to Q, {@link #dispatchApplyWindowInsets} had some issues: + * <ul> + * <li>The modified insets changed by {@link #onApplyWindowInsets} were passed to the + * entire view hierarchy in prefix order, including siblings as well as siblings of parents + * further down the hierarchy. This violates the basic concepts of the view hierarchy, and + * thus, the hierarchical dispatching mechanism was hard to use for apps.</li> + * + * <li>Dispatch was stopped after the insets were fully consumed. This is somewhat confusing + * for developers, but more importantly, by adding more granular information to + * {@link WindowInsets} it becomes really cumbersome to define what consumed actually means + * </li> + * </ul> + * + * In order to make window inset dispatching work properly, we dispatch window insets + * in the view hierarchy in a proper hierarchical manner and don't stop dispatching if the + * insets are consumed if this flag is set to {@code false}. + */ + static boolean sBrokenInsetsDispatch; + /** @hide */ @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) @Retention(RetentionPolicy.SOURCE) @@ -5108,6 +5128,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; + sBrokenInsetsDispatch = !ViewRootImpl.USE_NEW_INSETS + || targetSdkVersion < Build.VERSION_CODES.Q; + sCompatibilityDone = true; } } @@ -7660,10 +7683,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} - * {@link AccessibilityEvent} to make an announcement which is related to some - * sort of a context change for which none of the events representing UI transitions - * is a good fit. For example, announcing a new page in a book. If accessibility - * is not enabled this method does nothing. + * {@link AccessibilityEvent} to suggest that an accessibility service announce the + * specified text to its users. + * <p> + * Note: The event generated with this API carries no semantic meaning, and is appropriate only + * in exceptional situations. Apps can generally achieve correct behavior for accessibility by + * accurately supplying the semantics of their UI. + * They should not need to specify what exactly is announced to users. * * @param text The announcement text. */ @@ -25053,9 +25079,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } final ViewRootImpl root = mAttachInfo.mViewRootImpl; - final SurfaceSession session = new SurfaceSession(root.mSurface); + final SurfaceSession session = new SurfaceSession(); final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) .setName("drag surface") + .setParent(root.getSurfaceControl()) .setBufferSize(shadowSize.x, shadowSize.y) .setFormat(PixelFormat.TRANSLUCENT) .build(); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 8372032593b0..9d11397498cf 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -7111,6 +7111,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @Override public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { insets = super.dispatchApplyWindowInsets(insets); + if (View.sBrokenInsetsDispatch) { + return brokenDispatchApplyWindowInsets(insets); + } else { + return newDispatchApplyWindowInsets(insets); + } + } + + private WindowInsets brokenDispatchApplyWindowInsets(WindowInsets insets) { if (!insets.isConsumed()) { final int count = getChildCount(); for (int i = 0; i < count; i++) { @@ -7123,6 +7131,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return insets; } + private WindowInsets newDispatchApplyWindowInsets(WindowInsets insets) { + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + getChildAt(i).dispatchApplyWindowInsets(insets); + } + return insets; + } + /** * Returns the animation listener to which layout animation events are * sent. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3f7a5127339d..8e4dc670a2d3 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -432,6 +432,7 @@ public final class ViewRootImpl implements ViewParent, // Surface can never be reassigned or cleared (use Surface.clear()). @UnsupportedAppUsage public final Surface mSurface = new Surface(); + private final SurfaceControl mSurfaceControl = new SurfaceControl(); /** * Child surface of {@code mSurface} with the same bounds as its parent, and crop bounds @@ -1526,7 +1527,7 @@ public final class ViewRootImpl implements ViewParent, */ public void createBoundsSurface(int zOrderLayer) { if (mSurfaceSession == null) { - mSurfaceSession = new SurfaceSession(mSurface); + mSurfaceSession = new SurfaceSession(); } if (mBoundsSurfaceControl != null && mBoundsSurface.isValid()) { return; // surface control for bounds surface already exists. @@ -1534,6 +1535,7 @@ public final class ViewRootImpl implements ViewParent, mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Bounds for - " + getTitle().toString()) + .setParent(mSurfaceControl) .build(); setBoundsSurfaceCrop(); @@ -1567,6 +1569,8 @@ public final class ViewRootImpl implements ViewParent, private void destroySurface() { mSurface.release(); + mSurfaceControl.release(); + mSurfaceSession = null; if (mBoundsSurfaceControl != null) { @@ -1855,8 +1859,7 @@ public final class ViewRootImpl implements ViewParent, mContext.getResources().getConfiguration().isScreenRound(), mAttachInfo.mAlwaysConsumeNavBar, displayCutout); } else { - mLastWindowInsets = new WindowInsets(contentInsets, - null /* windowDecorInsets */, stableInsets, + mLastWindowInsets = new WindowInsets(contentInsets, stableInsets, mContext.getResources().getConfiguration().isScreenRound(), mAttachInfo.mAlwaysConsumeNavBar, displayCutout); } @@ -6801,7 +6804,12 @@ public final class ViewRootImpl implements ViewParent, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber, mTmpFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout, - mPendingMergedConfiguration, mSurface, mTempInsets); + mPendingMergedConfiguration, mSurfaceControl, mTempInsets); + if (mSurfaceControl.isValid()) { + mSurface.copyFrom(mSurfaceControl); + } else { + destroySurface(); + } mPendingAlwaysConsumeNavBar = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0; @@ -8483,6 +8491,10 @@ public final class ViewRootImpl implements ViewParent, mActivityRelaunched = true; } + public SurfaceControl getSurfaceControl() { + return mSurfaceControl; + } + /** * Class for managing the accessibility interaction connection * based on the global accessibility state. diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index 572d33103cf4..b3da727b2f4d 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -17,18 +17,33 @@ package android.view; -import android.annotation.NonNull; +import static android.view.WindowInsets.Type.FIRST; +import static android.view.WindowInsets.Type.IME; +import static android.view.WindowInsets.Type.LAST; +import static android.view.WindowInsets.Type.SIDE_BARS; +import static android.view.WindowInsets.Type.SIZE; +import static android.view.WindowInsets.Type.TOP_BAR; +import static android.view.WindowInsets.Type.all; +import static android.view.WindowInsets.Type.compatSystemInsets; +import static android.view.WindowInsets.Type.indexOf; + import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.graphics.Insets; import android.graphics.Rect; +import android.util.SparseArray; +import android.view.InsetsState.InternalInsetType; +import android.view.WindowInsets.Type.InsetType; +import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethod; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; import java.util.Objects; /** @@ -49,9 +64,9 @@ import java.util.Objects; */ public final class WindowInsets { - @NonNull private final Insets mSystemWindowInsets; - @NonNull private final Insets mWindowDecorInsets; - @NonNull private final Insets mStableInsets; + private final Insets[] mTypeInsetsMap; + private final Insets[] mTypeMaxInsetsMap; + @Nullable private Rect mTempRect; private final boolean mIsRound; @Nullable private final DisplayCutout mDisplayCutout; @@ -64,7 +79,6 @@ public final class WindowInsets { private final boolean mAlwaysConsumeNavBar; private final boolean mSystemWindowInsetsConsumed; - private final boolean mWindowDecorInsetsConsumed; private final boolean mStableInsetsConsumed; private final boolean mDisplayCutoutConsumed; @@ -78,7 +92,7 @@ public final class WindowInsets { public static final WindowInsets CONSUMED; static { - CONSUMED = new WindowInsets((Insets) null, null, null, false, false, null); + CONSUMED = new WindowInsets((Rect) null, null, false, false, null); } /** @@ -87,24 +101,38 @@ public final class WindowInsets { * A {@code null} inset indicates that the respective inset is consumed. * * @hide + * @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)} */ - public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets, + public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect, boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) { - this(insetsOrNull(systemWindowInsets), insetsOrNull(windowDecorInsets), - insetsOrNull(stableInsets), isRound, alwaysConsumeNavBar, displayCutout); + this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect), + isRound, alwaysConsumeNavBar, displayCutout); } - private WindowInsets(Insets systemWindowInsets, Insets windowDecorInsets, - Insets stableInsets, boolean isRound, boolean alwaysConsumeNavBar, - DisplayCutout displayCutout) { - mSystemWindowInsetsConsumed = systemWindowInsets == null; - mSystemWindowInsets = mSystemWindowInsetsConsumed ? Insets.NONE : systemWindowInsets; - - mWindowDecorInsetsConsumed = windowDecorInsets == null; - mWindowDecorInsets = mWindowDecorInsetsConsumed ? Insets.NONE : windowDecorInsets; + /** + * Construct a new WindowInsets from individual insets. + * + * {@code typeInsetsMap} and {@code typeMaxInsetsMap} are a map of indexOf(type) -> insets that + * contain the information what kind of system bars causes how much insets. The insets in this + * map are non-additive; i.e. they have the same origin. In other words: If two system bars + * overlap on one side, the insets of the larger bar will also include the insets of the smaller + * bar. + * + * {@code null} type inset map indicates that the respective inset is fully consumed. + * @hide + */ + public WindowInsets(@Nullable Insets[] typeInsetsMap, + @Nullable Insets[] typeMaxInsetsMap, boolean isRound, + boolean alwaysConsumeNavBar, DisplayCutout displayCutout) { + mSystemWindowInsetsConsumed = typeInsetsMap == null; + mTypeInsetsMap = mSystemWindowInsetsConsumed + ? new Insets[SIZE] + : typeInsetsMap.clone(); - mStableInsetsConsumed = stableInsets == null; - mStableInsets = mStableInsetsConsumed ? Insets.NONE : stableInsets; + mStableInsetsConsumed = typeMaxInsetsMap == null; + mTypeMaxInsetsMap = mStableInsetsConsumed + ? new Insets[SIZE] + : typeMaxInsetsMap.clone(); mIsRound = isRound; mAlwaysConsumeNavBar = alwaysConsumeNavBar; @@ -120,10 +148,7 @@ public final class WindowInsets { * @param src Source to copy insets from */ public WindowInsets(WindowInsets src) { - this(src.mSystemWindowInsetsConsumed ? null : src.mSystemWindowInsets, - src.mWindowDecorInsetsConsumed ? null : src.mWindowDecorInsets, - src.mStableInsetsConsumed ? null : src.mStableInsets, - src.mIsRound, src.mAlwaysConsumeNavBar, + this(src.mTypeInsetsMap, src.mTypeMaxInsetsMap, src.mIsRound, src.mAlwaysConsumeNavBar, displayCutoutCopyConstructorArgument(src)); } @@ -137,10 +162,64 @@ public final class WindowInsets { } } + /** + * @return The insets that include system bars indicated by {@code typeMask}, taken from + * {@code typeInsetMap}. + */ + private static Insets getInsets(Insets[] typeInsetsMap, @InsetType int typeMask) { + Insets result = null; + for (int i = FIRST; i <= LAST; i = i << 1) { + if ((typeMask & i) == 0) { + continue; + } + Insets insets = typeInsetsMap[indexOf(i)]; + if (insets == null) { + continue; + } + if (result == null) { + result = insets; + } else { + result = Insets.max(result, insets); + } + } + return result == null ? Insets.NONE : result; + } + + /** + * Sets all entries in {@code typeInsetsMap} that belong to {@code typeMask} to {@code insets}, + */ + private static void setInsets(Insets[] typeInsetsMap, @InsetType int typeMask, Insets insets) { + for (int i = FIRST; i <= LAST; i = i << 1) { + if ((typeMask & i) == 0) { + continue; + } + typeInsetsMap[indexOf(i)] = insets; + } + } + /** @hide */ @UnsupportedAppUsage public WindowInsets(Rect systemWindowInsets) { - this(systemWindowInsets, null, null, false, false, null); + this(createCompatTypeMap(systemWindowInsets), null, false, false, null); + } + + /** + * Creates a indexOf(type) -> inset map for which the {@code insets} is just mapped to + * {@link InsetType#topBar()} and {@link InsetType#sideBars()}, depending on the location of the + * inset. + */ + private static Insets[] createCompatTypeMap(@Nullable Rect insets) { + if (insets == null) { + return null; + } + Insets[] typeInsetMap = new Insets[SIZE]; + assignCompatInsets(typeInsetMap, insets); + return typeInsetMap; + } + + private static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) { + typeInsetMap[indexOf(TOP_BAR)] = Insets.of(0, insets.top, 0, 0); + typeInsetMap[indexOf(SIDE_BARS)] = Insets.of(insets.left, 0, insets.right, insets.bottom); } /** @@ -156,8 +235,8 @@ public final class WindowInsets { if (mTempRect == null) { mTempRect = new Rect(); } - mTempRect.set(mSystemWindowInsets.left, mSystemWindowInsets.top, - mSystemWindowInsets.right, mSystemWindowInsets.bottom); + Insets insets = getSystemWindowInsets(); + mTempRect.set(insets.left, insets.top, insets.right, insets.bottom); return mTempRect; } @@ -172,7 +251,46 @@ public final class WindowInsets { */ @NonNull public Insets getSystemWindowInsets() { - return mSystemWindowInsets; + return getInsets(mTypeInsetsMap, compatSystemInsets()); + } + + /** + * Returns the insets of a specific set of windows causing insets, denoted by the + * {@code typeMask} bit mask of {@link InsetType}s. + * + * @param typeMask Bit mask of {@link InsetType}s to query the insets for. + * @return The insets. + * + * @hide pending unhide + */ + public Insets getInsets(@InsetType int typeMask) { + return getInsets(mTypeInsetsMap, typeMask); + } + + /** + * Returns the maximum amount of insets a specific set of windows can cause, denoted by the + * {@code typeMask} bit mask of {@link InsetType}s. + * + * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially + * or fully obscured by the system window identified by {@code type}. 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 maximum inset will still provide the inset + * associated with the status bar being shown.</p> + * + * @param typeMask Bit mask of {@link InsetType}s to query the insets for. + * @return The insets. + * + * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Maximum + * insets are not available for this type as the height of the + * IME is dynamic depending on the {@link EditorInfo} of the + * currently focused view, as well as the UI state of the IME. + * @hide pending unhide + */ + public Insets getMaxInsets(@InsetType int typeMask) throws IllegalArgumentException { + if ((typeMask & IME) != 0) { + throw new IllegalArgumentException("Unable to query the maximum insets for IME"); + } + return getInsets(mTypeMaxInsetsMap, typeMask); } /** @@ -185,7 +303,7 @@ public final class WindowInsets { * @return The left system window inset */ public int getSystemWindowInsetLeft() { - return mSystemWindowInsets.left; + return getSystemWindowInsets().left; } /** @@ -198,7 +316,7 @@ public final class WindowInsets { * @return The top system window inset */ public int getSystemWindowInsetTop() { - return mSystemWindowInsets.top; + return getSystemWindowInsets().top; } /** @@ -211,7 +329,7 @@ public final class WindowInsets { * @return The right system window inset */ public int getSystemWindowInsetRight() { - return mSystemWindowInsets.right; + return getSystemWindowInsets().right; } /** @@ -224,63 +342,7 @@ public final class WindowInsets { * @return The bottom system window inset */ public int getSystemWindowInsetBottom() { - return mSystemWindowInsets.bottom; - } - - /** - * Returns the left window decor inset in pixels. - * - * <p>The window decor inset represents the area of the window content area that is - * partially or fully obscured by decorations within the window provided by the framework. - * This can include action bars, title bars, toolbars, etc.</p> - * - * @return The left window decor inset - * @hide pending API - */ - public int getWindowDecorInsetLeft() { - return mWindowDecorInsets.left; - } - - /** - * Returns the top window decor inset in pixels. - * - * <p>The window decor inset represents the area of the window content area that is - * partially or fully obscured by decorations within the window provided by the framework. - * This can include action bars, title bars, toolbars, etc.</p> - * - * @return The top window decor inset - * @hide pending API - */ - public int getWindowDecorInsetTop() { - return mWindowDecorInsets.top; - } - - /** - * Returns the right window decor inset in pixels. - * - * <p>The window decor inset represents the area of the window content area that is - * partially or fully obscured by decorations within the window provided by the framework. - * This can include action bars, title bars, toolbars, etc.</p> - * - * @return The right window decor inset - * @hide pending API - */ - public int getWindowDecorInsetRight() { - return mWindowDecorInsets.right; - } - - /** - * Returns the bottom window decor inset in pixels. - * - * <p>The window decor inset represents the area of the window content area that is - * partially or fully obscured by decorations within the window provided by the framework. - * This can include action bars, title bars, toolbars, etc.</p> - * - * @return The bottom window decor inset - * @hide pending API - */ - public int getWindowDecorInsetBottom() { - return mWindowDecorInsets.bottom; + return getSystemWindowInsets().bottom; } /** @@ -293,23 +355,7 @@ public final class WindowInsets { * @return true if any of the system window inset values are nonzero */ public boolean hasSystemWindowInsets() { - return mSystemWindowInsets.left != 0 || mSystemWindowInsets.top != 0 || - mSystemWindowInsets.right != 0 || mSystemWindowInsets.bottom != 0; - } - - /** - * Returns true if this WindowInsets has nonzero window decor insets. - * - * <p>The window decor inset represents the area of the window content area that is - * partially or fully obscured by decorations within the window provided by the framework. - * This can include action bars, title bars, toolbars, etc.</p> - * - * @return true if any of the window decor inset values are nonzero - * @hide pending API - */ - public boolean hasWindowDecorInsets() { - return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 || - mWindowDecorInsets.right != 0 || mWindowDecorInsets.bottom != 0; + return !getSystemWindowInsets().equals(Insets.NONE); } /** @@ -318,7 +364,8 @@ public final class WindowInsets { * @return true if any inset values are nonzero */ public boolean hasInsets() { - return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets() + return !getInsets(mTypeInsetsMap, all()).equals(Insets.NONE) + || !getInsets(mTypeMaxInsetsMap, all()).equals(Insets.NONE) || mDisplayCutout != null; } @@ -340,9 +387,7 @@ public final class WindowInsets { */ @NonNull public WindowInsets consumeDisplayCutout() { - return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets, - mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, - mStableInsetsConsumed ? null : mStableInsets, + return new WindowInsets(mTypeInsetsMap, mTypeMaxInsetsMap, mIsRound, mAlwaysConsumeNavBar, null /* displayCutout */); } @@ -362,7 +407,7 @@ public final class WindowInsets { * @return true if the insets have been fully consumed. */ public boolean isConsumed() { - return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed + return mSystemWindowInsetsConsumed && mStableInsetsConsumed && mDisplayCutoutConsumed; } @@ -387,9 +432,7 @@ public final class WindowInsets { */ @NonNull public WindowInsets consumeSystemWindowInsets() { - return new WindowInsets(null /* systemWindowInsets */, - mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, - mStableInsetsConsumed ? null : mStableInsets, + return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mIsRound, mAlwaysConsumeNavBar, displayCutoutCopyConstructorArgument(this)); } @@ -449,18 +492,6 @@ public final class WindowInsets { } /** - * @hide - */ - @NonNull - public WindowInsets consumeWindowDecorInsets() { - return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets, - null /* windowDecorInsets */, - mStableInsetsConsumed ? null : mStableInsets, - mIsRound, mAlwaysConsumeNavBar, - displayCutoutCopyConstructorArgument(this)); - } - - /** * Returns the stable insets in pixels. * * <p>The stable inset represents the area of a full-screen window that <b>may</b> be @@ -473,7 +504,7 @@ public final class WindowInsets { */ @NonNull public Insets getStableInsets() { - return mStableInsets; + return getInsets(mTypeMaxInsetsMap, compatSystemInsets()); } /** @@ -488,7 +519,7 @@ public final class WindowInsets { * @return The top stable inset */ public int getStableInsetTop() { - return mStableInsets.top; + return getStableInsets().top; } /** @@ -503,7 +534,7 @@ public final class WindowInsets { * @return The left stable inset */ public int getStableInsetLeft() { - return mStableInsets.left; + return getStableInsets().left; } /** @@ -518,7 +549,7 @@ public final class WindowInsets { * @return The right stable inset */ public int getStableInsetRight() { - return mStableInsets.right; + return getStableInsets().right; } /** @@ -533,7 +564,7 @@ public final class WindowInsets { * @return The bottom stable inset */ public int getStableInsetBottom() { - return mStableInsets.bottom; + return getStableInsets().bottom; } /** @@ -548,8 +579,7 @@ public final class WindowInsets { * @return true if any of the stable inset values are nonzero */ public boolean hasStableInsets() { - return mStableInsets.top != 0 || mStableInsets.left != 0 || mStableInsets.right != 0 - || mStableInsets.bottom != 0; + return !getStableInsets().equals(Insets.NONE); } /** @@ -559,9 +589,7 @@ public final class WindowInsets { */ @NonNull public WindowInsets consumeStableInsets() { - return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets, - mWindowDecorInsetsConsumed ? null : mWindowDecorInsets, - null /* stableInsets */, + return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null, mIsRound, mAlwaysConsumeNavBar, displayCutoutCopyConstructorArgument(this)); } @@ -575,9 +603,8 @@ public final class WindowInsets { @Override public String toString() { - return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets - + " windowDecorInsets=" + mWindowDecorInsets - + " stableInsets=" + mStableInsets + return "WindowInsets{systemWindowInsets=" + getSystemWindowInsets() + + " stableInsets=" + getStableInsets() + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "") + (isRound() ? " round" : "") + "}"; @@ -634,16 +661,16 @@ public final class WindowInsets { Preconditions.checkArgumentNonnegative(bottom); 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), + mSystemWindowInsetsConsumed + ? null + : insetInsets(mTypeInsetsMap, left, top, right, bottom), + mStableInsetsConsumed + ? null + : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom), mIsRound, mAlwaysConsumeNavBar, mDisplayCutoutConsumed - ? null : - mDisplayCutout == null + ? null + : mDisplayCutout == null ? DisplayCutout.NO_CUTOUT : mDisplayCutout.inset(left, top, right, bottom)); } @@ -653,23 +680,49 @@ public final class WindowInsets { if (this == o) return true; if (o == null || !(o instanceof WindowInsets)) return false; WindowInsets that = (WindowInsets) o; + return mIsRound == that.mIsRound && mAlwaysConsumeNavBar == that.mAlwaysConsumeNavBar && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed - && mWindowDecorInsetsConsumed == that.mWindowDecorInsetsConsumed && mStableInsetsConsumed == that.mStableInsetsConsumed && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed - && Objects.equals(mSystemWindowInsets, that.mSystemWindowInsets) - && Objects.equals(mWindowDecorInsets, that.mWindowDecorInsets) - && Objects.equals(mStableInsets, that.mStableInsets) + && Arrays.equals(mTypeInsetsMap, that.mTypeInsetsMap) + && Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap) && Objects.equals(mDisplayCutout, that.mDisplayCutout); } @Override public int hashCode() { - return Objects.hash(mSystemWindowInsets, mWindowDecorInsets, mStableInsets, mIsRound, - mDisplayCutout, mAlwaysConsumeNavBar, mSystemWindowInsetsConsumed, - mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed); + return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap), + mIsRound, mDisplayCutout, mAlwaysConsumeNavBar, mSystemWindowInsetsConsumed, + mStableInsetsConsumed, mDisplayCutoutConsumed); + } + + + /** + * Insets every inset in {@code typeInsetsMap} by the specified left, top, right, bottom. + * + * @return {@code typeInsetsMap} if no inset was modified; a copy of the map with the modified + * insets otherwise. + */ + private static Insets[] insetInsets( + Insets[] typeInsetsMap, int left, int top, int right, int bottom) { + boolean cloned = false; + for (int i = 0; i < SIZE; i++) { + Insets insets = typeInsetsMap[i]; + if (insets == null) { + continue; + } + Insets insetInsets = insetInsets(insets, left, top, right, bottom); + if (insetInsets != insets) { + if (!cloned) { + typeInsetsMap = typeInsetsMap.clone(); + cloned = true; + } + typeInsetsMap[i] = insetInsets; + } + } + return typeInsetsMap; } private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) { @@ -683,10 +736,6 @@ public final class WindowInsets { return Insets.of(newLeft, newTop, newRight, newBottom); } - private static Insets insetsOrNull(Rect insets) { - return insets != null ? Insets.of(insets) : null; - } - /** * @return whether system window insets have been consumed. */ @@ -699,11 +748,13 @@ public final class WindowInsets { */ public static class Builder { - private Insets mSystemWindowInsets; - private Insets mStableInsets; + private final Insets[] mTypeInsetsMap; + private final Insets[] mTypeMaxInsetsMap; + private boolean mSystemInsetsConsumed = true; + private boolean mStableInsetsConsumed = true; + private DisplayCutout mDisplayCutout; - private Insets mWindowDecorInsets; private boolean mIsRound; private boolean mAlwaysConsumeNavBar; @@ -711,6 +762,8 @@ public final class WindowInsets { * Creates a builder where all insets are initially consumed. */ public Builder() { + mTypeInsetsMap = new Insets[SIZE]; + mTypeMaxInsetsMap = new Insets[SIZE]; } /** @@ -719,12 +772,11 @@ public final class WindowInsets { * @param insets the instance to initialize from. */ public Builder(WindowInsets insets) { - mSystemWindowInsets = insets.mSystemWindowInsetsConsumed ? null - : insets.mSystemWindowInsets; - mStableInsets = insets.mStableInsetsConsumed ? null : insets.mStableInsets; + mTypeInsetsMap = insets.mTypeInsetsMap.clone(); + mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone(); + mSystemInsetsConsumed = insets.mSystemWindowInsetsConsumed; + mStableInsetsConsumed = insets.mStableInsetsConsumed; mDisplayCutout = displayCutoutCopyConstructorArgument(insets); - mWindowDecorInsets = insets.mWindowDecorInsetsConsumed ? null - : insets.mWindowDecorInsets; mIsRound = insets.mIsRound; mAlwaysConsumeNavBar = insets.mAlwaysConsumeNavBar; } @@ -742,7 +794,66 @@ public final class WindowInsets { @NonNull public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) { Preconditions.checkNotNull(systemWindowInsets); - mSystemWindowInsets = systemWindowInsets; + assignCompatInsets(mTypeInsetsMap, systemWindowInsets.toRect()); + mSystemInsetsConsumed = false; + return this; + } + + /** + * Sets the insets of a specific window type in pixels. + * + * <p>The insets represents the area of a a window that is partially or fully obscured by + * the system windows identified by {@code typeMask}. + * </p> + * + * @see #getInsets(int) + * + * @param typeMask The bitmask of {@link InsetType} to set the insets for. + * @param insets The insets to set. + * + * @return itself + * @hide pending unhide + */ + @NonNull + public Builder setInsets(@InsetType int typeMask, @NonNull Insets insets) { + Preconditions.checkNotNull(insets); + WindowInsets.setInsets(mTypeInsetsMap, typeMask, insets); + mSystemInsetsConsumed = false; + return this; + } + + /** + * Sets the maximum amount of insets a specific window type in pixels. + * + * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially + * or fully obscured by the system windows identified by {@code typeMask}. 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 maximum inset will still provide the + * inset associated with the status bar being shown.</p> + * + * @see #getMaxInsets(int) + * + * @param typeMask The bitmask of {@link InsetType} to set the insets for. + * @param insets The insets to set. + * + * @return itself + * + * @throws IllegalArgumentException If {@code typeMask} contains {@link Type#ime()}. Maximum + * insets are not available for this type as the height of + * the IME is dynamic depending on the {@link EditorInfo} + * of the currently focused view, as well as the UI + * state of the IME. + * @hide pending unhide + */ + @NonNull + public Builder setMaxInsets(@InsetType int typeMask, @NonNull Insets insets) + throws IllegalArgumentException{ + if (typeMask == IME) { + throw new IllegalArgumentException("Maximum inset not available for IME"); + } + Preconditions.checkNotNull(insets); + WindowInsets.setInsets(mTypeMaxInsetsMap, typeMask, insets); + mStableInsetsConsumed = false; return this; } @@ -761,7 +872,8 @@ public final class WindowInsets { @NonNull public Builder setStableInsets(@NonNull Insets stableInsets) { Preconditions.checkNotNull(stableInsets); - mStableInsets = stableInsets; + assignCompatInsets(mTypeInsetsMap, stableInsets.toRect()); + mStableInsetsConsumed = false; return this; } @@ -780,14 +892,6 @@ public final class WindowInsets { /** @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; @@ -807,8 +911,9 @@ public final class WindowInsets { */ @NonNull public WindowInsets build() { - return new WindowInsets(mSystemWindowInsets, mWindowDecorInsets, mStableInsets, - mIsRound, mAlwaysConsumeNavBar, mDisplayCutout); + return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap, + mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mIsRound, + mAlwaysConsumeNavBar, mDisplayCutout); } } @@ -818,10 +923,31 @@ public final class WindowInsets { */ public static final class Type { - static final int TOP_BAR = 0x1; + static final int FIRST = 0x1; + static final int TOP_BAR = FIRST; + static final int IME = 0x2; static final int SIDE_BARS = 0x4; - static final int WINDOW_DECOR = 0x8; + + static final int LAST = 0x8; + static final int SIZE = 4; + static final int WINDOW_DECOR = LAST; + + static int indexOf(@InsetType int type) { + switch (type) { + case TOP_BAR: + return 0; + case IME: + return 1; + case SIDE_BARS: + return 2; + case WINDOW_DECOR: + return 3; + default: + throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST," + + " type=" + type); + } + } private Type() { } @@ -870,6 +996,15 @@ public final class WindowInsets { } /** + * @return Inset types representing the list of bars that traditionally were denoted as + * system insets. + * @hide + */ + static @InsetType int compatSystemInsets() { + return TOP_BAR | SIDE_BARS | IME; + } + + /** * @return All inset types combined. */ public static @InsetType int all() { diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 56f973eb9e46..90ccc257b134 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -62,6 +62,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.IResultReceiver; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; +import com.android.internal.util.SyncResultReceiver; import org.xmlpull.v1.XmlPullParserException; @@ -75,8 +76,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; + //TODO: use java.lang.ref.Cleaner once Android supports Java 9 import sun.misc.Cleaner; @@ -324,6 +324,11 @@ public final class AutofillManager { public static final int FC_SERVICE_TIMEOUT = 5000; /** + * Timeout for calls to system_server. + */ + private static final int SYNC_CALLS_TIMEOUT_MS = 5000; + + /** * Makes an authentication id from a request id and a dataset id. * * @param requestId The request id. @@ -612,7 +617,8 @@ public final class AutofillManager { final AutofillClient client = getClient(); if (client != null) { - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver( + SYNC_CALLS_TIMEOUT_MS); try { mService.restoreSession(mSessionId, client.autofillClientGetActivityToken(), mServiceClient.asBinder(), receiver); @@ -732,9 +738,9 @@ public final class AutofillManager { */ @Nullable public FillEventHistory getFillEventHistory() { try { - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); mService.getFillEventHistory(receiver); - return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE); + return receiver.getParcelableResult(); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; @@ -1287,7 +1293,7 @@ public final class AutofillManager { public boolean hasEnabledAutofillServices() { if (mService == null) return false; - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); try { mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(), receiver); return receiver.getIntResult() == 1; @@ -1304,10 +1310,10 @@ public final class AutofillManager { public ComponentName getAutofillServiceComponentName() { if (mService == null) return null; - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); try { mService.getAutofillServiceComponentName(receiver); - return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE); + return receiver.getParcelableResult(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1330,9 +1336,9 @@ public final class AutofillManager { */ @Nullable public String getUserDataId() { try { - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); mService.getUserDataId(receiver); - return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING); + return receiver.getStringResult(); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; @@ -1352,9 +1358,9 @@ public final class AutofillManager { */ @Nullable public UserData getUserData() { try { - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); mService.getUserData(receiver); - return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE); + return receiver.getParcelableResult(); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; @@ -1390,7 +1396,7 @@ public final class AutofillManager { * the user. */ public boolean isFieldClassificationEnabled() { - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); try { mService.isFieldClassificationEnabled(receiver); return receiver.getIntResult() == 1; @@ -1413,10 +1419,10 @@ public final class AutofillManager { */ @Nullable public String getDefaultFieldClassificationAlgorithm() { - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); try { mService.getDefaultFieldClassificationAlgorithm(receiver); - return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING); + return receiver.getStringResult(); } catch (RemoteException e) { e.rethrowFromSystemServer(); return null; @@ -1433,11 +1439,10 @@ public final class AutofillManager { */ @NonNull public List<String> getAvailableFieldClassificationAlgorithms() { - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); try { mService.getAvailableFieldClassificationAlgorithms(receiver); - final String[] algorithms = receiver - .getObjectResult(SyncResultReceiver.TYPE_STRING_ARRAY); + final String[] algorithms = receiver.getStringArrayResult(); return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList(); } catch (RemoteException e) { e.rethrowFromSystemServer(); @@ -1458,7 +1463,7 @@ public final class AutofillManager { public boolean isAutofillSupported() { if (mService == null) return false; - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); try { mService.isServiceSupported(mContext.getUserId(), receiver); return receiver.getIntResult() == 1; @@ -1582,7 +1587,7 @@ public final class AutofillManager { final AutofillClient client = getClient(); if (client == null) return; // NOTE: getClient() already logged it.. - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); mService.startSession(client.autofillClientGetActivityToken(), mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(), mCallback != null, flags, client.autofillClientGetComponentName(), @@ -1665,7 +1670,7 @@ public final class AutofillManager { mServiceClient = new AutofillManagerClient(this); try { final int userId = mContext.getUserId(); - final SyncResultReceiver receiver = new SyncResultReceiver(); + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); mService.addClient(mServiceClient, userId, receiver); final int flags = receiver.getIntResult(); mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0; @@ -2986,104 +2991,4 @@ public final class AutofillManager { } } } - - /** - * @hide - */ - public static final class SyncResultReceiver extends IResultReceiver.Stub { - - private static final String EXTRA = "EXTRA"; - - /** - * How long to block waiting for {@link IResultReceiver} callbacks when calling server. - */ - private static final long BINDER_TIMEOUT_MS = 5000; - - private static final int TYPE_STRING = 0; - private static final int TYPE_STRING_ARRAY = 1; - private static final int TYPE_PARCELABLE = 2; - - private final CountDownLatch mLatch = new CountDownLatch(1); - private int mResult; - private Bundle mBundle; - - private void waitResult() { - try { - if (!mLatch.await(BINDER_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { - throw new IllegalStateException("Not called in " + BINDER_TIMEOUT_MS + "ms"); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - /** - * Gets the result from an operation that returns an {@code int}. - */ - int getIntResult() { - waitResult(); - return mResult; - } - - /** - * Gets the result from an operation that returns an {@code Object}. - * - * @param type type of expected object. - */ - @Nullable - @SuppressWarnings("unchecked") - <T> T getObjectResult(int type) { - waitResult(); - if (mBundle == null) { - return null; - } - switch (type) { - case TYPE_STRING: - return (T) mBundle.getString(EXTRA); - case TYPE_STRING_ARRAY: - return (T) mBundle.getStringArray(EXTRA); - case TYPE_PARCELABLE: - return (T) mBundle.getParcelable(EXTRA); - default: - throw new IllegalArgumentException("unsupported type: " + type); - } - } - - @Override - public void send(int resultCode, Bundle resultData) { - mResult = resultCode; - mBundle = resultData; - mLatch.countDown(); - } - - /** - * Creates a bundle for a {@code String} value. - */ - @NonNull - public static Bundle bundleFor(@Nullable String value) { - final Bundle bundle = new Bundle(); - bundle.putString(EXTRA, value); - return bundle; - } - - /** - * Creates a bundle for a {@code String[]} value. - */ - @NonNull - public static Bundle bundleFor(@Nullable String[] value) { - final Bundle bundle = new Bundle(); - bundle.putStringArray(EXTRA, value); - return bundle; - } - - /** - * Creates a bundle for a {@code Parcelable} value. - */ - @NonNull - public static Bundle bundleFor(@Nullable Parcelable value) { - final Bundle bundle = new Bundle(); - bundle.putParcelable(EXTRA, value); - return bundle; - } - } } diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java index 51668319cde2..04e725e64e9c 100644 --- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java @@ -33,7 +33,7 @@ import java.io.PrintWriter; final class ChildContentCaptureSession extends ContentCaptureSession { @NonNull - private final MainContentCaptureSession mParent; + private final ContentCaptureSession mParent; /** * {@link ContentCaptureContext} set by client, or {@code null} when it's the @@ -46,16 +46,25 @@ final class ChildContentCaptureSession extends ContentCaptureSession { private final ContentCaptureContext mClientContext; /** @hide */ - protected ChildContentCaptureSession(@NonNull MainContentCaptureSession parent, + protected ChildContentCaptureSession(@NonNull ContentCaptureSession parent, @NonNull ContentCaptureContext clientContext) { mParent = parent; mClientContext = Preconditions.checkNotNull(clientContext); } @Override - ContentCaptureSession newChild(@NonNull ContentCaptureContext context) { - // TODO(b/121033016): implement it - throw new UnsupportedOperationException("grand-children not implemented yet"); + MainContentCaptureSession getMainCaptureSession() { + if (mParent instanceof MainContentCaptureSession) { + return (MainContentCaptureSession) mParent; + } + return mParent.getMainCaptureSession(); + } + + @Override + ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) { + final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext); + getMainCaptureSession().notifyChildSessionStarted(mId, child.mId, clientContext); + return child; } @Override @@ -65,27 +74,27 @@ final class ChildContentCaptureSession extends ContentCaptureSession { @Override void onDestroy() { - mParent.notifyChildSessionFinished(mParent.mId, mId); + getMainCaptureSession().notifyChildSessionFinished(mParent.mId, mId); } @Override void internalNotifyViewAppeared(@NonNull ViewStructureImpl node) { - mParent.notifyViewAppeared(mId, node); + getMainCaptureSession().notifyViewAppeared(mId, node); } @Override void internalNotifyViewDisappeared(@NonNull AutofillId id) { - mParent.notifyViewDisappeared(mId, id); + getMainCaptureSession().notifyViewDisappeared(mId, id); } @Override void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text, int flags) { - mParent.notifyViewTextChanged(mId, id, text, flags); + getMainCaptureSession().notifyViewTextChanged(mId, id, text, flags); } @Override boolean isContentCaptureEnabled() { - return mParent.isContentCaptureEnabled(); + return getMainCaptureSession().isContentCaptureEnabled(); } @Override diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java index 9e3da9234b58..0d064307ce54 100644 --- a/core/java/android/view/contentcapture/ContentCaptureEvent.java +++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java @@ -251,6 +251,10 @@ public final class ContentCaptureEvent implements Parcelable { public String toString() { final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=") .append(getTypeAsString(mType)); + string.append(", session=").append(mSessionId); + if (mType == TYPE_SESSION_STARTED && mParentSessionId != null) { + string.append(", parent=").append(mParentSessionId); + } if (mFlags > 0) { string.append(", flags=").append(mFlags); } diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 983079073d02..e962e7c8fe41 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -117,13 +117,11 @@ public final class ContentCaptureManager { /** @hide */ public void onActivityStarted(@NonNull IBinder applicationToken, @NonNull ComponentName activityComponent) { - // TODO(b/121033016): must start all sessions getMainContentCaptureSession().start(applicationToken, activityComponent); } /** @hide */ public void onActivityStopped() { - // TODO(b/121033016): must finish all sessions getMainContentCaptureSession().destroy(); } @@ -135,7 +133,6 @@ public final class ContentCaptureManager { * @hide */ public void flush() { - // TODO(b/121033016): must flush all sessions getMainContentCaptureSession().flush(); } diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 46e6882b8643..344b9973fdb1 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -27,6 +27,7 @@ import android.view.ViewStructure; import android.view.autofill.AutofillId; import android.view.contentcapture.ViewNode.ViewStructureImpl; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; @@ -34,7 +35,6 @@ import dalvik.system.CloseGuard; import java.io.PrintWriter; import java.util.ArrayList; import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; /** * Session used to notify a system-provided Content Capture service about events associated with @@ -73,11 +73,11 @@ public abstract class ContentCaptureSession implements AutoCloseable { public static final int STATE_ACTIVE = 2; /** - * Session is disabled. + * Session is disabled because there is no service for this user. * * @hide */ - public static final int STATE_DISABLED = 3; + public static final int STATE_DISABLED_NO_SERVICE = 3; /** * Session is disabled because its id already existed on server. @@ -90,11 +90,14 @@ public abstract class ContentCaptureSession implements AutoCloseable { private final CloseGuard mCloseGuard = CloseGuard.get(); + private final Object mLock = new Object(); + /** * Guard use to ignore events after it's destroyed. */ @NonNull - private final AtomicBoolean mDestroyed = new AtomicBoolean(); + @GuardedBy("mLock") + private boolean mDestroyed; /** @hide */ @Nullable @@ -108,11 +111,8 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** * List of children session. */ - // TODO(b/121033016): need to synchonize access, either by changing on handler or UI thread - // (for now there's no handler on this class, so we need to wait for the next refactoring), - // most likely the former (as we have no guarantee that createContentCaptureSession() - // it will be called in the UiThread; for example, WebView most likely won't call on it) @Nullable + @GuardedBy("mLock") private ArrayList<ContentCaptureSession> mChildren; /** @hide */ @@ -120,6 +120,10 @@ public abstract class ContentCaptureSession implements AutoCloseable { mCloseGuard.open("destroy"); } + /** @hide */ + @NonNull + abstract MainContentCaptureSession getMainCaptureSession(); + /** * Gets the id used to identify this session. */ @@ -143,10 +147,12 @@ public abstract class ContentCaptureSession implements AutoCloseable { Log.d(TAG, "createContentCaptureSession(" + context + ": parent=" + mId + ", child=" + child.mId); } - if (mChildren == null) { - mChildren = new ArrayList<>(INITIAL_CHILDREN_CAPACITY); + synchronized (mLock) { + if (mChildren == null) { + mChildren = new ArrayList<>(INITIAL_CHILDREN_CAPACITY); + } + mChildren.add(child); } - mChildren.add(child); return child; } @@ -163,29 +169,31 @@ public abstract class ContentCaptureSession implements AutoCloseable { * <p>Once destroyed, any new notification will be dropped. */ public final void destroy() { - if (!mDestroyed.compareAndSet(false, true)) { - Log.e(TAG, "destroy(): already destroyed"); - return; - } - - mCloseGuard.close(); + synchronized (mLock) { + if (mDestroyed) { + Log.e(TAG, "destroy(" + mId + "): already destroyed"); + return; + } + mDestroyed = true; - //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, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId); - } + mCloseGuard.close(); - // Finish children first - if (mChildren != null) { - final int numberChildren = mChildren.size(); - if (VERBOSE) Log.v(TAG, "Destroying " + numberChildren + " children first"); - for (int i = 0; i < numberChildren; i++) { - final ContentCaptureSession child = mChildren.get(i); - try { - child.destroy(); - } catch (Exception e) { - Log.w(TAG, "exception destroying child session #" + i + ": " + e); + //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, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId); + } + // Finish children first + if (mChildren != null) { + final int numberChildren = mChildren.size(); + if (VERBOSE) Log.v(TAG, "Destroying " + numberChildren + " children first"); + for (int i = 0; i < numberChildren; i++) { + final ContentCaptureSession child = mChildren.get(i); + try { + child.destroy(); + } catch (Exception e) { + Log.w(TAG, "exception destroying child session #" + i + ": " + e); + } } } } @@ -305,23 +313,26 @@ public abstract class ContentCaptureSession implements AutoCloseable { } boolean isContentCaptureEnabled() { - return !mDestroyed.get(); + synchronized (mLock) { + return !mDestroyed; + } } @CallSuper void dump(@NonNull String prefix, @NonNull PrintWriter pw) { pw.print(prefix); pw.print("id: "); pw.println(mId); - pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed.get()); - if (mChildren != null && !mChildren.isEmpty()) { - final String prefix2 = prefix + " "; - final int numberChildren = mChildren.size(); - pw.print(prefix); pw.print("number children: "); pw.println(numberChildren); - for (int i = 0; i < numberChildren; i++) { - final ContentCaptureSession child = mChildren.get(i); - pw.print(prefix); pw.print(i); pw.println(": "); child.dump(prefix2, pw); + synchronized (mLock) { + pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed); + if (mChildren != null && !mChildren.isEmpty()) { + final String prefix2 = prefix + " "; + final int numberChildren = mChildren.size(); + pw.print(prefix); pw.print("number children: "); pw.println(numberChildren); + for (int i = 0; i < numberChildren; i++) { + final ContentCaptureSession child = mChildren.get(i); + pw.print(prefix); pw.print(i); pw.println(": "); child.dump(prefix2, pw); + } } } - } @Override @@ -341,8 +352,8 @@ public abstract class ContentCaptureSession implements AutoCloseable { return "WAITING_FOR_SERVER"; case STATE_ACTIVE: return "ACTIVE"; - case STATE_DISABLED: - return "DISABLED"; + case STATE_DISABLED_NO_SERVICE: + return "DISABLED_NO_SERVICE"; case STATE_DISABLED_DUPLICATED_ID: return "DISABLED_DUPLICATED_ID"; default: diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index baf4a35f179e..8be887b6d593 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -141,6 +141,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } @Override + MainContentCaptureSession getMainCaptureSession() { + return this; + } + + @Override ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) { final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext); notifyChildSessionStarted(mId, child.mId, clientContext); @@ -171,6 +176,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @Override void onDestroy() { + mHandler.removeMessages(MSG_FLUSH); mHandler.sendMessage( obtainMessage(MainContentCaptureSession::handleDestroySession, this)); } @@ -193,6 +199,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession { final int flags = 0; // TODO(b/111276913): get proper flags try { + if (mSystemServerInterface == null) return; + mSystemServerInterface.startSession(mContext.getUserId(), mApplicationToken, componentName, mId, flags, new IResultReceiver.Stub() { @Override @@ -237,7 +245,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { Log.w(TAG, "Failed to link to death on " + binder + ": " + e); } } - if (resultCode == STATE_DISABLED || resultCode == STATE_DISABLED_DUPLICATED_ID) { + if (resultCode == STATE_DISABLED_NO_SERVICE || resultCode == STATE_DISABLED_DUPLICATED_ID) { mDisabled.set(true); handleResetSession(/* resetState= */ false); } else { @@ -246,7 +254,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { if (VERBOSE) { Log.v(TAG, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get() - + ", binder=" + binder); + + ", binder=" + binder + ", events=" + (mEvents == null ? 0 : mEvents.size())); } } @@ -285,14 +293,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession { return; } - if (mState != STATE_ACTIVE) { + if (mState != STATE_ACTIVE && numberEvents >= MAX_BUFFER_SIZE) { // Callback from startSession hasn't been called yet - typically happens on system // apps that are started before the system service // TODO(b/111276913): try to ignore session while system is not ready / boot // not complete instead. Similarly, the manager service should return right away // when the user does not have a service set - if (VERBOSE) { - Log.v(TAG, "Closing session for " + getActivityDebugName() + if (DEBUG) { + Log.d(TAG, "Closing session for " + getActivityDebugName() + " after " + numberEvents + " delayed events and state " + getStateAsString(mState)); } @@ -331,7 +339,9 @@ public final class MainContentCaptureSession extends ContentCaptureSession { if (mEvents == null) return; if (mDirectServiceInterface == null) { - if (DEBUG) Log.d(TAG, "handleForceFlush(): hold your horses, client not ready yet!"); + if (VERBOSE) { + Log.v(TAG, "handleForceFlush(): hold your horses, client not ready: " + mEvents); + } if (!mHandler.hasMessages(MSG_FLUSH)) { handleScheduleFlush(/* checkExisting= */ false); } @@ -375,6 +385,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } try { + if (mSystemServerInterface == null) return; + mSystemServerInterface.finishSession(mContext.getUserId(), mId); } catch (RemoteException e) { Log.e(TAG, "Error destroying system-service session " + mId + " for " @@ -386,14 +398,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession { handleResetSession(/* resetState= */ true); } - // TODO(b/121033016): once we support multiple sessions, we might need to move some of these + // TODO(b/122454205): once we support multiple sessions, we might need to move some of these // clearings out. private void handleResetSession(boolean resetState) { if (resetState) { mState = STATE_UNKNOWN; } - // TODO(b/121033016): must reset children (which currently is owned by superclass) + // TODO(b/122454205): must reset children (which currently is owned by superclass) mApplicationToken = null; mComponentName = null; mEvents = null; @@ -426,7 +438,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { && !mDisabled.get(); } - // TODO(b/121033016): refactor "notifyXXXX" methods below to a common "Buffer" object that is + // TODO(b/122454205): refactor "notifyXXXX" methods below to a common "Buffer" object that is // shared between ActivityContentCaptureSession and ChildContentCaptureSession objects. Such // change should also get get rid of the "internalNotifyXXXX" methods above void notifyChildSessionStarted(@NonNull String parentSessionId, @@ -435,14 +447,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession { new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED) .setParentSessionId(parentSessionId) .setClientContext(clientContext), - /* forceFlush= */ false)); + /* forceFlush= */ true)); } void notifyChildSessionFinished(@NonNull String parentSessionId, @NonNull String childSessionId) { mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this, new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED) - .setParentSessionId(parentSessionId), /* forceFlush= */ false)); + .setParentSessionId(parentSessionId), /* forceFlush= */ true)); } void notifyViewAppeared(@NonNull String sessionId, @NonNull ViewStructureImpl node) { diff --git a/core/java/android/view/textclassifier/GenerateLinksLogger.java b/core/java/android/view/textclassifier/GenerateLinksLogger.java index 067513f1de67..3996b277aa1c 100644 --- a/core/java/android/view/textclassifier/GenerateLinksLogger.java +++ b/core/java/android/view/textclassifier/GenerateLinksLogger.java @@ -39,7 +39,6 @@ import java.util.UUID; public final class GenerateLinksLogger { private static final String LOG_TAG = "GenerateLinksLogger"; - private static final boolean DEBUG_LOG_ENABLED = false; private static final String ZERO = "0"; private final MetricsLogger mMetricsLogger; @@ -128,8 +127,9 @@ public final class GenerateLinksLogger { } private static void debugLog(LogMaker log) { - if (!DEBUG_LOG_ENABLED) return; - + if (!Log.ENABLE_FULL_LOGGING) { + return; + } final String callId = Objects.toString( log.getTaggedData(MetricsEvent.FIELD_LINKIFY_CALL_ID), ""); final String entityType = Objects.toString( @@ -143,7 +143,7 @@ public final class GenerateLinksLogger { final int latencyMs = Integer.parseInt( Objects.toString(log.getTaggedData(MetricsEvent.FIELD_LINKIFY_LATENCY), ZERO)); - Log.d(LOG_TAG, + Log.v(LOG_TAG, String.format(Locale.US, "%s:%s %d links (%d/%d chars) %dms %s", callId, entityType, numLinks, linkLength, textLength, latencyMs, log.getPackageName())); } diff --git a/core/java/android/view/textclassifier/Log.java b/core/java/android/view/textclassifier/Log.java index ef19ee56a843..5c60c09418b4 100644 --- a/core/java/android/view/textclassifier/Log.java +++ b/core/java/android/view/textclassifier/Log.java @@ -16,10 +16,12 @@ package android.view.textclassifier; -import android.util.Slog; - /** * Logging for android.view.textclassifier package. + * <p> + * To enable full log: + * 1. adb shell setprop log.tag.androidtc VERBOSE + * 2. adb shell stop && adb shell start */ final class Log { @@ -27,24 +29,32 @@ final class Log { * true: Enables full logging. * false: Limits logging to debug level. */ - private static final boolean ENABLE_FULL_LOGGING = false; + static final boolean ENABLE_FULL_LOGGING = + android.util.Log.isLoggable(TextClassifier.DEFAULT_LOG_TAG, android.util.Log.VERBOSE); + + private Log() { + } - private Log() {} + public static void v(String tag, String msg) { + if (ENABLE_FULL_LOGGING) { + android.util.Log.v(tag, msg); + } + } public static void d(String tag, String msg) { - Slog.d(tag, msg); + android.util.Log.d(tag, msg); } public static void w(String tag, String msg) { - Slog.w(tag, msg); + android.util.Log.w(tag, msg); } public static void e(String tag, String msg, Throwable tr) { if (ENABLE_FULL_LOGGING) { - Slog.e(tag, msg, tr); + android.util.Log.e(tag, msg, tr); } else { final String trString = (tr != null) ? tr.getClass().getSimpleName() : "??"; - Slog.d(tag, String.format("%s (%s)", msg, trString)); + android.util.Log.d(tag, String.format("%s (%s)", msg, trString)); } } } diff --git a/core/java/android/view/textclassifier/SelectionSessionLogger.java b/core/java/android/view/textclassifier/SelectionSessionLogger.java index cdacdd504eeb..48a568abb169 100644 --- a/core/java/android/view/textclassifier/SelectionSessionLogger.java +++ b/core/java/android/view/textclassifier/SelectionSessionLogger.java @@ -39,7 +39,6 @@ import java.util.StringJoiner; public final class SelectionSessionLogger { private static final String LOG_TAG = "SelectionSessionLogger"; - private static final boolean DEBUG_LOG_ENABLED = false; static final String CLASSIFIER_ID = "androidtc"; private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START; @@ -195,8 +194,9 @@ public final class SelectionSessionLogger { } private static void debugLog(LogMaker log) { - if (!DEBUG_LOG_ENABLED) return; - + if (!Log.ENABLE_FULL_LOGGING) { + return; + } final String widgetType = Objects.toString(log.getTaggedData(WIDGET_TYPE), UNKNOWN); final String widgetVersion = Objects.toString(log.getTaggedData(WIDGET_VERSION), ""); final String widget = widgetVersion.isEmpty() @@ -221,7 +221,7 @@ public final class SelectionSessionLogger { final int eventEnd = Integer.parseInt( Objects.toString(log.getTaggedData(EVENT_END), ZERO)); - Log.d(LOG_TAG, + Log.v(LOG_TAG, String.format(Locale.US, "%2d: %s/%s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)", index, type, subType, entity, eventStart, eventEnd, smartStart, smartEnd, widget, model)); diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java index 4c6419855f7c..45668c01a8d3 100644 --- a/core/java/android/view/textclassifier/TextClassificationSession.java +++ b/core/java/android/view/textclassifier/TextClassificationSession.java @@ -27,7 +27,6 @@ import com.android.internal.util.Preconditions; @WorkerThread final class TextClassificationSession implements TextClassifier { - /* package */ static final boolean DEBUG_LOG_ENABLED = true; private static final String LOG_TAG = "TextClassificationSession"; private final TextClassifier mDelegate; @@ -133,9 +132,7 @@ final class TextClassificationSession implements TextClassifier { if (event.getEventType() != SelectionEvent.EVENT_SELECTION_STARTED && mStartEvent == null) { - if (DEBUG_LOG_ENABLED) { - Log.d(LOG_TAG, "Selection session not yet started. Ignoring event"); - } + Log.d(LOG_TAG, "Selection session not yet started. Ignoring event"); return false; } diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java index f2fea02171f9..b84f6f07e414 100644 --- a/core/java/android/view/textclassifier/TextClassifierEvent.java +++ b/core/java/android/view/textclassifier/TextClassifierEvent.java @@ -116,6 +116,8 @@ public final class TextClassifierEvent implements Parcelable { public static final int TYPE_SELECTION_RESET = 18; /** User composed a reply. */ public static final int TYPE_MANUAL_REPLY = 19; + /** TextClassifier generated some actions */ + public static final int TYPE_ACTIONS_GENERATED = 20; @Category private final int mEventCategory; @Type private final int mEventType; diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java new file mode 100644 index 000000000000..439e594cc8fe --- /dev/null +++ b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java @@ -0,0 +1,151 @@ +/* + * 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.textclassifier; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_ENTITY_TYPE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_SESSION_ID; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_WIDGET_TYPE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_WIDGET_VERSION; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_EVENT_TIME; + +import android.metrics.LogMaker; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.Preconditions; + + +/** + * Log {@link TextClassifierEvent} by using Tron, only support language detection and + * conversation actions. + * + * @hide + */ +public final class TextClassifierEventTronLogger { + + private static final String TAG = "TCEventTronLogger"; + + private final MetricsLogger mMetricsLogger; + + public TextClassifierEventTronLogger() { + mMetricsLogger = new MetricsLogger(); + } + + @VisibleForTesting + public TextClassifierEventTronLogger(MetricsLogger metricsLogger) { + mMetricsLogger = Preconditions.checkNotNull(metricsLogger); + } + + /** Emits a text classifier event to the logs. */ + public void writeEvent(TextClassifierEvent event) { + Preconditions.checkNotNull(event); + int category = getCategory(event); + if (category == -1) { + Log.w(TAG, "Unknown category: " + event.getEventCategory()); + return; + } + final LogMaker log = new LogMaker(category) + .setType(getLogType(event)) + .addTaggedData(FIELD_SELECTION_SESSION_ID, event.getResultId()) + .addTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME, event.getEventTime()) + .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, + SelectionSessionLogger.SignatureParser.getModelName(event.getResultId())) + .addTaggedData(FIELD_SELECTION_ENTITY_TYPE, event.getEntityType()); + TextClassificationContext eventContext = event.getEventContext(); + if (eventContext != null) { + log.addTaggedData(FIELD_SELECTION_WIDGET_TYPE, eventContext.getWidgetType()); + log.addTaggedData(FIELD_SELECTION_WIDGET_VERSION, eventContext.getWidgetVersion()); + log.setPackageName(eventContext.getPackageName()); + } + mMetricsLogger.write(log); + debugLog(log); + } + + private static int getCategory(TextClassifierEvent event) { + switch (event.getEventCategory()) { + case TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS: + return MetricsEvent.CONVERSATION_ACTIONS; + case TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION: + return MetricsEvent.LANGUAGE_DETECTION; + } + return -1; + } + + private static int getLogType(TextClassifierEvent event) { + switch (event.getEventType()) { + case TextClassifierEvent.TYPE_SMART_ACTION: + return MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE; + case TextClassifierEvent.TYPE_ACTIONS_SHOWN: + return MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN; + case TextClassifierEvent.TYPE_MANUAL_REPLY: + return MetricsEvent.ACTION_TEXT_CLASSIFIER_MANUAL_REPLY; + default: + return MetricsEvent.VIEW_UNKNOWN; + } + } + + private String toCategoryName(int category) { + switch (category) { + case MetricsEvent.CONVERSATION_ACTIONS: + return "conversation_actions"; + case MetricsEvent.LANGUAGE_DETECTION: + return "language_detection"; + } + return "unknown"; + } + + private String toEventName(int logType) { + switch (logType) { + case MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE: + return "smart_share"; + case MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN: + return "actions_shown"; + case MetricsEvent.ACTION_TEXT_CLASSIFIER_MANUAL_REPLY: + return "manual_reply"; + case MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED: + return "actions_generated"; + } + return "unknown"; + } + + private void debugLog(LogMaker log) { + if (!Log.ENABLE_FULL_LOGGING) { + return; + } + final String id = String.valueOf(log.getTaggedData(FIELD_SELECTION_SESSION_ID)); + final String categoryName = toCategoryName(log.getCategory()); + final String eventName = toEventName(log.getType()); + final String widgetType = String.valueOf(log.getTaggedData(FIELD_SELECTION_WIDGET_TYPE)); + final String widgetVersion = + String.valueOf(log.getTaggedData(FIELD_SELECTION_WIDGET_VERSION)); + final String model = String.valueOf(log.getTaggedData(FIELD_TEXTCLASSIFIER_MODEL)); + final String entityType = String.valueOf(log.getTaggedData(FIELD_SELECTION_ENTITY_TYPE)); + + StringBuilder builder = new StringBuilder(); + builder.append("writeEvent: "); + builder.append("id=").append(id); + builder.append(", category=").append(categoryName); + builder.append(", eventName=").append(eventName); + builder.append(", widgetType=").append(widgetType); + builder.append(", widgetVersion=").append(widgetVersion); + builder.append(", model=").append(model); + builder.append(", entityType=").append(entityType); + + Log.v(TAG, builder.toString()); + } +} diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index fcd06c384921..d5b9eb1d09dc 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -115,9 +115,9 @@ public final class TextClassifierImpl implements TextClassifier { @GuardedBy("mLock") // Do not access outside this lock. private ActionsSuggestionsModel mActionsImpl; - private final Object mLoggerLock = new Object(); - @GuardedBy("mLoggerLock") // Do not access outside this lock. - private SelectionSessionLogger mSessionLogger; + private final SelectionSessionLogger mSessionLogger = new SelectionSessionLogger(); + private final TextClassifierEventTronLogger mTextClassifierEventTronLogger = + new TextClassifierEventTronLogger(); private final TextClassificationConstants mSettings; @@ -337,12 +337,7 @@ public final class TextClassifierImpl implements TextClassifier { @Override public void onSelectionEvent(SelectionEvent event) { Preconditions.checkNotNull(event); - synchronized (mLoggerLock) { - if (mSessionLogger == null) { - mSessionLogger = new SelectionSessionLogger(); - } - mSessionLogger.writeEvent(event); - } + mSessionLogger.writeEvent(event); } @Override @@ -350,6 +345,7 @@ public final class TextClassifierImpl implements TextClassifier { if (DEBUG) { Log.d(DEFAULT_LOG_TAG, "onTextClassifierEvent() called with: event = [" + event + "]"); } + mTextClassifierEventTronLogger.writeEvent(event); } /** @inheritDoc */ diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index 49e11b8baf51..9f7aa6a2852a 100644 --- a/core/java/android/webkit/WebViewZygote.java +++ b/core/java/android/webkit/WebViewZygote.java @@ -159,6 +159,7 @@ public class WebViewZygote { 0, // runtimeFlags "webview_zygote", // seInfo sPackage.applicationInfo.primaryCpuAbi, // abi + TextUtils.join(",", Build.SUPPORTED_ABIS), null); // instructionSet // All the work below is usually done by LoadedApk, but the zygote can't talk to diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 7d027574198d..20febc2f21cd 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -104,8 +104,9 @@ public final class Magnifier { private final int mDefaultHorizontalSourceToMagnifierOffset; // The vertical offset between the source and window coords when #show(float, float) is used. private final int mDefaultVerticalSourceToMagnifierOffset; - // Whether the magnifier will be clamped inside the main surface and not overlap system insets. - private final boolean mForcePositionWithinWindowSystemInsetsBounds; + // Whether the area where the magnifier can be positioned will be clipped to the main window + // and within system insets. + private final boolean mClippingEnabled; // The behavior of the left bound of the rectangle where the content can be copied from. private @SourceBound int mLeftContentBound; // The behavior of the top bound of the rectangle where the content can be copied from. @@ -165,7 +166,7 @@ public final class Magnifier { params.mOverlay = new ColorDrawable(a.getColor( R.styleable.Magnifier_magnifierColorOverlay, Color.TRANSPARENT)); a.recycle(); - params.mForcePositionWithinWindowSystemInsetsBounds = true; + params.mClippingEnabled = true; params.mLeftContentBound = SOURCE_BOUND_MAX_VISIBLE; params.mTopContentBound = SOURCE_BOUND_MAX_IN_SURFACE; params.mRightContentBound = SOURCE_BOUND_MAX_VISIBLE; @@ -203,8 +204,7 @@ public final class Magnifier { params.mHorizontalDefaultSourceToMagnifierOffset; mDefaultVerticalSourceToMagnifierOffset = params.mVerticalDefaultSourceToMagnifierOffset; - mForcePositionWithinWindowSystemInsetsBounds = - params.mForcePositionWithinWindowSystemInsetsBounds; + mClippingEnabled = params.mClippingEnabled; mLeftContentBound = params.mLeftContentBound; mTopContentBound = params.mTopContentBound; mRightContentBound = params.mRightContentBound; @@ -271,7 +271,7 @@ public final class Magnifier { if (mWindow == null) { synchronized (mLock) { mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(), - mParentSurface.mSurface, mWindowWidth, mWindowHeight, + mParentSurface.mSurfaceControl, mWindowWidth, mWindowHeight, mWindowElevation, mWindowCornerRadius, mOverlay != null ? mOverlay : new ColorDrawable(Color.TRANSPARENT), Handler.getMain() /* draw the magnifier on the UI thread */, mLock, @@ -447,7 +447,7 @@ public final class Magnifier { } /** - * Returns the overlay to be drawn on the top of the magnifier content, or + * Returns the overlay to be drawn on the top of the magnifier, or * {@code null} if no overlay should be drawn. * @return the overlay * @see Magnifier.Builder#setOverlay(Drawable) @@ -459,13 +459,15 @@ public final class Magnifier { /** * Returns whether the magnifier position will be adjusted such that the magnifier will be - * fully within the bounds of the main application window, by also avoiding any overlap with - * system insets (such as the one corresponding to the status bar). + * fully within the bounds of the main application window, by also avoiding any overlap + * with system insets (such as the one corresponding to the status bar) i.e. whether the + * area where the magnifier can be positioned will be clipped to the main application window + * and the system insets. * @return whether the magnifier position will be adjusted - * @see Magnifier.Builder#setForcePositionWithinWindowSystemInsetsBounds(boolean) + * @see Magnifier.Builder#setClippingEnabled(boolean) */ - public boolean isForcePositionWithinWindowSystemInsetsBounds() { - return mForcePositionWithinWindowSystemInsetsBounds; + public boolean isClippingEnabled() { + return mClippingEnabled; } /** @@ -528,17 +530,20 @@ public final class Magnifier { final int surfaceHeight = viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom; validMainWindowSurface = - new SurfaceInfo(mainWindowSurface, surfaceWidth, surfaceHeight, true); + new SurfaceInfo(viewRootImpl.getSurfaceControl(), mainWindowSurface, + surfaceWidth, surfaceHeight, true); } } // Get the surface backing the magnified view, if it is a SurfaceView. SurfaceInfo validSurfaceViewSurface = SurfaceInfo.NULL; if (mView instanceof SurfaceView) { + final SurfaceControl sc = ((SurfaceView) mView).getSurfaceControl(); final SurfaceHolder surfaceHolder = ((SurfaceView) mView).getHolder(); final Surface surfaceViewSurface = surfaceHolder.getSurface(); - if (surfaceViewSurface != null && surfaceViewSurface.isValid()) { + + if (sc != null && sc.isValid()) { final Rect surfaceFrame = surfaceHolder.getSurfaceFrame(); - validSurfaceViewSurface = new SurfaceInfo(surfaceViewSurface, + validSurfaceViewSurface = new SurfaceInfo(sc, surfaceViewSurface, surfaceFrame.right, surfaceFrame.bottom, false); } } @@ -708,7 +713,7 @@ public final class Magnifier { * @return the current window coordinates, after they are clamped inside the parent surface */ private Point getCurrentClampedWindowCoordinates() { - if (!mForcePositionWithinWindowSystemInsetsBounds) { + if (!mClippingEnabled) { // No position adjustment should be done, so return the raw coordinates. return new Point(mWindowCoords); } @@ -733,15 +738,18 @@ public final class Magnifier { * Contains a surface and metadata corresponding to it. */ private static class SurfaceInfo { - public static final SurfaceInfo NULL = new SurfaceInfo(null, 0, 0, false); + public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, false); private Surface mSurface; + private SurfaceControl mSurfaceControl; private int mWidth; private int mHeight; private boolean mIsMainWindowSurface; - SurfaceInfo(final Surface surface, final int width, final int height, + SurfaceInfo(final SurfaceControl surfaceControl, final Surface surface, + final int width, final int height, final boolean isMainWindowSurface) { + mSurfaceControl = surfaceControl; mSurface = surface; mWidth = width; mHeight = height; @@ -819,7 +827,7 @@ public final class Magnifier { private Bitmap mCurrentContent; InternalPopupWindow(final Context context, final Display display, - final Surface parentSurface, final int width, final int height, + final SurfaceControl parentSurfaceControl, final int width, final int height, final float elevation, final float cornerRadius, final Drawable overlay, final Handler handler, final Object lock, final Callback callback) { mDisplay = display; @@ -834,12 +842,13 @@ public final class Magnifier { // Setup the surface we will use for drawing the content and shadow. mSurfaceWidth = mContentWidth + 2 * mOffsetX; mSurfaceHeight = mContentHeight + 2 * mOffsetY; - mSurfaceSession = new SurfaceSession(parentSurface); + mSurfaceSession = new SurfaceSession(); mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setFormat(PixelFormat.TRANSLUCENT) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setName("magnifier surface") .setFlags(SurfaceControl.HIDDEN) + .setParent(parentSurfaceControl) .build(); mSurface = new Surface(); mSurface.copyFrom(mSurfaceControl); @@ -1129,7 +1138,7 @@ public final class Magnifier { private @Nullable Drawable mOverlay; private int mHorizontalDefaultSourceToMagnifierOffset; private int mVerticalDefaultSourceToMagnifierOffset; - private boolean mForcePositionWithinWindowSystemInsetsBounds; + private boolean mClippingEnabled; private @SourceBound int mLeftContentBound; private @SourceBound int mTopContentBound; private @SourceBound int mRightContentBound; @@ -1157,7 +1166,7 @@ public final class Magnifier { resources.getDimensionPixelSize(R.dimen.default_magnifier_vertical_offset); mOverlay = new ColorDrawable(resources.getColor( R.color.default_magnifier_color_overlay, null)); - mForcePositionWithinWindowSystemInsetsBounds = true; + mClippingEnabled = true; mLeftContentBound = SOURCE_BOUND_MAX_VISIBLE; mTopContentBound = SOURCE_BOUND_MAX_VISIBLE; mRightContentBound = SOURCE_BOUND_MAX_VISIBLE; @@ -1220,11 +1229,11 @@ public final class Magnifier { } /** - * Sets an overlay that will be drawn on the top of the magnifier content. - * In general, the overlay should not be opaque, in order to let the expected magnifier - * content be partially visible. The default overlay is {@code null} (no overlay). - * As an example, TextView applies a white {@link ColorDrawable} overlay with - * 5% alpha, aiming to make the magnifier distinguishable when shown in dark + * Sets an overlay that will be drawn on the top of the magnifier. + * In general, the overlay should not be opaque, in order to let the magnified + * content be partially visible in the magnifier. The default overlay is {@code null} + * (no overlay). As an example, TextView applies a white {@link ColorDrawable} + * overlay with 5% alpha, aiming to make the magnifier distinguishable when shown in dark * application regions. To disable the overlay, the parameter should be set * to {@code null}. If not null, the overlay will be automatically redrawn * when the drawable is invalidated. To achieve this, the magnifier will set a new @@ -1258,22 +1267,24 @@ public final class Magnifier { * Defines the behavior of the magnifier when it is requested to position outside the * surface of the main application window. The default value is {@code true}, which means * that the position will be adjusted such that the magnifier will be fully within the - * bounds of the main application window, by also avoiding any overlap with system insets - * (such as the one corresponding to the status bar). If you require a custom behavior, this - * flag should be set to {@code false}, meaning that the magnifier will be able to cross the - * main application surface boundaries (and also overlap the system insets). This should be - * handled with care, when passing coordinates to {@link #show(float, float)}; note that: + * bounds of the main application window, while also avoiding any overlap with system insets + * (such as the one corresponding to the status bar). If this flag is set to {@code false}, + * the area where the magnifier can be positioned will no longer be clipped, so the + * magnifier will be able to extend outside the main application window boundaries (and also + * overlap the system insets). This can be useful if you require a custom behavior, but it + * should be handled with care, when passing coordinates to {@link #show(float, float)}; + * note that: * <ul> * <li>in a multiwindow context, if the magnifier crosses the boundary between the two * windows, it will not be able to show over the window of the other application</li> * <li>if the magnifier overlaps the status bar, there is no guarantee about which one * will be displayed on top. This should be handled with care.</li> * </ul> - * @param force whether the magnifier position will be adjusted + * @param clip whether the magnifier position will be adjusted */ @NonNull - public Builder setForcePositionWithinWindowSystemInsetsBounds(boolean force) { - mForcePositionWithinWindowSystemInsetsBounds = force; + public Builder setClippingEnabled(boolean clip) { + mClippingEnabled = clip; return this; } diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java index 6a3a8f0821d8..dc9a585b56e2 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -454,6 +454,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { (RelativeLayout.LayoutParams) mAmPmLayout.getLayoutParams(); if (params.getRule(RelativeLayout.RIGHT_OF) != 0 || params.getRule(RelativeLayout.LEFT_OF) != 0) { + final int margin = (int) (mContext.getResources().getDisplayMetrics().density * 8); // Horizontal mode, with AM/PM appearing to left/right of hours and minutes. final boolean isAmPmAtLeft; if (TextUtils.getLayoutDirectionFromLocale(mLocale) == View.LAYOUT_DIRECTION_LTR) { @@ -461,10 +462,6 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { } else { isAmPmAtLeft = !isAmPmAtStart; } - if (mIsAmPmAtLeft == isAmPmAtLeft) { - // AM/PM is already at the correct location. No change needed. - return; - } if (isAmPmAtLeft) { params.removeRule(RelativeLayout.RIGHT_OF); @@ -473,6 +470,14 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { params.removeRule(RelativeLayout.LEFT_OF); params.addRule(RelativeLayout.RIGHT_OF, mMinuteView.getId()); } + + if (isAmPmAtStart) { + params.setMarginStart(0); + params.setMarginEnd(margin); + } else { + params.setMarginStart(margin); + params.setMarginEnd(0); + } mIsAmPmAtLeft = isAmPmAtLeft; } else if (params.getRule(RelativeLayout.BELOW) != 0 || params.getRule(RelativeLayout.ABOVE) != 0) { diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java index 96d3baf7cf0b..f61a03bccb78 100644 --- a/core/java/com/android/internal/app/ResolverComparator.java +++ b/core/java/com/android/internal/app/ResolverComparator.java @@ -22,44 +22,36 @@ import android.app.usage.UsageStatsManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; +import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; -import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; -import android.content.SharedPreferences; -import android.content.ServiceConnection; import android.metrics.LogMaker; -import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; -import android.os.storage.StorageManager; import android.os.UserHandle; -import android.service.resolver.IResolverRankerService; import android.service.resolver.IResolverRankerResult; +import android.service.resolver.IResolverRankerService; import android.service.resolver.ResolverRankerService; import android.service.resolver.ResolverTarget; -import android.text.TextUtils; -import android.util.ArrayMap; import android.util.Log; + import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import java.io.File; -import java.lang.InterruptedException; import java.text.Collator; import java.util.ArrayList; import java.util.Comparator; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /** * Ranks and compares packages based on usage stats. @@ -90,6 +82,8 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { private final Collator mCollator; private final boolean mHttp; + // can be null if mHttp == false or current user has no default browser package + private final String mDefaultBrowserPackageName; private final PackageManager mPm; private final UsageStatsManager mUsm; private final Map<String, UsageStats> mStats; @@ -184,6 +178,10 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { getContentAnnotations(intent); mAction = intent.getAction(); mRankerServiceName = new ComponentName(mContext, this.getClass()); + + mDefaultBrowserPackageName = mHttp + ? mPm.getDefaultBrowserPackageNameAsUser(UserHandle.myUserId()) + : null; } // get annotations of content from intent. @@ -312,7 +310,14 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { if (mHttp) { // Special case: we want filters that match URI paths/schemes to be // ordered before others. This is for the case when opening URIs, - // to make native apps go above browsers. + // to make native apps go above browsers - except for 1 even more special case + // which is the default browser, as we want that to go above them all. + if (isDefaultBrowser(lhs)) { + return -1; + } + if (isDefaultBrowser(rhs)) { + return 1; + } final boolean lhsSpecific = ResolverActivity.isSpecificUriMatch(lhs.match); final boolean rhsSpecific = ResolverActivity.isSpecificUriMatch(rhs.match); if (lhsSpecific != rhsSpecific) { @@ -419,6 +424,20 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> { } } + private boolean isDefaultBrowser(ResolveInfo ri) { + // It makes sense to prefer the default browser + // only if the targeted user is the current user + if (ri.targetUserId != UserHandle.USER_CURRENT) { + return false; + } + + if (ri.activityInfo.packageName != null + && ri.activityInfo.packageName.equals(mDefaultBrowserPackageName)) { + return true; + } + return false; + } + // records metrics for evaluation. private void logMetrics(int selectedPos) { if (mRankerServiceName != null) { diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 0a7cff6856e5..9bacf9b6c2b9 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -20,6 +20,7 @@ import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; + import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.Nullable; @@ -33,10 +34,8 @@ import com.android.internal.util.ProcFileReader; import libcore.io.IoUtils; -import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; -import java.io.FileReader; import java.io.IOException; import java.net.ProtocolException; import java.util.Arrays; @@ -127,7 +126,7 @@ public class NetworkStatsFactory { } public NetworkStatsFactory() { - this(new File("/proc/"), new File("/sys/fs/bpf/traffic_uid_stats_map").exists()); + this(new File("/proc/"), new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists()); } @VisibleForTesting diff --git a/core/java/com/android/internal/os/AppZygoteInit.java b/core/java/com/android/internal/os/AppZygoteInit.java new file mode 100644 index 000000000000..afe6dade62ac --- /dev/null +++ b/core/java/com/android/internal/os/AppZygoteInit.java @@ -0,0 +1,105 @@ +/* + * 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.internal.os; + +import android.app.LoadedApk; +import android.content.pm.ApplicationInfo; +import android.net.LocalSocket; +import android.util.Log; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Startup class for an Application zygote process. + * + * See {@link ZygoteInit} for generic zygote startup documentation. + * + * @hide + */ +class AppZygoteInit { + public static final String TAG = "AppZygoteInit"; + + private static ZygoteServer sServer; + + private static class AppZygoteServer extends ZygoteServer { + @Override + protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList) + throws IOException { + return new AppZygoteConnection(socket, abiList); + } + } + + private static class AppZygoteConnection extends ZygoteConnection { + AppZygoteConnection(LocalSocket socket, String abiList) throws IOException { + super(socket, abiList); + } + + @Override + protected void preload() { + // Nothing to preload by default. + } + + @Override + protected boolean isPreloadComplete() { + // App zygotes don't preload any classes or resources or defaults, all of their + // preloading is package specific. + return true; + } + + @Override + protected boolean canPreloadApp() { + return true; + } + + @Override + protected void handlePreloadApp(ApplicationInfo appInfo) { + Log.i(TAG, "Beginning application preload for " + appInfo.packageName); + LoadedApk loadedApk = new LoadedApk(null, appInfo, null, null, false, true, false); + ClassLoader loader = loadedApk.getClassLoader(); + Class<?> cl; + Method m; + try { + cl = Class.forName(appInfo.packageName + ".ZygotePreload", true, loader); + m = cl.getMethod("doPreload"); + m.setAccessible(true); + m.invoke(null); + } catch (ClassNotFoundException e) { + // Don't treat this as an error since an app may not want to do any preloads + Log.w(TAG, "No ZygotePreload class found for " + appInfo.packageName); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + Log.e(TAG, "AppZygote application preload failed for " + + appInfo.packageName, e); + } + try { + DataOutputStream socketOut = getSocketOutputStream(); + socketOut.writeInt(loader != null ? 1 : 0); + } catch (IOException e) { + throw new IllegalStateException("Error writing to command socket", e); + } + + Log.i(TAG, "Application preload done"); + } + } + + public static void main(String[] argv) { + AppZygoteServer server = new AppZygoteServer(); + ChildZygoteInit.runZygoteServer(server, argv); + } +} diff --git a/core/java/com/android/internal/os/ChildZygoteInit.java b/core/java/com/android/internal/os/ChildZygoteInit.java new file mode 100644 index 000000000000..f90cd0224596 --- /dev/null +++ b/core/java/com/android/internal/os/ChildZygoteInit.java @@ -0,0 +1,99 @@ +/* + * 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.internal.os; + +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.util.Log; + +/** + * ChildZygoteInit is shared by both the Application and WebView zygote to initialize + * and run a (child) Zygote server. + * + * @hide + */ +public class ChildZygoteInit { + private static final String TAG = "ChildZygoteInit"; + + static String parseSocketNameFromArgs(String[] argv) { + for (String arg : argv) { + if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) { + return arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length()); + } + } + + return null; + } + + static String parseAbiListFromArgs(String[] argv) { + for (String arg : argv) { + if (arg.startsWith(Zygote.CHILD_ZYGOTE_ABI_LIST_ARG)) { + return arg.substring(Zygote.CHILD_ZYGOTE_ABI_LIST_ARG.length()); + } + } + + return null; + } + + /** + * Starts a ZygoteServer and listens for requests + * + * @param server An instance of a ZygoteServer to listen on + * @param args Passed in arguments for this ZygoteServer + */ + static void runZygoteServer(ZygoteServer server, String[] args) { + String socketName = parseSocketNameFromArgs(args); + if (socketName == null) { + throw new NullPointerException("No socketName specified"); + } + + String abiList = parseAbiListFromArgs(args); + if (abiList == null) { + throw new NullPointerException("No abiList specified"); + } + + try { + Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + } catch (ErrnoException ex) { + throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex); + } + + final Runnable caller; + try { + server.registerServerSocketAtAbstractName(socketName); + + // Add the abstract socket to the FD whitelist so that the native zygote code + // can properly detach it after forking. + Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName); + + // The select loop returns early in the child process after a fork and + // loops forever in the zygote. + caller = server.runSelectLoop(abiList); + } catch (RuntimeException e) { + Log.e(TAG, "Fatal exception:", e); + throw e; + } finally { + server.closeServerSocket(); + } + + // We're in the child process and have exited the select loop. Proceed to execute the + // command. + if (caller != null) { + caller.run(); + } + } +} diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java index 9f2434e97d7a..0b329d70f7af 100644 --- a/core/java/com/android/internal/os/WebViewZygoteInit.java +++ b/core/java/com/android/internal/os/WebViewZygoteInit.java @@ -18,11 +18,7 @@ package com.android.internal.os; import android.app.ApplicationLoaders; import android.net.LocalSocket; -import android.net.LocalServerSocket; import android.os.Build; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; import android.text.TextUtils; import android.util.Log; import android.webkit.WebViewFactory; @@ -44,8 +40,6 @@ import java.lang.reflect.Method; class WebViewZygoteInit { public static final String TAG = "WebViewZygoteInit"; - private static ZygoteServer sServer; - private static class WebViewZygoteServer extends ZygoteServer { @Override protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList) @@ -127,48 +121,7 @@ class WebViewZygoteInit { public static void main(String argv[]) { Log.i(TAG, "Starting WebViewZygoteInit"); - - String socketName = null; - for (String arg : argv) { - Log.i(TAG, arg); - if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) { - socketName = arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length()); - } - } - if (socketName == null) { - throw new RuntimeException("No " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + " specified"); - } - - try { - Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); - } catch (ErrnoException ex) { - throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex); - } - - sServer = new WebViewZygoteServer(); - - final Runnable caller; - try { - sServer.registerServerSocketAtAbstractName(socketName); - - // Add the abstract socket to the FD whitelist so that the native zygote code - // can properly detach it after forking. - Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName); - - // The select loop returns early in the child process after a fork and - // loops forever in the zygote. - caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS)); - } catch (RuntimeException e) { - Log.e(TAG, "Fatal exception:", e); - throw e; - } finally { - sServer.closeServerSocket(); - } - - // We're in the child process and have exited the select loop. Proceed to execute the - // command. - if (caller != null) { - caller.run(); - } + WebViewZygoteServer server = new WebViewZygoteServer(); + ChildZygoteInit.runZygoteServer(server, argv); } } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 65b9fad97d89..d720c689f5de 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -98,6 +98,12 @@ public final class Zygote { */ public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket="; + /** + * An extraArg passed when a zygote process is forking a child-zygote, specifying the + * requested ABI for the child Zygote. + */ + public static final String CHILD_ZYGOTE_ABI_LIST_ARG = "--abi-list="; + private Zygote() {} /** Called for some security initialization before any fork. */ diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index f182c4d447df..5990d72d89b4 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -27,9 +27,11 @@ import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEO import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC; import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS; +import android.content.pm.ApplicationInfo; import android.net.Credentials; import android.net.LocalSocket; import android.os.FactoryTest; +import android.os.Parcel; import android.os.Process; import android.os.SystemProperties; import android.os.Trace; @@ -52,6 +54,7 @@ import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; /** * A connection that can make spawn requests. @@ -168,6 +171,21 @@ class ZygoteConnection { return null; } + if (canPreloadApp() && parsedArgs.mPreloadApp != null) { + byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp); + Parcel appInfoParcel = Parcel.obtain(); + appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length); + appInfoParcel.setDataPosition(0); + ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel); + appInfoParcel.recycle(); + if (appInfo != null) { + handlePreloadApp(appInfo); + } else { + throw new IllegalArgumentException("Failed to deserialize --preload-app"); + } + return null; + } + if (parsedArgs.apiBlacklistExemptions != null) { handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions); return null; @@ -341,7 +359,15 @@ class ZygoteConnection { protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName, String cacheKey) { - throw new RuntimeException("Zyogte does not support package preloading"); + throw new RuntimeException("Zygote does not support package preloading"); + } + + protected boolean canPreloadApp() { + return false; + } + + protected void handlePreloadApp(ApplicationInfo aInfo) { + throw new RuntimeException("Zygote does not support app preloading"); } /** @@ -467,6 +493,12 @@ class ZygoteConnection { String preloadPackage; /** + * A Base64 string representing a serialize ApplicationInfo Parcel, + when using --preload-app. + */ + String mPreloadApp; + + /** * The native library path of the package to preload, when using --preload-package. */ String preloadPackageLibs; @@ -666,6 +698,8 @@ class ZygoteConnection { instructionSet = arg.substring(arg.indexOf('=') + 1); } else if (arg.startsWith("--app-data-dir=")) { appDataDir = arg.substring(arg.indexOf('=') + 1); + } else if (arg.equals("--preload-app")) { + mPreloadApp = args[++curArg]; } else if (arg.equals("--preload-package")) { preloadPackage = args[++curArg]; preloadPackageLibs = args[++curArg]; @@ -714,6 +748,11 @@ class ZygoteConnection { throw new IllegalArgumentException( "Unexpected arguments after --preload-package."); } + } else if (mPreloadApp != null) { + if (args.length - curArg > 0) { + throw new IllegalArgumentException( + "Unexpected arguments after --preload-app."); + } } else if (expectRuntimeArgs) { if (!seenRuntimeArgs) { throw new IllegalArgumentException("Unexpected argument : " + args[curArg]); diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index e2c23de70c00..cdaf33f03528 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -232,7 +232,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind // This is the caption view for the window, containing the caption and window control // buttons. The visibility of this decor depends on the workspace and the window type. // If the window type does not require such a view, this member might be null. - DecorCaptionView mDecorCaptionView; + private DecorCaptionView mDecorCaptionView; private boolean mWindowResizeCallbacksAdded = false; private Drawable.Callback mLastBackgroundDrawableCb = null; @@ -977,6 +977,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind @Override public void onWindowSystemUiVisibilityChanged(int visible) { updateColorViews(null /* insets */, true /* animate */); + updateDecorCaptionStatus(getResources().getConfiguration()); } @Override @@ -1855,8 +1856,27 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - final boolean displayWindowDecor = - newConfig.windowConfiguration.hasWindowDecorCaption(); + updateDecorCaptionStatus(newConfig); + + updateAvailableWidth(); + initializeElevation(); + } + + /** + * Determines if the workspace is entirely covered by the window. + * @return {@code true} when the window is filling the entire screen/workspace. + **/ + private boolean isFillingScreen(Configuration config) { + final boolean isFullscreen = config.windowConfiguration.getWindowingMode() + == WindowConfiguration.WINDOWING_MODE_FULLSCREEN; + return isFullscreen && (0 != ((getWindowSystemUiVisibility() | getSystemUiVisibility()) + & (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_LOW_PROFILE))); + } + + private void updateDecorCaptionStatus(Configuration config) { + final boolean displayWindowDecor = config.windowConfiguration.hasWindowDecorCaption() + && !isFillingScreen(config); if (mDecorCaptionView == null && displayWindowDecor) { // Configuration now requires a caption. final LayoutInflater inflater = mWindow.getLayoutInflater(); @@ -1875,9 +1895,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mDecorCaptionView.onConfigurationChanged(displayWindowDecor); enableCaption(displayWindowDecor); } - - updateAvailableWidth(); - initializeElevation(); } void onResourcesLoaded(LayoutInflater inflater, int layoutResource) { diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java new file mode 100644 index 000000000000..9a346ac93a8d --- /dev/null +++ b/core/java/com/android/internal/util/SyncResultReceiver.java @@ -0,0 +1,145 @@ +/* + * 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.internal.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Bundle; +import android.os.Parcelable; +import android.os.RemoteException; + +import com.android.internal.os.IResultReceiver; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * A {@code IResultReceiver} implementation that can be used to make "sync" Binder calls by blocking + * until it receives a result + * + * @hide + */ +public final class SyncResultReceiver extends IResultReceiver.Stub { + + private static final String EXTRA = "EXTRA"; + + private final CountDownLatch mLatch = new CountDownLatch(1); + private final int mTimeoutMs; + private int mResult; + private Bundle mBundle; + + /** + * Default constructor. + * + * @param timeoutMs how long to block waiting for {@link IResultReceiver} callbacks. + */ + public SyncResultReceiver(int timeoutMs) { + mTimeoutMs = timeoutMs; + } + + private void waitResult() throws TimeoutException { + try { + if (!mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("Not called in " + mTimeoutMs + "ms"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new TimeoutException("Interrupted"); + } + } + + /** + * Gets the result from an operation that returns an {@code int}. + */ + public int getIntResult() throws TimeoutException { + waitResult(); + return mResult; + } + + /** + * Gets the result from an operation that returns an {@code String}. + */ + @Nullable + public String getStringResult() throws TimeoutException { + waitResult(); + return mBundle == null ? null : mBundle.getString(EXTRA); + } + + /** + * Gets the result from an operation that returns a {@code String[]}. + */ + @Nullable + public String[] getStringArrayResult() throws TimeoutException { + waitResult(); + return mBundle == null ? null : mBundle.getStringArray(EXTRA); + } + + /** + * Gets the result from an operation that returns a {@code Parcelable}. + */ + @Nullable + public <P extends Parcelable> P getParcelableResult() throws TimeoutException { + waitResult(); + return mBundle == null ? null : mBundle.getParcelable(EXTRA); + } + + @Override + public void send(int resultCode, Bundle resultData) { + mResult = resultCode; + mBundle = resultData; + mLatch.countDown(); + } + + /** + * Creates a bundle for a {@code String} value so it can be retrieved by + * {@link #getStringResult()}. + */ + @NonNull + public static Bundle bundleFor(@Nullable String value) { + final Bundle bundle = new Bundle(); + bundle.putString(EXTRA, value); + return bundle; + } + + /** + * Creates a bundle for a {@code String[]} value so it can be retrieved by + * {@link #getStringArrayResult()}. + */ + @NonNull + public static Bundle bundleFor(@Nullable String[] value) { + final Bundle bundle = new Bundle(); + bundle.putStringArray(EXTRA, value); + return bundle; + } + + /** + * Creates a bundle for a {@code Parcelable} value so it can be retrieved by + * {@link #getParcelableResult()}. + */ + @NonNull + public static Bundle bundleFor(@Nullable Parcelable value) { + final Bundle bundle = new Bundle(); + bundle.putParcelable(EXTRA, value); + return bundle; + } + + /** @hide */ + public static final class TimeoutException extends RemoteException { + private TimeoutException(String msg) { + super(msg); + } + } +} diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java index b41911360358..21558d3d3518 100644 --- a/core/java/com/android/internal/widget/DecorCaptionView.java +++ b/core/java/com/android/internal/widget/DecorCaptionView.java @@ -319,23 +319,12 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, mOwner.notifyRestrictedCaptionAreaCallback(mMaximize.getLeft(), mMaximize.getTop(), mClose.getRight(), mClose.getBottom()); } - /** - * Determine if the workspace is entirely covered by the window. - * @return Returns true when the window is filling the entire screen/workspace. - **/ - private boolean isFillingScreen() { - return (0 != ((getWindowSystemUiVisibility() | getSystemUiVisibility()) & - (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_LOW_PROFILE))); - } /** * Updates the visibility of the caption. **/ private void updateCaptionVisibility() { - // Don't show the caption if the window has e.g. entered full screen. - boolean invisible = isFillingScreen() || !mShow; - mCaption.setVisibility(invisible ? GONE : VISIBLE); + mCaption.setVisibility(mShow ? VISIBLE : GONE); mCaption.setOnTouchListener(this); } diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 9ae05f4c1e08..4b0ab5b2d6ce 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -231,7 +231,7 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream, } if (isMutable && isHardware) { - doThrowIAE(env, "Bitmaps with Config.HARWARE are always immutable"); + doThrowIAE(env, "Bitmaps with Config.HARDWARE are always immutable"); return nullObjectReturn("Cannot create mutable hardware bitmap"); } diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 3329e2047085..f201ceb40ff4 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -875,6 +875,11 @@ static jint android_os_Binder_getCallingUid() return IPCThreadState::self()->getCallingUid(); } +static jboolean android_os_Binder_isHandlingTransaction() +{ + return IPCThreadState::self()->isServingCall(); +} + static jlong android_os_Binder_clearCallingIdentity() { return IPCThreadState::self()->clearCallingIdentity(); @@ -960,6 +965,8 @@ static const JNINativeMethod gBinderMethods[] = { // @CriticalNative { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid }, // @CriticalNative + { "isHandlingTransaction", "()Z", (void*)android_os_Binder_isHandlingTransaction }, + // @CriticalNative { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity }, { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity }, // @CriticalNative diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 6576587899be..9ce6df1832a6 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -438,8 +438,9 @@ static jobject nativeGetDisplayedContentSamplingAttributes(JNIEnv* env, jclass c static jboolean nativeSetDisplayedContentSamplingEnabled(JNIEnv* env, jclass clazz, jobject tokenObj, jboolean enable, jint componentMask, jint maxFrames) { sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); - return SurfaceComposerClient::setDisplayContentSamplingEnabled( + status_t rc = SurfaceComposerClient::setDisplayContentSamplingEnabled( token, enable, componentMask, maxFrames); + return rc == OK; } static jobject nativeGetDisplayedContentSample(JNIEnv* env, jclass clazz, jobject tokenObj, @@ -869,14 +870,6 @@ static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong transa transaction->setOverrideScalingMode(ctrl, scalingMode); } -static void nativeDestroyInTransaction(JNIEnv* env, jclass clazz, - jlong transactionObj, - jlong nativeObject) { - auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); - auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject); - transaction->destroySurface(ctrl); -} - static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) { auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); return javaObjectForIBinder(env, ctrl->getHandle()); @@ -916,6 +909,17 @@ static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) return reinterpret_cast<jlong>(surface.get()); } +static jlong nativeCopyFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj) { + sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj)); + if (surface == nullptr) { + return 0; + } + + sp<SurfaceControl> newSurface = new SurfaceControl(surface); + newSurface->incStrong((void *)nativeCreate); + return reinterpret_cast<jlong>(newSurface.get()); +} + static void nativeWriteToParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); @@ -924,7 +928,9 @@ static void nativeWriteToParcel(JNIEnv* env, jclass clazz, return; } SurfaceControl* const self = reinterpret_cast<SurfaceControl *>(nativeObject); - self->writeToParcel(parcel); + if (self != nullptr) { + self->writeToParcel(parcel); + } } // ---------------------------------------------------------------------------- @@ -934,6 +940,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeCreate }, {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel }, + {"nativeCopyFromSurfaceControl", "(J)J" , + (void*)nativeCopyFromSurfaceControl }, {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel }, {"nativeRelease", "(J)V", @@ -1032,8 +1040,6 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSeverChildren } , {"nativeSetOverrideScalingMode", "(JJI)V", (void*)nativeSetOverrideScalingMode }, - {"nativeDestroy", "(JJ)V", - (void*)nativeDestroyInTransaction }, {"nativeGetHandle", "(J)Landroid/os/IBinder;", (void*)nativeGetHandle }, {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZI)Landroid/graphics/GraphicBuffer;", diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp index 30c00302eefd..191f748d80bf 100644 --- a/core/jni/android_view_SurfaceSession.cpp +++ b/core/jni/android_view_SurfaceSession.cpp @@ -46,13 +46,6 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz) { return reinterpret_cast<jlong>(client); } -static jlong nativeCreateScoped(JNIEnv* env, jclass clazz, jlong surfaceObject) { - Surface *parent = reinterpret_cast<Surface*>(surfaceObject); - SurfaceComposerClient* client = new SurfaceComposerClient(parent->getIGraphicBufferProducer()); - client->incStrong((void*)nativeCreate); - return reinterpret_cast<jlong>(client); -} - static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) { SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr); client->decStrong((void*)nativeCreate); @@ -67,8 +60,6 @@ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "()J", (void*)nativeCreate }, - { "nativeCreateScoped", "(J)J", - (void*)nativeCreateScoped }, { "nativeDestroy", "(J)V", (void*)nativeDestroy }, { "nativeKill", "(J)V", diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index a914369a036c..a00fde9ed0e3 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -436,11 +436,12 @@ message GlobalSettingsProto { // Ordered GPU debug layer list for GLES // i.e. <layer1>:<layer2>:...:<layerN> optional SettingProto debug_layers_gles = 7; - // Apps opt in to load graphics driver from Game Update Package - // instead of native graphcis driver through developer options. + // GUP - List of Apps selected to use Game Update Packages optional SettingProto gup_dev_opt_in_apps = 8; - // Apps on the black list that are forbidden to useGame Update Package. - optional SettingProto gup_black_list = 9; + // GUP - List of Apps selected not to use Game Update Packages + optional SettingProto gup_dev_opt_out_apps = 9; + // GUP - List of Apps that are forbidden to use Game Update Packages + optional SettingProto gup_black_list = 10; } optional Gpu gpu = 59; @@ -558,6 +559,8 @@ message GlobalSettingsProto { // ringer mode. optional SettingProto mode_ringer = 75 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto apply_ramping_ringer = 147 [ (android.privacy).dest = DEST_AUTOMATIC ]; + message MultiSim { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -1017,5 +1020,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 147; + // Next tag = 148; } diff --git a/core/proto/android/stats/docsui/docsui_enums.proto b/core/proto/android/stats/docsui/docsui_enums.proto index 6cb606ad1cab..655b5e326019 100644 --- a/core/proto/android/stats/docsui/docsui_enums.proto +++ b/core/proto/android/stats/docsui/docsui_enums.proto @@ -33,13 +33,14 @@ enum MimeType { MIME_UNKNOWN = 0; MIME_NONE = 1; MIME_ANY = 2; - MIME_AUDIO = 3; - MIME_IMAGE = 4; - MIME_MESSAGE = 5; - MIME_MULTIPART = 6; - MIME_TEXT = 7; - MIME_VIDEO = 8; - MIME_OTHER = 9; + MIME_APPLICATION = 3; + MIME_AUDIO = 4; + MIME_IMAGE = 5; + MIME_MESSAGE = 6; + MIME_MULTIPART = 7; + MIME_TEXT = 8; + MIME_VIDEO = 9; + MIME_OTHER = 10; } enum Root { @@ -163,6 +164,8 @@ enum UserAction { ACTION_EXTRACT_TO = 29; ACTION_VIEW_IN_APPLICATION = 30; ACTION_INSPECTOR = 31; + ACTION_SEARCH_CHIP = 32; + ACTION_SEARCH_HISTORY = 33; } enum InvalidScopedAccess { @@ -172,3 +175,20 @@ enum InvalidScopedAccess { SCOPED_DIR_ACCESS_ERROR = 3; SCOPED_DIR_ACCESS_DEPRECATED = 4; } + +enum SearchType { + TYPE_UNKNOWN = 0; + TYPE_CHIP_IMAGES = 1; + TYPE_CHIP_AUDIOS = 2; + TYPE_CHIP_VIDEOS = 3; + TYPE_CHIP_DOCS = 4; + TYPE_SEARCH_HISTORY = 5; + TYPE_SEARCH_STRING = 6; +} + +enum SearchMode { + SEARCH_UNKNOWN = 0; + SEARCH_KEYWORD = 1; + SEARCH_CHIPS = 2; + SEARCH_KEYWORD_N_CHIPS = 3; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 0778304d26aa..449a7b3305ad 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2256,7 +2256,7 @@ <!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks --> <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" - android:protectionLevel="signature|privileged" /> + android:protectionLevel="signature" /> <!-- @SystemApi @TestApi @hide Allows an application to embed other activities --> <permission android:name="android.permission.ACTIVITY_EMBEDDING" diff --git a/core/res/res/drawable/ic_account_circle.xml b/core/res/res/drawable/ic_account_circle.xml index f7317dbc5245..71691add7322 100644 --- a/core/res/res/drawable/ic_account_circle.xml +++ b/core/res/res/drawable/ic_account_circle.xml @@ -14,18 +14,14 @@ Copyright (C) 2014 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48.0dp" - android:height="48.0dp" - android:viewportWidth="20.0" - android:viewportHeight="20.0"> - <group - android:translateX="-2" - android:translateY="-2" > - <path - android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33C4.62,15.49 4,13.82 4,12c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,13.82 19.38,15.49 18.36,16.83z" - android:fillColor="#FFFFFFFF" /> - <path - android:pathData="M12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13c1.94,0 3.5,-1.56 3.5,-3.5S13.94,6 12,6z" - android:fillColor="#FFFFFFFF" /> - </group> + android:width="48dp" + android:height="48dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33C4.62,15.49 4,13.82 4,12c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,13.82 19.38,15.49 18.36,16.83z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13c1.94,0 3.5,-1.56 3.5,-3.5S13.94,6 12,6z"/> </vector> diff --git a/core/res/res/drawable/ic_battery.xml b/core/res/res/drawable/ic_battery.xml new file mode 100644 index 000000000000..bd40f4df505e --- /dev/null +++ b/core/res/res/drawable/ic_battery.xml @@ -0,0 +1,25 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal"> + <path + android:fillColor="#FF000000" + android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4z"/> +</vector> diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml index 1dad9776851e..5ab504528366 100644 --- a/core/res/res/drawable/ic_corp_badge.xml +++ b/core/res/res/drawable/ic_corp_badge.xml @@ -15,22 +15,11 @@ Copyright (C) 2018 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="20dp" - android:height="20dp" - android:viewportWidth="48" - android:viewportHeight="48"> - + android:width="48dp" + android:height="48dp" + android:viewportWidth="24" + android:viewportHeight="24"> <path - android:fillType="evenOdd" - android:strokeColor="#1A73E8" - android:strokeWidth="4" - android:pathData="M 24 2 C 36.1502644963 2 46 11.8497355037 46 24 C 46 36.1502644963 36.1502644963 46 24 46 C 11.8497355037 46 2 36.1502644963 2 24 C 2 11.8497355037 11.8497355037 2 24 2 Z" /> - <group - android:translateX="10.400000" - android:translateY="10.400000"> - <path - android:fillColor="#1A73E8" - android:strokeWidth="1" - android:pathData="M24.2971429,5.38947368 L18.9485714,5.38947368 L18.9485714,2.80902256 C18.9485714,1.37687218 17.7585143,0.228571429 16.2742857,0.228571429 L10.9257143,0.228571429 C9.44148571,0.228571429 8.25142857,1.37687218 8.25142857,2.80902256 L8.25142857,5.38947368 L2.90285714,5.38947368 C1.41862857,5.38947368 0.241942857,6.53777444 0.241942857,7.96992481 L0.228571429,22.162406 C0.228571429,23.5945564 1.41862857,24.7428571 2.90285714,24.7428571 L24.2971429,24.7428571 C25.7813714,24.7428571 26.9714286,23.5945564 26.9714286,22.162406 L26.9714286,7.96992481 C26.9714286,6.53777444 25.7813714,5.38947368 24.2971429,5.38947368 Z M13.6,17.0015038 C12.1291429,17.0015038 10.9257143,15.8403008 10.9257143,14.4210526 C10.9257143,13.0018045 12.1291429,11.8406015 13.6,11.8406015 C15.0708571,11.8406015 16.2742857,13.0018045 16.2742857,14.4210526 C16.2742857,15.8403008 15.0708571,17.0015038 13.6,17.0015038 Z M16.2742857,5.38947368 L10.9257143,5.38947368 L10.9257143,2.80902256 L16.2742857,2.80902256 L16.2742857,5.38947368 Z" /> - </group> + android:fillColor="@*android:color/accent_device_default_light" + android:pathData="M20,6h-4V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v2H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM10,4h4v2h-4V4zM20,19H4V8h16V19z"/> </vector>
\ No newline at end of file diff --git a/core/res/res/layout/time_picker_header_material.xml b/core/res/res/layout/time_picker_header_material.xml index adb2b62f799c..30c10b118121 100644 --- a/core/res/res/layout/time_picker_header_material.xml +++ b/core/res/res/layout/time_picker_header_material.xml @@ -76,16 +76,14 @@ android:layout_height="wrap_content" android:layout_toRightOf="@+id/minutes" android:layout_alignBaseline="@+id/minutes" - android:paddingStart="4dp" - android:paddingEnd="4dp" + android:layout_marginStart="8dp" + android:layout_marginEnd="0dp" android:orientation="vertical" android:baselineAlignedChildIndex="1"> <RadioButton android:id="@+id/am_label" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingLeft="4dp" - android:paddingRight="4dp" android:paddingTop="8dp" android:paddingBottom="8dp" android:layout_marginBottom="-8dp" @@ -101,8 +99,6 @@ android:id="@+id/pm_label" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingLeft="4dp" - android:paddingRight="4dp" android:paddingTop="8dp" android:paddingBottom="8dp" android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel" diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 183c2e8cf486..fa3a549463f5 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3660,7 +3660,12 @@ the settings for this service. This setting cannot be changed at runtime. --> <attr name="settingsActivity" /> <!-- Attribute whether the accessibility service wants to be able to retrieve the - active window content. This setting cannot be changed at runtime. --> + active window content. This setting cannot be changed at runtime. + <p> + Required to allow setting the {@link android.accessibilityservice + #AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag. + </p> + --> <attr name="canRetrieveWindowContent" format="boolean" /> <!-- Attribute whether the accessibility service wants to be able to request touch exploration mode in which touched items are spoken aloud and the UI can be diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e4abf8f4cf49..1c98c66b1f48 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1169,7 +1169,7 @@ <integer name="config_lowBatteryAutoTriggerDefaultLevel">15</integer> <!-- The app which will handle routine based automatic battery saver, if empty the UI for - routine based battery saver will be hidden --> + routine based battery saver will be hidden --> <string name="config_batterySaverScheduleProvider"></string> <!-- Close low battery warning when battery level reaches the lowBatteryWarningLevel @@ -1404,6 +1404,13 @@ <integer-array name="config_autoBrightnessLevels"> </integer-array> + <!-- Timeout (in milliseconds) after which we remove the effects any user interactions might've + had on the brightness mapping. This timeout doesn't start until we transition to a + non-interactive display policy so that we don't reset while users are using their devices, + but also so that we don't erroneously keep the short-term model if the device is dozing + but the display is fully on. --> + <integer name="config_autoBrightnessShortTermModelTimeout">300000</integer> + <!-- Array of output values for LCD backlight corresponding to the lux values in the config_autoBrightnessLevels array. This array should have size one greater than the size of the config_autoBrightnessLevels array. diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a7bc57afa749..0878562e00fb 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -5238,6 +5238,15 @@ <!-- Content description of the overlay icon in the notification. [CHAR LIMIT=NONE] --> <string name="notification_appops_overlay_active">displaying over other apps on your screen</string> + <!-- Dynamic mode battery saver strings --> + <!-- The user visible name of the notification channel for the routine mode battery saver fyi notification [CHAR_LIMIT=80]--> + <string name="dynamic_mode_notification_channel_name">Routine Mode info notification</string> + <!-- Title of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]--> + <string name="dynamic_mode_notification_title">Battery may run out before usual charge</string> + <!-- Summary of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]--> + <string name="dynamic_mode_notification_summary">Battery Saver activated to extend battery life</string> + + <!-- Strings for car --> <!-- String displayed when loading a user in the car [CHAR LIMIT=30] --> <string name="car_loading_profile">Loading</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index e8cbf666c03c..01fbf80f4e63 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1964,6 +1964,7 @@ <java-symbol type="integer" name="config_screenBrightnessDark" /> <java-symbol type="integer" name="config_screenBrightnessDim" /> <java-symbol type="integer" name="config_screenBrightnessDoze" /> + <java-symbol type="integer" name="config_autoBrightnessShortTermModelTimeout" /> <java-symbol type="integer" name="config_shutdownBatteryTemperature" /> <java-symbol type="integer" name="config_undockedHdmiRotation" /> <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" /> @@ -3519,4 +3520,9 @@ <!-- For Secondary Launcher --> <java-symbol type="string" name="config_secondaryHomeComponent" /> + + <java-symbol type="string" name="dynamic_mode_notification_channel_name" /> + <java-symbol type="string" name="dynamic_mode_notification_title" /> + <java-symbol type="string" name="dynamic_mode_notification_summary" /> + <java-symbol type="drawable" name="ic_battery" /> </resources> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index 0f4ca66dcd68..d60313a4402c 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -1454,12 +1454,17 @@ easier. <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item> <!-- action bar --> + <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid</item> <item name="actionBarTheme">@style/ThemeOverlay.DeviceDefault.ActionBar</item> <item name="popupTheme">@style/ThemeOverlay.DeviceDefault.Popup.Light</item> <!-- Color palette --> + <item name="colorBackground">@color/background_device_default_light</item> + <item name="colorPrimary">@color/primary_device_default_settings_light</item> <item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item> <item name="colorSecondary">@color/secondary_device_default_settings_light</item> + <item name="colorAccent">@color/accent_device_default_light</item> + <item name="colorError">@color/error_color_device_default_light</item> <item name="colorEdgeEffect">@android:color/black</item> <!-- Add white nav bar with divider that matches material --> @@ -1467,9 +1472,16 @@ easier. <item name="navigationBarColor">@android:color/white</item> <item name="windowLightNavigationBar">true</item> + <!-- Dialog attributes --> + <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item> + <!-- Button styles --> + <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item> <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> + <!-- Progress bar attributes --> + <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> + <item name="listDivider">@color/list_divider_color_light</item> </style> diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java index 534c5cdec259..6c9c3c111ff8 100644 --- a/core/tests/coretests/src/android/os/BinderTest.java +++ b/core/tests/coretests/src/android/os/BinderTest.java @@ -43,4 +43,13 @@ public class BinderTest extends TestCase { Binder.restoreCallingWorkSource(token); assertEquals(UID, Binder.getCallingWorkSourceUid()); } + + @SmallTest + public void testGetCallingUidOrThrow() throws Exception { + try { + Binder.getCallingUidOrThrow(); + throw new AssertionError("IllegalStateException expected"); + } catch (IllegalStateException expected) { + } + } } diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index ac57d20a438a..f8633565cc86 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -114,6 +114,7 @@ public class SettingsBackupTest { Settings.Global.ANOMALY_CONFIG_VERSION, Settings.Global.APN_DB_UPDATE_CONTENT_URL, Settings.Global.APN_DB_UPDATE_METADATA_URL, + Settings.Global.APPLY_RAMPING_RINGER, Settings.Global.APP_BINDING_CONSTANTS, Settings.Global.APP_IDLE_CONSTANTS, Settings.Global.APP_OPS_CONSTANTS, @@ -269,6 +270,7 @@ public class SettingsBackupTest { Settings.Global.GNSS_SATELLITE_BLACKLIST, Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS, Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, + Settings.Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED, Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, Settings.Global.HDMI_CONTROL_ENABLED, Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, @@ -476,6 +478,7 @@ public class SettingsBackupTest { Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, Settings.Global.GUP_DEV_OPT_IN_APPS, + Settings.Global.GUP_DEV_OPT_OUT_APPS, Settings.Global.GUP_BLACK_LIST, Settings.Global.GPU_DEBUG_LAYER_APP, Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, diff --git a/core/tests/coretests/src/android/text/TextLineTest.java b/core/tests/coretests/src/android/text/TextLineTest.java index 61f976a7308d..2fe882c8f9f8 100644 --- a/core/tests/coretests/src/android/text/TextLineTest.java +++ b/core/tests/coretests/src/android/text/TextLineTest.java @@ -254,6 +254,18 @@ public class TextLineTest { } @Test + public void testMeasure_wordSpacing() { + final TextPaint paint = new TextPaint(); + paint.setTypeface(TYPEFACE); + paint.setTextSize(10.0f); // make 1em = 10px + paint.setWordSpacing(10.0f); + + TextLine tl = getTextLine("I I", paint); + assertMeasurements(tl, 3, false, + new float[]{0.0f, 10.0f, 120.0f, 130.0f}); + } + + @Test public void testHandleRun_ellipsizedReplacementSpan_isSkipped() { final Spannable text = new SpannableStringBuilder("This is a... text"); diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java index 9807f26ad367..95af525c3746 100644 --- a/core/tests/coretests/src/android/view/InsetsStateTest.java +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -29,12 +29,14 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertNotEquals; +import android.graphics.Insets; import android.graphics.Rect; import android.os.Parcel; import android.platform.test.annotations.Presubmit; import android.support.test.filters.FlakyTest; import android.support.test.runner.AndroidJUnit4; import android.util.SparseIntArray; +import android.view.WindowInsets.Type; import org.junit.Test; import org.junit.runner.RunWith; @@ -56,9 +58,12 @@ public class InsetsStateTest { SparseIntArray typeSideMap = new SparseIntArray(); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, DisplayCutout.NO_CUTOUT, typeSideMap); - assertEquals(new Rect(0, 100, 0, 100), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all())); assertEquals(INSET_SIDE_TOP, typeSideMap.get(TYPE_TOP_BAR)); assertEquals(INSET_SIDE_BOTTOM, typeSideMap.get(TYPE_IME)); + assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar())); + assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.ime())); } @Test @@ -70,7 +75,11 @@ public class InsetsStateTest { WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, DisplayCutout.NO_CUTOUT, null); assertEquals(100, insets.getStableInsetBottom()); - assertEquals(new Rect(0, 0, 0, 200), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 0, 0, 100), insets.getMaxInsets(Type.all())); + assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.all())); + assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.sideBars())); + assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.ime())); } @Test @@ -81,7 +90,9 @@ public class InsetsStateTest { mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false, DisplayCutout.NO_CUTOUT, null); - assertEquals(new Rect(0, 100, 20, 0), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar())); + assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.sideBars())); } @Test diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java index 1c2df2cfedb1..1513a1a7d222 100644 --- a/core/tests/coretests/src/android/view/WindowInsetsTest.java +++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java @@ -16,12 +16,19 @@ package android.view; +import static android.view.WindowInsets.Type.ime; +import static android.view.WindowInsets.Type.indexOf; +import static android.view.WindowInsets.Type.sideBars; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.graphics.Insets; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.view.WindowInsets.Builder; +import android.view.WindowInsets.Type; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,13 +40,13 @@ public class WindowInsetsTest { @Test public void systemWindowInsets_afterConsuming_isConsumed() { - assertTrue(new WindowInsets(new Rect(1, 2, 3, 4), null, null, false, false, null) + assertTrue(new WindowInsets(new Rect(1, 2, 3, 4), null, false, false, null) .consumeSystemWindowInsets().isConsumed()); } @Test public void multiNullConstructor_isConsumed() { - assertTrue(new WindowInsets(null, null, null, false, false, null).isConsumed()); + assertTrue(new WindowInsets((Rect) null, null, false, false, null).isConsumed()); } @Test @@ -47,4 +54,12 @@ public class WindowInsetsTest { assertTrue(new WindowInsets((Rect) null).isConsumed()); } + @Test + public void typeMap() { + Builder b = new WindowInsets.Builder(); + b.setInsets(sideBars(), Insets.of(0, 0, 0, 100)); + b.setInsets(ime(), Insets.of(0, 0, 0, 300)); + WindowInsets insets = b.build(); + assertEquals(300, insets.getSystemWindowInsets().bottom); + } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java index 81ec85eb2ea5..82eaf88fb07a 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java @@ -368,6 +368,7 @@ public class TextClassifierTest { assertThat(textLanguage, isTextLanguage("ja")); } + /* DISABLED: b/122467291 @Test public void testSuggestConversationActions_textReplyOnly_maxThree() { if (isTextClassifierDisabled()) return; @@ -395,7 +396,7 @@ public class TextClassifierTest { assertThat(conversationAction, isConversationAction(ConversationActions.TYPE_TEXT_REPLY)); } - } + }*/ @Test public void testSuggestConversationActions_textReplyOnly_noMax() { diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java new file mode 100644 index 000000000000..344f79dcc48e --- /dev/null +++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java @@ -0,0 +1,107 @@ +/* + * 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.textclassifier.logging; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.CONVERSATION_ACTIONS; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_ENTITY_TYPE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_WIDGET_TYPE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_EVENT_TIME; + +import static com.google.common.truth.Truth.assertThat; + +import android.metrics.LogMaker; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.view.textclassifier.ConversationActions; +import android.view.textclassifier.TextClassificationContext; +import android.view.textclassifier.TextClassifierEvent; +import android.view.textclassifier.TextClassifierEventTronLogger; + +import com.android.internal.logging.MetricsLogger; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class TextClassifierEventTronLoggerTest { + private static final String WIDGET_TYPE = "notification"; + private static final String PACKAGE_NAME = "pkg"; + private static final long EVENT_TIME = System.currentTimeMillis(); + + + @Mock + private MetricsLogger mMetricsLogger; + private TextClassifierEventTronLogger mTextClassifierEventTronLogger; + + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mTextClassifierEventTronLogger = new TextClassifierEventTronLogger(mMetricsLogger); + } + + @Test + public void testWriteEvent() { + TextClassificationContext textClassificationContext = + new TextClassificationContext.Builder(PACKAGE_NAME, WIDGET_TYPE) + .build(); + TextClassifierEvent textClassifierEvent = + new TextClassifierEvent.Builder( + TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, + TextClassifierEvent.TYPE_SMART_ACTION) + .setEntityType(ConversationActions.TYPE_CALL_PHONE) + .setEventTime(EVENT_TIME) + .setEventContext(textClassificationContext) + .build(); + + mTextClassifierEventTronLogger.writeEvent(textClassifierEvent); + + ArgumentCaptor<LogMaker> captor = ArgumentCaptor.forClass(LogMaker.class); + Mockito.verify(mMetricsLogger).write(captor.capture()); + LogMaker logMaker = captor.getValue(); + assertThat(logMaker.getCategory()).isEqualTo( + CONVERSATION_ACTIONS); + assertThat(logMaker.getType()).isEqualTo( + ACTION_TEXT_SELECTION_SMART_SHARE); + assertThat(logMaker.getTaggedData(FIELD_SELECTION_ENTITY_TYPE)) + .isEqualTo(ConversationActions.TYPE_CALL_PHONE); + assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME)) + .isEqualTo(EVENT_TIME); + assertThat(logMaker.getPackageName()).isEqualTo(PACKAGE_NAME); + assertThat(logMaker.getTaggedData(FIELD_SELECTION_WIDGET_TYPE)) + .isEqualTo(WIDGET_TYPE); + } + + @Test + public void testWriteEvent_unsupportedCategory() { + TextClassifierEvent textClassifierEvent = + new TextClassifierEvent.Builder( + TextClassifierEvent.CATEGORY_SELECTION, + TextClassifierEvent.TYPE_SMART_ACTION) + .build(); + + mTextClassifierEventTronLogger.writeEvent(textClassifierEvent); + + Mockito.verify(mMetricsLogger, Mockito.never()).write(Mockito.any(LogMaker.class)); + } +} diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java index 218566e8cdf0..d782c0c0308d 100644 --- a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java +++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java @@ -167,7 +167,7 @@ public class ActionBarOverlayLayoutTest { } private WindowInsets insetsWith(Insets content, DisplayCutout cutout) { - return new WindowInsets(content.toRect(), null, null, false, false, cutout); + return new WindowInsets(content.toRect(), null, false, false, cutout); } private ViewGroup createViewGroupWithId(int id) { diff --git a/core/tests/hdmitests/Android.mk b/core/tests/hdmitests/Android.mk index e0d2c09a6f0f..2ca31a6a240a 100644 --- a/core/tests/hdmitests/Android.mk +++ b/core/tests/hdmitests/Android.mk @@ -20,7 +20,7 @@ LOCAL_MODULE_TAGS := tests # Include all test java files LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_STATIC_JAVA_LIBRARIES := android-support-test frameworks-base-testutils +LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules frameworks-base-testutils LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := HdmiCecTests diff --git a/core/tests/hdmitests/AndroidManifest.xml b/core/tests/hdmitests/AndroidManifest.xml index 1460b4168581..f8ed118d2338 100644 --- a/core/tests/hdmitests/AndroidManifest.xml +++ b/core/tests/hdmitests/AndroidManifest.xml @@ -22,7 +22,7 @@ <uses-library android:name="android.test.runner" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="android.hardware.hdmi" android:label="HDMI CEC Tests"/> diff --git a/core/tests/hdmitests/AndroidTest.xml b/core/tests/hdmitests/AndroidTest.xml index 7ef672d344c5..0c8da28cab7c 100644 --- a/core/tests/hdmitests/AndroidTest.xml +++ b/core/tests/hdmitests/AndroidTest.xml @@ -29,6 +29,6 @@ <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="android.hardware.hdmi" /> <option name="hidden-api-checks" value="false"/> - <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/> </test> </configuration>
\ No newline at end of file diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java index 7b76a0819e22..0dd9d0904746 100644 --- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java +++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java @@ -18,15 +18,18 @@ package android.hardware.hdmi; import android.os.Handler; import android.os.test.TestLooper; -import android.support.test.filters.SmallTest; import android.util.Log; -import java.util.List; + +import androidx.test.filters.SmallTest; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.util.List; + /** * Tests for {@link HdmiAudioSystemClient} */ diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index b65bc1d4d9d4..221708b8c94d 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -29,7 +29,6 @@ <permission name="android.permission.DUMP"/> <permission name="android.permission.GET_APP_OPS_STATS"/> <permission name="android.permission.INTERACT_ACROSS_USERS"/> - <permission name="android.permission.MANAGE_ACTIVITY_STACKS"/> <permission name="android.permission.MANAGE_DEBUGGING"/> <permission name="android.permission.MANAGE_SENSOR_PRIVACY"/> <permission name="android.permission.MANAGE_USB"/> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 58b57e5b7efd..fbe613db47da 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -242,6 +242,32 @@ applications that come with the platform <permission name="android.permission.WRITE_SECURE_SETTINGS"/> </privapp-permissions> + <privapp-permissions package="com.android.mainline.networkstack"> + <permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/> + <permission name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"/> + <permission name="android.permission.CONNECTIVITY_INTERNAL"/> + <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/> + <permission name="android.permission.CONTROL_VPN"/> + <permission name="android.permission.LOCAL_MAC_ADDRESS"/> + <permission name="android.permission.MANAGE_IPSEC_TUNNELS"/> + <permission name="android.permission.MANAGE_NETWORK_POLICY"/> + <permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/> + <permission name="android.permission.MANAGE_USB"/> + <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/> + <permission name="android.permission.NETWORK_SETTINGS"/> + <permission name="android.permission.NETWORK_STACK" /> + <permission name="android.permission.NET_TUNNELING"/> + <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/> + <permission name="android.permission.PEERS_MAC_ADDRESS"/> + <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> + <permission name="android.permission.READ_PRECISE_PHONE_STATE"/> + <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> + <permission name="android.permission.READ_WIFI_CREDENTIAL"/> + <permission name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"/> + <permission name="android.permission.TETHER_PRIVILEGED"/> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + </privapp-permissions> + <privapp-permissions package="com.android.server.telecom"> <permission name="android.permission.BIND_CONNECTION_SERVICE"/> <permission name="android.permission.BIND_INCALL_SERVICE"/> @@ -289,7 +315,6 @@ applications that come with the platform <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.LOCAL_MAC_ADDRESS"/> <permission name="android.permission.MANAGE_ACCESSIBILITY"/> - <permission name="android.permission.MANAGE_ACTIVITY_STACKS"/> <permission name="android.permission.MANAGE_DEVICE_ADMINS"/> <permission name="android.permission.MANAGE_USB"/> <permission name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/> diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index 6a4079256268..21531ab54681 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -99,6 +99,46 @@ <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font> </family> + <family name="arbutus-slab"> + <font weight="400" style="normal">ArbutusSlab-Regular.ttf</font> + </family> + + <family name="arvo"> + <font weight="400" style="normal">Arvo-Regular.ttf</font> + <font weight="400" style="italic">Arvo-Italic.ttf</font> + <font weight="700" style="normal">Arvo-Bold.ttf</font> + <font weight="700" style="italic">Arvo-BoldItalic.ttf</font> + </family> + <alias name="arvo-bold" to="arvo" weight="700" /> + + <family name="lato"> + <font weight="400" style="normal">Lato-Regular.ttf</font> + <font weight="400" style="italic">Lato-Italic.ttf</font> + <font weight="700" style="normal">Lato-Bold.ttf</font> + <font weight="700" style="italic">Lato-BoldItalic.ttf</font> + </family> + <alias name="lato-bold" to="lato" weight="700" /> + + <family name="rubik"> + <font weight="400" style="normal">Rubik-Regular.ttf</font> + <font weight="400" style="italic">Rubik-Italic.ttf</font> + <font weight="500" style="normal">Rubik-Medium.ttf</font> + <font weight="500" style="italic">Rubik-MediumItalic.ttf</font> + <font weight="700" style="normal">Rubik-Bold.ttf</font> + <font weight="700" style="italic">Rubik-BoldItalic.ttf</font> + </family> + <alias name="rubik-medium" to="rubik" weight="500" /> + + <family name="source-sans-pro"> + <font weight="400" style="normal">SourceSansPro-Regular.ttf</font> + <font weight="400" style="italic">SourceSansPro-Italic.ttf</font> + <font weight="600" style="normal">SourceSansPro-SemiBold.ttf</font> + <font weight="600" style="italic">SourceSansPro-SemiBoldItalic.ttf</font> + <font weight="700" style="normal">SourceSansPro-Bold.ttf</font> + <font weight="700" style="italic">SourceSansPro-BoldItalic.ttf</font> + </family> + <alias name="source-sans-pro-semi-bold" to="source-sans-pro" weight="600" /> + <!-- fallback fonts --> <family lang="und-Arab" variant="elegant"> <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font> @@ -312,9 +352,8 @@ <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font> </family> <family lang="und-Mymr" variant="elegant"> - <font weight="400" style="normal">NotoSansMyanmar-Regular.otf</font> - <font weight="500" style="normal">NotoSansMyanmar-Medium.otf</font> - <font weight="700" style="normal">NotoSansMyanmar-Bold.otf</font> + <font weight="400" style="normal">NotoSansMyanmar-Regular-ZawDecode.ttf</font> + <font weight="700" style="normal">NotoSansMyanmar-Bold-ZawDecode.ttf</font> <font weight="400" style="normal" fallbackFor="serif">NotoSerifMyanmar-Regular.otf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifMyanmar-Bold.otf</font> </family> diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk index bb8add1187e7..c6c7d3bca724 100644 --- a/data/sounds/AllAudio.mk +++ b/data/sounds/AllAudio.mk @@ -15,227 +15,227 @@ LOCAL_PATH := frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \ - $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \ - $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \ - $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \ - $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \ - $(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \ - $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Barium.ogg:system/media/audio/alarms/Barium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \ - $(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \ - $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \ - $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Scandium.ogg:system/media/audio/alarms/Scandium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \ - $(LOCAL_PATH)/notifications/Aldebaran.ogg:system/media/audio/notifications/Aldebaran.ogg \ - $(LOCAL_PATH)/notifications/Altair.ogg:system/media/audio/notifications/Altair.ogg \ - $(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \ - $(LOCAL_PATH)/notifications/Antares.ogg:system/media/audio/notifications/Antares.ogg \ - $(LOCAL_PATH)/notifications/ogg/Antimony.ogg:system/media/audio/notifications/Antimony.ogg \ - $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Argon.ogg:system/media/audio/notifications/Argon.ogg \ - $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \ - $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \ - $(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:system/media/audio/notifications/Beryllium.ogg \ - $(LOCAL_PATH)/notifications/Betelgeuse.ogg:system/media/audio/notifications/Betelgeuse.ogg \ - $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg \ - $(LOCAL_PATH)/notifications/Canopus.ogg:system/media/audio/notifications/Canopus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \ - $(LOCAL_PATH)/notifications/Castor.ogg:system/media/audio/notifications/Castor.ogg \ - $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:system/media/audio/notifications/Cobalt.ogg \ - $(LOCAL_PATH)/notifications/Cricket.ogg:system/media/audio/notifications/Cricket.ogg \ - $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \ - $(LOCAL_PATH)/notifications/Deneb.ogg:system/media/audio/notifications/Deneb.ogg \ - $(LOCAL_PATH)/notifications/Doink.ogg:system/media/audio/notifications/Doink.ogg \ - $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \ - $(LOCAL_PATH)/notifications/Drip.ogg:system/media/audio/notifications/Drip.ogg \ - $(LOCAL_PATH)/notifications/Electra.ogg:system/media/audio/notifications/Electra.ogg \ - $(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \ - $(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \ - $(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \ - $(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:system/media/audio/notifications/Fluorine.ogg \ - $(LOCAL_PATH)/notifications/Fomalhaut.ogg:system/media/audio/notifications/Fomalhaut.ogg \ - $(LOCAL_PATH)/notifications/ogg/Gallium.ogg:system/media/audio/notifications/Gallium.ogg \ - $(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \ - $(LOCAL_PATH)/notifications/ogg/Helium.ogg:system/media/audio/notifications/Helium.ogg \ - $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \ - $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:system/media/audio/notifications/Iridium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Krypton.ogg:system/media/audio/notifications/Krypton.ogg \ - $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \ - $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \ - $(LOCAL_PATH)/notifications/Merope.ogg:system/media/audio/notifications/Merope.ogg \ - $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \ - $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \ - $(LOCAL_PATH)/notifications/ogg/Palladium.ogg:system/media/audio/notifications/Palladium.ogg \ - $(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:system/media/audio/notifications/Plastic_Pipe.ogg \ - $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \ - $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ - $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \ - $(LOCAL_PATH)/notifications/ogg/Radon.ogg:system/media/audio/notifications/Radon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:system/media/audio/notifications/Rubidium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Selenium.ogg:system/media/audio/notifications/Selenium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \ - $(LOCAL_PATH)/notifications/Sirrah.ogg:system/media/audio/notifications/Sirrah.ogg \ - $(LOCAL_PATH)/notifications/SpaceSeed.ogg:system/media/audio/notifications/SpaceSeed.ogg \ - $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ - $(LOCAL_PATH)/notifications/ogg/Strontium.ogg:system/media/audio/notifications/Strontium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \ - $(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \ - $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \ - $(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \ - $(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \ - $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ - $(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \ - $(LOCAL_PATH)/notifications/ogg/Xenon.ogg:system/media/audio/notifications/Xenon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:system/media/audio/notifications/Zirconium.ogg \ - $(LOCAL_PATH)/notifications/arcturus.ogg:system/media/audio/notifications/arcturus.ogg \ - $(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \ - $(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \ - $(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \ - $(LOCAL_PATH)/notifications/regulus.ogg:system/media/audio/notifications/regulus.ogg \ - $(LOCAL_PATH)/notifications/sirius.ogg:system/media/audio/notifications/sirius.ogg \ - $(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \ - $(LOCAL_PATH)/notifications/vega.ogg:system/media/audio/notifications/vega.ogg \ - $(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:system/media/audio/ringtones/ANDROMEDA.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ - $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:system/media/audio/ringtones/Atria.ogg \ - $(LOCAL_PATH)/ringtones/BOOTES.ogg:system/media/audio/ringtones/BOOTES.ogg \ - $(LOCAL_PATH)/newwavelabs/Backroad.ogg:system/media/audio/ringtones/Backroad.ogg \ - $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \ - $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \ - $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \ - $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \ - $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \ - $(LOCAL_PATH)/newwavelabs/BussaMove.ogg:system/media/audio/ringtones/BussaMove.ogg \ - $(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:system/media/audio/ringtones/CANISMAJOR.ogg \ - $(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:system/media/audio/ringtones/CASSIOPEIA.ogg \ - $(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \ - $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \ - $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \ - $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:system/media/audio/ringtones/CaribbeanIce.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ - $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \ - $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \ - $(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:system/media/audio/ringtones/CrayonRock.ogg \ - $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \ - $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \ - $(LOCAL_PATH)/newwavelabs/DancinFool.ogg:system/media/audio/ringtones/DancinFool.ogg \ - $(LOCAL_PATH)/newwavelabs/Ding.ogg:system/media/audio/ringtones/Ding.ogg \ - $(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:system/media/audio/ringtones/DonMessWivIt.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \ - $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg \ - $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \ - $(LOCAL_PATH)/newwavelabs/Enter_the_Nexus.ogg:system/media/audio/ringtones/Enter_the_Nexus.ogg \ - $(LOCAL_PATH)/ringtones/Eridani.ogg:system/media/audio/ringtones/Eridani.ogg \ - $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \ - $(LOCAL_PATH)/ringtones/FreeFlight.ogg:system/media/audio/ringtones/FreeFlight.ogg \ - $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:system/media/audio/ringtones/FriendlyGhost.ogg \ - $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \ - $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:system/media/audio/ringtones/GameOverGuitar.ogg \ - $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \ - $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \ - $(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \ - $(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:system/media/audio/ringtones/HalfwayHome.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \ - $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:system/media/audio/ringtones/InsertCoin.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \ - $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \ - $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \ - $(LOCAL_PATH)/ringtones/Lyra.ogg:system/media/audio/ringtones/Lyra.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ - $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \ - $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \ - $(LOCAL_PATH)/newwavelabs/Nairobi.ogg:system/media/audio/ringtones/Nairobi.ogg \ - $(LOCAL_PATH)/newwavelabs/Nassau.ogg:system/media/audio/ringtones/Nassau.ogg \ - $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \ - $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \ - $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ - $(LOCAL_PATH)/ringtones/PERSEUS.ogg:system/media/audio/ringtones/PERSEUS.ogg \ - $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \ - $(LOCAL_PATH)/newwavelabs/Playa.ogg:system/media/audio/ringtones/Playa.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:system/media/audio/ringtones/Rasalas.ogg \ - $(LOCAL_PATH)/newwavelabs/Revelation.ogg:system/media/audio/ringtones/Revelation.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \ - $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \ - $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \ - $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \ - $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \ - $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \ - $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:system/media/audio/ringtones/RomancingTheTone.ogg \ - $(LOCAL_PATH)/newwavelabs/Safari.ogg:system/media/audio/ringtones/Safari.ogg \ - $(LOCAL_PATH)/newwavelabs/Savannah.ogg:system/media/audio/ringtones/Savannah.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ - $(LOCAL_PATH)/newwavelabs/Seville.ogg:system/media/audio/ringtones/Seville.ogg \ - $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \ - $(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:system/media/audio/ringtones/SilkyWay.ogg \ - $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:system/media/audio/ringtones/SitarVsSitar.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ - $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:system/media/audio/ringtones/SpringyJalopy.ogg \ - $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \ - $(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \ - $(LOCAL_PATH)/ringtones/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \ - $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \ - $(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:system/media/audio/ringtones/Thunderfoot.ogg \ - $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \ - $(LOCAL_PATH)/ringtones/URSAMINOR.ogg:system/media/audio/ringtones/URSAMINOR.ogg \ - $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \ - $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \ - $(LOCAL_PATH)/ringtones/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg \ - $(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg \ - $(LOCAL_PATH)/ringtones/hydra.ogg:system/media/audio/ringtones/hydra.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/ogg/VideoStop_48k.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \ - $(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:system/media/audio/ui/ChargingStarted.ogg \ - $(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:system/media/audio/ui/InCallNotification.ogg \ - $(LOCAL_PATH)/effects/ogg/NFCFailure.ogg:system/media/audio/ui/NFCFailure.ogg \ - $(LOCAL_PATH)/effects/ogg/NFCInitiated.ogg:system/media/audio/ui/NFCInitiated.ogg \ - $(LOCAL_PATH)/effects/ogg/NFCSuccess.ogg:system/media/audio/ui/NFCSuccess.ogg \ - $(LOCAL_PATH)/effects/ogg/NFCTransferComplete.ogg:system/media/audio/ui/NFCTransferComplete.ogg \ - $(LOCAL_PATH)/effects/ogg/NFCTransferInitiated.ogg:system/media/audio/ui/NFCTransferInitiated.ogg \ + $(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \ + $(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \ + $(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \ + $(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \ + $(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \ + $(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \ + $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Barium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Barium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Cesium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Fermium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Hassium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \ + $(LOCAL_PATH)/alarms/ogg/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neptunium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Nobelium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \ + $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \ + $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Plutonium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Promethium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Scandium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Scandium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \ + $(LOCAL_PATH)/notifications/Aldebaran.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Aldebaran.ogg \ + $(LOCAL_PATH)/notifications/Altair.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Altair.ogg \ + $(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \ + $(LOCAL_PATH)/notifications/Antares.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Antares.ogg \ + $(LOCAL_PATH)/notifications/ogg/Antimony.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Antimony.ogg \ + $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Argon.ogg \ + $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \ + $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Bellatrix.ogg \ + $(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beryllium.ogg \ + $(LOCAL_PATH)/notifications/Betelgeuse.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Betelgeuse.ogg \ + $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg \ + $(LOCAL_PATH)/notifications/Canopus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Canopus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \ + $(LOCAL_PATH)/notifications/Castor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Castor.ogg \ + $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Cobalt.ogg \ + $(LOCAL_PATH)/notifications/Cricket.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Cricket.ogg \ + $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \ + $(LOCAL_PATH)/notifications/Deneb.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Deneb.ogg \ + $(LOCAL_PATH)/notifications/Doink.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Doink.ogg \ + $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \ + $(LOCAL_PATH)/notifications/Drip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Drip.ogg \ + $(LOCAL_PATH)/notifications/Electra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Electra.ogg \ + $(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \ + $(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \ + $(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \ + $(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Fluorine.ogg \ + $(LOCAL_PATH)/notifications/Fomalhaut.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Fomalhaut.ogg \ + $(LOCAL_PATH)/notifications/ogg/Gallium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Gallium.ogg \ + $(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \ + $(LOCAL_PATH)/notifications/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Helium.ogg \ + $(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \ + $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Iridium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Krypton.ogg \ + $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \ + $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Lalande.ogg \ + $(LOCAL_PATH)/notifications/Merope.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Merope.ogg \ + $(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \ + $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \ + $(LOCAL_PATH)/notifications/ogg/Palladium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Palladium.ogg \ + $(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Plastic_Pipe.ogg \ + $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \ + $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \ + $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Proxima.ogg \ + $(LOCAL_PATH)/notifications/ogg/Radon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Radon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Rubidium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Selenium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Selenium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \ + $(LOCAL_PATH)/notifications/Sirrah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Sirrah.ogg \ + $(LOCAL_PATH)/notifications/SpaceSeed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/SpaceSeed.ogg \ + $(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \ + $(LOCAL_PATH)/notifications/ogg/Strontium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Strontium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Syrma.ogg \ + $(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \ + $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Thallium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Thallium.ogg \ + $(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \ + $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Upsilon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \ + $(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \ + $(LOCAL_PATH)/notifications/ogg/Xenon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Xenon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Zirconium.ogg \ + $(LOCAL_PATH)/notifications/arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/arcturus.ogg \ + $(LOCAL_PATH)/notifications/moonbeam.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/moonbeam.ogg \ + $(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \ + $(LOCAL_PATH)/notifications/pizzicato.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pizzicato.ogg \ + $(LOCAL_PATH)/notifications/regulus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/regulus.ogg \ + $(LOCAL_PATH)/notifications/sirius.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/sirius.ogg \ + $(LOCAL_PATH)/notifications/tweeters.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/tweeters.ogg \ + $(LOCAL_PATH)/notifications/vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/vega.ogg \ + $(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ANDROMEDA.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \ + $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Atria.ogg \ + $(LOCAL_PATH)/ringtones/BOOTES.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BOOTES.ogg \ + $(LOCAL_PATH)/newwavelabs/Backroad.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Backroad.ogg \ + $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BeatPlucker.ogg \ + $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BentleyDubs.ogg \ + $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Big_Easy.ogg \ + $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \ + $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Bollywood.ogg \ + $(LOCAL_PATH)/newwavelabs/BussaMove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BussaMove.ogg \ + $(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CANISMAJOR.ogg \ + $(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CASSIOPEIA.ogg \ + $(LOCAL_PATH)/newwavelabs/Cairo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cairo.ogg \ + $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Calypso_Steel.ogg \ + $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CanisMajor.ogg \ + $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CaribbeanIce.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \ + $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Champagne_Edition.ogg \ + $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Club_Cubano.ogg \ + $(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrayonRock.ogg \ + $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrazyDream.ogg \ + $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \ + $(LOCAL_PATH)/newwavelabs/DancinFool.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DancinFool.ogg \ + $(LOCAL_PATH)/newwavelabs/Ding.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ding.ogg \ + $(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DonMessWivIt.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \ + $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DreamTheme.ogg \ + $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eastern_Sky.ogg \ + $(LOCAL_PATH)/newwavelabs/Enter_the_Nexus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Enter_the_Nexus.ogg \ + $(LOCAL_PATH)/ringtones/Eridani.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eridani.ogg \ + $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \ + $(LOCAL_PATH)/ringtones/FreeFlight.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FreeFlight.ogg \ + $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FriendlyGhost.ogg \ + $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Funk_Yall.ogg \ + $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/GameOverGuitar.ogg \ + $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Gimme_Mo_Town.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \ + $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Glacial_Groove.ogg \ + $(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \ + $(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/HalfwayHome.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \ + $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/InsertCoin.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Kuma.ogg \ + $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \ + $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \ + $(LOCAL_PATH)/ringtones/Lyra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Lyra.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \ + $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \ + $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \ + $(LOCAL_PATH)/newwavelabs/Nairobi.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Nairobi.ogg \ + $(LOCAL_PATH)/newwavelabs/Nassau.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Nassau.ogg \ + $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/NewPlayer.ogg \ + $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/No_Limits.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises1.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises1.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises2.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises2.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises3.ogg \ + $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \ + $(LOCAL_PATH)/ringtones/PERSEUS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/PERSEUS.ogg \ + $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Paradise_Island.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Perseus.ogg \ + $(LOCAL_PATH)/newwavelabs/Playa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Playa.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rasalas.ogg \ + $(LOCAL_PATH)/newwavelabs/Revelation.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Revelation.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \ + $(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \ + $(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \ + $(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \ + $(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \ + $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Road_Trip.ogg \ + $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/RomancingTheTone.ogg \ + $(LOCAL_PATH)/newwavelabs/Safari.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Safari.ogg \ + $(LOCAL_PATH)/newwavelabs/Savannah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Savannah.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \ + $(LOCAL_PATH)/newwavelabs/Seville.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Seville.ogg \ + $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Shes_All_That.ogg \ + $(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SilkyWay.ogg \ + $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SitarVsSitar.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \ + $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SpringyJalopy.ogg \ + $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Steppin_Out.ogg \ + $(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \ + $(LOCAL_PATH)/ringtones/Testudo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Testudo.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \ + $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Third_Eye.ogg \ + $(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Thunderfoot.ogg \ + $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \ + $(LOCAL_PATH)/ringtones/URSAMINOR.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/URSAMINOR.ogg \ + $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/UrsaMinor.ogg \ + $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/VeryAlarmed.ogg \ + $(LOCAL_PATH)/ringtones/Vespa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Vespa.ogg \ + $(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg \ + $(LOCAL_PATH)/ringtones/hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/hydra.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/ogg/VideoStop_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/WirelessChargingStarted.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/ChargingStarted.ogg \ + $(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/InCallNotification.ogg \ + $(LOCAL_PATH)/effects/ogg/NFCFailure.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCFailure.ogg \ + $(LOCAL_PATH)/effects/ogg/NFCInitiated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCInitiated.ogg \ + $(LOCAL_PATH)/effects/ogg/NFCSuccess.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCSuccess.ogg \ + $(LOCAL_PATH)/effects/ogg/NFCTransferComplete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCTransferComplete.ogg \ + $(LOCAL_PATH)/effects/ogg/NFCTransferInitiated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCTransferInitiated.ogg \ diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk index 72aa7fe1c38a..699dbd68048d 100644 --- a/data/sounds/AudioPackage10.mk +++ b/data/sounds/AudioPackage10.mk @@ -8,63 +8,63 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \ - $(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \ - $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \ - $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoStop_48k.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/material/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/material/ogg/LowBattery_48k.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:system/media/audio/ui/ChargingStarted.ogg \ - $(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:system/media/audio/ui/InCallNotification.ogg \ - $(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \ - $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \ - $(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \ - $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \ - $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \ - $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ - $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \ - $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ - $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \ - $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \ - $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:system/media/audio/ringtones/Atria.ogg \ - $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:system/media/audio/ringtones/Rasalas.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg + $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \ + $(LOCAL_PATH)/alarms/ogg/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \ + $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoRecord_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoStop_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/material/ogg/camera_click_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/material/ogg/LowBattery_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/ChargingStarted.ogg \ + $(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/InCallNotification.ogg \ + $(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/WirelessChargingStarted.ogg \ + $(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \ + $(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \ + $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \ + $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \ + $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \ + $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \ + $(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \ + $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Syrma.ogg \ + $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Atria.ogg \ + $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Kuma.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rasalas.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk index 665ce521690e..99dfd0a6d455 100644 --- a/data/sounds/AudioPackage11.mk +++ b/data/sounds/AudioPackage11.mk @@ -8,63 +8,63 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \ - $(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \ - $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \ - $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoStop_48k.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/material/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/material/ogg/LowBattery_48k.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:system/media/audio/ui/ChargingStarted.ogg \. - $(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:system/media/audio/ui/InCallNotification.ogg \ - $(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \ - $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \ - $(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \ - $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \ - $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \ - $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ - $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \ - $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ - $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \ - $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Tejat_proc48.ogg:system/media/audio/notifications/Tejat.ogg \ - $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:system/media/audio/ringtones/Atria.ogg \ - $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:system/media/audio/ringtones/Rasalas.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg + $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \ + $(LOCAL_PATH)/alarms/ogg/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \ + $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoRecord_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoStop_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/material/ogg/camera_click_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/material/ogg/LowBattery_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/ChargingStarted.ogg \. + $(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/InCallNotification.ogg \ + $(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/WirelessChargingStarted.ogg \ + $(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \ + $(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \ + $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \ + $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \ + $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \ + $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \ + $(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \ + $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Syrma.ogg \ + $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat_proc48.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Atria.ogg \ + $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Kuma.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rasalas.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg diff --git a/data/sounds/AudioPackage12.mk b/data/sounds/AudioPackage12.mk index 44a8f9e34cd3..6159a89e8489 100644 --- a/data/sounds/AudioPackage12.mk +++ b/data/sounds/AudioPackage12.mk @@ -16,15 +16,15 @@ EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete Keypre MATERIAL_EFFECT_FILES := camera_click VideoRecord LowBattery WirelessChargingStarted VideoStop PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\ - $(LOCAL_PATH)/alarms/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg) + $(LOCAL_PATH)/alarms/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\ - $(LOCAL_PATH)/notifications/ogg/$(fn).ogg:system/media/audio/notifications/$(fn).ogg) + $(LOCAL_PATH)/notifications/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\ - $(LOCAL_PATH)/ringtones/ogg/$(fn).ogg:system/media/audio/ringtones/$(fn).ogg) + $(LOCAL_PATH)/ringtones/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\ - $(LOCAL_PATH)/effects/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\ - $(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) diff --git a/data/sounds/AudioPackage12_48.mk b/data/sounds/AudioPackage12_48.mk index 09fab041505e..2899cd160d24 100644 --- a/data/sounds/AudioPackage12_48.mk +++ b/data/sounds/AudioPackage12_48.mk @@ -17,21 +17,21 @@ MATERIAL_EFFECT_FILES := camera_click VideoRecord LowBattery WirelessChargingSta # Alarms not yet available in 48 kHz PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\ - $(LOCAL_PATH)/alarms/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg) + $(LOCAL_PATH)/alarms/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\ - $(LOCAL_PATH)/notifications/ogg/$(fn)_48k.ogg:system/media/audio/notifications/$(fn).ogg) + $(LOCAL_PATH)/notifications/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\ - $(LOCAL_PATH)/ringtones/ogg/$(fn)_48k.ogg:system/media/audio/ringtones/$(fn).ogg) + $(LOCAL_PATH)/ringtones/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\ - $(LOCAL_PATH)/effects/ogg/$(fn)_48k.ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\ - $(LOCAL_PATH)/effects/material/ogg/$(fn)_48k.ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) # no gold-plated version yet PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg diff --git a/data/sounds/AudioPackage13.mk b/data/sounds/AudioPackage13.mk index de4ee047986d..9423c0b9ba5b 100644 --- a/data/sounds/AudioPackage13.mk +++ b/data/sounds/AudioPackage13.mk @@ -17,15 +17,15 @@ EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete Keypre MATERIAL_EFFECT_FILES := camera_click VideoRecord WirelessChargingStarted LowBattery VideoStop PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\ - $(LOCAL_PATH)/alarms/material/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg) + $(LOCAL_PATH)/alarms/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\ - $(LOCAL_PATH)/notifications/material/ogg/$(fn).ogg:system/media/audio/notifications/$(fn).ogg) + $(LOCAL_PATH)/notifications/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\ - $(LOCAL_PATH)/ringtones/material/ogg/$(fn).ogg:system/media/audio/ringtones/$(fn).ogg) + $(LOCAL_PATH)/ringtones/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\ - $(LOCAL_PATH)/effects/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\ - $(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) diff --git a/data/sounds/AudioPackage13_48.mk b/data/sounds/AudioPackage13_48.mk index 889d58172290..806c4e26152b 100644 --- a/data/sounds/AudioPackage13_48.mk +++ b/data/sounds/AudioPackage13_48.mk @@ -17,21 +17,21 @@ EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete Keypre MATERIAL_EFFECT_FILES := camera_click VideoRecord WirelessChargingStarted LowBattery VideoStop PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\ - $(LOCAL_PATH)/alarms/material/ogg/$(fn)_48k.ogg:system/media/audio/alarms/$(fn).ogg) + $(LOCAL_PATH)/alarms/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\ - $(LOCAL_PATH)/notifications/material/ogg/$(fn)_48k.ogg:system/media/audio/notifications/$(fn).ogg) + $(LOCAL_PATH)/notifications/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\ - $(LOCAL_PATH)/ringtones/material/ogg/$(fn)_48k.ogg:system/media/audio/ringtones/$(fn).ogg) + $(LOCAL_PATH)/ringtones/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\ - $(LOCAL_PATH)/effects/ogg/$(fn)_48k.ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\ - $(LOCAL_PATH)/effects/material/ogg/$(fn)_48k.ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) # no gold-plated version yet PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg diff --git a/data/sounds/AudioPackage14.mk b/data/sounds/AudioPackage14.mk index c903a2b0eb97..3d161aabbf95 100644 --- a/data/sounds/AudioPackage14.mk +++ b/data/sounds/AudioPackage14.mk @@ -18,15 +18,15 @@ EFFECT_FILES := Effect_Tick KeypressReturn KeypressInvalid KeypressDelete Keypre MATERIAL_EFFECT_FILES := camera_click VideoRecord WirelessChargingStarted LowBattery VideoStop PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\ - $(LOCAL_PATH)/alarms/material/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg) + $(LOCAL_PATH)/alarms/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\ - $(LOCAL_PATH)/notifications/material/ogg/$(fn).ogg:system/media/audio/notifications/$(fn).ogg) + $(LOCAL_PATH)/notifications/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\ - $(LOCAL_PATH)/ringtones/material/ogg/$(fn).ogg:system/media/audio/ringtones/$(fn).ogg) + $(LOCAL_PATH)/ringtones/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\ - $(LOCAL_PATH)/effects/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\ - $(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg) + $(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg) diff --git a/data/sounds/AudioPackage2.mk b/data/sounds/AudioPackage2.mk index 40319c4505ec..bc4e8fbe811a 100644 --- a/data/sounds/AudioPackage2.mk +++ b/data/sounds/AudioPackage2.mk @@ -10,98 +10,98 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \ - $(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \ - $(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \ - $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \ - $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \ - $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \ - $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \ - $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \ - $(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \ - $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \ - $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \ - $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \ - $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \ - $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \ - $(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \ - $(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \ - $(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \ - $(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \ - $(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \ - $(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \ - $(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \ - $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \ - $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg + $(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \ + $(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \ + $(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \ + $(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \ + $(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \ + $(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \ + $(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \ + $(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \ + $(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \ + $(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \ + $(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \ + $(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \ + $(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \ + $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \ + $(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \ + $(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \ + $(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \ + $(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/notifications/moonbeam.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/moonbeam.ogg \ + $(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \ + $(LOCAL_PATH)/notifications/pizzicato.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pizzicato.ogg \ + $(LOCAL_PATH)/notifications/tweeters.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/tweeters.ogg \ + $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BeatPlucker.ogg \ + $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg ifneq ($(MINIMAL_NEWWAVELABS),true) PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \ - $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \ - $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:system/media/audio/ringtones/CaribbeanIce.ogg \ - $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \ - $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \ - $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:system/media/audio/ringtones/FriendlyGhost.ogg \ - $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:system/media/audio/ringtones/GameOverGuitar.ogg \ - $(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \ - $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:system/media/audio/ringtones/InsertCoin.ogg \ - $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \ - $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \ - $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \ - $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \ - $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \ - $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \ - $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:system/media/audio/ringtones/RomancingTheTone.ogg \ - $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:system/media/audio/ringtones/SitarVsSitar.ogg \ - $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:system/media/audio/ringtones/SpringyJalopy.ogg \ - $(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \ - $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \ - $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \ - $(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \ - $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \ - $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \ - $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \ - $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \ - $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \ - $(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \ - $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \ - $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg \ - $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \ - $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \ - $(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \ - $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \ - $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \ - $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \ - $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \ - $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \ - $(LOCAL_PATH)/newwavelabs/Savannah.ogg:system/media/audio/ringtones/Savannah.ogg \ - $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \ - $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \ - $(LOCAL_PATH)/newwavelabs/Seville.ogg:system/media/audio/ringtones/Seville.ogg \ - $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \ - $(LOCAL_PATH)/newwavelabs/Revelation.ogg:system/media/audio/ringtones/Revelation.ogg \ - $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \ - $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \ - $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \ - $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \ - $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \ - $(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:system/media/audio/ringtones/Thunderfoot.ogg + $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BentleyDubs.ogg \ + $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \ + $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CaribbeanIce.ogg \ + $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \ + $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \ + $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FriendlyGhost.ogg \ + $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/GameOverGuitar.ogg \ + $(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \ + $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/InsertCoin.ogg \ + $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \ + $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \ + $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \ + $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \ + $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/NewPlayer.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises1.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises1.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises2.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises2.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises3.ogg \ + $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \ + $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/RomancingTheTone.ogg \ + $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SitarVsSitar.ogg \ + $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SpringyJalopy.ogg \ + $(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \ + $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \ + $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/VeryAlarmed.ogg \ + $(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg \ + $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \ + $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \ + $(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \ + $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \ + $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \ + $(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \ + $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrazyDream.ogg \ + $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DreamTheme.ogg \ + $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Big_Easy.ogg \ + $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Bollywood.ogg \ + $(LOCAL_PATH)/newwavelabs/Cairo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cairo.ogg \ + $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Calypso_Steel.ogg \ + $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Champagne_Edition.ogg \ + $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Club_Cubano.ogg \ + $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eastern_Sky.ogg \ + $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Funk_Yall.ogg \ + $(LOCAL_PATH)/newwavelabs/Savannah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Savannah.ogg \ + $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Gimme_Mo_Town.ogg \ + $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Glacial_Groove.ogg \ + $(LOCAL_PATH)/newwavelabs/Seville.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Seville.ogg \ + $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/No_Limits.ogg \ + $(LOCAL_PATH)/newwavelabs/Revelation.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Revelation.ogg \ + $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Paradise_Island.ogg \ + $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Road_Trip.ogg \ + $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Shes_All_That.ogg \ + $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Steppin_Out.ogg \ + $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Third_Eye.ogg \ + $(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Thunderfoot.ogg endif diff --git a/data/sounds/AudioPackage3.mk b/data/sounds/AudioPackage3.mk index a05de723c8f1..a98fb74a0f2a 100644 --- a/data/sounds/AudioPackage3.mk +++ b/data/sounds/AudioPackage3.mk @@ -10,94 +10,94 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \ - $(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \ - $(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \ - $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \ - $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \ - $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \ - $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \ - $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \ - $(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \ - $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \ - $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \ - $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \ - $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \ - $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \ - $(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \ - $(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \ - $(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \ - $(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \ - $(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \ - $(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \ - $(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \ - $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \ - $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg + $(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \ + $(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \ + $(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \ + $(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \ + $(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \ + $(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \ + $(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \ + $(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \ + $(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \ + $(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \ + $(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \ + $(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \ + $(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \ + $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \ + $(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \ + $(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \ + $(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \ + $(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/notifications/moonbeam.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/moonbeam.ogg \ + $(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \ + $(LOCAL_PATH)/notifications/pizzicato.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pizzicato.ogg \ + $(LOCAL_PATH)/notifications/tweeters.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/tweeters.ogg \ + $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BeatPlucker.ogg \ + $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg ifneq ($(MINIMAL_NEWWAVELABS),true) PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \ - $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \ - $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \ - $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \ - $(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \ - $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \ - $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \ - $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \ - $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \ - $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \ - $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \ - $(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \ - $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \ - $(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \ - $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \ - $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \ - $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \ - $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \ - $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \ - $(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \ - $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \ - $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \ - $(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \ - $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \ - $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \ - $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \ - $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \ - $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \ - $(LOCAL_PATH)/newwavelabs/Savannah.ogg:system/media/audio/ringtones/Savannah.ogg \ - $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \ - $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \ - $(LOCAL_PATH)/newwavelabs/Seville.ogg:system/media/audio/ringtones/Seville.ogg \ - $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \ - $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \ - $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \ - $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \ - $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \ - $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \ - $(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:system/media/audio/ringtones/Thunderfoot.ogg \ - $(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:system/media/audio/ringtones/HalfwayHome.ogg \ - $(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:system/media/audio/ringtones/CrayonRock.ogg \ - $(LOCAL_PATH)/newwavelabs/DancinFool.ogg:system/media/audio/ringtones/DancinFool.ogg \ - $(LOCAL_PATH)/newwavelabs/BussaMove.ogg:system/media/audio/ringtones/BussaMove.ogg \ - $(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:system/media/audio/ringtones/DonMessWivIt.ogg \ - $(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:system/media/audio/ringtones/SilkyWay.ogg \ - $(LOCAL_PATH)/newwavelabs/Playa.ogg:system/media/audio/ringtones/Playa.ogg + $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BentleyDubs.ogg \ + $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \ + $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \ + $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \ + $(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \ + $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \ + $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \ + $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \ + $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \ + $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/NewPlayer.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises1.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises1.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises2.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises2.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises3.ogg \ + $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \ + $(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \ + $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \ + $(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg \ + $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \ + $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \ + $(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \ + $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \ + $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \ + $(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \ + $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Big_Easy.ogg \ + $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Bollywood.ogg \ + $(LOCAL_PATH)/newwavelabs/Cairo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cairo.ogg \ + $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Calypso_Steel.ogg \ + $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Champagne_Edition.ogg \ + $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Club_Cubano.ogg \ + $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eastern_Sky.ogg \ + $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Funk_Yall.ogg \ + $(LOCAL_PATH)/newwavelabs/Savannah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Savannah.ogg \ + $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Gimme_Mo_Town.ogg \ + $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Glacial_Groove.ogg \ + $(LOCAL_PATH)/newwavelabs/Seville.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Seville.ogg \ + $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/No_Limits.ogg \ + $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Paradise_Island.ogg \ + $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Road_Trip.ogg \ + $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Shes_All_That.ogg \ + $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Steppin_Out.ogg \ + $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Third_Eye.ogg \ + $(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Thunderfoot.ogg \ + $(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/HalfwayHome.ogg \ + $(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrayonRock.ogg \ + $(LOCAL_PATH)/newwavelabs/DancinFool.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DancinFool.ogg \ + $(LOCAL_PATH)/newwavelabs/BussaMove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BussaMove.ogg \ + $(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DonMessWivIt.ogg \ + $(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SilkyWay.ogg \ + $(LOCAL_PATH)/newwavelabs/Playa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Playa.ogg endif diff --git a/data/sounds/AudioPackage4.mk b/data/sounds/AudioPackage4.mk index d376a2d91f6c..54c3c025d978 100644 --- a/data/sounds/AudioPackage4.mk +++ b/data/sounds/AudioPackage4.mk @@ -10,98 +10,98 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \ - $(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \ - $(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \ - $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \ - $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \ - $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \ - $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \ - $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \ - $(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \ - $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \ - $(LOCAL_PATH)/notifications/Cricket.ogg:system/media/audio/notifications/Cricket.ogg \ - $(LOCAL_PATH)/notifications/Doink.ogg:system/media/audio/notifications/Doink.ogg \ - $(LOCAL_PATH)/notifications/Drip.ogg:system/media/audio/notifications/Drip.ogg \ - $(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \ - $(LOCAL_PATH)/notifications/SpaceSeed.ogg:system/media/audio/notifications/SpaceSeed.ogg \ - $(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \ - $(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \ - $(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \ - $(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \ - $(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \ - $(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:system/media/audio/notifications/Plastic_Pipe.ogg \ - $(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \ - $(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \ - $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \ - $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \ - $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \ - $(LOCAL_PATH)/ringtones/FreeFlight.ogg:system/media/audio/ringtones/FreeFlight.ogg \ - $(LOCAL_PATH)/newwavelabs/Backroad.ogg:system/media/audio/ringtones/Backroad.ogg \ - $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg + $(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \ + $(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \ + $(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \ + $(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \ + $(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \ + $(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \ + $(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \ + $(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \ + $(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \ + $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \ + $(LOCAL_PATH)/notifications/Cricket.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Cricket.ogg \ + $(LOCAL_PATH)/notifications/Doink.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Doink.ogg \ + $(LOCAL_PATH)/notifications/Drip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Drip.ogg \ + $(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \ + $(LOCAL_PATH)/notifications/SpaceSeed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/SpaceSeed.ogg \ + $(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \ + $(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \ + $(LOCAL_PATH)/notifications/moonbeam.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/moonbeam.ogg \ + $(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \ + $(LOCAL_PATH)/notifications/pizzicato.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pizzicato.ogg \ + $(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Plastic_Pipe.ogg \ + $(LOCAL_PATH)/notifications/tweeters.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/tweeters.ogg \ + $(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \ + $(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \ + $(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \ + $(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \ + $(LOCAL_PATH)/ringtones/FreeFlight.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FreeFlight.ogg \ + $(LOCAL_PATH)/newwavelabs/Backroad.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Backroad.ogg \ + $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg ifneq ($(MINIMAL_NEWWAVELABS),true) PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \ - $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \ - $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \ - $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \ - $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \ - $(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \ - $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \ - $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \ - $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \ - $(LOCAL_PATH)/newwavelabs/BussaMove.ogg:system/media/audio/ringtones/BussaMove.ogg \ - $(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \ - $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \ - $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \ - $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \ - $(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:system/media/audio/ringtones/CrayonRock.ogg \ - $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \ - $(LOCAL_PATH)/newwavelabs/DancinFool.ogg:system/media/audio/ringtones/DancinFool.ogg \ - $(LOCAL_PATH)/newwavelabs/Ding.ogg:system/media/audio/ringtones/Ding.ogg \ - $(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:system/media/audio/ringtones/DonMessWivIt.ogg \ - $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \ - $(LOCAL_PATH)/newwavelabs/Enter_the_Nexus.ogg:system/media/audio/ringtones/Enter_the_Nexus.ogg \ - $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \ - $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \ - $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \ - $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \ - $(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \ - $(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:system/media/audio/ringtones/HalfwayHome.ogg \ - $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \ - $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \ - $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \ - $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \ - $(LOCAL_PATH)/newwavelabs/Nairobi.ogg:system/media/audio/ringtones/Nairobi.ogg \ - $(LOCAL_PATH)/newwavelabs/Nassau.ogg:system/media/audio/ringtones/Nassau.ogg \ - $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \ - $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \ - $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \ - $(LOCAL_PATH)/newwavelabs/Playa.ogg:system/media/audio/ringtones/Playa.ogg \ - $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \ - $(LOCAL_PATH)/newwavelabs/Safari.ogg:system/media/audio/ringtones/Safari.ogg \ - $(LOCAL_PATH)/newwavelabs/Seville.ogg:system/media/audio/ringtones/Seville.ogg \ - $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \ - $(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:system/media/audio/ringtones/SilkyWay.ogg \ - $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \ - $(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \ - $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \ - $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \ - $(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg + $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \ + $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \ + $(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \ + $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \ + $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \ + $(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \ + $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Big_Easy.ogg \ + $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \ + $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Bollywood.ogg \ + $(LOCAL_PATH)/newwavelabs/BussaMove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BussaMove.ogg \ + $(LOCAL_PATH)/newwavelabs/Cairo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cairo.ogg \ + $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Calypso_Steel.ogg \ + $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Champagne_Edition.ogg \ + $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Club_Cubano.ogg \ + $(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrayonRock.ogg \ + $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \ + $(LOCAL_PATH)/newwavelabs/DancinFool.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DancinFool.ogg \ + $(LOCAL_PATH)/newwavelabs/Ding.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ding.ogg \ + $(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DonMessWivIt.ogg \ + $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eastern_Sky.ogg \ + $(LOCAL_PATH)/newwavelabs/Enter_the_Nexus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Enter_the_Nexus.ogg \ + $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \ + $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Funk_Yall.ogg \ + $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Gimme_Mo_Town.ogg \ + $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Glacial_Groove.ogg \ + $(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \ + $(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/HalfwayHome.ogg \ + $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \ + $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \ + $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \ + $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \ + $(LOCAL_PATH)/newwavelabs/Nairobi.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Nairobi.ogg \ + $(LOCAL_PATH)/newwavelabs/Nassau.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Nassau.ogg \ + $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/No_Limits.ogg \ + $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \ + $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Paradise_Island.ogg \ + $(LOCAL_PATH)/newwavelabs/Playa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Playa.ogg \ + $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Road_Trip.ogg \ + $(LOCAL_PATH)/newwavelabs/Safari.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Safari.ogg \ + $(LOCAL_PATH)/newwavelabs/Seville.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Seville.ogg \ + $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Shes_All_That.ogg \ + $(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SilkyWay.ogg \ + $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Steppin_Out.ogg \ + $(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \ + $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Third_Eye.ogg \ + $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \ + $(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg endif diff --git a/data/sounds/AudioPackage5.mk b/data/sounds/AudioPackage5.mk index 72384c8b9146..8a03a2e1eb1d 100644 --- a/data/sounds/AudioPackage5.mk +++ b/data/sounds/AudioPackage5.mk @@ -8,69 +8,69 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \ - $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \ - $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \ - $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \ - $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \ - $(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/notifications/Aldebaran.ogg:system/media/audio/notifications/Aldebaran.ogg \ - $(LOCAL_PATH)/notifications/Altair.ogg:system/media/audio/notifications/Altair.ogg \ - $(LOCAL_PATH)/notifications/Antares.ogg:system/media/audio/notifications/Antares.ogg \ - $(LOCAL_PATH)/notifications/arcturus.ogg:system/media/audio/notifications/arcturus.ogg \ - $(LOCAL_PATH)/notifications/Betelgeuse.ogg:system/media/audio/notifications/Betelgeuse.ogg \ - $(LOCAL_PATH)/notifications/Canopus.ogg:system/media/audio/notifications/Canopus.ogg \ - $(LOCAL_PATH)/notifications/Capella.ogg:system/media/audio/notifications/Capella.ogg \ - $(LOCAL_PATH)/notifications/Castor.ogg:system/media/audio/notifications/Castor.ogg \ - $(LOCAL_PATH)/notifications/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ - $(LOCAL_PATH)/notifications/Deneb.ogg:system/media/audio/notifications/Deneb.ogg \ - $(LOCAL_PATH)/notifications/Electra.ogg:system/media/audio/notifications/Electra.ogg \ - $(LOCAL_PATH)/notifications/Fomalhaut.ogg:system/media/audio/notifications/Fomalhaut.ogg \ - $(LOCAL_PATH)/notifications/Merope.ogg:system/media/audio/notifications/Merope.ogg \ - $(LOCAL_PATH)/notifications/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \ - $(LOCAL_PATH)/notifications/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ - $(LOCAL_PATH)/notifications/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ - $(LOCAL_PATH)/notifications/regulus.ogg:system/media/audio/notifications/regulus.ogg \ - $(LOCAL_PATH)/notifications/sirius.ogg:system/media/audio/notifications/sirius.ogg \ - $(LOCAL_PATH)/notifications/Sirrah.ogg:system/media/audio/notifications/Sirrah.ogg \ - $(LOCAL_PATH)/notifications/vega.ogg:system/media/audio/notifications/vega.ogg \ - $(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:system/media/audio/ringtones/ANDROMEDA.ogg \ - $(LOCAL_PATH)/ringtones/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ - $(LOCAL_PATH)/ringtones/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ - $(LOCAL_PATH)/ringtones/BOOTES.ogg:system/media/audio/ringtones/BOOTES.ogg \ - $(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:system/media/audio/ringtones/CANISMAJOR.ogg \ - $(LOCAL_PATH)/ringtones/Carina.ogg:system/media/audio/ringtones/Carina.ogg \ - $(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:system/media/audio/ringtones/CASSIOPEIA.ogg \ - $(LOCAL_PATH)/ringtones/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ - $(LOCAL_PATH)/ringtones/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \ - $(LOCAL_PATH)/ringtones/Draco.ogg:system/media/audio/ringtones/Draco.ogg \ - $(LOCAL_PATH)/ringtones/Eridani.ogg:system/media/audio/ringtones/Eridani.ogg \ - $(LOCAL_PATH)/ringtones/hydra.ogg:system/media/audio/ringtones/hydra.ogg \ - $(LOCAL_PATH)/ringtones/Lyra.ogg:system/media/audio/ringtones/Lyra.ogg \ - $(LOCAL_PATH)/ringtones/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ - $(LOCAL_PATH)/ringtones/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ - $(LOCAL_PATH)/ringtones/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ - $(LOCAL_PATH)/ringtones/PERSEUS.ogg:system/media/audio/ringtones/PERSEUS.ogg \ - $(LOCAL_PATH)/ringtones/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \ - $(LOCAL_PATH)/ringtones/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \ - $(LOCAL_PATH)/ringtones/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \ - $(LOCAL_PATH)/ringtones/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ - $(LOCAL_PATH)/ringtones/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ - $(LOCAL_PATH)/ringtones/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \ - $(LOCAL_PATH)/ringtones/URSAMINOR.ogg:system/media/audio/ringtones/URSAMINOR.ogg \ - $(LOCAL_PATH)/ringtones/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg + $(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \ + $(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \ + $(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \ + $(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \ + $(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \ + $(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/notifications/Aldebaran.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Aldebaran.ogg \ + $(LOCAL_PATH)/notifications/Altair.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Altair.ogg \ + $(LOCAL_PATH)/notifications/Antares.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Antares.ogg \ + $(LOCAL_PATH)/notifications/arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/arcturus.ogg \ + $(LOCAL_PATH)/notifications/Betelgeuse.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Betelgeuse.ogg \ + $(LOCAL_PATH)/notifications/Canopus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Canopus.ogg \ + $(LOCAL_PATH)/notifications/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \ + $(LOCAL_PATH)/notifications/Castor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Castor.ogg \ + $(LOCAL_PATH)/notifications/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \ + $(LOCAL_PATH)/notifications/Deneb.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Deneb.ogg \ + $(LOCAL_PATH)/notifications/Electra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Electra.ogg \ + $(LOCAL_PATH)/notifications/Fomalhaut.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Fomalhaut.ogg \ + $(LOCAL_PATH)/notifications/Merope.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Merope.ogg \ + $(LOCAL_PATH)/notifications/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \ + $(LOCAL_PATH)/notifications/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \ + $(LOCAL_PATH)/notifications/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \ + $(LOCAL_PATH)/notifications/regulus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/regulus.ogg \ + $(LOCAL_PATH)/notifications/sirius.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/sirius.ogg \ + $(LOCAL_PATH)/notifications/Sirrah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Sirrah.ogg \ + $(LOCAL_PATH)/notifications/vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/vega.ogg \ + $(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ANDROMEDA.ogg \ + $(LOCAL_PATH)/ringtones/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \ + $(LOCAL_PATH)/ringtones/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \ + $(LOCAL_PATH)/ringtones/BOOTES.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BOOTES.ogg \ + $(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CANISMAJOR.ogg \ + $(LOCAL_PATH)/ringtones/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \ + $(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CASSIOPEIA.ogg \ + $(LOCAL_PATH)/ringtones/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \ + $(LOCAL_PATH)/ringtones/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \ + $(LOCAL_PATH)/ringtones/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \ + $(LOCAL_PATH)/ringtones/Eridani.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eridani.ogg \ + $(LOCAL_PATH)/ringtones/hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/hydra.ogg \ + $(LOCAL_PATH)/ringtones/Lyra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Lyra.ogg \ + $(LOCAL_PATH)/ringtones/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \ + $(LOCAL_PATH)/ringtones/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \ + $(LOCAL_PATH)/ringtones/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \ + $(LOCAL_PATH)/ringtones/PERSEUS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/PERSEUS.ogg \ + $(LOCAL_PATH)/ringtones/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \ + $(LOCAL_PATH)/ringtones/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \ + $(LOCAL_PATH)/ringtones/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \ + $(LOCAL_PATH)/ringtones/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \ + $(LOCAL_PATH)/ringtones/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \ + $(LOCAL_PATH)/ringtones/Testudo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Testudo.ogg \ + $(LOCAL_PATH)/ringtones/URSAMINOR.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/URSAMINOR.ogg \ + $(LOCAL_PATH)/ringtones/Vespa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Vespa.ogg diff --git a/data/sounds/AudioPackage6.mk b/data/sounds/AudioPackage6.mk index 5413704f0fac..a778261c0a22 100644 --- a/data/sounds/AudioPackage6.mk +++ b/data/sounds/AudioPackage6.mk @@ -8,41 +8,41 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/alarms/ogg/Barium.ogg:system/media/audio/alarms/Barium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Scandium.ogg:system/media/audio/alarms/Scandium.ogg \ - $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/notifications/ogg/Antimony.ogg:system/media/audio/notifications/Antimony.ogg \ - $(LOCAL_PATH)/notifications/ogg/Argon.ogg:system/media/audio/notifications/Argon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:system/media/audio/notifications/Beryllium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:system/media/audio/notifications/Cobalt.ogg \ - $(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:system/media/audio/notifications/Fluorine.ogg \ - $(LOCAL_PATH)/notifications/ogg/Gallium.ogg:system/media/audio/notifications/Gallium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Helium.ogg:system/media/audio/notifications/Helium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:system/media/audio/notifications/Iridium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Krypton.ogg:system/media/audio/notifications/Krypton.ogg \ - $(LOCAL_PATH)/notifications/ogg/Palladium.ogg:system/media/audio/notifications/Palladium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Radon.ogg:system/media/audio/notifications/Radon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:system/media/audio/notifications/Rubidium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Selenium.ogg:system/media/audio/notifications/Selenium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Strontium.ogg:system/media/audio/notifications/Strontium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \ - $(LOCAL_PATH)/notifications/ogg/Xenon.ogg:system/media/audio/notifications/Xenon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:system/media/audio/notifications/Zirconium.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ + $(LOCAL_PATH)/alarms/ogg/Barium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Barium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Cesium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Plutonium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Scandium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Scandium.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/notifications/ogg/Antimony.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Antimony.ogg \ + $(LOCAL_PATH)/notifications/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Argon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beryllium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Cobalt.ogg \ + $(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Fluorine.ogg \ + $(LOCAL_PATH)/notifications/ogg/Gallium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Gallium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Helium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Iridium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Krypton.ogg \ + $(LOCAL_PATH)/notifications/ogg/Palladium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Palladium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Radon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Radon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Rubidium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Selenium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Selenium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Strontium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Strontium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Thallium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Thallium.ogg \ + $(LOCAL_PATH)/notifications/ogg/Xenon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Xenon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Zirconium.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \ diff --git a/data/sounds/AudioPackage7.mk b/data/sounds/AudioPackage7.mk index e4763be2d4aa..27e349d2262e 100644 --- a/data/sounds/AudioPackage7.mk +++ b/data/sounds/AudioPackage7.mk @@ -8,64 +8,64 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \ - $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \ - $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \ - $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \ - $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \ - $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \ - $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \ - $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ - $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \ - $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \ - $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ - $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \ - $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ - $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \ - $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg + $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Cesium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Fermium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Hassium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neptunium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Nobelium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Plutonium.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \ + $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Bellatrix.ogg \ + $(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \ + $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Lalande.ogg \ + $(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \ + $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \ + $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \ + $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Proxima.ogg \ + $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \ + $(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Upsilon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \ + $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CanisMajor.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Perseus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \ + $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/UrsaMinor.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg diff --git a/data/sounds/AudioPackage7alt.mk b/data/sounds/AudioPackage7alt.mk index 30e617316ef4..a0f4d89ff32c 100644 --- a/data/sounds/AudioPackage7alt.mk +++ b/data/sounds/AudioPackage7alt.mk @@ -8,63 +8,63 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/alarms/ogg-jp/Argon.ogg:system/media/audio/alarms/Argon.ogg \ - $(LOCAL_PATH)/alarms/ogg-jp/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \ - $(LOCAL_PATH)/alarms/ogg-jp/Helium.ogg:system/media/audio/alarms/Helium.ogg \ - $(LOCAL_PATH)/alarms/ogg-jp/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \ - $(LOCAL_PATH)/alarms/ogg-jp/Neon.ogg:system/media/audio/alarms/Neon.ogg \ - $(LOCAL_PATH)/alarms/ogg-jp/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \ - $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \ - $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \ - $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \ - $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \ - $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \ - $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \ - $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ - $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \ - $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \ - $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ - $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \ - $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ - $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \ - $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg + $(LOCAL_PATH)/alarms/ogg-jp/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \ + $(LOCAL_PATH)/alarms/ogg-jp/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \ + $(LOCAL_PATH)/alarms/ogg-jp/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \ + $(LOCAL_PATH)/alarms/ogg-jp/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \ + $(LOCAL_PATH)/alarms/ogg-jp/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \ + $(LOCAL_PATH)/alarms/ogg-jp/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \ + $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Bellatrix.ogg \ + $(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \ + $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Lalande.ogg \ + $(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \ + $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \ + $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \ + $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Proxima.ogg \ + $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \ + $(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Upsilon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \ + $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CanisMajor.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Perseus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \ + $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/UrsaMinor.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg diff --git a/data/sounds/AudioPackage8.mk b/data/sounds/AudioPackage8.mk index b38e62dec6ad..032b4d26ed6f 100644 --- a/data/sounds/AudioPackage8.mk +++ b/data/sounds/AudioPackage8.mk @@ -8,66 +8,66 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \ - $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \ - $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \ - $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \ - $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \ - $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \ - $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \ - $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ - $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \ - $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \ - $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ - $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \ - $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \ - $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \ - $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg + $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Cesium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Fermium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Hassium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neptunium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Nobelium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Plutonium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Promethium.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \ + $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Bellatrix.ogg \ + $(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \ + $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Lalande.ogg \ + $(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \ + $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \ + $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \ + $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Proxima.ogg \ + $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \ + $(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Upsilon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \ + $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CanisMajor.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Perseus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \ + $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/UrsaMinor.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg diff --git a/data/sounds/AudioPackage9.mk b/data/sounds/AudioPackage9.mk index dbe1350f304a..53cc8c08a76c 100644 --- a/data/sounds/AudioPackage9.mk +++ b/data/sounds/AudioPackage9.mk @@ -8,43 +8,43 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \ - $(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \ - $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \ - $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \ - $(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \ - $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \ - $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \ - $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \ - $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \ - $(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \ - $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \ - $(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \ - $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \ - $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \ - $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \ - $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \ - $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \ - $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \ - $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \ - $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \ - $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \ - $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \ - $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg + $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \ + $(LOCAL_PATH)/alarms/ogg/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \ + $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \ + $(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \ + $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \ + $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \ + $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \ + $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \ + $(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \ + $(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \ + $(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \ + $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \ + $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \ + $(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \ + $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \ + $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \ + $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \ + $(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \ + $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Syrma.ogg \ + $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \ + $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \ + $(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg diff --git a/data/sounds/AudioPackageGo.mk b/data/sounds/AudioPackageGo.mk index 0296219fe9b4..e3b27f2cd962 100644 --- a/data/sounds/AudioPackageGo.mk +++ b/data/sounds/AudioPackageGo.mk @@ -20,30 +20,30 @@ LOCAL_PATH := frameworks/base/data/sounds # Ring_Synth_04 : Flutey Phone # Alarm_Beep_03 : Beep Beep Beep PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \ - $(LOCAL_PATH)/notifications/ogg/Argon.ogg:system/media/audio/notifications/Argon.ogg \ - $(LOCAL_PATH)/notifications/Canopus.ogg:system/media/audio/notifications/Canopus.ogg \ - $(LOCAL_PATH)/notifications/Deneb.ogg:system/media/audio/notifications/Deneb.ogg \ - $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \ - $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:system/media/audio/notifications/Iridium.ogg \ - $(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \ - $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \ - $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \ - $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \ - $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \ - $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \ - $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \ - $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \ - $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \ - $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \ - $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \ - $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \ - $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \ - $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \ + $(LOCAL_PATH)/notifications/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Argon.ogg \ + $(LOCAL_PATH)/notifications/Canopus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Canopus.ogg \ + $(LOCAL_PATH)/notifications/Deneb.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Deneb.ogg \ + $(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \ + $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Iridium.ogg \ + $(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \ + $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \ + $(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \ + $(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \ + $(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \ + $(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Kuma.ogg \ + $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \ + $(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \ + $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \ + $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \ + $(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \ + $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \ + $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ diff --git a/data/sounds/AudioTv.mk b/data/sounds/AudioTv.mk index 91265af77fa5..d0006b787f49 100644 --- a/data/sounds/AudioTv.mk +++ b/data/sounds/AudioTv.mk @@ -15,8 +15,8 @@ LOCAL_PATH := frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg + $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg diff --git a/data/sounds/OriginalAudio.mk b/data/sounds/OriginalAudio.mk index f68375205d89..4d74d1224caa 100644 --- a/data/sounds/OriginalAudio.mk +++ b/data/sounds/OriginalAudio.mk @@ -9,67 +9,67 @@ LOCAL_PATH:= frameworks/base/data/sounds PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \ - $(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \ - $(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \ - $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \ - $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \ - $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \ - $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \ - $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \ - $(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \ - $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \ - $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \ - $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \ - $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \ - $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \ - $(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \ - $(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \ - $(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \ - $(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \ - $(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \ - $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \ - $(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \ - $(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \ - $(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \ - $(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \ - $(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \ - $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \ - $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg + $(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \ + $(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \ + $(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \ + $(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \ + $(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \ + $(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \ + $(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \ + $(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \ + $(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \ + $(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \ + $(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \ + $(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \ + $(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \ + $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \ + $(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \ + $(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \ + $(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \ + $(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ + $(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \ + $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \ + $(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ + $(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ + $(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \ + $(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \ + $(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \ + $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BeatPlucker.ogg \ + $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg ifneq ($(MINIMAL_NEWWAVELABS),true) PRODUCT_COPY_FILES += \ - $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \ - $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \ - $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:system/media/audio/ringtones/CaribbeanIce.ogg \ - $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \ - $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \ - $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:system/media/audio/ringtones/FriendlyGhost.ogg \ - $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:system/media/audio/ringtones/GameOverGuitar.ogg \ - $(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \ - $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:system/media/audio/ringtones/InsertCoin.ogg \ - $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \ - $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \ - $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \ - $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \ - $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \ - $(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \ - $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \ - $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:system/media/audio/ringtones/RomancingTheTone.ogg \ - $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:system/media/audio/ringtones/SitarVsSitar.ogg \ - $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:system/media/audio/ringtones/SpringyJalopy.ogg \ - $(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \ - $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \ - $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \ - $(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \ - $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \ - $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \ - $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \ - $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \ - $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \ - $(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \ - $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \ - $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg + $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BentleyDubs.ogg \ + $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \ + $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CaribbeanIce.ogg \ + $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \ + $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \ + $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FriendlyGhost.ogg \ + $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/GameOverGuitar.ogg \ + $(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \ + $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/InsertCoin.ogg \ + $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \ + $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \ + $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \ + $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \ + $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/NewPlayer.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises1.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises1.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises2.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises2.ogg \ + $(LOCAL_PATH)/newwavelabs/Noises3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises3.ogg \ + $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \ + $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/RomancingTheTone.ogg \ + $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SitarVsSitar.ogg \ + $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SpringyJalopy.ogg \ + $(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \ + $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \ + $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/VeryAlarmed.ogg \ + $(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg \ + $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \ + $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \ + $(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \ + $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \ + $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \ + $(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \ + $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrazyDream.ogg \ + $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DreamTheme.ogg endif diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java index 76eab4a7905a..fcebad339f2b 100644 --- a/drm/java/android/drm/DrmManagerClient.java +++ b/drm/java/android/drm/DrmManagerClient.java @@ -831,6 +831,7 @@ public class DrmManagerClient implements AutoCloseable { * content://media/<table_name>/<row_index> (or) * file://sdcard/test.mp4 * http://test.com/test.mp4 + * https://test.com/test.mp4 * * Here <table_name> shall be "video" or "audio" or "images" * <row_index> the index of the content in given table @@ -843,7 +844,7 @@ public class DrmManagerClient implements AutoCloseable { scheme.equals(ContentResolver.SCHEME_FILE)) { path = uri.getPath(); - } else if (scheme.equals("http")) { + } else if (scheme.equals("http") || scheme.equals("https")) { path = uri.toString(); } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) { diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index adab1a9c5c51..022fbdc9df74 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -440,7 +440,8 @@ public class BitmapFactory { if (opts == null) return; if (opts.inBitmap != null && opts.inBitmap.getConfig() == Bitmap.Config.HARDWARE) { - throw new IllegalArgumentException("Bitmaps with Config.HARWARE are always immutable"); + throw new IllegalArgumentException( + "Bitmaps with Config.HARDWARE are always immutable"); } if (opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) { diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index 2227cf5ef2e0..f0efb581dab6 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -1354,9 +1354,9 @@ public abstract class ColorSpace { */ @NonNull static ColorSpace get(@IntRange(from = MIN_ID, to = MAX_ID) int index) { - if (index < 0 || index > Named.values().length) { + if (index < 0 || index >= Named.values().length) { throw new IllegalArgumentException("Invalid ID, must be in the range [0.." + - Named.values().length + "]"); + Named.values().length + ")"); } return sNamedColorSpaces[index]; } diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index b33cfe2ec511..0c515a41689d 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -81,7 +81,7 @@ public: explicit Matrix4(const float* v) { load(v); } - Matrix4(const SkMatrix& v) { // NOLINT, implicit + Matrix4(const SkMatrix& v) { // NOLINT(google-explicit-constructor) load(v); } diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index d6362ef10aad..24443c8c9836 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -57,15 +57,15 @@ public: inline Rect(float width, float height) : left(0.0f), top(0.0f), right(width), bottom(height) {} - inline Rect(const SkIRect& rect) - : // NOLINT, implicit + inline Rect(const SkIRect& rect) // NOLINT(google-explicit-constructor) + : left(rect.fLeft) , top(rect.fTop) , right(rect.fRight) , bottom(rect.fBottom) {} - inline Rect(const SkRect& rect) - : // NOLINT, implicit + inline Rect(const SkRect& rect) // NOLINT(google-explicit-constructor) + : left(rect.fLeft) , top(rect.fTop) , right(rect.fRight) diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index ab95e69c4e26..cc62fdc76ef8 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -678,15 +678,15 @@ void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) { // Canvas draw operations: Text // ---------------------------------------------------------------------------- -void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x, +void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x, float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, float totalAdvance) { if (count <= 0 || paint.nothingToDraw()) return; - SkFont font = SkFont::LEGACY_ExtractFromPaint(paint); SkPaint paintCopy(paint); if (mPaintFilter) { mPaintFilter->filter(&paintCopy); } + SkFont font = SkFont::LEGACY_ExtractFromPaint(paintCopy); SkASSERT(paintCopy.getTextEncoding() == kGlyphID_SkTextEncoding); // Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and // older. @@ -708,13 +708,13 @@ 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, + const Paint& paint, const SkPath& path, size_t start, size_t end) { - SkFont font = SkFont::LEGACY_ExtractFromPaint(paint); SkPaint paintCopy(paint); if (mPaintFilter) { mPaintFilter->filter(&paintCopy); } + SkFont font = SkFont::LEGACY_ExtractFromPaint(paintCopy); SkASSERT(paintCopy.getTextEncoding() == kGlyphID_SkTextEncoding); const int N = end - start; diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index 4ab0a59447ee..3fe2bce06b41 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -158,11 +158,11 @@ protected: void reset(SkCanvas* skiaCanvas); void drawDrawable(SkDrawable* drawable) { mCanvas->drawDrawable(drawable); } - virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x, + virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x, float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, float totalAdvance) override; virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, - const SkPaint& paint, const SkPath& path, size_t start, + const Paint& paint, const SkPath& path, size_t start, size_t end) override; /** This class acts as a copy on write SkPaint. diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp index 5b7ae70e821c..9170d6d1dc50 100644 --- a/libs/hwui/WebViewFunctorManager.cpp +++ b/libs/hwui/WebViewFunctorManager.cpp @@ -18,6 +18,7 @@ #include <private/hwui/WebViewFunctor.h> #include "Properties.h" +#include "renderthread/RenderThread.h" #include <log/log.h> #include <utils/Trace.h> @@ -90,6 +91,10 @@ void WebViewFunctor::destroyContext() { mHasContext = false; ATRACE_NAME("WebViewFunctor::onContextDestroyed"); mCallbacks.onContextDestroyed(mFunctor, mData); + + // grContext may be null in unit tests. + auto* grContext = renderthread::RenderThread::getInstance().getGrContext(); + if (grContext) grContext->resetContext(); } } diff --git a/libs/hwui/debug/GlesErrorCheckWrapper.h b/libs/hwui/debug/GlesErrorCheckWrapper.h index ee5cc1f46de8..791400bf30ec 100644 --- a/libs/hwui/debug/GlesErrorCheckWrapper.h +++ b/libs/hwui/debug/GlesErrorCheckWrapper.h @@ -24,7 +24,7 @@ namespace debug { class GlesErrorCheckWrapper : public GlesDriver { public: - GlesErrorCheckWrapper(GlesDriver& base) : mBase(base) {} + explicit GlesErrorCheckWrapper(GlesDriver& base) : mBase(base) {} #define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override; #include "gles_decls.in" diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index a09da6bf359e..277148e3d556 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -38,7 +38,7 @@ static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkSca canvas->drawRect(left, top, right, bottom, paint); } -void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { +void Canvas::drawTextDecorations(float x, float y, float length, const Paint& paint) { uint32_t flags; PaintFilter* paintFilter = getPaintFilter(); if (paintFilter) { diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 4c5365d3c170..11e8579a481f 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -303,18 +303,18 @@ public: static int GetApiLevel() { return sApiLevel; } protected: - void drawTextDecorations(float x, float y, float length, const SkPaint& paint); + void drawTextDecorations(float x, float y, float length, const Paint& paint); /** * glyphFunc: valid only for the duration of the call and should not be cached. * drawText: count is of glyphs * totalAdvance: used to define width of text decorations (underlines, strikethroughs). */ - virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x, + virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x, float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, float totalAdvance) = 0; virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, - const SkPaint& paint, const SkPath& path, size_t start, + const Paint& paint, const SkPath& path, size_t start, size_t end) = 0; static int sApiLevel; diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index c1a3b6d1143b..92ffda9486bb 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -46,7 +46,7 @@ public: Paint(); Paint(const Paint& paint); - Paint(const SkPaint& paint); // NOLINT(implicit) + Paint(const SkPaint& paint); // NOLINT(google-explicit-constructor) ~Paint(); Paint& operator=(const Paint& other); diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp index a5faae7d5068..c3563dbfd3cd 100644 --- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp @@ -36,8 +36,6 @@ namespace android { namespace uirenderer { namespace skiapipeline { -static std::mutex sLock{}; -static ThreadBase* sGLDrawThread = nullptr; static renderthread::EglManager sEglManager; // ScopedDrawRequest makes sure a GL thread is started and EGL context is initialized on it. @@ -47,32 +45,20 @@ public: private: void beginDraw() { - std::lock_guard _lock{sLock}; - - if (!sGLDrawThread) { - sGLDrawThread = new ThreadBase{}; - } - - if (!sGLDrawThread->isRunning()) { - sGLDrawThread->start("GLFunctorThread"); - } - if (!sEglManager.hasEglContext()) { - sGLDrawThread->queue().runSync([]() { sEglManager.initialize(); }); + sEglManager.initialize(); } } }; void VkInteropFunctorDrawable::vkInvokeFunctor(Functor* functor) { ScopedDrawRequest _drawRequest{}; - sGLDrawThread->queue().runSync([&]() { - EGLDisplay display = sEglManager.eglDisplay(); - DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; - if (display != EGL_NO_DISPLAY) { - mode = DrawGlInfo::kModeProcess; - } - (*functor)(mode, nullptr); - }); + EGLDisplay display = sEglManager.eglDisplay(); + DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; + if (display != EGL_NO_DISPLAY) { + mode = DrawGlInfo::kModeProcess; + } + (*functor)(mode, nullptr); } #define FENCE_TIMEOUT 2000000000 @@ -113,7 +99,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { // TODO: draw command has completed. // TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See // TODO: GrVkGpu::destroyResources() for example. - bool success = sGLDrawThread->queue().runSync([&]() -> bool { + { ATRACE_FORMAT("WebViewDraw_%dx%d", mFBInfo.width(), mFBInfo.height()); EGLDisplay display = sEglManager.eglDisplay(); LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", @@ -125,7 +111,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { if (autoImage.image == EGL_NO_IMAGE_KHR) { ALOGW("Could not create EGL image, err =%s", uirenderer::renderthread::EglManager::eglErrorString()); - return false; + return; } AutoSkiaGlTexture glTexture; @@ -156,7 +142,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Failed framebuffer check for created target buffer: %s", GLUtils::getGLFramebufferError()); - return false; + return; } glDisable(GL_STENCIL_TEST); @@ -183,11 +169,6 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, "Failed to wait for the fence %#x", eglGetError()); eglDestroySyncKHR(display, glDrawFinishedFence); - return true; - }); - - if (!success) { - return; } SkPaint paint; @@ -208,15 +189,14 @@ VkInteropFunctorDrawable::~VkInteropFunctorDrawable() { if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) { if (lp->listener) { ScopedDrawRequest _drawRequest{}; - sGLDrawThread->queue().runSync( - [&]() { lp->listener->onGlFunctorReleased(lp->functor); }); + lp->listener->onGlFunctorReleased(lp->functor); } } } void VkInteropFunctorDrawable::syncFunctor(const WebViewSyncData& data) const { ScopedDrawRequest _drawRequest{}; - sGLDrawThread->queue().runSync([&]() { FunctorDrawable::syncFunctor(data); }); + FunctorDrawable::syncFunctor(data); } } // namespace skiapipeline diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 7acc44ca65b7..6c04232ab7f5 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -30,6 +30,7 @@ #include <gui/Surface.h> #include <math.h> #include <set> +#include <SkMathPriv.h> namespace android { namespace uirenderer { @@ -42,11 +43,6 @@ namespace renderthread { #define SURFACE_SIZE_MULTIPLIER (12.0f * 4.0f) #define BACKGROUND_RETENTION_PERCENTAGE (0.5f) -// for super large fonts we will draw them as paths so no need to keep linearly -// increasing the font cache size. -#define FONT_CACHE_MIN_MB (0.5f) -#define FONT_CACHE_MAX_MB (4.0f) - CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display.w * display.h) { mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas( mMaxSurfaceArea / 2, @@ -106,25 +102,10 @@ public: void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) { contextOptions->fAllowPathMaskCaching = true; - float screenMP = mMaxSurfaceArea / 1024.0f / 1024.0f; - float fontCacheMB = 0; - float decimalVal = std::modf(screenMP, &fontCacheMB); - - // This is a basic heuristic to size the cache to a multiple of 512 KB - if (decimalVal > 0.8f) { - fontCacheMB += 1.0f; - } else if (decimalVal > 0.5f) { - fontCacheMB += 0.5f; - } - - // set limits on min/max size of the cache - fontCacheMB = std::max(FONT_CACHE_MIN_MB, std::min(FONT_CACHE_MAX_MB, fontCacheMB)); - - // We must currently set the size of the text cache based on the size of the - // display even though we like to be dynamicallysizing it to the size of the window. - // Skia's implementation doesn't provide a mechanism to resize the font cache due to - // the potential cost of recreating the glyphs. - contextOptions->fGlyphCacheTextureMaximumBytes = fontCacheMB * 1024 * 1024; + // This sets the maximum size for a single texture atlas in the GPU font cache. If necessary, + // the cache can allocate additional textures that are counted against the total cache limits + // provided to Skia. + contextOptions->fGlyphCacheTextureMaximumBytes = GrNextSizePow2(mMaxSurfaceArea); if (mTaskManager.canRunTasks()) { if (!mTaskProcessor.get()) { diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 12666b323d11..5272227509c8 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -123,6 +123,7 @@ private: friend class RenderProxy; friend class DummyVsyncSource; friend class android::uirenderer::TestUtils; + friend class android::uirenderer::WebViewFunctor; RenderThread(); virtual ~RenderThread(); diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp index 3d50d2d7e59c..8a16b2077f6f 100644 --- a/libs/hwui/service/GraphicsStatsService.cpp +++ b/libs/hwui/service/GraphicsStatsService.cpp @@ -48,7 +48,7 @@ static void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int outFd); class FileDescriptor { public: - FileDescriptor(int fd) : mFd(fd) {} + explicit FileDescriptor(int fd) : mFd(fd) {} ~FileDescriptor() { if (mFd != -1) { close(mFd); @@ -56,7 +56,7 @@ public: } } bool valid() { return mFd != -1; } - operator int() { return mFd; } + operator int() { return mFd; } // NOLINT(google-explicit-constructor) private: int mFd; @@ -64,7 +64,7 @@ private: class FileOutputStreamLite : public io::ZeroCopyOutputStream { public: - FileOutputStreamLite(int fd) : mCopyAdapter(fd), mImpl(&mCopyAdapter) {} + explicit FileOutputStreamLite(int fd) : mCopyAdapter(fd), mImpl(&mCopyAdapter) {} virtual ~FileOutputStreamLite() {} int GetErrno() { return mCopyAdapter.mErrno; } @@ -82,7 +82,7 @@ private: int mFd; int mErrno = 0; - FDAdapter(int fd) : mFd(fd) {} + explicit FDAdapter(int fd) : mFd(fd) {} virtual ~FDAdapter() {} virtual bool Write(const void* buffer, int size) override { @@ -139,6 +139,7 @@ bool GraphicsStatsService::parseFromFile(const std::string& path, uint32_t file_version = *reinterpret_cast<uint32_t*>(addr); if (file_version != sCurrentFileVersion) { ALOGW("file_version mismatch! expected %d got %d", sCurrentFileVersion, file_version); + munmap(addr, sb.st_size); return false; } @@ -150,6 +151,7 @@ bool GraphicsStatsService::parseFromFile(const std::string& path, ALOGW("Parse failed on '%s' error='%s'", path.c_str(), output->InitializationErrorString().c_str()); } + munmap(addr, sb.st_size); return success; } diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 7aa9b82e3583..16a27598c56a 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -82,7 +82,7 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint float y) { auto utf16 = asciiToUtf16(text); uint32_t length = strlen(text); - SkPaint glyphPaint(paint); + Paint glyphPaint(paint); glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding); canvas->drawText(utf16.get(), length, // text buffer 0, length, // draw range @@ -93,7 +93,7 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, const SkPath& path) { auto utf16 = asciiToUtf16(text); - SkPaint glyphPaint(paint); + Paint glyphPaint(paint); glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding); canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, glyphPaint, nullptr); diff --git a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp index 1d3d60716d68..5af7d43d7f66 100644 --- a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp +++ b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp @@ -31,7 +31,7 @@ static bool _BitmapFillrate( class BitmapFillrate : public TestScene { public: - BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator) + explicit BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator) : TestScene(), mAllocator(allocator) {} void createContent(int width, int height, Canvas& canvas) override { @@ -70,4 +70,4 @@ private: BitmapAllocationTestUtils::BitmapAllocator mAllocator; std::vector<sp<RenderNode> > mNodes; -};
\ No newline at end of file +}; diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp index ad11a1d32310..510766073b08 100644 --- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp +++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp @@ -26,7 +26,7 @@ static bool _BitmapShaders(BitmapAllocationTestUtils::registerBitmapAllocationSc class BitmapShaders : public TestScene { public: - BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator) + explicit BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator) : TestScene(), mAllocator(allocator) {} sp<RenderNode> card; diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp index a64e8444a9b1..286f5f194aed 100644 --- a/libs/hwui/tests/common/scenes/TvApp.cpp +++ b/libs/hwui/tests/common/scenes/TvApp.cpp @@ -48,7 +48,7 @@ static bool _TvAppNoRoundedCornerColorFilter( class TvApp : public TestScene { public: - TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator) + explicit TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator) : TestScene(), mAllocator(allocator) {} sp<RenderNode> mBg; @@ -232,7 +232,7 @@ private: class TvAppNoRoundedCorner : public TvApp { public: - TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {} + explicit TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {} private: virtual float roundedCornerRadius() override { return dp(0); } @@ -240,7 +240,7 @@ private: class TvAppColorFilter : public TvApp { public: - TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {} + explicit TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {} private: virtual bool useOverlay() override { return false; } @@ -248,7 +248,7 @@ private: class TvAppNoRoundedCornerColorFilter : public TvApp { public: - TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) + explicit TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {} private: diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp index 479c462bd1a6..635429dea359 100644 --- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp +++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp @@ -44,7 +44,7 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac static const int CANVAS_HEIGHT = 100; class PropertyTestCanvas : public TestCanvasBase { public: - PropertyTestCanvas(std::function<void(const SkCanvas&)> callback) + explicit PropertyTestCanvas(std::function<void(const SkCanvas&)> callback) : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT), mCallback(callback) {} void onDrawRect(const SkRect& rect, const SkPaint& paint) override { EXPECT_EQ(mDrawCounter++, 0); diff --git a/libs/hwui/tests/unit/ThreadBaseTests.cpp b/libs/hwui/tests/unit/ThreadBaseTests.cpp index 1168ff211202..817c1f3d3e43 100644 --- a/libs/hwui/tests/unit/ThreadBaseTests.cpp +++ b/libs/hwui/tests/unit/ThreadBaseTests.cpp @@ -95,7 +95,7 @@ TEST(ThreadBase, lifecyclePerf) { }; struct Counter { - Counter(EventCount* count) : mCount(count) { mCount->construct++; } + explicit Counter(EventCount* count) : mCount(count) { mCount->construct++; } Counter(const Counter& other) : mCount(other.mCount) { if (mCount) mCount->copy++; @@ -148,4 +148,4 @@ TEST(ThreadBase, lifecycle) { ASSERT_EQ(1, dummyObject->getStrongCount()); ASSERT_EQ(2, lifecycleTestHelper(dummyObject)); ASSERT_EQ(1, dummyObject->getStrongCount()); -}
\ No newline at end of file +} diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h index b401fcf58f76..9c4a1be4b269 100644 --- a/libs/hwui/utils/LinearAllocator.h +++ b/libs/hwui/utils/LinearAllocator.h @@ -168,7 +168,7 @@ public: }; // enable allocators to be constructed from other templated types template <class U> - LinearStdAllocator(const LinearStdAllocator<U>& other) // NOLINT(implicit) + LinearStdAllocator(const LinearStdAllocator<U>& other) // NOLINT(google-explicit-constructor) : linearAllocator(other.linearAllocator) {} T* allocate(size_t num, const void* = 0) { diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index b5313256e4dc..866634e17513 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -16,9 +16,6 @@ package com.android.internal.location; -import java.io.UnsupportedEncodingException; -import java.util.concurrent.TimeUnit; - import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -26,20 +23,23 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.location.LocationManager; import android.location.INetInitiatedListener; +import android.location.LocationManager; +import android.os.RemoteException; import android.os.SystemClock; -import android.telephony.TelephonyManager; +import android.os.UserHandle; import android.telephony.PhoneNumberUtils; import android.telephony.PhoneStateListener; -import android.os.RemoteException; -import android.os.UserHandle; +import android.telephony.TelephonyManager; import android.util.Log; -import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.R; +import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.telephony.GsmAlphabet; +import java.io.UnsupportedEncodingException; +import java.util.concurrent.TimeUnit; + /** * A GPS Network-initiated Handler class used by LocationManager. * @@ -92,9 +92,6 @@ public class GpsNetInitiatedHandler { public static final int GPS_ENC_SUPL_UCS2 = 3; public static final int GPS_ENC_UNKNOWN = -1; - // Limit on SUPL NI emergency mode time extension after emergency sessions ends - private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300; // 5 minute maximum - private final Context mContext; private final TelephonyManager mTelephonyManager; private final PhoneStateListener mPhoneStateListener; @@ -252,19 +249,9 @@ public class GpsNetInitiatedHandler { } public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) { - if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) { - Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds - + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS); - emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS; - } else if (emergencyExtensionSeconds < 0) { - Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds - + " is negative, reset to zero."); - emergencyExtensionSeconds = 0; - } mEmergencyExtensionMillis = TimeUnit.SECONDS.toMillis(emergencyExtensionSeconds); } - // Handles NI events from HAL public void handleNiNotification(GpsNiNotification notif) { if (DEBUG) Log.d(TAG, "in handleNiNotification () :" diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java index cef66147f395..df96994b0c36 100644 --- a/media/java/android/media/MediaPlayer2.java +++ b/media/java/android/media/MediaPlayer2.java @@ -537,6 +537,19 @@ public class MediaPlayer2 implements AutoCloseable public native long getCurrentPosition(); /** + * Gets the duration of the current data source. + * Same as {@link #getDuration(DataSourceDesc)} with + * {@code dsd = getCurrentDataSource()}. + * + * @return the duration in milliseconds, if no duration is available + * (for example, if streaming live content), -1 is returned. + * @throws NullPointerException if current data source is null + */ + public long getDuration() { + return getDuration(getCurrentDataSource()); + } + + /** * Gets the duration of the dsd. * * @param dsd the descriptor of data source of which you want to get duration @@ -559,6 +572,18 @@ public class MediaPlayer2 implements AutoCloseable private native long native_getDuration(long srcId); /** + * Gets the buffered media source position of current data source. + * Same as {@link #getBufferedPosition(DataSourceDesc)} with + * {@code dsd = getCurrentDataSource()}. + * + * @return the current buffered media source position in milliseconds + * @throws NullPointerException if current data source is null + */ + public long getBufferedPosition() { + return getBufferedPosition(getCurrentDataSource()); + } + + /** * Gets the buffered media source position of given dsd. * 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 @@ -1309,11 +1334,11 @@ public class MediaPlayer2 implements AutoCloseable return addTask(new Task(CALL_COMPLETED_SET_WAKE_LOCK, false) { @Override void process() { - boolean washeld = false; + boolean wasHeld = false; if (mWakeLock != null) { if (mWakeLock.isHeld()) { - washeld = true; + wasHeld = true; mWakeLock.release(); } } @@ -1321,7 +1346,7 @@ public class MediaPlayer2 implements AutoCloseable mWakeLock = wakeLock; if (mWakeLock != null) { mWakeLock.setReferenceCounted(false); - if (washeld) { + if (wasHeld) { mWakeLock.acquire(); } } @@ -2015,6 +2040,21 @@ public class MediaPlayer2 implements AutoCloseable }; /** + * Returns a List of track information of current data source. + * Same as {@link #getTrackInfo(DataSourceDesc)} with + * {@code dsd = getCurrentDataSource()}. + * + * @return List of track info. The total number of tracks is the array length. + * Must be called again if an external timed text source has been added after + * addTimedTextSource method is called. + * @throws IllegalStateException if it is called in an invalid state. + * @throws NullPointerException if current data source is null + */ + public @NonNull List<TrackInfo> getTrackInfo() { + return getTrackInfo(getCurrentDataSource()); + } + + /** * Returns a List of track information. * * @param dsd the descriptor of data source of which you want to get track info @@ -2024,7 +2064,6 @@ public class MediaPlayer2 implements AutoCloseable * @throws IllegalStateException if it is called in an invalid state. * @throws NullPointerException if dsd is null */ - public @NonNull List<TrackInfo> getTrackInfo(@NonNull DataSourceDesc dsd) { if (dsd == null) { throw new NullPointerException("non-null dsd is expected"); @@ -2060,9 +2099,34 @@ public class MediaPlayer2 implements AutoCloseable } /** - * Returns the index of the audio, video, or subtitle track currently selected for playback, + * Returns the index of the audio, video, or subtitle track currently selected for playback. + * The return value is an index into the array returned by {@link #getTrackInfo}, and can + * be used in calls to {@link #selectTrack(int)} or {@link #deselectTrack(int)}. + * Same as {@link #getSelectedTrack(DataSourceDesc, int)} with + * {@code dsd = getCurrentDataSource()}. + * + * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO}, + * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or + * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE} + * @return index of the audio, video, or subtitle track currently selected for playback; + * a negative integer is returned when there is no selected track for {@code trackType} or + * when {@code trackType} is not one of audio, video, or subtitle. + * @throws IllegalStateException if called after {@link #close()} + * @throws NullPointerException if current data source is null + * + * @see #getTrackInfo() + * @see #selectTrack(int) + * @see #deselectTrack(int) + */ + public int getSelectedTrack(int trackType) { + return getSelectedTrack(getCurrentDataSource(), trackType); + } + + /** + * Returns the index of the audio, video, or subtitle track currently selected for playback. * The return value is an index into the array returned by {@link #getTrackInfo}, and can - * be used in calls to {@link #selectTrack} or {@link #deselectTrack}. + * be used in calls to {@link #selectTrack(DataSourceDesc, int)} or + * {@link #deselectTrack(DataSourceDesc, int)}. * * @param dsd the descriptor of data source of which you want to get selected track * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO}, @@ -2074,9 +2138,9 @@ public class MediaPlayer2 implements AutoCloseable * @throws IllegalStateException if called after {@link #close()} * @throws NullPointerException if dsd is null * - * @see #getTrackInfo - * @see #selectTrack - * @see #deselectTrack + * @see #getTrackInfo(DataSourceDesc) + * @see #selectTrack(DataSourceDesc, int) + * @see #deselectTrack(DataSourceDesc, int) */ public int getSelectedTrack(@NonNull DataSourceDesc dsd, int trackType) { if (dsd == null) { @@ -2100,6 +2164,23 @@ public class MediaPlayer2 implements AutoCloseable } /** + * Selects a track of current data source. + * Same as {@link #selectTrack(DataSourceDesc, int)} with + * {@code dsd = getCurrentDataSource()}. + * + * @param index the index of the track to be selected. The valid range of the index + * is 0..total number of track - 1. The total number of tracks as well as the type of + * each individual track can be found by calling {@link #getTrackInfo()} method. + * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. + * + * @see MediaPlayer2#getTrackInfo() + */ + // This is an asynchronous call. + public Object selectTrack(int index) { + return selectTrack(getCurrentDataSource(), index); + } + + /** * Selects a track. * <p> * If a MediaPlayer2 is in invalid state, it throws an IllegalStateException exception. @@ -2123,10 +2204,10 @@ public class MediaPlayer2 implements AutoCloseable * @param dsd the descriptor of data source of which you want to select track * @param index the index of the track to be selected. The valid range of the index * is 0..total number of track - 1. The total number of tracks as well as the type of - * each individual track can be found by calling {@link #getTrackInfo} method. + * each individual track can be found by calling {@link #getTrackInfo(DataSourceDesc)} method. * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. * - * @see MediaPlayer2#getTrackInfo + * @see MediaPlayer2#getTrackInfo(DataSourceDesc) */ // This is an asynchronous call. public Object selectTrack(@NonNull DataSourceDesc dsd, int index) { @@ -2139,6 +2220,23 @@ public class MediaPlayer2 implements AutoCloseable } /** + * Deselect a track of current data source. + * Same as {@link #deselectTrack(DataSourceDesc, int)} with + * {@code dsd = getCurrentDataSource()}. + * + * @param index the index of the track to be deselected. The valid range of the index + * is 0..total number of tracks - 1. The total number of tracks as well as the type of + * each individual track can be found by calling {@link #getTrackInfo()} method. + * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. + * + * @see MediaPlayer2#getTrackInfo() + */ + // This is an asynchronous call. + public Object deselectTrack(int index) { + return deselectTrack(getCurrentDataSource(), index); + } + + /** * Deselect a track. * <p> * Currently, the track must be a timed text track and no audio or video tracks can be @@ -2151,7 +2249,7 @@ public class MediaPlayer2 implements AutoCloseable * each individual track can be found by calling {@link #getTrackInfo} method. * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. * - * @see MediaPlayer2#getTrackInfo + * @see MediaPlayer2#getTrackInfo(DataSourceDesc) */ // This is an asynchronous call. public Object deselectTrack(@NonNull DataSourceDesc dsd, int index) { diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index b16002900799..25b1df26fd40 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -456,6 +456,9 @@ public class MediaRecorder implements AudioRouting, /** VP8/VORBIS data in a WEBM container */ public static final int WEBM = 9; + /** @hide HEIC data in a HEIF container */ + public static final int HEIF = 10; + /** Opus data in a Ogg container */ public static final int OGG = 11; }; @@ -699,6 +702,12 @@ public class MediaRecorder implements AudioRouting, * is no guarantee that the recorder will have stopped by the time the * listener is notified. * + * <p>When using MPEG-4 container ({@link #setOutputFormat(int)} with + * {@link OutputFormat#MPEG_4}), it is recommended to set maximum duration that fits the use + * case. Setting a larger than required duration may result in a larger than needed output file + * because of space reserved for MOOV box expecting large movie data in this recording session. + * Unused space of MOOV box is turned into FREE box in the output file.</p> + * * @param max_duration_ms the maximum duration in ms (if zero or negative, disables the duration limit) * */ @@ -714,6 +723,12 @@ public class MediaRecorder implements AudioRouting, * is no guarantee that the recorder will have stopped by the time the * listener is notified. * + * <p>When using MPEG-4 container ({@link #setOutputFormat(int)} with + * {@link OutputFormat#MPEG_4}), it is recommended to set maximum filesize that fits the use + * case. Setting a larger than required filesize may result in a larger than needed output file + * because of space reserved for MOOV box expecting large movie data in this recording session. + * Unused space of MOOV box is turned into FREE box in the output file.</p> + * * @param max_filesize_bytes the maximum filesize in bytes (if zero or negative, disables the limit) * */ diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index e61bf5b48223..a843881e95ae 100644 --- a/media/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl @@ -21,8 +21,8 @@ import android.content.pm.ParceledListSlice; import android.media.MediaMetadata; import android.media.Rating; import android.media.session.ISessionControllerCallback; +import android.media.session.MediaController; import android.media.session.MediaSession; -import android.media.session.ParcelableVolumeInfo; import android.media.session.PlaybackState; import android.net.Uri; import android.os.Bundle; @@ -47,7 +47,7 @@ interface ISessionController { String getTag(); PendingIntent getLaunchPendingIntent(); long getFlags(); - ParcelableVolumeInfo getVolumeAttributes(); + MediaController.PlaybackInfo getVolumeAttributes(); void adjustVolume(String packageName, String opPackageName, in ISessionControllerCallback caller, boolean asSystemService, int direction, int flags); diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl index cf3176706d7e..fac8897d1b89 100644 --- a/media/java/android/media/session/ISessionControllerCallback.aidl +++ b/media/java/android/media/session/ISessionControllerCallback.aidl @@ -17,8 +17,8 @@ package android.media.session; import android.content.pm.ParceledListSlice; import android.media.MediaMetadata; -import android.media.session.ParcelableVolumeInfo; import android.media.session.PlaybackState; +import android.media.session.MediaController; import android.media.session.MediaSession; import android.os.Bundle; @@ -35,5 +35,5 @@ oneway interface ISessionControllerCallback { void onQueueChanged(in ParceledListSlice queue); void onQueueTitleChanged(CharSequence title); void onExtrasChanged(in Bundle extras); - void onVolumeInfoChanged(in ParcelableVolumeInfo info); + void onVolumeInfoChanged(in MediaController.PlaybackInfo info); } diff --git a/media/java/android/media/session/ParcelableVolumeInfo.aidl b/media/java/android/media/session/MediaController.aidl index c4250f097fb4..17167f45d0e3 100644 --- a/media/java/android/media/session/ParcelableVolumeInfo.aidl +++ b/media/java/android/media/session/MediaController.aidl @@ -15,4 +15,4 @@ package android.media.session; -parcelable ParcelableVolumeInfo; +parcelable MediaController.PlaybackInfo; diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 181ee5327547..ef2df15da8f4 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -32,6 +32,8 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; import android.os.ResultReceiver; import android.text.TextUtils; @@ -327,10 +329,7 @@ public final class MediaController { */ public @Nullable PlaybackInfo getPlaybackInfo() { try { - ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes(); - return new PlaybackInfo(result.volumeType, result.audioAttrs, result.controlType, - result.maxVolume, result.currentVolume); - + return mSessionBinder.getVolumeAttributes(); } catch (RemoteException e) { Log.wtf(TAG, "Error calling getAudioInfo.", e); } @@ -986,15 +985,15 @@ public final class MediaController { * Holds information about the current playback and how audio is handled for * this session. */ - public static final class PlaybackInfo { - /** - * The session uses remote playback. - */ - public static final int PLAYBACK_TYPE_REMOTE = 2; + public static final class PlaybackInfo implements Parcelable { /** * The session uses local playback. */ public static final int PLAYBACK_TYPE_LOCAL = 1; + /** + * The session uses remote playback. + */ + public static final int PLAYBACK_TYPE_REMOTE = 2; private final int mVolumeType; private final int mVolumeControl; @@ -1005,12 +1004,20 @@ public final class MediaController { /** * @hide */ - public PlaybackInfo(int type, AudioAttributes attrs, int control, int max, int current) { + public PlaybackInfo(int type, int control, int max, int current, AudioAttributes attrs) { mVolumeType = type; - mAudioAttrs = attrs; mVolumeControl = control; mMaxVolume = max; mCurrentVolume = current; + mAudioAttrs = attrs; + } + + PlaybackInfo(Parcel in) { + mVolumeType = in.readInt(); + mVolumeControl = in.readInt(); + mMaxVolume = in.readInt(); + mCurrentVolume = in.readInt(); + mAudioAttrs = in.readParcelable(null); } /** @@ -1027,18 +1034,6 @@ public final class MediaController { } /** - * Get the audio attributes for this session. The attributes will affect - * volume handling for the session. When the volume type is - * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the - * remote volume handler. - * - * @return The attributes for this session. - */ - public AudioAttributes getAudioAttributes() { - return mAudioAttrs; - } - - /** * Get the type of volume control that can be used. One of: * <ul> * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li> @@ -1070,6 +1065,52 @@ public final class MediaController { public int getCurrentVolume() { return mCurrentVolume; } + + /** + * Get the audio attributes for this session. The attributes will affect + * volume handling for the session. When the volume type is + * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the + * remote volume handler. + * + * @return The attributes for this session. + */ + public AudioAttributes getAudioAttributes() { + return mAudioAttrs; + } + + @Override + public String toString() { + return "volumeType=" + mVolumeType + ", volumeControl=" + mVolumeControl + + ", maxVolume=" + mMaxVolume + ", currentVolume=" + mCurrentVolume + + ", audioAttrs=" + mAudioAttrs; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mVolumeType); + dest.writeInt(mVolumeControl); + dest.writeInt(mMaxVolume); + dest.writeInt(mCurrentVolume); + dest.writeParcelable(mAudioAttrs, flags); + } + + public static final Parcelable.Creator<PlaybackInfo> CREATOR = + new Parcelable.Creator<PlaybackInfo>() { + @Override + public PlaybackInfo createFromParcel(Parcel in) { + return new PlaybackInfo(in); + } + + @Override + public PlaybackInfo[] newArray(int size) { + return new PlaybackInfo[size]; + } + }; } private final static class CallbackStub extends ISessionControllerCallback.Stub { @@ -1138,11 +1179,9 @@ public final class MediaController { } @Override - public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) { + public void onVolumeInfoChanged(PlaybackInfo info) { MediaController controller = mController.get(); if (controller != null) { - PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs, - pvi.controlType, pvi.maxVolume, pvi.currentVolume); controller.postMessage(MSG_UPDATE_VOLUME, info, null); } } @@ -1154,7 +1193,7 @@ public final class MediaController { private boolean mRegistered = false; public MessageHandler(Looper looper, MediaController.Callback cb) { - super(looper, null, true); + super(looper); mCallback = cb; } @@ -1193,6 +1232,7 @@ public final class MediaController { public void post(int what, Object obj, Bundle data) { Message msg = obtainMessage(what, obj); + msg.setAsynchronous(true); msg.setData(data); msg.sendToTarget(); } diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 8962bb7fb4c4..df8cc35945d3 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -1453,7 +1453,7 @@ public final class MediaSession { private RemoteUserInfo mCurrentControllerInfo; public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) { - super(looper, null, true); + super(looper); mCallback = callback; mCallback.mHandler = this; } @@ -1461,6 +1461,7 @@ public final class MediaSession { public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) { Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj); Message msg = obtainMessage(what, objWithCaller); + msg.setAsynchronous(true); msg.setData(data); if (delayMs > 0) { sendMessageDelayed(msg, delayMs); diff --git a/media/java/android/media/session/ParcelableVolumeInfo.java b/media/java/android/media/session/ParcelableVolumeInfo.java deleted file mode 100644 index f59c9756d466..000000000000 --- a/media/java/android/media/session/ParcelableVolumeInfo.java +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright 2014, 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.media.session; - -import android.media.AudioAttributes; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Convenience class for passing information about the audio configuration of a - * session. The public implementation is {@link MediaController.PlaybackInfo}. - * - * @hide - */ -public class ParcelableVolumeInfo implements Parcelable { - public int volumeType; - public AudioAttributes audioAttrs; - public int controlType; - public int maxVolume; - public int currentVolume; - - public ParcelableVolumeInfo(int volumeType, AudioAttributes audioAttrs, int controlType, - int maxVolume, - int currentVolume) { - this.volumeType = volumeType; - this.audioAttrs = audioAttrs; - this.controlType = controlType; - this.maxVolume = maxVolume; - this.currentVolume = currentVolume; - } - - public ParcelableVolumeInfo(Parcel from) { - volumeType = from.readInt(); - controlType = from.readInt(); - maxVolume = from.readInt(); - currentVolume = from.readInt(); - audioAttrs = AudioAttributes.CREATOR.createFromParcel(from); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(volumeType); - dest.writeInt(controlType); - dest.writeInt(maxVolume); - dest.writeInt(currentVolume); - audioAttrs.writeToParcel(dest, flags); - } - - - public static final Parcelable.Creator<ParcelableVolumeInfo> CREATOR - = new Parcelable.Creator<ParcelableVolumeInfo>() { - @Override - public ParcelableVolumeInfo createFromParcel(Parcel in) { - return new ParcelableVolumeInfo(in); - } - - @Override - public ParcelableVolumeInfo[] newArray(int size) { - return new ParcelableVolumeInfo[size]; - } - }; -} diff --git a/media/jni/Android.bp b/media/jni/Android.bp index f75f69b4f2ee..d6b6339b8f5f 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -102,7 +102,6 @@ cc_library_shared { "libhidlbase", "libhidlmemory", - "libpowermanager", // Used by JWakeLock. Will be replace with public SDJ API. "libmediametrics", // Used by MediaMetrics. Will be replaced with stable C API. "libbinder", // Used by JWakeLock and MediaMetrics. @@ -111,6 +110,7 @@ cc_library_shared { // NDK or NDK-compliant "libandroid", + "libbinder_ndk", "libmediandk", "libnativehelper_compat_libc++", "liblog", diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp index 7e6a8abbce90..9b4e730cfb5e 100644 --- a/media/jni/android_media_MediaPlayer2.cpp +++ b/media/jni/android_media_MediaPlayer2.cpp @@ -86,7 +86,8 @@ using media::VolumeShaper; // ---------------------------------------------------------------------------- struct fields_t { - jfieldID context; + jfieldID context; // passed from Java to native, used for creating JWakeLock + jfieldID nativeContext; // mNativeContext in MediaPlayer2.java jfieldID surface_texture; jmethodID post_event; @@ -225,21 +226,21 @@ void JNIMediaPlayer2Listener::notify(int64_t srcId, int msg, int ext1, int ext2, static sp<MediaPlayer2> getMediaPlayer(JNIEnv* env, jobject thiz) { Mutex::Autolock l(sLock); - MediaPlayer2* const p = (MediaPlayer2*)env->GetLongField(thiz, fields.context); + MediaPlayer2* const p = (MediaPlayer2*)env->GetLongField(thiz, fields.nativeContext); return sp<MediaPlayer2>(p); } static sp<MediaPlayer2> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer2>& player) { Mutex::Autolock l(sLock); - sp<MediaPlayer2> old = (MediaPlayer2*)env->GetLongField(thiz, fields.context); + sp<MediaPlayer2> old = (MediaPlayer2*)env->GetLongField(thiz, fields.nativeContext); if (player.get()) { player->incStrong((void*)setMediaPlayer); } if (old != 0) { old->decStrong((void*)setMediaPlayer); } - env->SetLongField(thiz, fields.context, (jlong)player.get()); + env->SetLongField(thiz, fields.nativeContext, (jlong)player.get()); return old; } @@ -955,11 +956,16 @@ android_media_MediaPlayer2_native_init(JNIEnv *env) return; } - fields.context = env->GetFieldID(clazz, "mNativeContext", "J"); + fields.context = env->GetFieldID(clazz, "mContext", "Landroid/content/Context;"); if (fields.context == NULL) { return; } + fields.nativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); + if (fields.nativeContext == NULL) { + return; + } + fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;JIII[B)V"); if (fields.post_event == NULL) { @@ -1013,7 +1019,8 @@ android_media_MediaPlayer2_native_setup(JNIEnv *env, jobject thiz, jint sessionId, jobject weak_this) { ALOGV("native_setup"); - sp<MediaPlayer2> mp = MediaPlayer2::Create(sessionId); + jobject context = env->GetObjectField(thiz, fields.context); + sp<MediaPlayer2> mp = MediaPlayer2::Create(sessionId, context); if (mp == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; diff --git a/native/android/net.c b/native/android/net.c index 4cac371f313b..a8104fc23041 100644 --- a/native/android/net.c +++ b/native/android/net.c @@ -84,26 +84,28 @@ int android_getaddrinfofornetwork(net_handle_t network, return android_getaddrinfofornet(node, service, hints, netid, 0, res); } -int android_res_nquery(net_handle_t network, const char *dname, int ns_class, int ns_type) { +int android_res_nquery(net_handle_t network, const char *dname, + int ns_class, int ns_type, enum ResNsendFlags flags) { unsigned netid; if (!getnetidfromhandle(network, &netid)) { return -ENONET; } - return resNetworkQuery(netid, dname, ns_class, ns_type); + return resNetworkQuery(netid, dname, ns_class, ns_type, flags); } int android_res_nresult(int fd, int *rcode, uint8_t *answer, size_t anslen) { return resNetworkResult(fd, rcode, answer, anslen); } -int android_res_nsend(net_handle_t network, const uint8_t *msg, size_t msglen) { +int android_res_nsend(net_handle_t network, const uint8_t *msg, size_t msglen, + enum ResNsendFlags flags) { unsigned netid; if (!getnetidfromhandle(network, &netid)) { return -ENONET; } - return resNetworkSend(netid, msg, msglen); + return resNetworkSend(netid, msg, msglen, flags); } void android_res_cancel(int nsend_fd) { diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp index 820bac509d2e..6c1ceaba4d46 100644 --- a/native/webview/plat_support/draw_functor.cpp +++ b/native/webview/plat_support/draw_functor.cpp @@ -82,13 +82,9 @@ int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) { .onDestroyed = &onDestroyed, }; if (!callbacks_initialized) { - switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) { - case uirenderer::RenderMode::OpenGL_ES: - webview_functor_callbacks.gles.draw = &draw_gl; - break; - case uirenderer::RenderMode::Vulkan: - break; - } + // Under uirenderer::RenderMode::Vulkan, whether gles or vk union should + // be populated should match whether the vk-gl interop is used. + webview_functor_callbacks.gles.draw = &draw_gl; callbacks_initialized = true; } SupportData* support = new SupportData{ diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java index 62502ef60e96..6d960d7b9e21 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java @@ -18,8 +18,8 @@ package com.android.systemui.car; import android.content.Context; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; /** Auto-specific implementation of {@link NotificationInterruptionStateProvider}. */ public class CarNotificationInterruptionStateProvider extends @@ -29,7 +29,7 @@ public class CarNotificationInterruptionStateProvider extends } @Override - public boolean shouldHeadsUp(NotificationData.Entry entry) { + public boolean shouldHeadsUp(NotificationEntry entry) { // Because space is usually constrained in the auto use-case, there should not be a // pinned notification when the shade has been expanded. Ensure this by not pinning any // notification if the shade is already opened. diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java index af52c00388f3..fab1bcc83447 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java @@ -366,9 +366,9 @@ public class Assistant extends NotificationAssistantService { } @Override - public void onNotificationDirectReply(@NonNull String key) { - if (DEBUG) Log.i(TAG, "onNotificationDirectReply " + key); - mSmartActionsHelper.onNotificationDirectReply(key); + public void onNotificationDirectReplied(@NonNull String key) { + if (DEBUG) Log.i(TAG, "onNotificationDirectReplied " + key); + mSmartActionsHelper.onNotificationDirectReplied(key); } @Override diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java index 56c415816558..a9d8f62d53f4 100644 --- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java +++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java @@ -165,7 +165,7 @@ public class SmartActionsHelper { } } - void onNotificationDirectReply(@NonNull String key) { + void onNotificationDirectReplied(@NonNull String key) { if (mTextClassifier == null) { return; } @@ -383,8 +383,7 @@ public class SmartActionsHelper { remoteAction.getIcon(), remoteAction.getTitle(), remoteAction.getActionIntent()) - .setSemanticAction( - Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) + .setContextual(true) .addExtras(Bundle.forPair(KEY_ACTION_TYPE, classification.getEntity(0))) .build(); actions.add(action); diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java index da382a003621..7d74788e21c0 100644 --- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java +++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java @@ -241,7 +241,7 @@ public class SmartActionHelperTest { when(mNotificationEntry.getNotification()).thenReturn(notification); mSmartActionsHelper.suggestReplies(mNotificationEntry); - mSmartActionsHelper.onNotificationDirectReply(NOTIFICATION_KEY); + mSmartActionsHelper.onNotificationDirectReplied(NOTIFICATION_KEY); ArgumentCaptor<TextClassifierEvent> argumentCaptor = ArgumentCaptor.forClass(TextClassifierEvent.class); diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp index 55bb5175c28d..4688848dee0f 100644 --- a/packages/NetworkStack/Android.bp +++ b/packages/NetworkStack/Android.bp @@ -22,6 +22,10 @@ java_library { srcs: [ "src/**/*.java", ], + static_libs: [ + "dhcp-packet-lib", + "frameworks-net-shared-utils", + ] } // Updatable network stack packaged as an application diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml index d1c5cb67197e..8516d9485f57 100644 --- a/packages/NetworkStack/AndroidManifest.xml +++ b/packages/NetworkStack/AndroidManifest.xml @@ -17,7 +17,7 @@ */ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.google.android.networkstack" + package="com.android.mainline.networkstack" android:sharedUserId="android.uid.networkstack"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> diff --git a/services/net/java/android/net/dhcp/DhcpLease.java b/packages/NetworkStack/src/android/net/dhcp/DhcpLease.java index 6cdd2aa8579d..6849cfadc22a 100644 --- a/services/net/java/android/net/dhcp/DhcpLease.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpLease.java @@ -58,6 +58,11 @@ public class DhcpLease { mHostname = hostname; } + /** + * Get the clientId associated with this lease, if any. + * + * <p>If the lease is not associated to a clientId, this returns null. + */ @Nullable public byte[] getClientId() { if (mClientId == null) { @@ -97,6 +102,11 @@ public class DhcpLease { (hostname == null ? mHostname : hostname)); } + /** + * Determine whether this lease matches a client with the specified parameters. + * @param clientId clientId of the client if any, or null otherwise. + * @param hwAddr Hardware address of the client. + */ public boolean matchesClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) { if (mClientId != null) { return Arrays.equals(mClientId, clientId); @@ -110,7 +120,7 @@ public class DhcpLease { if (!(obj instanceof DhcpLease)) { return false; } - final DhcpLease other = (DhcpLease)obj; + final DhcpLease other = (DhcpLease) obj; return Arrays.equals(mClientId, other.mClientId) && mHwAddr.equals(other.mHwAddr) && mNetAddr.equals(other.mNetAddr) diff --git a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java index 2dda42124c75..0d298de4f5f8 100644 --- a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java @@ -21,7 +21,8 @@ import static android.net.NetworkUtils.intToInet4AddressHTH; import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH; import static android.net.dhcp.DhcpLease.EXPIRATION_NEVER; import static android.net.dhcp.DhcpLease.inet4AddrToString; -import static android.net.util.NetworkConstants.IPV4_ADDR_BITS; + +import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_BITS; import static java.lang.Math.min; @@ -29,8 +30,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.IpPrefix; import android.net.MacAddress; -import android.net.util.SharedLog; import android.net.dhcp.DhcpServer.Clock; +import android.net.util.SharedLog; import android.util.ArrayMap; import java.net.Inet4Address; @@ -117,7 +118,7 @@ class DhcpLeaseRepository { */ private final LinkedHashMap<Inet4Address, Long> mDeclinedAddrs = new LinkedHashMap<>(); - public DhcpLeaseRepository(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs, + DhcpLeaseRepository(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs, long leaseTimeMs, @NonNull SharedLog log, @NonNull Clock clock) { updateParams(prefix, reservedAddrs, leaseTimeMs); mLog = log; @@ -250,8 +251,8 @@ class DhcpLeaseRepository { // reqAddr null (RENEWING/REBINDING): client renewing its own lease for clientAddr. // reqAddr set with sid not set (INIT-REBOOT): client verifying configuration. // In both cases, throw if clientAddr or reqAddr does not match the known lease. - throw new InvalidAddressException("Incorrect address for client in " + - (reqAddr != null ? "INIT-REBOOT" : "RENEWING/REBINDING")); + throw new InvalidAddressException("Incorrect address for client in " + + (reqAddr != null ? "INIT-REBOOT" : "RENEWING/REBINDING")); } } diff --git a/services/net/java/android/net/dhcp/DhcpPacketListener.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java index 6f620c5ce30e..dce8b619494e 100644 --- a/services/net/java/android/net/dhcp/DhcpPacketListener.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java @@ -32,32 +32,32 @@ import java.net.InetSocketAddress; */ abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payload> { static final class Payload { - final byte[] bytes = new byte[DhcpPacket.MAX_LENGTH]; - Inet4Address srcAddr; - int srcPort; + protected final byte[] mBytes = new byte[DhcpPacket.MAX_LENGTH]; + protected Inet4Address mSrcAddr; + protected int mSrcPort; } - public DhcpPacketListener(@NonNull Handler handler) { + DhcpPacketListener(@NonNull Handler handler) { super(handler, new Payload()); } @Override protected int recvBufSize(@NonNull Payload buffer) { - return buffer.bytes.length; + return buffer.mBytes.length; } @Override protected final void handlePacket(@NonNull Payload recvbuf, int length) { - if (recvbuf.srcAddr == null) { + if (recvbuf.mSrcAddr == null) { return; } try { - final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.bytes, length, + final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.mBytes, length, DhcpPacket.ENCAP_BOOTP); - onReceive(packet, recvbuf.srcAddr, recvbuf.srcPort); + onReceive(packet, recvbuf.mSrcAddr, recvbuf.mSrcPort); } catch (DhcpPacket.ParseException e) { - logParseError(recvbuf.bytes, length, e); + logParseError(recvbuf.mBytes, length, e); } } @@ -66,11 +66,11 @@ abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payl throws Exception { final InetSocketAddress addr = new InetSocketAddress(); final int read = Os.recvfrom( - fd, packetBuffer.bytes, 0, packetBuffer.bytes.length, 0 /* flags */, addr); + fd, packetBuffer.mBytes, 0, packetBuffer.mBytes.length, 0 /* flags */, addr); // Buffers with null srcAddr will be dropped in handlePacket() - packetBuffer.srcAddr = inet4AddrOrNull(addr); - packetBuffer.srcPort = addr.getPort(); + packetBuffer.mSrcAddr = inet4AddrOrNull(addr); + packetBuffer.mSrcPort = addr.getPort(); return read; } diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java index 35d29e75c0e4..14e293694ebd 100644 --- a/services/net/java/android/net/dhcp/DhcpServer.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java @@ -23,7 +23,8 @@ import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME; import static android.net.dhcp.DhcpPacket.DHCP_SERVER; import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; -import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; +import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT; +import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; @@ -32,21 +33,28 @@ import static android.system.OsConstants.SO_BINDTODEVICE; import static android.system.OsConstants.SO_BROADCAST; import static android.system.OsConstants.SO_REUSEADDR; +import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE; +import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission; + import static java.lang.Integer.toUnsignedLong; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.INetworkStackStatusCallback; import android.net.MacAddress; import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.SharedLog; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; import android.os.SystemClock; import android.system.ErrnoException; import android.system.Os; import android.text.TextUtils; +import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; @@ -70,7 +78,7 @@ import java.util.ArrayList; * on the looper asynchronously. * @hide */ -public class DhcpServer { +public class DhcpServer extends IDhcpServer.Stub { private static final String REPO_TAG = "Repository"; // Lease time to transmit to client instead of a negative time in case a lease expired before @@ -82,7 +90,7 @@ public class DhcpServer { private static final int CMD_UPDATE_PARAMS = 3; @NonNull - private final ServerHandler mHandler; + private final HandlerThread mHandlerThread; @NonNull private final String mIfName; @NonNull @@ -93,14 +101,25 @@ public class DhcpServer { private final Dependencies mDeps; @NonNull private final Clock mClock; - @NonNull - private final DhcpPacketListener mPacketListener; @Nullable + private volatile ServerHandler mHandler; + + // Accessed only on the handler thread + @Nullable + private DhcpPacketListener mPacketListener; + @Nullable private FileDescriptor mSocket; @NonNull private DhcpServingParams mServingParams; + /** + * Clock to be used by DhcpServer to track time for lease expiration. + * + * <p>The clock should track time as may be measured by clients obtaining a lease. It does not + * need to be monotonous across restarts of the server as long as leases are cleared when the + * server is stopped. + */ public static class Clock { /** * @see SystemClock#elapsedRealtime() @@ -110,15 +129,51 @@ public class DhcpServer { } } + /** + * Dependencies for the DhcpServer. Useful to be mocked in tests. + */ public interface Dependencies { + /** + * Send a packet to the specified datagram socket. + * + * @param fd File descriptor of the socket. + * @param buffer Data to be sent. + * @param dst Destination address of the packet. + */ void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer, @NonNull InetAddress dst) throws ErrnoException, IOException; + + /** + * Create a DhcpLeaseRepository for the server. + * @param servingParams Parameters used to serve DHCP requests. + * @param log Log to be used by the repository. + * @param clock Clock that the repository must use to track time. + */ DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams, @NonNull SharedLog log, @NonNull Clock clock); + + /** + * Create a packet listener that will send packets to be processed. + */ DhcpPacketListener makePacketListener(); + + /** + * Create a clock that the server will use to track time. + */ Clock makeClock(); + + /** + * Add an entry to the ARP cache table. + * @param fd Datagram socket file descriptor that must use the new entry. + */ void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr, @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException; + + /** + * Verify that the caller is allowed to call public methods on DhcpServer. + * @throws SecurityException The caller is not allowed to call public methods on DhcpServer. + */ + void checkCaller() throws SecurityException; } private class DependenciesImpl implements Dependencies { @@ -134,7 +189,7 @@ public class DhcpServer { return new DhcpLeaseRepository( DhcpServingParams.makeIpPrefix(servingParams.serverAddr), servingParams.excludedAddrs, - servingParams.dhcpLeaseTimeSecs*1000, log.forSubComponent(REPO_TAG), clock); + servingParams.dhcpLeaseTimeSecs * 1000, log.forSubComponent(REPO_TAG), clock); } @Override @@ -152,6 +207,11 @@ public class DhcpServer { @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException { NetworkUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd); } + + @Override + public void checkCaller() { + checkNetworkStackCallingPermission(); + } } private static class MalformedPacketException extends Exception { @@ -160,41 +220,62 @@ public class DhcpServer { } } - public DhcpServer(@NonNull Looper looper, @NonNull String ifName, + public DhcpServer(@NonNull String ifName, @NonNull DhcpServingParams params, @NonNull SharedLog log) { - this(looper, ifName, params, log, null); + this(new HandlerThread(DhcpServer.class.getSimpleName() + "." + ifName), + ifName, params, log, null); } @VisibleForTesting - DhcpServer(@NonNull Looper looper, @NonNull String ifName, + DhcpServer(@NonNull HandlerThread handlerThread, @NonNull String ifName, @NonNull DhcpServingParams params, @NonNull SharedLog log, @Nullable Dependencies deps) { if (deps == null) { deps = new DependenciesImpl(); } - mHandler = new ServerHandler(looper); + mHandlerThread = handlerThread; mIfName = ifName; mServingParams = params; mLog = log; mDeps = deps; mClock = deps.makeClock(); - mPacketListener = deps.makePacketListener(); mLeaseRepo = deps.makeLeaseRepository(mServingParams, mLog, mClock); } /** * Start listening for and responding to packets. + * + * <p>It is not legal to call this method more than once; in particular the server cannot be + * restarted after being stopped. */ - public void start() { - mHandler.sendEmptyMessage(CMD_START_DHCP_SERVER); + @Override + public void start(@Nullable INetworkStackStatusCallback cb) { + mDeps.checkCaller(); + mHandlerThread.start(); + mHandler = new ServerHandler(mHandlerThread.getLooper()); + sendMessage(CMD_START_DHCP_SERVER, cb); } /** * Update serving parameters. All subsequently received requests will be handled with the new * parameters, and current leases that are incompatible with the new parameters are dropped. */ - public void updateParams(@NonNull DhcpServingParams params) { - sendMessage(CMD_UPDATE_PARAMS, params); + @Override + public void updateParams(@Nullable DhcpServingParamsParcel params, + @Nullable INetworkStackStatusCallback cb) throws RemoteException { + mDeps.checkCaller(); + final DhcpServingParams parsedParams; + try { + // throws InvalidParameterException with null params + parsedParams = DhcpServingParams.fromParcelableObject(params); + } catch (DhcpServingParams.InvalidParameterException e) { + mLog.e("Invalid parameters sent to DhcpServer", e); + if (cb != null) { + cb.onStatusAvailable(STATUS_INVALID_ARGUMENT); + } + return; + } + sendMessage(CMD_UPDATE_PARAMS, new Pair<>(parsedParams, cb)); } /** @@ -203,38 +284,63 @@ public class DhcpServer { * <p>As the server is stopped asynchronously, some packets may still be processed shortly after * calling this method. */ - public void stop() { - mHandler.sendEmptyMessage(CMD_STOP_DHCP_SERVER); + @Override + public void stop(@Nullable INetworkStackStatusCallback cb) { + mDeps.checkCaller(); + sendMessage(CMD_STOP_DHCP_SERVER, cb); } private void sendMessage(int what, @Nullable Object obj) { + if (mHandler == null) { + mLog.e("Attempting to send a command to stopped DhcpServer: " + what); + return; + } mHandler.sendMessage(mHandler.obtainMessage(what, obj)); } private class ServerHandler extends Handler { - public ServerHandler(@NonNull Looper looper) { + ServerHandler(@NonNull Looper looper) { super(looper); } @Override public void handleMessage(@NonNull Message msg) { + final INetworkStackStatusCallback cb; switch (msg.what) { case CMD_UPDATE_PARAMS: - final DhcpServingParams params = (DhcpServingParams) msg.obj; + final Pair<DhcpServingParams, INetworkStackStatusCallback> pair = + (Pair<DhcpServingParams, INetworkStackStatusCallback>) msg.obj; + final DhcpServingParams params = pair.first; mServingParams = params; mLeaseRepo.updateParams( DhcpServingParams.makeIpPrefix(mServingParams.serverAddr), params.excludedAddrs, params.dhcpLeaseTimeSecs); + + cb = pair.second; break; case CMD_START_DHCP_SERVER: - // This is a no-op if the listener is already started + mPacketListener = mDeps.makePacketListener(); mPacketListener.start(); + cb = (INetworkStackStatusCallback) msg.obj; break; case CMD_STOP_DHCP_SERVER: - // This is a no-op if the listener was not started - mPacketListener.stop(); + if (mPacketListener != null) { + mPacketListener.stop(); + mPacketListener = null; + } + mHandlerThread.quitSafely(); + cb = (INetworkStackStatusCallback) msg.obj; break; + default: + return; + } + if (cb != null) { + try { + cb.onStatusAvailable(STATUS_SUCCESS); + } catch (RemoteException e) { + mLog.e("Could not send status back to caller", e); + } } } } @@ -496,22 +602,24 @@ public class DhcpServer { } private class PacketListener extends DhcpPacketListener { - public PacketListener() { + PacketListener() { super(mHandler); } @Override - protected void onReceive(DhcpPacket packet, Inet4Address srcAddr, int srcPort) { + protected void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr, + int srcPort) { processPacket(packet, srcPort); } @Override - protected void logError(String msg, Exception e) { + protected void logError(@NonNull String msg, Exception e) { mLog.e("Error receiving packet: " + msg, e); } @Override - protected void logParseError(byte[] packet, int length, DhcpPacket.ParseException e) { + protected void logParseError(@NonNull byte[] packet, int length, + @NonNull DhcpPacket.ParseException e) { mLog.e("Error parsing packet", e); } @@ -533,7 +641,7 @@ public class DhcpServer { return mSocket; } catch (IOException | ErrnoException e) { mLog.e("Error creating UDP socket", e); - DhcpServer.this.stop(); + DhcpServer.this.stop(null); return null; } finally { TrafficStats.setThreadStatsTag(oldTag); diff --git a/services/net/java/android/net/dhcp/DhcpServingParams.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java index df15ba1c5507..f38888aafbd6 100644 --- a/services/net/java/android/net/dhcp/DhcpServingParams.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java @@ -17,13 +17,16 @@ package android.net.dhcp; import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; -import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; -import static android.net.util.NetworkConstants.IPV4_MAX_MTU; -import static android.net.util.NetworkConstants.IPV4_MIN_MTU; +import static android.net.NetworkUtils.intToInet4AddressHTH; + +import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE; +import static com.android.server.util.NetworkStackConstants.IPV4_MAX_MTU; +import static com.android.server.util.NetworkStackConstants.IPV4_MIN_MTU; import static java.lang.Integer.toUnsignedLong; import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.NetworkUtils; @@ -103,6 +106,41 @@ public class DhcpServingParams { this.metered = metered; } + /** + * Create parameters from a stable AIDL-compatible parcel. + * @throws InvalidParameterException The parameters parcelable is null or invalid. + */ + public static DhcpServingParams fromParcelableObject(@Nullable DhcpServingParamsParcel parcel) + throws InvalidParameterException { + if (parcel == null) { + throw new InvalidParameterException("Null serving parameters"); + } + final LinkAddress serverAddr = new LinkAddress( + intToInet4AddressHTH(parcel.serverAddr), + parcel.serverAddrPrefixLength); + return new Builder() + .setServerAddr(serverAddr) + .setDefaultRouters(toInet4AddressSet(parcel.defaultRouters)) + .setDnsServers(toInet4AddressSet(parcel.dnsServers)) + .setExcludedAddrs(toInet4AddressSet(parcel.excludedAddrs)) + .setDhcpLeaseTimeSecs(parcel.dhcpLeaseTimeSecs) + .setLinkMtu(parcel.linkMtu) + .setMetered(parcel.metered) + .build(); + } + + private static Set<Inet4Address> toInet4AddressSet(@Nullable int[] addrs) { + if (addrs == null) { + return new HashSet<>(0); + } + + final HashSet<Inet4Address> res = new HashSet<>(); + for (int addr : addrs) { + res.add(intToInet4AddressHTH(addr)); + } + return res; + } + @NonNull public Inet4Address getServerInet4Addr() { return (Inet4Address) serverAddr.getAddress(); @@ -134,13 +172,13 @@ public class DhcpServingParams { * of the parameters. */ public static class Builder { - private LinkAddress serverAddr; - private Set<Inet4Address> defaultRouters; - private Set<Inet4Address> dnsServers; - private Set<Inet4Address> excludedAddrs; - private long dhcpLeaseTimeSecs; - private int linkMtu = MTU_UNSET; - private boolean metered; + private LinkAddress mServerAddr; + private Set<Inet4Address> mDefaultRouters; + private Set<Inet4Address> mDnsServers; + private Set<Inet4Address> mExcludedAddrs; + private long mDhcpLeaseTimeSecs; + private int mLinkMtu = MTU_UNSET; + private boolean mMetered; /** * Set the server address and served prefix for the DHCP server. @@ -148,7 +186,7 @@ public class DhcpServingParams { * <p>This parameter is required. */ public Builder setServerAddr(@NonNull LinkAddress serverAddr) { - this.serverAddr = serverAddr; + this.mServerAddr = serverAddr; return this; } @@ -159,7 +197,7 @@ public class DhcpServingParams { * always be set explicitly before building the {@link DhcpServingParams}. */ public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) { - this.defaultRouters = defaultRouters; + this.mDefaultRouters = defaultRouters; return this; } @@ -189,7 +227,7 @@ public class DhcpServingParams { * {@link DhcpServingParams}. */ public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) { - this.dnsServers = dnsServers; + this.mDnsServers = dnsServers; return this; } @@ -219,7 +257,7 @@ public class DhcpServingParams { * and do not need to be set here. */ public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) { - this.excludedAddrs = excludedAddrs; + this.mExcludedAddrs = excludedAddrs; return this; } @@ -239,7 +277,7 @@ public class DhcpServingParams { * <p>This parameter is required. */ public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) { - this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs; + this.mDhcpLeaseTimeSecs = dhcpLeaseTimeSecs; return this; } @@ -250,7 +288,7 @@ public class DhcpServingParams { * is optional and defaults to {@link #MTU_UNSET}. */ public Builder setLinkMtu(int linkMtu) { - this.linkMtu = linkMtu; + this.mLinkMtu = linkMtu; return this; } @@ -260,7 +298,7 @@ public class DhcpServingParams { * <p>If not set, the default value is false. */ public Builder setMetered(boolean metered) { - this.metered = metered; + this.mMetered = metered; return this; } @@ -274,54 +312,57 @@ public class DhcpServingParams { */ @NonNull public DhcpServingParams build() throws InvalidParameterException { - if (serverAddr == null) { + if (mServerAddr == null) { throw new InvalidParameterException("Missing serverAddr"); } - if (defaultRouters == null) { + if (mDefaultRouters == null) { throw new InvalidParameterException("Missing defaultRouters"); } - if (dnsServers == null) { + if (mDnsServers == null) { // Empty set is OK, but enforce explicitly setting it throw new InvalidParameterException("Missing dnsServers"); } - if (dhcpLeaseTimeSecs <= 0 || dhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) { - throw new InvalidParameterException("Invalid lease time: " + dhcpLeaseTimeSecs); + if (mDhcpLeaseTimeSecs <= 0 || mDhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) { + throw new InvalidParameterException("Invalid lease time: " + mDhcpLeaseTimeSecs); } - if (linkMtu != MTU_UNSET && (linkMtu < IPV4_MIN_MTU || linkMtu > IPV4_MAX_MTU)) { - throw new InvalidParameterException("Invalid link MTU: " + linkMtu); + if (mLinkMtu != MTU_UNSET && (mLinkMtu < IPV4_MIN_MTU || mLinkMtu > IPV4_MAX_MTU)) { + throw new InvalidParameterException("Invalid link MTU: " + mLinkMtu); } - if (!serverAddr.isIPv4()) { + if (!mServerAddr.isIPv4()) { throw new InvalidParameterException("serverAddr must be IPv4"); } - if (serverAddr.getPrefixLength() < MIN_PREFIX_LENGTH - || serverAddr.getPrefixLength() > MAX_PREFIX_LENGTH) { + if (mServerAddr.getPrefixLength() < MIN_PREFIX_LENGTH + || mServerAddr.getPrefixLength() > MAX_PREFIX_LENGTH) { throw new InvalidParameterException("Prefix length is not in supported range"); } - final IpPrefix prefix = makeIpPrefix(serverAddr); - for (Inet4Address addr : defaultRouters) { + final IpPrefix prefix = makeIpPrefix(mServerAddr); + for (Inet4Address addr : mDefaultRouters) { if (!prefix.contains(addr)) { throw new InvalidParameterException(String.format( - "Default router %s is not in server prefix %s", addr, serverAddr)); + "Default router %s is not in server prefix %s", addr, mServerAddr)); } } final Set<Inet4Address> excl = new HashSet<>(); - if (excludedAddrs != null) { - excl.addAll(excludedAddrs); + if (mExcludedAddrs != null) { + excl.addAll(mExcludedAddrs); } - excl.add((Inet4Address) serverAddr.getAddress()); - excl.addAll(defaultRouters); - excl.addAll(dnsServers); + excl.add((Inet4Address) mServerAddr.getAddress()); + excl.addAll(mDefaultRouters); + excl.addAll(mDnsServers); - return new DhcpServingParams(serverAddr, - Collections.unmodifiableSet(new HashSet<>(defaultRouters)), - Collections.unmodifiableSet(new HashSet<>(dnsServers)), + return new DhcpServingParams(mServerAddr, + Collections.unmodifiableSet(new HashSet<>(mDefaultRouters)), + Collections.unmodifiableSet(new HashSet<>(mDnsServers)), Collections.unmodifiableSet(excl), - dhcpLeaseTimeSecs, linkMtu, metered); + mDhcpLeaseTimeSecs, mLinkMtu, mMetered); } } + /** + * Utility method to create an IpPrefix with the address and prefix length of a LinkAddress. + */ @NonNull static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) { return new IpPrefix(addr.getAddress(), addr.getPrefixLength()); diff --git a/packages/NetworkStack/src/android/net/util/SharedLog.java b/packages/NetworkStack/src/android/net/util/SharedLog.java new file mode 100644 index 000000000000..74bc1470293f --- /dev/null +++ b/packages/NetworkStack/src/android/net/util/SharedLog.java @@ -0,0 +1,197 @@ +/* + * 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 android.net.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.text.TextUtils; +import android.util.LocalLog; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.StringJoiner; + + +/** + * Class to centralize logging functionality for tethering. + * + * All access to class methods other than dump() must be on the same thread. + * + * @hide + */ +public class SharedLog { + private static final int DEFAULT_MAX_RECORDS = 500; + private static final String COMPONENT_DELIMITER = "."; + + private enum Category { + NONE, + ERROR, + MARK, + WARN, + }; + + private final LocalLog mLocalLog; + // The tag to use for output to the system log. This is not output to the + // LocalLog because that would be redundant. + private final String mTag; + // The component (or subcomponent) of a system that is sharing this log. + // This can grow in depth if components call forSubComponent() to obtain + // their SharedLog instance. The tag is not included in the component for + // brevity. + private final String mComponent; + + public SharedLog(String tag) { + this(DEFAULT_MAX_RECORDS, tag); + } + + public SharedLog(int maxRecords, String tag) { + this(new LocalLog(maxRecords), tag, tag); + } + + private SharedLog(LocalLog localLog, String tag, String component) { + mLocalLog = localLog; + mTag = tag; + mComponent = component; + } + + /** + * Create a SharedLog based on this log with an additional component prefix on each logged line. + */ + public SharedLog forSubComponent(String component) { + if (!isRootLogInstance()) { + component = mComponent + COMPONENT_DELIMITER + component; + } + return new SharedLog(mLocalLog, mTag, component); + } + + /** + * Dump the contents of this log. + * + * <p>This method may be called on any thread. + */ + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + mLocalLog.readOnlyLocalLog().dump(fd, writer, args); + } + + ////// + // Methods that both log an entry and emit it to the system log. + ////// + + /** + * Log an error due to an exception. This does not include the exception stacktrace. + * + * <p>The log entry will be also added to the system log. + * @see #e(String, Throwable) + */ + public void e(Exception e) { + Log.e(mTag, record(Category.ERROR, e.toString())); + } + + /** + * Log an error message. + * + * <p>The log entry will be also added to the system log. + */ + public void e(String msg) { + Log.e(mTag, record(Category.ERROR, msg)); + } + + /** + * Log an error due to an exception, with the exception stacktrace if provided. + * + * <p>The error and exception message appear in the shared log, but the stacktrace is only + * logged in general log output (logcat). The log entry will be also added to the system log. + */ + public void e(@NonNull String msg, @Nullable Throwable exception) { + if (exception == null) { + e(msg); + return; + } + Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception); + } + + /** + * Log an informational message. + * + * <p>The log entry will be also added to the system log. + */ + public void i(String msg) { + Log.i(mTag, record(Category.NONE, msg)); + } + + /** + * Log a warning message. + * + * <p>The log entry will be also added to the system log. + */ + public void w(String msg) { + Log.w(mTag, record(Category.WARN, msg)); + } + + ////// + // Methods that only log an entry (and do NOT emit to the system log). + ////// + + /** + * Log a general message to be only included in the in-memory log. + * + * <p>The log entry will *not* be added to the system log. + */ + public void log(String msg) { + record(Category.NONE, msg); + } + + /** + * Log a general, formatted message to be only included in the in-memory log. + * + * <p>The log entry will *not* be added to the system log. + * @see String#format(String, Object...) + */ + public void logf(String fmt, Object... args) { + log(String.format(fmt, args)); + } + + /** + * Log a message with MARK level. + * + * <p>The log entry will *not* be added to the system log. + */ + public void mark(String msg) { + record(Category.MARK, msg); + } + + private String record(Category category, String msg) { + final String entry = logLine(category, msg); + mLocalLog.log(entry); + return entry; + } + + private String logLine(Category category, String msg) { + final StringJoiner sj = new StringJoiner(" "); + if (!isRootLogInstance()) sj.add("[" + mComponent + "]"); + if (category != Category.NONE) sj.add(category.toString()); + return sj.add(msg).toString(); + } + + // Check whether this SharedLog instance is nominally the top level in + // a potential hierarchy of shared logs (the root of a tree), + // or is a subcomponent within the hierarchy. + private boolean isRootLogInstance() { + return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag); + } +} diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java index 5afaf586f74d..7fea1e038cee 100644 --- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java +++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java @@ -16,15 +16,24 @@ package com.android.server; -import static android.os.Binder.getCallingUid; +import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT; +import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; +import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; + +import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Service; import android.content.Intent; import android.net.INetworkStackConnector; +import android.net.dhcp.DhcpServer; +import android.net.dhcp.DhcpServingParams; +import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.IDhcpServerCallbacks; +import android.net.util.SharedLog; import android.os.IBinder; -import android.os.Process; +import android.os.RemoteException; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -54,21 +63,37 @@ public class NetworkStackService extends Service { } private static class NetworkStackConnector extends INetworkStackConnector.Stub { - // TODO: makeDhcpServer(), etc. will go here. + @NonNull + private final SharedLog mLog = new SharedLog(TAG); + + @Override + public void makeDhcpServer(@NonNull String ifName, @NonNull DhcpServingParamsParcel params, + @NonNull IDhcpServerCallbacks cb) throws RemoteException { + checkNetworkStackCallingPermission(); + final DhcpServer server; + try { + server = new DhcpServer( + ifName, + DhcpServingParams.fromParcelableObject(params), + mLog.forSubComponent(ifName + ".DHCP")); + } catch (DhcpServingParams.InvalidParameterException e) { + mLog.e("Invalid DhcpServingParams", e); + cb.onDhcpServerCreated(STATUS_INVALID_ARGUMENT, null); + return; + } catch (Exception e) { + mLog.e("Unknown error starting DhcpServer", e); + cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); + return; + } + cb.onDhcpServerCreated(STATUS_SUCCESS, server); + } @Override protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args) { - checkCaller(); + checkNetworkStackCallingPermission(); fout.println("NetworkStack logs:"); - // TODO: dump logs here - } - } - - private static void checkCaller() { - // TODO: check that the calling PID is the system server. - if (getCallingUid() != Process.SYSTEM_UID && getCallingUid() != Process.ROOT_UID) { - throw new SecurityException("Invalid caller: " + getCallingUid()); + mLog.dump(fd, fout, args); } } } diff --git a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java new file mode 100644 index 000000000000..bb5900c53e52 --- /dev/null +++ b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java @@ -0,0 +1,45 @@ +/* + * 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.util; + +/** + * Network constants used by the network stack. + */ +public final class NetworkStackConstants { + + /** + * IPv4 constants. + * + * See also: + * - https://tools.ietf.org/html/rfc791 + */ + public static final int IPV4_ADDR_BITS = 32; + public static final int IPV4_MIN_MTU = 68; + public static final int IPV4_MAX_MTU = 65_535; + + /** + * DHCP constants. + * + * See also: + * - https://tools.ietf.org/html/rfc2131 + */ + public static final int INFINITE_LEASE = 0xffffffff; + + private NetworkStackConstants() { + throw new UnsupportedOperationException("This class is not to be instantiated"); + } +} diff --git a/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java b/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java new file mode 100644 index 000000000000..733f87393c32 --- /dev/null +++ b/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java @@ -0,0 +1,42 @@ +/* + * 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.util; + +import static android.os.Binder.getCallingUid; + +import android.os.Process; + +/** + * Utility class to check calling permissions on the network stack. + */ +public final class PermissionUtil { + + /** + * Check that the caller is allowed to communicate with the network stack. + * @throws SecurityException The caller is not allowed to communicate with the network stack. + */ + public static void checkNetworkStackCallingPermission() { + // TODO: check that the calling PID is the system server. + if (getCallingUid() != Process.SYSTEM_UID && getCallingUid() != Process.ROOT_UID) { + throw new SecurityException("Invalid caller: " + getCallingUid()); + } + } + + private PermissionUtil() { + throw new UnsupportedOperationException("This class is not to be instantiated"); + } +} diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp new file mode 100644 index 000000000000..bd7ff2a75703 --- /dev/null +++ b/packages/NetworkStack/tests/Android.bp @@ -0,0 +1,35 @@ +// +// 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. +// + +android_test { + name: "NetworkStackTests", + srcs: ["src/**/*.java"], + static_libs: [ + "android-support-test", + "mockito-target-extended-minus-junit4", + "NetworkStackLib", + "testables", + ], + libs: [ + "android.test.runner", + "android.test.base", + ], + jni_libs: [ + // For mockito extended + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ] +}
\ No newline at end of file diff --git a/packages/NetworkStack/tests/AndroidManifest.xml b/packages/NetworkStack/tests/AndroidManifest.xml new file mode 100644 index 000000000000..8b8474f57e28 --- /dev/null +++ b/packages/NetworkStack/tests/AndroidManifest.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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.server.networkstack.tests"> + <application android:debuggable="true"> + <uses-library android:name="android.test.runner" /> + </application> + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.server.networkstack.tests" + android:label="Networking service tests"> + </instrumentation> +</manifest>
\ No newline at end of file diff --git a/packages/NetworkStack/tests/AndroidTest.xml b/packages/NetworkStack/tests/AndroidTest.xml new file mode 100644 index 000000000000..6b08b57731b7 --- /dev/null +++ b/packages/NetworkStack/tests/AndroidTest.xml @@ -0,0 +1,29 @@ +<?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. +--> +<configuration description="Runs Tests for NetworkStack"> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="NetworkStackTests.apk" /> + </target_preparer> + + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="framework-base-presubmit" /> + <option name="test-tag" value="NetworkStackTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.server.networkstack.tests" /> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration>
\ No newline at end of file diff --git a/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java index 7f8e7b5456c2..51d50d9eb13a 100644 --- a/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java +++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java @@ -16,6 +16,7 @@ package android.net.dhcp; +import static android.net.InetAddresses.parseNumericAddress; import static android.net.dhcp.DhcpLease.HOSTNAME_NONE; import static android.net.dhcp.DhcpLeaseRepository.CLIENTID_UNSPEC; import static android.net.dhcp.DhcpLeaseRepository.INETADDR_UNSPEC; @@ -29,14 +30,13 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.when; import static java.lang.String.format; -import static java.net.InetAddress.parseNumericAddress; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.IpPrefix; import android.net.MacAddress; -import android.net.util.SharedLog; import android.net.dhcp.DhcpServer.Clock; +import android.net.util.SharedLog; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -126,7 +126,7 @@ public class DhcpLeaseRepositoryTest { mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS); // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses - requestAddresses((byte)11); + requestAddresses((byte) 11); try { mRepo.getOffer(null, TEST_MAC_2, diff --git a/tests/net/java/android/net/dhcp/DhcpServerTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java index ab9bd84b05cb..d4c1e2e16731 100644 --- a/tests/net/java/android/net/dhcp/DhcpServerTest.java +++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java @@ -16,11 +16,13 @@ package android.net.dhcp; +import static android.net.InetAddresses.parseNumericAddress; import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME; import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; import static android.net.dhcp.DhcpPacket.INADDR_ANY; import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; +import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -33,14 +35,14 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static java.net.InetAddress.parseNumericAddress; - import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.INetworkStackStatusCallback; import android.net.LinkAddress; import android.net.MacAddress; import android.net.dhcp.DhcpLeaseRepository.InvalidAddressException; @@ -48,9 +50,11 @@ import android.net.dhcp.DhcpLeaseRepository.OutOfAddressesException; import android.net.dhcp.DhcpServer.Clock; import android.net.dhcp.DhcpServer.Dependencies; import android.net.util.SharedLog; -import android.os.test.TestLooper; +import android.os.HandlerThread; import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.testing.TestableLooper.RunWithLooper; import org.junit.After; import org.junit.Before; @@ -67,10 +71,10 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; -@RunWith(AndroidJUnit4.class) +@RunWith(AndroidTestingRunner.class) @SmallTest +@RunWithLooper public class DhcpServerTest { - private static final String PROP_DEXMAKER_SHARE_CLASSLOADER = "dexmaker.share_classloader"; private static final String TEST_IFACE = "testiface"; private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2"); @@ -113,18 +117,25 @@ public class DhcpServerTest { private ArgumentCaptor<Inet4Address> mResponseDstAddrCaptor; @NonNull - private TestLooper mLooper; + private HandlerThread mHandlerThread; + @NonNull + private TestableLooper mLooper; @NonNull private DhcpServer mServer; @Nullable private String mPrevShareClassloaderProp; + private final INetworkStackStatusCallback mAssertSuccessCallback = + new INetworkStackStatusCallback.Stub() { + @Override + public void onStatusAvailable(int statusCode) { + assertEquals(STATUS_SUCCESS, statusCode); + } + }; + @Before public void setUp() throws Exception { - // Allow mocking package-private classes - mPrevShareClassloaderProp = System.getProperty(PROP_DEXMAKER_SHARE_CLASSLOADER); - System.setProperty(PROP_DEXMAKER_SHARE_CLASSLOADER, "true"); MockitoAnnotations.initMocks(this); when(mDeps.makeLeaseRepository(any(), any(), any())).thenReturn(mRepository); @@ -143,20 +154,22 @@ public class DhcpServerTest { .setExcludedAddrs(TEST_EXCLUDED_ADDRS) .build(); - mLooper = new TestLooper(); - mServer = new DhcpServer(mLooper.getLooper(), TEST_IFACE, servingParams, + mLooper = TestableLooper.get(this); + mHandlerThread = spy(new HandlerThread("TestDhcpServer")); + when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper()); + mServer = new DhcpServer(mHandlerThread, TEST_IFACE, servingParams, new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps); - mServer.start(); - mLooper.dispatchAll(); + mServer.start(mAssertSuccessCallback); + mLooper.processAllMessages(); } @After - public void tearDown() { - // Calling stop() several times is not an issue - mServer.stop(); - System.setProperty(PROP_DEXMAKER_SHARE_CLASSLOADER, - (mPrevShareClassloaderProp == null ? "" : mPrevShareClassloaderProp)); + public void tearDown() throws Exception { + mServer.stop(mAssertSuccessCallback); + mLooper.processMessages(1); + verify(mPacketListener, times(1)).stop(); + verify(mHandlerThread, times(1)).quitSafely(); } @Test @@ -165,13 +178,6 @@ public class DhcpServerTest { } @Test - public void testStop() throws Exception { - mServer.stop(); - mLooper.dispatchAll(); - verify(mPacketListener, times(1)).stop(); - } - - @Test public void testDiscover() throws Exception { // TODO: refactor packet construction to eliminate unnecessary/confusing/duplicate fields when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC), diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java index b6a4073a64da..3ca0564f24d6 100644 --- a/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java +++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java @@ -16,17 +16,18 @@ package android.net.dhcp; +import static android.net.InetAddresses.parseNumericAddress; +import static android.net.NetworkUtils.inet4AddressToIntHTH; import static android.net.dhcp.DhcpServingParams.MTU_UNSET; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; -import static java.net.InetAddress.parseNumericAddress; - import android.annotation.NonNull; import android.annotation.Nullable; import android.net.LinkAddress; +import android.net.NetworkUtils; import android.net.dhcp.DhcpServingParams.InvalidParameterException; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -35,8 +36,10 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.lang.reflect.Modifier; import java.net.Inet4Address; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -56,6 +59,7 @@ public class DhcpServingParamsTest { private static final int TEST_MTU = 1500; private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>( Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201"))); + private static final boolean TEST_METERED = true; @Before public void setUp() { @@ -65,7 +69,8 @@ public class DhcpServingParamsTest { .setDnsServers(TEST_DNS_SERVERS) .setServerAddr(TEST_LINKADDR) .setLinkMtu(TEST_MTU) - .setExcludedAddrs(TEST_EXCLUDED_ADDRS); + .setExcludedAddrs(TEST_EXCLUDED_ADDRS) + .setMetered(TEST_METERED); } @Test @@ -91,6 +96,7 @@ public class DhcpServingParamsTest { assertEquals(TEST_DNS_SERVERS, params.dnsServers); assertEquals(TEST_LINKADDR, params.serverAddr); assertEquals(TEST_MTU, params.linkMtu); + assertEquals(TEST_METERED, params.metered); assertContains(params.excludedAddrs, TEST_EXCLUDED_ADDRS); assertContains(params.excludedAddrs, TEST_DEFAULT_ROUTERS); @@ -159,6 +165,44 @@ public class DhcpServingParamsTest { mBuilder.setDefaultRouters(parseAddr("192.168.254.254")).build(); } + @Test + public void testFromParcelableObject() throws InvalidParameterException { + final DhcpServingParams params = mBuilder.build(); + final DhcpServingParamsParcel parcel = new DhcpServingParamsParcel(); + parcel.defaultRouters = toIntArray(TEST_DEFAULT_ROUTERS); + parcel.dhcpLeaseTimeSecs = TEST_LEASE_TIME_SECS; + parcel.dnsServers = toIntArray(TEST_DNS_SERVERS); + parcel.serverAddr = inet4AddressToIntHTH(TEST_SERVER_ADDR); + parcel.serverAddrPrefixLength = TEST_LINKADDR.getPrefixLength(); + parcel.linkMtu = TEST_MTU; + parcel.excludedAddrs = toIntArray(TEST_EXCLUDED_ADDRS); + parcel.metered = TEST_METERED; + final DhcpServingParams parceled = DhcpServingParams.fromParcelableObject(parcel); + + assertEquals(params.defaultRouters, parceled.defaultRouters); + assertEquals(params.dhcpLeaseTimeSecs, parceled.dhcpLeaseTimeSecs); + assertEquals(params.dnsServers, parceled.dnsServers); + assertEquals(params.serverAddr, parceled.serverAddr); + assertEquals(params.linkMtu, parceled.linkMtu); + assertEquals(params.excludedAddrs, parceled.excludedAddrs); + assertEquals(params.metered, parceled.metered); + + // Ensure that we do not miss any field if added in the future + final long numFields = Arrays.stream(DhcpServingParams.class.getDeclaredFields()) + .filter(f -> !Modifier.isStatic(f.getModifiers())) + .count(); + assertEquals(7, numFields); + } + + @Test(expected = InvalidParameterException.class) + public void testFromParcelableObject_NullArgument() throws InvalidParameterException { + DhcpServingParams.fromParcelableObject(null); + } + + private static int[] toIntArray(Collection<Inet4Address> addrs) { + return addrs.stream().mapToInt(NetworkUtils::inet4AddressToIntHTH).toArray(); + } + private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) { for (final T elem : subset) { assertContains(set, elem); diff --git a/packages/NetworkStack/tests/src/com/android/server/util/SharedLogTest.java b/packages/NetworkStack/tests/src/com/android/server/util/SharedLogTest.java new file mode 100644 index 000000000000..07ad3123bc53 --- /dev/null +++ b/packages/NetworkStack/tests/src/com/android/server/util/SharedLogTest.java @@ -0,0 +1,96 @@ +/* + * 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.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.net.util.SharedLog; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class SharedLogTest { + private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}"; + private static final String TIMESTAMP = "HH:MM:SS"; + + @Test + public void testBasicOperation() { + final SharedLog logTop = new SharedLog("top"); + logTop.mark("first post!"); + + final SharedLog logLevel2a = logTop.forSubComponent("twoA"); + final SharedLog logLevel2b = logTop.forSubComponent("twoB"); + logLevel2b.e("2b or not 2b"); + logLevel2b.e("No exception", null); + logLevel2b.e("Wait, here's one", new Exception("Test")); + logLevel2a.w("second post?"); + + final SharedLog logLevel3 = logLevel2a.forSubComponent("three"); + logTop.log("still logging"); + logLevel3.log("3 >> 2"); + logLevel2a.mark("ok: last post"); + + final String[] expected = { + " - MARK first post!", + " - [twoB] ERROR 2b or not 2b", + " - [twoB] ERROR No exception", + // No stacktrace in shared log, only in logcat + " - [twoB] ERROR Wait, here's one: Test", + " - [twoA] WARN second post?", + " - still logging", + " - [twoA.three] 3 >> 2", + " - [twoA] MARK ok: last post", + }; + // Verify the logs are all there and in the correct order. + verifyLogLines(expected, logTop); + + // In fact, because they all share the same underlying LocalLog, + // every subcomponent SharedLog's dump() is identical. + verifyLogLines(expected, logLevel2a); + verifyLogLines(expected, logLevel2b); + verifyLogLines(expected, logLevel3); + } + + private static void verifyLogLines(String[] expected, SharedLog log) { + final ByteArrayOutputStream ostream = new ByteArrayOutputStream(); + final PrintWriter pw = new PrintWriter(ostream, true); + log.dump(null, pw, null); + + final String dumpOutput = ostream.toString(); + assertTrue(dumpOutput != null); + assertTrue(!"".equals(dumpOutput)); + + final String[] lines = dumpOutput.split("\n"); + assertEquals(expected.length, lines.length); + + for (int i = 0; i < expected.length; i++) { + String got = lines[i]; + String want = expected[i]; + assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want)); + assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP), + got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP)); + } + } +} diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java index eed66e94a9ef..d332bac3bb6d 100644 --- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java +++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java @@ -77,7 +77,7 @@ import java.util.Arrays; */ public class BarChartPreference extends Preference { - static final int MAXIMUM_BAR_VIEWS = 4; + public static final int MAXIMUM_BAR_VIEWS = 4; private static final String TAG = "BarChartPreference"; private static final int[] BAR_VIEWS = { R.id.bar_view1, diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 7dcc3acb1dae..03c620580423 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1137,9 +1137,6 @@ <!-- The notice header of Third-party licenses. not translatable --> <string name="notice_header" translatable="false"></string> - <!-- UI debug setting: opt in to use updated graphics driver? [CHAR LIMIT=100] --> - <string name="gup_dev_opt_in_app_summary">Opt in app to use Game Update Package in developement</string> - <!-- Name of the phone device [CHAR LIMIT=NONE] --> <string name="media_transfer_phone_device_name">Phone speaker</string> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index 6abe76a1e753..595aeb3ecc10 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -1,5 +1,7 @@ package com.android.settingslib; +import static android.telephony.ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN; + import android.annotation.ColorInt; import android.content.Context; import android.content.Intent; @@ -429,12 +431,14 @@ public class Utils { // and do not support voice service, and on these SIM cards, we // want to show signal bars for data service as well as the "no // service" or "emergency calls only" text that indicates that voice - // is not available. + // is not available. Note that we ignore the IWLAN service state + // because that state indicates the use of VoWIFI and not cell service int state = serviceState.getState(); int dataState = serviceState.getDataRegState(); if (state == ServiceState.STATE_OUT_OF_SERVICE || state == ServiceState.STATE_EMERGENCY_ONLY) { - if (dataState == ServiceState.STATE_IN_SERVICE) { + if (dataState == ServiceState.STATE_IN_SERVICE + && serviceState.getDataNetworkType() != RIL_RADIO_TECHNOLOGY_IWLAN) { return ServiceState.STATE_IN_SERVICE; } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java index 594d767675c8..86f04389604c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java @@ -247,6 +247,15 @@ public class UtilsTest { } @Test + public void isInService_voiceOutOfServiceDataInServiceOnIwLan_returnFalse() { + when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); + when(mServiceState.getDataNetworkType()) + .thenReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN); + when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE); + assertThat(Utils.isInService(mServiceState)).isFalse(); + } + + @Test public void isInService_voiceOutOfServiceDataOutOfService_returnFalse() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 526efcb35262..419273ee28bb 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -708,6 +708,9 @@ class SettingsProtoDumpUtil { Settings.Global.GUP_DEV_OPT_IN_APPS, GlobalSettingsProto.Gpu.GUP_DEV_OPT_IN_APPS); dumpSetting(s, p, + Settings.Global.GUP_DEV_OPT_OUT_APPS, + GlobalSettingsProto.Gpu.GUP_DEV_OPT_OUT_APPS); + dumpSetting(s, p, Settings.Global.GUP_BLACK_LIST, GlobalSettingsProto.Gpu.GUP_BLACK_LIST); p.end(gpuToken); diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 4e0cbe093c49..ed18dc728402 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -24,14 +24,13 @@ android:layout_gravity="@integer/notification_panel_layout_gravity" android:background="@android:color/transparent" android:baselineAligned="false" - android:clickable="true" + android:clickable="false" android:clipChildren="false" android:clipToPadding="false" android:paddingTop="0dp" android:paddingEnd="0dp" android:paddingStart="0dp" - android:elevation="4dp" - android:importantForAccessibility="no" > + android:elevation="4dp" > <include layout="@layout/quick_status_bar_header_system_icons" /> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 570d351a8b71..27d624ab0b58 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -16,6 +16,8 @@ import com.android.systemui.Dependency; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import java.util.Objects; import java.util.TimeZone; @@ -82,6 +84,24 @@ public class KeyguardClockSwitch extends RelativeLayout { } } }; + private final StatusBarStateController.StateListener mStateListener = + new StatusBarStateController.StateListener() { + @Override + public void onStateChanged(int newState) { + if (mBigClockContainer == null) { + return; + } + if (newState == StatusBarState.SHADE) { + if (mBigClockContainer.getVisibility() == View.VISIBLE) { + mBigClockContainer.setVisibility(View.INVISIBLE); + } + } else { + if (mBigClockContainer.getVisibility() == View.INVISIBLE) { + mBigClockContainer.setVisibility(View.VISIBLE); + } + } + } + }; public KeyguardClockSwitch(Context context) { this(context, null); @@ -104,12 +124,14 @@ public class KeyguardClockSwitch extends RelativeLayout { super.onAttachedToWindow(); Dependency.get(PluginManager.class).addPluginListener(mClockPluginListener, ClockPlugin.class); + Dependency.get(StatusBarStateController.class).addCallback(mStateListener); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); Dependency.get(PluginManager.class).removePluginListener(mClockPluginListener); + Dependency.get(StatusBarStateController.class).removeCallback(mStateListener); } /** @@ -238,4 +260,9 @@ public class KeyguardClockSwitch extends RelativeLayout { PluginListener getClockPluginListener() { return mClockPluginListener; } + + @VisibleForTesting (otherwise = VisibleForTesting.NONE) + StatusBarStateController.StateListener getStateListener() { + return mStateListener; + } } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 3cc9bb6f668f..9d810645f6a2 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -56,12 +56,12 @@ import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationRowBinder; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java index b0b7e6c88984..96b62ac918ab 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java @@ -24,9 +24,9 @@ import android.service.notification.StatusBarNotification; import android.util.Log; import com.android.internal.statusbar.NotificationVisibility; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import javax.inject.Inject; import javax.inject.Singleton; @@ -49,18 +49,18 @@ public class ForegroundServiceNotificationListener { mForegroundServiceController = foregroundServiceController; notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override - public void onPendingEntryAdded(NotificationData.Entry entry) { + public void onPendingEntryAdded(NotificationEntry entry) { addNotification(entry.notification, entry.importance); } @Override - public void onEntryUpdated(NotificationData.Entry entry) { + public void onPostEntryUpdated(NotificationEntry entry) { updateNotification(entry.notification, entry.importance); } @Override public void onEntryRemoved( - NotificationData.Entry entry, + NotificationEntry entry, NotificationVisibility visibility, boolean removedByUser) { removeNotification(entry.notification); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 5347a5cb16b6..d0111cb1a5b3 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -40,9 +40,9 @@ import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; import com.android.systemui.statusbar.ScrimView; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 644723321103..75776098decf 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -35,9 +35,9 @@ import android.widget.FrameLayout; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.StatusBarWindowController; import java.util.ArrayList; @@ -180,7 +180,7 @@ public class BubbleController { /** * Adds a bubble associated with the provided notification entry or updates it if it exists. */ - public void addBubble(NotificationData.Entry notif) { + public void addBubble(NotificationEntry notif) { if (mBubbles.containsKey(notif.key)) { // It's an update BubbleView bubble = mBubbles.get(notif.key); @@ -226,7 +226,7 @@ public class BubbleController { bv.getEntry().setBubbleDismissed(true); } - NotificationData.Entry entry = mNotificationEntryManager.getNotificationData().get(key); + NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key); if (entry != null) { entry.setBubbleDismissed(true); if (!DEBUG_DEMOTE_TO_NOTIF) { @@ -241,7 +241,7 @@ public class BubbleController { @SuppressWarnings("FieldCanBeLocal") private final NotificationEntryListener mEntryListener = new NotificationEntryListener() { @Override - public void onPendingEntryAdded(NotificationData.Entry entry) { + public void onPendingEntryAdded(NotificationEntry entry) { if (shouldAutoBubble(mContext, entry)) { entry.setIsBubble(true); } @@ -275,7 +275,7 @@ public class BubbleController { } ArrayList<BubbleView> viewsToRemove = new ArrayList<>(); for (BubbleView bv : mBubbles.values()) { - NotificationData.Entry entry = bv.getEntry(); + NotificationEntry entry = bv.getEntry(); if (entry != null) { if (entry.isRowRemoved() || entry.isBubbleDismissed() || entry.isRowDismissed()) { viewsToRemove.add(bv); @@ -332,7 +332,7 @@ public class BubbleController { /** * Whether the notification should bubble or not. */ - private static boolean shouldAutoBubble(Context context, NotificationData.Entry entry) { + private static boolean shouldAutoBubble(Context context, NotificationEntry entry) { if (entry.isBubbleDismissed()) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index dfd18b23a5e3..d69e7b3ae924 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -40,7 +40,7 @@ import androidx.annotation.Nullable; import com.android.internal.widget.ViewClippingUtil; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.ViewState; @@ -247,7 +247,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F * @param bubbleView the view to update in the stack. * @param entry the entry to update it with. */ - public void updateBubble(BubbleView bubbleView, NotificationData.Entry entry) { + public void updateBubble(BubbleView bubbleView, NotificationEntry entry) { // TODO - move to top of bubble stack, make it show its update if it makes sense bubbleView.update(entry); if (bubbleView.equals(mExpandedBubble)) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java index 6c47aac712f6..3307992e779a 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java @@ -31,7 +31,7 @@ import android.widget.LinearLayout; import com.android.internal.util.ContrastColorUtil; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; /** @@ -43,7 +43,7 @@ public class BubbleView extends LinearLayout implements BubbleTouchHandler.Float private Context mContext; private View mIconView; - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; private int mBubbleSize; private int mIconSize; @@ -72,7 +72,7 @@ public class BubbleView extends LinearLayout implements BubbleTouchHandler.Float * * @param entry the notification to display as a bubble. */ - public void setNotif(NotificationData.Entry entry) { + public void setNotif(NotificationEntry entry) { removeAllViews(); // TODO: migrate to inflater mIconView = new ImageView(mContext); @@ -89,7 +89,7 @@ public class BubbleView extends LinearLayout implements BubbleTouchHandler.Float /** * Updates the UI based on the entry. */ - public void update(NotificationData.Entry entry) { + public void update(NotificationEntry entry) { mEntry = entry; Notification n = entry.notification.getNotification(); Icon ic = n.getLargeIcon() != null ? n.getLargeIcon() : n.getSmallIcon(); @@ -112,7 +112,7 @@ public class BubbleView extends LinearLayout implements BubbleTouchHandler.Float /** * @return the notification entry associated with this bubble. */ - public NotificationData.Entry getEntry() { + public NotificationEntry getEntry() { return mEntry; } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index 6a0e8ad35736..c4c8bc703802 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -50,9 +50,9 @@ import androidx.slice.builders.SliceAction; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.NextAlarmControllerImpl; import com.android.systemui.statusbar.policy.ZenModeController; @@ -68,7 +68,7 @@ import java.util.concurrent.TimeUnit; */ public class KeyguardSliceProvider extends SliceProvider implements NextAlarmController.NextAlarmChangeCallback, ZenModeController.Callback, - NotificationMediaManager.MediaListener { + NotificationMediaManager.MediaListener, StatusBarStateController.StateListener { private static final StyleSpan BOLD_STYLE = new StyleSpan(Typeface.BOLD); public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main"; @@ -109,7 +109,9 @@ public class KeyguardSliceProvider extends SliceProvider implements private AlarmManager.AlarmClockInfo mNextAlarmInfo; private PendingIntent mPendingIntent; protected NotificationMediaManager mMediaManager; + private StatusBarStateController mStatusBarStateController; protected MediaMetadata mMediaMetaData; + protected boolean mDozing; /** * Receiver responsible for time ticking and updating the date format. @@ -167,9 +169,20 @@ public class KeyguardSliceProvider extends SliceProvider implements mMediaUri = Uri.parse(KEYGUARD_MEDIA_URI); } - public void initDependencies() { - mMediaManager = Dependency.get(NotificationMediaManager.class); + /** + * Initialize dependencies that don't exist during {@link android.content.ContentProvider} + * instantiation. + * + * @param mediaManager {@link NotificationMediaManager} singleton. + * @param statusBarStateController {@link StatusBarStateController} singleton. + */ + public void initDependencies( + NotificationMediaManager mediaManager, + StatusBarStateController statusBarStateController) { + mMediaManager = mediaManager; mMediaManager.addCallback(this); + mStatusBarStateController = statusBarStateController; + mStatusBarStateController.addCallback(this); } @AnyThread @@ -179,7 +192,7 @@ public class KeyguardSliceProvider extends SliceProvider implements Slice slice; synchronized (this) { ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); - if (mMediaMetaData != null) { + if (needsMediaLocked()) { addMediaLocked(builder); } else { builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText)); @@ -193,6 +206,10 @@ public class KeyguardSliceProvider extends SliceProvider implements return slice; } + protected boolean needsMediaLocked() { + return mMediaMetaData != null && mDozing; + } + protected void addMediaLocked(ListBuilder listBuilder) { if (mMediaMetaData != null) { SpannableStringBuilder builder = new SpannableStringBuilder(); @@ -209,7 +226,7 @@ public class KeyguardSliceProvider extends SliceProvider implements } RowBuilder mediaBuilder = new RowBuilder(mMediaUri).setTitle(builder); - Icon notificationIcon = mMediaManager.getMediaIcon(); + Icon notificationIcon = mMediaManager == null ? null : mMediaManager.getMediaIcon(); if (notificationIcon != null) { IconCompat icon = IconCompat.createFromIcon(notificationIcon); mediaBuilder.addEndItem(icon, ListBuilder.ICON_IMAGE); @@ -389,13 +406,35 @@ public class KeyguardSliceProvider extends SliceProvider implements @Override public void onMetadataChanged(MediaMetadata metadata) { + final boolean notify; synchronized (this) { + boolean neededMedia = needsMediaLocked(); mMediaMetaData = metadata; + notify = neededMedia != needsMediaLocked(); + } + if (notify) { + notifyChange(); } - notifyChange(); } protected void notifyChange() { mContentResolver.notifyChange(mSliceUri, null /* observer */); } + + @Override + public void onDozingChanged(boolean isDozing) { + final boolean notify; + synchronized (this) { + boolean neededMedia = needsMediaLocked(); + mDozing = isDozing; + notify = neededMedia != needsMediaLocked(); + } + if (notify) { + notifyChange(); + } + } + + @Override + public void onStateChanged(int newState) { + } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java index 1e0d4d01f167..b09d6e163b77 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java @@ -36,8 +36,7 @@ public class PipAppOpsListener { private Handler mHandler; private IActivityManager mActivityManager; private AppOpsManager mAppOpsManager; - - private PipMotionHelper mMotionHelper; + private Callback mCallback; private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() { @Override @@ -52,7 +51,7 @@ public class PipAppOpsListener { if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) && mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid, packageName) != MODE_ALLOWED) { - mHandler.post(() -> mMotionHelper.dismissPip()); + mHandler.post(() -> mCallback.dismissPip()); } } } catch (NameNotFoundException e) { @@ -63,12 +62,12 @@ public class PipAppOpsListener { }; public PipAppOpsListener(Context context, IActivityManager activityManager, - PipMotionHelper motionHelper) { + Callback callback) { mContext = context; mHandler = new Handler(mContext.getMainLooper()); mActivityManager = activityManager; mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - mMotionHelper = motionHelper; + mCallback = callback; } public void onActivityPinned(String packageName) { @@ -89,4 +88,10 @@ public class PipAppOpsListener { private void unregisterAppOpsListener() { mAppOpsManager.stopWatchingMode(mAppOpsChangedListener); } -}
\ No newline at end of file + + /** Callback for PipAppOpsListener to request changes to the PIP window. */ + public interface Callback { + /** Dismisses the PIP window. */ + void dismissPip(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 38583564f5b0..82aa4737af99 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -55,7 +55,7 @@ import java.io.PrintWriter; /** * A helper to animate and manipulate the PiP. */ -public class PipMotionHelper implements Handler.Callback { +public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback { private static final String TAG = "PipMotionHelper"; private static final boolean DEBUG = false; @@ -172,7 +172,8 @@ public class PipMotionHelper implements Handler.Callback { /** * Dismisses the pinned stack. */ - void dismissPip() { + @Override + public void dismissPip() { if (DEBUG) { Log.d(TAG, "dismissPip: callers=\n" + Debug.getCallers(5, " ")); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java index e63f88a898cc..e030e404af6a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java @@ -284,17 +284,10 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, public void updateEverything() { post(() -> { updateVisibilities(); - updateClickabilities(); setClickable(false); }); } - private void updateClickabilities() { - mMultiUserSwitch.setClickable(mMultiUserSwitch.getVisibility() == View.VISIBLE); - mEdit.setClickable(mEdit.getVisibility() == View.VISIBLE); - mSettingsButton.setClickable(mSettingsButton.getVisibility() == View.VISIBLE); - } - private void updateVisibilities() { mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE); mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 72245999b084..40c60396e40d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -426,6 +426,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements if (mExpanded == expanded) return; mExpanded = expanded; mHeaderQsPanel.setExpanded(expanded); + updateEverything(); } /** @@ -697,6 +698,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements .start(); } + public void updateEverything() { + post(() -> setClickable(false)); + } + public void setQSPanel(final QSPanel qsPanel) { mQsPanel = qsPanel; setupHost(qsPanel.getHost()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java index bc381699494a..a776d0fbb45e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java @@ -16,8 +16,6 @@ package com.android.systemui.statusbar; -import static com.android.systemui.statusbar.notification.NotificationData.Entry; - import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; @@ -29,6 +27,7 @@ import android.util.Log; import android.view.accessibility.AccessibilityEvent; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import java.util.stream.Stream; @@ -48,7 +47,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim * NotificationManagerService side, but we keep it to prevent the UI from looking weird and * will remove when possible. See {@link NotificationLifetimeExtender} */ - protected final ArraySet<Entry> mExtendedLifetimeAlertEntries = new ArraySet<>(); + protected final ArraySet<NotificationEntry> mExtendedLifetimeAlertEntries = new ArraySet<>(); protected NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback; protected int mMinimumDisplayTime; @@ -61,7 +60,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim * Adds the notification to be managed. * @param entry entry to show */ - public void showNotification(@NonNull Entry entry) { + public void showNotification(@NonNull NotificationEntry entry) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "showNotification"); } @@ -139,7 +138,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim * @return the entry */ @Nullable - public Entry getEntry(@NonNull String key) { + public NotificationEntry getEntry(@NonNull String key) { AlertEntry entry = mAlertEntries.get(key); return entry != null ? entry.mEntry : null; } @@ -149,7 +148,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim * @return all entries */ @NonNull - public Stream<Entry> getAllEntries() { + public Stream<NotificationEntry> getAllEntries() { return mAlertEntries.values().stream().map(headsUpEntry -> headsUpEntry.mEntry); } @@ -180,7 +179,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim * Add a new entry and begin managing it. * @param entry the entry to add */ - protected final void addAlertEntry(@NonNull Entry entry) { + protected final void addAlertEntry(@NonNull NotificationEntry entry) { AlertEntry alertEntry = createAlertEntry(); alertEntry.setEntry(entry); mAlertEntries.put(entry.key, alertEntry); @@ -203,7 +202,7 @@ public abstract class AlertingNotificationManager implements NotificationLifetim if (alertEntry == null) { return; } - Entry entry = alertEntry.mEntry; + NotificationEntry entry = alertEntry.mEntry; mAlertEntries.remove(key); onAlertEntryRemoved(alertEntry); entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); @@ -250,12 +249,12 @@ public abstract class AlertingNotificationManager implements NotificationLifetim } @Override - public boolean shouldExtendLifetime(Entry entry) { + public boolean shouldExtendLifetime(NotificationEntry entry) { return !canRemoveImmediately(entry.key); } @Override - public void setShouldManageLifetime(Entry entry, boolean shouldExtend) { + public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) { if (shouldExtend) { mExtendedLifetimeAlertEntries.add(entry); } else { @@ -265,17 +264,17 @@ public abstract class AlertingNotificationManager implements NotificationLifetim /////////////////////////////////////////////////////////////////////////////////////////////// protected class AlertEntry implements Comparable<AlertEntry> { - @Nullable public Entry mEntry; + @Nullable public NotificationEntry mEntry; public long mPostTime; public long mEarliestRemovaltime; @Nullable protected Runnable mRemoveAlertRunnable; - public void setEntry(@NonNull final Entry entry) { + public void setEntry(@NonNull final NotificationEntry entry) { setEntry(entry, () -> removeAlertEntry(entry.key)); } - public void setEntry(@NonNull final Entry entry, + public void setEntry(@NonNull final NotificationEntry entry, @Nullable Runnable removeAlertRunnable) { mEntry = entry; mRemoveAlertRunnable = removeAlertRunnable; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java index 9bfd4ee24ff0..a3beb96780d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java @@ -25,7 +25,7 @@ import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import javax.inject.Inject; @@ -83,7 +83,7 @@ public class AmbientPulseManager extends AlertingNotificationManager { @Override protected void onAlertEntryAdded(AlertEntry alertEntry) { - NotificationData.Entry entry = alertEntry.mEntry; + NotificationEntry entry = alertEntry.mEntry; entry.setAmbientPulsing(true); for (OnAmbientChangedListener listener : mListeners) { listener.onAmbientStateChanged(entry, true); @@ -92,7 +92,7 @@ public class AmbientPulseManager extends AlertingNotificationManager { @Override protected void onAlertEntryRemoved(AlertEntry alertEntry) { - NotificationData.Entry entry = alertEntry.mEntry; + NotificationEntry entry = alertEntry.mEntry; entry.setAmbientPulsing(false); for (OnAmbientChangedListener listener : mListeners) { listener.onAmbientStateChanged(entry, false); @@ -131,7 +131,7 @@ public class AmbientPulseManager extends AlertingNotificationManager { * @param entry the entry that changed * @param isPulsing true if the entry is now pulsing, false otherwise */ - void onAmbientStateChanged(NotificationData.Entry entry, boolean isPulsing); + void onAmbientStateChanged(NotificationEntry entry, boolean isPulsing); } private final class AmbientEntry extends AlertEntry { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java index 758fb7a9971e..22d1d5b233ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java @@ -18,12 +18,14 @@ package com.android.systemui.statusbar; import android.animation.Animator; import android.content.Context; +import android.util.Log; import android.view.ViewPropertyAnimator; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.systemui.Interpolators; import com.android.systemui.statusbar.notification.NotificationUtils; +import com.android.systemui.statusbar.phone.StatusBar; /** * Utility class to calculate general fling animation when the finger is released. @@ -196,9 +198,16 @@ public class FlingAnimationUtils { if (startGradient != mCachedStartGradient || velocityFactor != mCachedVelocityFactor) { float speedup = mSpeedUpFactor * (1.0f - velocityFactor); - mInterpolator = new PathInterpolator(speedup, - speedup * startGradient, - mLinearOutSlowInX2, mY2); + float x1 = speedup; + float y1 = speedup * startGradient; + float x2 = mLinearOutSlowInX2; + float y2 = mY2; + try { + mInterpolator = new PathInterpolator(x1, y1, x2, y2); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Illegal path with " + + "x1=" + x1 + " y1=" + y1 + " x2=" + x2 + " y2=" + y2, e); + } mCachedStartGradient = startGradient; mCachedVelocityFactor = velocityFactor; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java index e2177774a75d..3f1ff33437b9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java @@ -32,7 +32,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.AlphaOptimizedLinearLayout; import com.android.systemui.R; import com.android.systemui.plugins.DarkIconDispatcher; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.util.List; @@ -50,7 +50,7 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout { private int mEndMargin; private View mIconPlaceholder; private TextView mTextView; - private NotificationData.Entry mShowingEntry; + private NotificationEntry mShowingEntry; private Rect mLayoutedIconRect = new Rect(); private int[] mTmpPosition = new int[2]; private boolean mFirstLayout = true; @@ -162,7 +162,7 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout { mTextView = findViewById(R.id.text); } - public void setEntry(NotificationData.Entry entry) { + public void setEntry(NotificationEntry entry) { if (entry != null) { mShowingEntry = entry; CharSequence text = entry.headsUpStatusBarText; @@ -261,7 +261,7 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout { return super.fitSystemWindows(insets); } - public NotificationData.Entry getShowingEntry() { + public NotificationEntry getShowingEntry() { return mShowingEntry; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java index ecd9814c3073..0f295ba75fe4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java @@ -2,7 +2,7 @@ package com.android.systemui.statusbar; import androidx.annotation.NonNull; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; /** * Interface for anything that may need to keep notifications managed even after @@ -24,7 +24,7 @@ public interface NotificationLifetimeExtender { * @param entry the entry containing the notification to check * @return true if the notification lifetime should be extended */ - boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry); + boolean shouldExtendLifetime(@NonNull NotificationEntry entry); /** * Sets whether or not the lifetime should be managed by the extender. In practice, if @@ -37,7 +37,7 @@ public interface NotificationLifetimeExtender { * @param entry the entry that needs an extended lifetime * @param shouldManage true if the extender should manage the entry now, false otherwise */ - void setShouldManageLifetime(@NonNull NotificationData.Entry entry, boolean shouldManage); + void setShouldManageLifetime(@NonNull NotificationEntry entry, boolean shouldManage); /** * The callback for when the notification is now safe to remove (i.e. its lifetime has ended). diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java index bc662e3d8855..f46ded4d61d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java @@ -18,7 +18,7 @@ import android.content.pm.UserInfo; import android.service.notification.StatusBarNotification; import android.util.SparseArray; -import com.android.systemui.statusbar.notification.NotificationData.Entry; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; public interface NotificationLockscreenUserManager { String PERMISSION_SELF = "com.android.systemui.permission.SELF"; @@ -55,7 +55,7 @@ public interface NotificationLockscreenUserManager { void updatePublicMode(); - boolean needsRedaction(Entry entry); + boolean needsRedaction(NotificationEntry entry); boolean userAllowsPrivateNotificationsInPublic(int currentUserId); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index bba4369b5e01..d5f4d0461ba4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -46,9 +46,9 @@ import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.recents.OverviewProxyService; 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.NotificationUtils; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardMonitor; @@ -407,7 +407,7 @@ public class NotificationLockscreenUserManagerImpl implements } /** @return true if the entry needs redaction when on the lockscreen. */ - public boolean needsRedaction(NotificationData.Entry ent) { + public boolean needsRedaction(NotificationEntry ent) { int userId = ent.notification.getUserId(); boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index e59bc2a82c4c..7412702abfea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -46,9 +46,9 @@ import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.Interpolators; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.statusbar.notification.NotificationData.Entry; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.ScrimController; @@ -156,7 +156,7 @@ public class NotificationMediaManager implements Dumpable { notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override public void onEntryRemoved( - Entry entry, + NotificationEntry entry, NotificationVisibility visibility, boolean removedByUser) { onNotificationRemoved(entry.key); @@ -188,7 +188,7 @@ public class NotificationMediaManager implements Dumpable { return null; } synchronized (mEntryManager.getNotificationData()) { - Entry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey); + NotificationEntry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey); if (entry == null || entry.expandedIcon == null) { return null; } @@ -210,15 +210,15 @@ public class NotificationMediaManager implements Dumpable { boolean metaDataChanged = false; synchronized (mEntryManager.getNotificationData()) { - ArrayList<Entry> activeNotifications = + ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData().getActiveNotifications(); final int N = activeNotifications.size(); // Promote the media notification with a controller in 'playing' state, if any. - Entry mediaNotification = null; + NotificationEntry mediaNotification = null; MediaController controller = null; for (int i = 0; i < N; i++) { - final Entry entry = activeNotifications.get(i); + final NotificationEntry entry = activeNotifications.get(i); if (entry.isMediaNotification()) { final MediaSession.Token token = @@ -258,7 +258,7 @@ public class NotificationMediaManager implements Dumpable { final String pkg = aController.getPackageName(); for (int i = 0; i < N; i++) { - final Entry entry = activeNotifications.get(i); + final NotificationEntry entry = activeNotifications.get(i); if (entry.notification.getPackageName().equals(pkg)) { if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: found controller matching " diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 1ab9c5c2b4a2..7d6231f27885 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -51,9 +51,9 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dumpable; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.RemoteInputView; @@ -103,7 +103,7 @@ public class NotificationRemoteInputManager implements Dumpable { * Notifications that are already removed but are kept around because the remote input is * actively being used (i.e. user is typing in it). See {@link RemoteInputActiveExtender}. */ - protected final ArraySet<NotificationData.Entry> mEntriesKeptForRemoteInputActive = + protected final ArraySet<NotificationEntry> mEntriesKeptForRemoteInputActive = new ArraySet<>(); // Dependencies: @@ -253,7 +253,7 @@ public class NotificationRemoteInputManager implements Dumpable { notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override public void onEntryRemoved( - @Nullable NotificationData.Entry entry, + @Nullable NotificationEntry entry, NotificationVisibility visibility, boolean removedByUser) { if (removedByUser && entry != null) { @@ -269,7 +269,7 @@ public class NotificationRemoteInputManager implements Dumpable { mRemoteInputController = new RemoteInputController(delegate); mRemoteInputController.addCallback(new RemoteInputController.Callback() { @Override - public void onRemoteInputSent(NotificationData.Entry entry) { + public void onRemoteInputSent(NotificationEntry entry) { if (FORCE_REMOTE_INPUT_HISTORY && isNotificationKeptForRemoteInputHistory(entry.key)) { mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key); @@ -413,7 +413,7 @@ public class NotificationRemoteInputManager implements Dumpable { } @VisibleForTesting - void onPerformRemoveNotification(NotificationData.Entry entry, final String key) { + void onPerformRemoveNotification(NotificationEntry entry, final String key) { if (mKeysKeptForRemoteInputHistory.contains(key)) { mKeysKeptForRemoteInputHistory.remove(key); } @@ -424,7 +424,7 @@ public class NotificationRemoteInputManager implements Dumpable { public void onPanelCollapsed() { for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) { - NotificationData.Entry entry = mEntriesKeptForRemoteInputActive.valueAt(i); + NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i); mRemoteInputController.removeRemoteInput(entry, null); if (mNotificationLifetimeFinishedCallback != null) { mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key); @@ -437,7 +437,7 @@ public class NotificationRemoteInputManager implements Dumpable { return mKeysKeptForRemoteInputHistory.contains(key); } - public boolean shouldKeepForRemoteInputHistory(NotificationData.Entry entry) { + public boolean shouldKeepForRemoteInputHistory(NotificationEntry entry) { if (entry.isDismissed()) { return false; } @@ -447,7 +447,7 @@ public class NotificationRemoteInputManager implements Dumpable { return (mRemoteInputController.isSpinning(entry.key) || entry.hasJustSentRemoteInput()); } - public boolean shouldKeepForSmartReplyHistory(NotificationData.Entry entry) { + public boolean shouldKeepForSmartReplyHistory(NotificationEntry entry) { if (entry.isDismissed()) { return false; } @@ -467,13 +467,13 @@ public class NotificationRemoteInputManager implements Dumpable { @VisibleForTesting StatusBarNotification rebuildNotificationForCanceledSmartReplies( - NotificationData.Entry entry) { + NotificationEntry entry) { return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */, false /* showSpinner */); } @VisibleForTesting - StatusBarNotification rebuildNotificationWithRemoteInput(NotificationData.Entry entry, + StatusBarNotification rebuildNotificationWithRemoteInput(NotificationEntry entry, CharSequence remoteInputText, boolean showSpinner) { StatusBarNotification sbn = entry.notification; @@ -530,7 +530,7 @@ public class NotificationRemoteInputManager implements Dumpable { } @VisibleForTesting - public Set<NotificationData.Entry> getEntriesKeptForRemoteInputActive() { + public Set<NotificationEntry> getEntriesKeptForRemoteInputActive() { return mEntriesKeptForRemoteInputActive; } @@ -553,12 +553,12 @@ public class NotificationRemoteInputManager implements Dumpable { */ protected class RemoteInputHistoryExtender extends RemoteInputExtender { @Override - public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) { + public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) { return shouldKeepForRemoteInputHistory(entry); } @Override - public void setShouldManageLifetime(NotificationData.Entry entry, + public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) { if (shouldExtend) { CharSequence remoteInputText = entry.remoteInputText; @@ -599,12 +599,12 @@ public class NotificationRemoteInputManager implements Dumpable { */ protected class SmartReplyHistoryExtender extends RemoteInputExtender { @Override - public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) { + public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) { return shouldKeepForSmartReplyHistory(entry); } @Override - public void setShouldManageLifetime(NotificationData.Entry entry, + public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) { if (shouldExtend) { StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry); @@ -637,7 +637,7 @@ public class NotificationRemoteInputManager implements Dumpable { */ protected class RemoteInputActiveExtender extends RemoteInputExtender { @Override - public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) { + public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) { if (entry.isDismissed()) { return false; } @@ -645,7 +645,7 @@ public class NotificationRemoteInputManager implements Dumpable { } @Override - public void setShouldManageLifetime(NotificationData.Entry entry, + public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) { if (shouldExtend) { if (Log.isLoggable(TAG, Log.DEBUG)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java index f23ae3f6bfb7..f0d804dbc7a3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java @@ -24,7 +24,7 @@ import android.text.TextUtils; import androidx.annotation.VisibleForTesting; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.util.ArrayList; import java.util.Arrays; @@ -52,7 +52,7 @@ public class NotificationUiAdjustment { } public static NotificationUiAdjustment extractFromNotificationEntry( - NotificationData.Entry entry) { + NotificationEntry entry) { return new NotificationUiAdjustment( entry.key, entry.systemGeneratedSmartActions, entry.smartReplies); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index 017a9c368fdf..bf6caa010e9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -27,9 +27,9 @@ import android.view.ViewGroup; import com.android.systemui.R; import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -150,13 +150,13 @@ public class NotificationViewHierarchyManager { */ //TODO: Rewrite this to focus on Entries, or some other data object instead of views public void updateNotificationViews() { - ArrayList<NotificationData.Entry> activeNotifications = mEntryManager.getNotificationData() + ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData() .getActiveNotifications(); ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size()); - ArrayList<NotificationData.Entry> toBubble = new ArrayList<>(); + ArrayList<NotificationEntry> toBubble = new ArrayList<>(); final int N = activeNotifications.size(); for (int i = 0; i < N; i++) { - NotificationData.Entry ent = activeNotifications.get(i); + NotificationEntry ent = activeNotifications.get(i); if (ent.isRowDismissed() || ent.isRowRemoved()) { // we don't want to update removed notifications because they could // temporarily become children if they were isolated before. @@ -187,7 +187,7 @@ public class NotificationViewHierarchyManager { ent.getRow().setSensitive(sensitive, deviceSensitive); ent.getRow().setNeedsRedaction(needsRedaction); if (mGroupManager.isChildInGroupWithSummary(ent.notification)) { - NotificationData.Entry summary = mGroupManager.getGroupSummary(ent.notification); + NotificationEntry summary = mGroupManager.getGroupSummary(ent.notification); List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(summary.getRow()); if (orderedChildren == null) { @@ -271,7 +271,7 @@ public class NotificationViewHierarchyManager { for (int i = 0; i < toBubble.size(); i++) { // TODO: might make sense to leave them in the shade and just reposition them - NotificationData.Entry ent = toBubble.get(i); + NotificationEntry ent = toBubble.get(i); mBubbleController.addBubble(ent); } @@ -385,7 +385,7 @@ public class NotificationViewHierarchyManager { } while(!stack.isEmpty()) { ExpandableNotificationRow row = stack.pop(); - NotificationData.Entry entry = row.getEntry(); + NotificationEntry entry = row.getEntry(); boolean isChildNotification = mGroupManager.isChildInGroupWithSummary(entry.notification); @@ -408,7 +408,7 @@ public class NotificationViewHierarchyManager { if (!showOnKeyguard) { // min priority notifications should show if their summary is showing if (mGroupManager.isChildInGroupWithSummary(entry.notification)) { - NotificationData.Entry summary = mGroupManager.getLogicalGroupSummary( + NotificationEntry summary = mGroupManager.getLogicalGroupSummary( entry.notification); if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard( summary.notification)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java index e8abcc2bd80e..998cf523d3df 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java @@ -24,7 +24,7 @@ import android.util.ArrayMap; import android.util.Pair; import com.android.internal.util.Preconditions; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.policy.RemoteInputView; import java.lang.ref.WeakReference; @@ -38,7 +38,7 @@ public class RemoteInputController { private static final boolean ENABLE_REMOTE_INPUT = SystemProperties.getBoolean("debug.enable_remote_input", true); - private final ArrayList<Pair<WeakReference<NotificationData.Entry>, Object>> mOpen + private final ArrayList<Pair<WeakReference<NotificationEntry>, Object>> mOpen = new ArrayList<>(); private final ArrayMap<String, Object> mSpinning = new ArrayMap<>(); private final ArrayList<Callback> mCallbacks = new ArrayList<>(3); @@ -101,7 +101,7 @@ public class RemoteInputController { * @param entry the entry for which a remote input is now active. * @param token a token identifying the view that is managing the remote input */ - public void addRemoteInput(NotificationData.Entry entry, Object token) { + public void addRemoteInput(NotificationEntry entry, Object token) { Preconditions.checkNotNull(entry); Preconditions.checkNotNull(token); @@ -122,7 +122,7 @@ public class RemoteInputController { * the entry is only removed if the token matches the last added token for this * entry. If null, the entry is removed regardless. */ - public void removeRemoteInput(NotificationData.Entry entry, Object token) { + public void removeRemoteInput(NotificationEntry entry, Object token) { Preconditions.checkNotNull(entry); pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token); @@ -173,7 +173,7 @@ public class RemoteInputController { return mSpinning.get(key) == token; } - private void apply(NotificationData.Entry entry) { + private void apply(NotificationEntry entry) { mDelegate.setRemoteInputActive(entry, isRemoteInputActive(entry)); boolean remoteInputActive = isRemoteInputActive(); int N = mCallbacks.size(); @@ -185,7 +185,7 @@ public class RemoteInputController { /** * @return true if {@param entry} has an active RemoteInput */ - public boolean isRemoteInputActive(NotificationData.Entry entry) { + public boolean isRemoteInputActive(NotificationEntry entry) { return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */, null /* removeToken */); } @@ -208,10 +208,10 @@ public class RemoteInputController { * @return true if {@param contains} is in the set of active remote inputs */ private boolean pruneWeakThenRemoveAndContains( - NotificationData.Entry contains, NotificationData.Entry remove, Object removeToken) { + NotificationEntry contains, NotificationEntry remove, Object removeToken) { boolean found = false; for (int i = mOpen.size() - 1; i >= 0; i--) { - NotificationData.Entry item = mOpen.get(i).first.get(); + NotificationEntry item = mOpen.get(i).first.get(); Object itemToken = mOpen.get(i).second; boolean removeTokenMatches = (removeToken == null || itemToken == removeToken); @@ -235,7 +235,7 @@ public class RemoteInputController { mCallbacks.add(callback); } - public void remoteInputSent(NotificationData.Entry entry) { + public void remoteInputSent(NotificationEntry entry) { int N = mCallbacks.size(); for (int i = 0; i < N; i++) { mCallbacks.get(i).onRemoteInputSent(entry); @@ -248,16 +248,16 @@ public class RemoteInputController { } // Make a copy because closing the remote inputs will modify mOpen. - ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size()); + ArrayList<NotificationEntry> list = new ArrayList<>(mOpen.size()); for (int i = mOpen.size() - 1; i >= 0; i--) { - NotificationData.Entry entry = mOpen.get(i).first.get(); + NotificationEntry entry = mOpen.get(i).first.get(); if (entry != null && entry.rowExists()) { list.add(entry); } } for (int i = list.size() - 1; i >= 0; i--) { - NotificationData.Entry entry = list.get(i); + NotificationEntry entry = list.get(i); if (entry.rowExists()) { entry.closeRemoteInput(); } @@ -268,31 +268,31 @@ public class RemoteInputController { mDelegate.requestDisallowLongPressAndDismiss(); } - public void lockScrollTo(NotificationData.Entry entry) { + public void lockScrollTo(NotificationEntry entry) { mDelegate.lockScrollTo(entry); } public interface Callback { default void onRemoteInputActive(boolean active) {} - default void onRemoteInputSent(NotificationData.Entry entry) {} + default void onRemoteInputSent(NotificationEntry entry) {} } public interface Delegate { /** * Activate remote input if necessary. */ - void setRemoteInputActive(NotificationData.Entry entry, boolean remoteInputActive); - - /** - * Request that the view does not dismiss nor perform long press for the current touch. - */ - void requestDisallowLongPressAndDismiss(); - - /** - * Request that the view is made visible by scrolling to it, and keep the scroll locked until - * the user scrolls, or {@param v} loses focus or is detached. - */ - void lockScrollTo(NotificationData.Entry entry); + void setRemoteInputActive(NotificationEntry entry, boolean remoteInputActive); + + /** + * Request that the view does not dismiss nor perform long press for the current touch. + */ + void requestDisallowLongPressAndDismiss(); + + /** + * Request that the view is made visible by scrolling to it, and keep the scroll locked until + * the user scrolls, or {@param entry} loses focus or is detached. + */ + void lockScrollTo(NotificationEntry entry); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java index 9e91133aff09..573c1f8ee509 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java @@ -21,8 +21,8 @@ import android.util.ArraySet; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.util.Set; @@ -54,7 +54,7 @@ public class SmartReplyController { /** * Notifies StatusBarService a smart reply is sent. */ - public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply, + public void smartReplySent(NotificationEntry entry, int replyIndex, CharSequence reply, boolean generatedByAssistant) { mCallback.onSmartReplySent(entry, reply); mSendingKeys.add(entry.key); @@ -70,7 +70,7 @@ public class SmartReplyController { * Notifies StatusBarService a smart action is clicked. */ public void smartActionClicked( - NotificationData.Entry entry, int actionIndex, Notification.Action action, + NotificationEntry entry, int actionIndex, Notification.Action action, boolean generatedByAssistant) { final int count = mEntryManager.getNotificationData().getActiveNotifications().size(); final int rank = mEntryManager.getNotificationData().getRank(entry.key); @@ -95,7 +95,7 @@ public class SmartReplyController { /** * Smart Replies and Actions have been added to the UI. */ - public void smartSuggestionsAdded(final NotificationData.Entry entry, int replyCount, + public void smartSuggestionsAdded(final NotificationEntry entry, int replyCount, int actionCount, boolean generatedByAssistant) { try { mBarService.onNotificationSmartSuggestionsAdded( @@ -105,7 +105,7 @@ public class SmartReplyController { } } - public void stopSending(final NotificationData.Entry entry) { + public void stopSending(final NotificationEntry entry) { if (entry != null) { mSendingKeys.remove(entry.notification.getKey()); } @@ -121,6 +121,6 @@ public class SmartReplyController { * @param entry the entry for the notification * @param reply the reply that was sent */ - void onSmartReplySent(NotificationData.Entry entry, CharSequence reply); + void onSmartReplySent(NotificationEntry entry, CharSequence reply); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java index 2bb0d5ce9161..60d8cf460627 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java @@ -29,6 +29,7 @@ import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.AmbientPulseManager; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInflater; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -71,18 +72,18 @@ public class NotificationAlertingManager { notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override - public void onEntryInflated(NotificationData.Entry entry, int inflatedFlags) { + public void onEntryInflated(NotificationEntry entry, int inflatedFlags) { showAlertingView(entry, inflatedFlags); } @Override - public void onEntryUpdated(NotificationData.Entry entry) { + public void onPostEntryUpdated(NotificationEntry entry) { updateAlertState(entry); } @Override public void onEntryRemoved( - NotificationData.Entry entry, + NotificationEntry entry, NotificationVisibility visibility, boolean removedByUser) { stopAlerting(entry.key); @@ -101,7 +102,7 @@ public class NotificationAlertingManager { * @param entry entry to add * @param inflatedFlags flags representing content views that were inflated */ - private void showAlertingView(NotificationData.Entry entry, + private void showAlertingView(NotificationEntry entry, @NotificationInflater.InflationFlag int inflatedFlags) { if ((inflatedFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) { // Possible for shouldHeadsUp to change between the inflation starting and ending. @@ -123,7 +124,7 @@ public class NotificationAlertingManager { } } - private void updateAlertState(NotificationData.Entry entry) { + private void updateAlertState(NotificationEntry entry) { boolean alertAgain = alertAgain(entry, entry.notification.getNotification()); AlertingNotificationManager alertManager; boolean shouldAlert; @@ -150,7 +151,7 @@ public class NotificationAlertingManager { } private static boolean alertAgain( - NotificationData.Entry oldEntry, Notification newNotification) { + NotificationEntry oldEntry, Notification newNotification) { return oldEntry == null || !oldEntry.hasInterrupted() || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java deleted file mode 100644 index a51896ee69fc..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java +++ /dev/null @@ -1,1072 +0,0 @@ -/* - * Copyright (C) 2008 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.notification; - -import static android.app.Notification.CATEGORY_ALARM; -import static android.app.Notification.CATEGORY_CALL; -import static android.app.Notification.CATEGORY_EVENT; -import static android.app.Notification.CATEGORY_MESSAGE; -import static android.app.Notification.CATEGORY_REMINDER; -import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; -import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; -import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; -import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; -import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; - -import android.annotation.NonNull; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.Person; -import android.content.Context; -import android.graphics.drawable.Icon; -import android.os.Bundle; -import android.os.Parcelable; -import android.os.SystemClock; -import android.service.notification.NotificationListenerService.Ranking; -import android.service.notification.NotificationListenerService.RankingMap; -import android.service.notification.SnoozeCriterion; -import android.service.notification.StatusBarNotification; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.view.View; -import android.widget.ImageView; - -import androidx.annotation.Nullable; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.statusbar.StatusBarIcon; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.ContrastColorUtil; -import com.android.systemui.Dependency; -import com.android.systemui.statusbar.InflationTask; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.StatusBarIconView; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.NotificationGuts; -import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; -import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.statusbar.policy.HeadsUpManager; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; - -/** - * The list of currently displaying notifications. - */ -public class NotificationData { - - private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class); - - /** - * These dependencies are late init-ed - */ - private KeyguardEnvironment mEnvironment; - private NotificationMediaManager mMediaManager; - - private HeadsUpManager mHeadsUpManager; - - public static final class Entry { - private static final long LAUNCH_COOLDOWN = 2000; - private static final long REMOTE_INPUT_COOLDOWN = 500; - private static final long INITIALIZATION_DELAY = 400; - private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN; - private static final int COLOR_INVALID = 1; - public final String key; - public StatusBarNotification notification; - public NotificationChannel channel; - public long lastAudiblyAlertedMs; - public boolean noisy; - public boolean ambient; - public int importance; - public StatusBarIconView icon; - public StatusBarIconView expandedIcon; - private boolean interruption; - public boolean autoRedacted; // whether the redacted notification was generated by us - public int targetSdk; - private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET; - public CharSequence remoteInputText; - public List<SnoozeCriterion> snoozeCriteria; - public int userSentiment = Ranking.USER_SENTIMENT_NEUTRAL; - /** Smart Actions provided by the NotificationAssistantService. */ - @NonNull - public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList(); - public CharSequence[] smartReplies = new CharSequence[0]; - @VisibleForTesting - public int suppressedVisualEffects; - public boolean suspended; - - private Entry parent; // our parent (if we're in a group) - private ArrayList<Entry> children = new ArrayList<Entry>(); - private ExpandableNotificationRow row; // the outer expanded view - - private int mCachedContrastColor = COLOR_INVALID; - private int mCachedContrastColorIsFor = COLOR_INVALID; - private InflationTask mRunningTask = null; - private Throwable mDebugThrowable; - public CharSequence remoteInputTextWhenReset; - public long lastRemoteInputSent = NOT_LAUNCHED_YET; - public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3); - public CharSequence headsUpStatusBarText; - public CharSequence headsUpStatusBarTextPublic; - - private long initializationTime = -1; - - /** - * Whether or not this row represents a system notification. Note that if this is - * {@code null}, that means we were either unable to retrieve the info or have yet to - * retrieve the info. - */ - public Boolean mIsSystemNotification; - - /** - * Has the user sent a reply through this Notification. - */ - private boolean hasSentReply; - - /** - * Whether this notification should be displayed as a bubble. - */ - private boolean mIsBubble; - - /** - * Whether the user has dismissed this notification when it was in bubble form. - */ - private boolean mUserDismissedBubble; - - public Entry(StatusBarNotification n) { - this(n, null); - } - - public Entry(StatusBarNotification n, @Nullable Ranking ranking) { - this.key = n.getKey(); - this.notification = n; - if (ranking != null) { - populateFromRanking(ranking); - } - } - - public void populateFromRanking(@NonNull Ranking ranking) { - channel = ranking.getChannel(); - lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis(); - importance = ranking.getImportance(); - ambient = ranking.isAmbient(); - snoozeCriteria = ranking.getSnoozeCriteria(); - userSentiment = ranking.getUserSentiment(); - systemGeneratedSmartActions = ranking.getSmartActions() == null - ? Collections.emptyList() : ranking.getSmartActions(); - smartReplies = ranking.getSmartReplies() == null - ? new CharSequence[0] - : ranking.getSmartReplies().toArray(new CharSequence[0]); - suppressedVisualEffects = ranking.getSuppressedVisualEffects(); - suspended = ranking.isSuspended(); - } - - public void setInterruption() { - interruption = true; - } - - public boolean hasInterrupted() { - return interruption; - } - - public void setIsBubble(boolean bubbleable) { - mIsBubble = bubbleable; - } - - public boolean isBubble() { - return mIsBubble; - } - - public void setBubbleDismissed(boolean userDismissed) { - mUserDismissedBubble = userDismissed; - } - - public boolean isBubbleDismissed() { - return mUserDismissedBubble; - } - - /** - * Resets the notification entry to be re-used. - */ - public void reset() { - if (row != null) { - row.reset(); - } - } - - public ExpandableNotificationRow getRow() { - return row; - } - - //TODO: This will go away when we have a way to bind an entry to a row - public void setRow(ExpandableNotificationRow row) { - this.row = row; - } - - @Nullable - public List<Entry> getChildren() { - if (children.size() <= 0) { - return null; - } - - return children; - } - - public void notifyFullScreenIntentLaunched() { - setInterruption(); - lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime(); - } - - public boolean hasJustLaunchedFullScreenIntent() { - return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN; - } - - public boolean hasJustSentRemoteInput() { - return SystemClock.elapsedRealtime() < lastRemoteInputSent + REMOTE_INPUT_COOLDOWN; - } - - public boolean hasFinishedInitialization() { - return initializationTime == -1 || - SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY; - } - - /** - * Create the icons for a notification - * @param context the context to create the icons with - * @param sbn the notification - * @throws InflationException - */ - public void createIcons(Context context, StatusBarNotification sbn) - throws InflationException { - Notification n = sbn.getNotification(); - final Icon smallIcon = n.getSmallIcon(); - if (smallIcon == null) { - throw new InflationException("No small icon in notification from " - + sbn.getPackageName()); - } - - // Construct the icon. - icon = new StatusBarIconView(context, - sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); - icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - - // Construct the expanded icon. - expandedIcon = new StatusBarIconView(context, - sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); - expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - final StatusBarIcon ic = new StatusBarIcon( - sbn.getUser(), - sbn.getPackageName(), - smallIcon, - n.iconLevel, - n.number, - StatusBarIconView.contentDescForNotification(context, n)); - if (!icon.set(ic) || !expandedIcon.set(ic)) { - icon = null; - expandedIcon = null; - throw new InflationException("Couldn't create icon: " + ic); - } - expandedIcon.setVisibility(View.INVISIBLE); - expandedIcon.setOnVisibilityChangedListener( - newVisibility -> { - if (row != null) { - row.setIconsVisible(newVisibility != View.VISIBLE); - } - }); - } - - public void setIconTag(int key, Object tag) { - if (icon != null) { - icon.setTag(key, tag); - expandedIcon.setTag(key, tag); - } - } - - /** - * Update the notification icons. - * - * @param context the context to create the icons with. - * @param sbn the notification to read the icon from. - * @throws InflationException - */ - public void updateIcons(Context context, StatusBarNotification sbn) - throws InflationException { - if (icon != null) { - // Update the icon - Notification n = sbn.getNotification(); - final StatusBarIcon ic = new StatusBarIcon( - notification.getUser(), - notification.getPackageName(), - n.getSmallIcon(), - n.iconLevel, - n.number, - StatusBarIconView.contentDescForNotification(context, n)); - icon.setNotification(sbn); - expandedIcon.setNotification(sbn); - if (!icon.set(ic) || !expandedIcon.set(ic)) { - throw new InflationException("Couldn't update icon: " + ic); - } - } - } - - public int getContrastedColor(Context context, boolean isLowPriority, - int backgroundColor) { - int rawColor = isLowPriority ? Notification.COLOR_DEFAULT : - notification.getNotification().color; - if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) { - return mCachedContrastColor; - } - final int contrasted = ContrastColorUtil.resolveContrastColor(context, rawColor, - backgroundColor); - mCachedContrastColorIsFor = rawColor; - mCachedContrastColor = contrasted; - return mCachedContrastColor; - } - - /** - * Abort all existing inflation tasks - */ - public void abortTask() { - if (mRunningTask != null) { - mRunningTask.abort(); - mRunningTask = null; - } - } - - public void setInflationTask(InflationTask abortableTask) { - // abort any existing inflation - InflationTask existing = mRunningTask; - abortTask(); - mRunningTask = abortableTask; - if (existing != null && mRunningTask != null) { - mRunningTask.supersedeTask(existing); - } - } - - public void onInflationTaskFinished() { - mRunningTask = null; - } - - @VisibleForTesting - public InflationTask getRunningTask() { - return mRunningTask; - } - - /** - * Set a throwable that is used for debugging - * - * @param debugThrowable the throwable to save - */ - public void setDebugThrowable(Throwable debugThrowable) { - mDebugThrowable = debugThrowable; - } - - public Throwable getDebugThrowable() { - return mDebugThrowable; - } - - public void onRemoteInputInserted() { - lastRemoteInputSent = NOT_LAUNCHED_YET; - remoteInputTextWhenReset = null; - } - - public void setHasSentReply() { - hasSentReply = true; - } - - public boolean isLastMessageFromReply() { - if (!hasSentReply) { - return false; - } - Bundle extras = notification.getNotification().extras; - CharSequence[] replyTexts = extras.getCharSequenceArray( - Notification.EXTRA_REMOTE_INPUT_HISTORY); - if (!ArrayUtils.isEmpty(replyTexts)) { - return true; - } - Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES); - if (messages != null && messages.length > 0) { - Parcelable message = messages[messages.length - 1]; - if (message instanceof Bundle) { - Notification.MessagingStyle.Message lastMessage = - Notification.MessagingStyle.Message.getMessageFromBundle( - (Bundle) message); - if (lastMessage != null) { - Person senderPerson = lastMessage.getSenderPerson(); - if (senderPerson == null) { - return true; - } - Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON); - return Objects.equals(user, senderPerson); - } - } - } - return false; - } - - public void setInitializationTime(long time) { - if (initializationTime == -1) { - initializationTime = time; - } - } - - public void sendAccessibilityEvent(int eventType) { - if (row != null) { - row.sendAccessibilityEvent(eventType); - } - } - - /** - * Used by NotificationMediaManager to determine... things - * @return {@code true} if we are a media notification - */ - public boolean isMediaNotification() { - if (row == null) return false; - - return row.isMediaRow(); - } - - /** - * We are a top level child if our parent is the list of notifications duh - * @return {@code true} if we're a top level notification - */ - public boolean isTopLevelChild() { - return row != null && row.isTopLevelChild(); - } - - public void resetUserExpansion() { - if (row != null) row.resetUserExpansion(); - } - - public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) { - if (row != null) row.freeContentViewWhenSafe(inflationFlag); - } - - public void setAmbientPulsing(boolean pulsing) { - if (row != null) row.setAmbientPulsing(pulsing); - } - - public boolean rowExists() { - return row != null; - } - - public boolean isRowDismissed() { - return row != null && row.isDismissed(); - } - - public boolean isRowRemoved() { - return row != null && row.isRemoved(); - } - - /** - * @return {@code true} if the row is null or removed - */ - public boolean isRemoved() { - //TODO: recycling invalidates this - return row == null || row.isRemoved(); - } - - /** - * @return {@code true} if the row is null or dismissed - */ - public boolean isDismissed() { - //TODO: recycling - return row == null || row.isDismissed(); - } - - public boolean isRowPinned() { - return row != null && row.isPinned(); - } - - public void setRowPinned(boolean pinned) { - if (row != null) row.setPinned(pinned); - } - - public boolean isRowAnimatingAway() { - return row != null && row.isHeadsUpAnimatingAway(); - } - - public boolean isRowHeadsUp() { - return row != null && row.isHeadsUp(); - } - - public void setHeadsUp(boolean shouldHeadsUp) { - if (row != null) row.setHeadsUp(shouldHeadsUp); - } - - public boolean mustStayOnScreen() { - return row != null && row.mustStayOnScreen(); - } - - public void setHeadsUpIsVisible() { - if (row != null) row.setHeadsUpIsVisible(); - } - - //TODO: i'm imagining a world where this isn't just the row, but I could be rwong - public ExpandableNotificationRow getHeadsUpAnimationView() { - return row; - } - - public void setUserLocked(boolean userLocked) { - if (row != null) row.setUserLocked(userLocked); - } - - public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) { - if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion); - } - - public void setGroupExpansionChanging(boolean changing) { - if (row != null) row.setGroupExpansionChanging(changing); - } - - public void notifyHeightChanged(boolean needsAnimation) { - if (row != null) row.notifyHeightChanged(needsAnimation); - } - - public void closeRemoteInput() { - if (row != null) row.closeRemoteInput(); - } - - public boolean areChildrenExpanded() { - return row != null && row.areChildrenExpanded(); - } - - public boolean keepInParent() { - return row != null && row.keepInParent(); - } - - //TODO: probably less confusing to say "is group fully visible" - public boolean isGroupNotFullyVisible() { - return row == null || row.isGroupNotFullyVisible(); - } - - public NotificationGuts getGuts() { - if (row != null) return row.getGuts(); - return null; - } - - public boolean hasLowPriorityStateUpdated() { - return row != null && row.hasLowPriorityStateUpdated(); - } - - public void removeRow() { - if (row != null) row.setRemoved(); - } - - public boolean isSummaryWithChildren() { - return row != null && row.isSummaryWithChildren(); - } - - public void setKeepInParent(boolean keep) { - if (row != null) row.setKeepInParent(keep); - } - - public void onDensityOrFontScaleChanged() { - if (row != null) row.onDensityOrFontScaleChanged(); - } - - public boolean areGutsExposed() { - return row != null && row.getGuts() != null && row.getGuts().isExposed(); - } - - public boolean isChildInGroup() { - return parent == null; - } - - public void setLowPriorityStateUpdated(boolean updated) { - if (row != null) row.setLowPriorityStateUpdated(updated); - } - - /** - * @return Can the underlying notification be cleared? This can be different from whether the - * notification can be dismissed in case notifications are sensitive on the lockscreen. - * @see #canViewBeDismissed() - */ - public boolean isClearable() { - if (notification == null || !notification.isClearable()) { - return false; - } - if (children.size() > 0) { - for (int i = 0; i < children.size(); i++) { - Entry child = children.get(i); - if (!child.isClearable()) { - return false; - } - } - } - return true; - } - - public boolean canViewBeDismissed() { - if (row == null) return true; - return row.canViewBeDismissed(); - } - - boolean isExemptFromDndVisualSuppression() { - if (isNotificationBlockedByPolicy(notification.getNotification())) { - return false; - } - - if ((notification.getNotification().flags - & Notification.FLAG_FOREGROUND_SERVICE) != 0) { - return true; - } - if (notification.getNotification().isMediaNotification()) { - return true; - } - if (mIsSystemNotification != null && mIsSystemNotification) { - return true; - } - return false; - } - - private boolean shouldSuppressVisualEffect(int effect) { - if (isExemptFromDndVisualSuppression()) { - return false; - } - return (suppressedVisualEffects & effect) != 0; - } - - /** - * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_FULL_SCREEN_INTENT} - * is set for this entry. - */ - public boolean shouldSuppressFullScreenIntent() { - return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); - } - - /** - * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_PEEK} - * is set for this entry. - */ - public boolean shouldSuppressPeek() { - return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_PEEK); - } - - /** - * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_STATUS_BAR} - * is set for this entry. - */ - public boolean shouldSuppressStatusBar() { - return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_STATUS_BAR); - } - - /** - * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_AMBIENT} - * is set for this entry. - */ - public boolean shouldSuppressAmbient() { - return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_AMBIENT); - } - - /** - * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_NOTIFICATION_LIST} - * is set for this entry. - */ - public boolean shouldSuppressNotificationList() { - return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_NOTIFICATION_LIST); - } - } - - private final ArrayMap<String, Entry> mEntries = new ArrayMap<>(); - private final ArrayList<Entry> mSortedAndFiltered = new ArrayList<>(); - private final ArrayList<Entry> mFilteredForUser = new ArrayList<>(); - - private final NotificationGroupManager mGroupManager - = Dependency.get(NotificationGroupManager.class); - - private RankingMap mRankingMap; - private final Ranking mTmpRanking = new Ranking(); - - public void setHeadsUpManager(HeadsUpManager headsUpManager) { - mHeadsUpManager = headsUpManager; - } - - private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() { - private final Ranking mRankingA = new Ranking(); - private final Ranking mRankingB = new Ranking(); - - @Override - public int compare(Entry a, Entry b) { - final StatusBarNotification na = a.notification; - final StatusBarNotification nb = b.notification; - int aImportance = NotificationManager.IMPORTANCE_DEFAULT; - int bImportance = NotificationManager.IMPORTANCE_DEFAULT; - int aRank = 0; - int bRank = 0; - - if (mRankingMap != null) { - // RankingMap as received from NoMan - getRanking(a.key, mRankingA); - getRanking(b.key, mRankingB); - aImportance = mRankingA.getImportance(); - bImportance = mRankingB.getImportance(); - aRank = mRankingA.getRank(); - bRank = mRankingB.getRank(); - } - - String mediaNotification = getMediaManager().getMediaNotificationKey(); - - // IMPORTANCE_MIN media streams are allowed to drift to the bottom - final boolean aMedia = a.key.equals(mediaNotification) - && aImportance > NotificationManager.IMPORTANCE_MIN; - final boolean bMedia = b.key.equals(mediaNotification) - && bImportance > NotificationManager.IMPORTANCE_MIN; - - boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH && - isSystemNotification(na); - boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH && - isSystemNotification(nb); - - boolean isHeadsUp = a.row.isHeadsUp(); - if (isHeadsUp != b.row.isHeadsUp()) { - return isHeadsUp ? -1 : 1; - } else if (isHeadsUp) { - // Provide consistent ranking with headsUpManager - return mHeadsUpManager.compare(a, b); - } else if (a.row.isAmbientPulsing() != b.row.isAmbientPulsing()) { - return a.row.isAmbientPulsing() ? -1 : 1; - } else if (aMedia != bMedia) { - // Upsort current media notification. - return aMedia ? -1 : 1; - } else if (aSystemMax != bSystemMax) { - // Upsort PRIORITY_MAX system notifications - return aSystemMax ? -1 : 1; - } else if (aRank != bRank) { - return aRank - bRank; - } else { - return Long.compare(nb.getNotification().when, na.getNotification().when); - } - } - }; - - private KeyguardEnvironment getEnvironment() { - if (mEnvironment == null) { - mEnvironment = Dependency.get(KeyguardEnvironment.class); - } - return mEnvironment; - } - - private NotificationMediaManager getMediaManager() { - if (mMediaManager == null) { - mMediaManager = Dependency.get(NotificationMediaManager.class); - } - return mMediaManager; - } - - /** - * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment} - * - * <p> - * This call doesn't update the list of active notifications. Call {@link #filterAndSort()} - * when the environment changes. - * <p> - * Don't hold on to or modify the returned list. - */ - public ArrayList<Entry> getActiveNotifications() { - return mSortedAndFiltered; - } - - public ArrayList<Entry> getNotificationsForCurrentUser() { - mFilteredForUser.clear(); - - synchronized (mEntries) { - final int N = mEntries.size(); - for (int i = 0; i < N; i++) { - Entry entry = mEntries.valueAt(i); - final StatusBarNotification sbn = entry.notification; - if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) { - continue; - } - mFilteredForUser.add(entry); - } - } - return mFilteredForUser; - } - - public Entry get(String key) { - return mEntries.get(key); - } - - public void add(Entry entry) { - synchronized (mEntries) { - mEntries.put(entry.notification.getKey(), entry); - } - mGroupManager.onEntryAdded(entry); - - updateRankingAndSort(mRankingMap); - } - - public Entry remove(String key, RankingMap ranking) { - Entry removed; - synchronized (mEntries) { - removed = mEntries.remove(key); - } - if (removed == null) return null; - mGroupManager.onEntryRemoved(removed); - updateRankingAndSort(ranking); - return removed; - } - - /** Updates the given notification entry with the provided ranking. */ - public void update(Entry entry, RankingMap ranking, StatusBarNotification notification) { - updateRanking(ranking); - final StatusBarNotification oldNotification = entry.notification; - entry.notification = notification; - mGroupManager.onEntryUpdated(entry, oldNotification); - } - - public void updateRanking(RankingMap ranking) { - updateRankingAndSort(ranking); - } - - public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) { - synchronized (mEntries) { - final int N = mEntries.size(); - for (int i = 0; i < N; i++) { - Entry entry = mEntries.valueAt(i); - if (uid == entry.notification.getUid() - && pkg.equals(entry.notification.getPackageName()) - && key.equals(entry.key)) { - if (showIcon) { - entry.mActiveAppOps.add(appOp); - } else { - entry.mActiveAppOps.remove(appOp); - } - } - } - } - } - - /** - * Returns true if this notification should be displayed in the high-priority notifications - * section (and on the lockscreen and status bar). - */ - public boolean isHighPriority(StatusBarNotification statusBarNotification) { - if (mRankingMap != null) { - getRanking(statusBarNotification.getKey(), mTmpRanking); - if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT - || statusBarNotification.getNotification().isForegroundService() - || statusBarNotification.getNotification().hasMediaSession()) { - return true; - } - if (mGroupManager.isSummaryOfGroup(statusBarNotification)) { - for (Entry child : mGroupManager.getLogicalChildren(statusBarNotification)) { - if (isHighPriority(child.notification)) { - return true; - } - } - } - } - return false; - } - - public boolean isAmbient(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return mTmpRanking.isAmbient(); - } - return false; - } - - public int getVisibilityOverride(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return mTmpRanking.getVisibilityOverride(); - } - return Ranking.VISIBILITY_NO_OVERRIDE; - } - - /** - * Categories that are explicitly called out on DND settings screens are always blocked, if - * DND has flagged them, even if they are foreground or system notifications that might - * otherwise visually bypass DND. - */ - private static boolean isNotificationBlockedByPolicy(Notification n) { - if (isCategory(CATEGORY_CALL, n) - || isCategory(CATEGORY_MESSAGE, n) - || isCategory(CATEGORY_ALARM, n) - || isCategory(CATEGORY_EVENT, n) - || isCategory(CATEGORY_REMINDER, n)) { - return true; - } - return false; - } - - private static boolean isCategory(String category, Notification n) { - return Objects.equals(n.category, category); - } - - public int getImportance(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return mTmpRanking.getImportance(); - } - return NotificationManager.IMPORTANCE_UNSPECIFIED; - } - - public String getOverrideGroupKey(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return mTmpRanking.getOverrideGroupKey(); - } - return null; - } - - public List<SnoozeCriterion> getSnoozeCriteria(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return mTmpRanking.getSnoozeCriteria(); - } - return null; - } - - public NotificationChannel getChannel(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return mTmpRanking.getChannel(); - } - return null; - } - - public int getRank(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return mTmpRanking.getRank(); - } - return 0; - } - - public boolean shouldHide(String key) { - if (mRankingMap != null) { - getRanking(key, mTmpRanking); - return mTmpRanking.isSuspended(); - } - return false; - } - - private void updateRankingAndSort(RankingMap ranking) { - if (ranking != null) { - mRankingMap = ranking; - synchronized (mEntries) { - final int N = mEntries.size(); - for (int i = 0; i < N; i++) { - Entry entry = mEntries.valueAt(i); - if (!getRanking(entry.key, mTmpRanking)) { - continue; - } - final StatusBarNotification oldSbn = entry.notification.cloneLight(); - final String overrideGroupKey = getOverrideGroupKey(entry.key); - if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) { - entry.notification.setOverrideGroupKey(overrideGroupKey); - mGroupManager.onEntryUpdated(entry, oldSbn); - } - entry.populateFromRanking(mTmpRanking); - } - } - } - filterAndSort(); - } - - /** - * Get the ranking from the current ranking map. - * - * @param key the key to look up - * @param outRanking the ranking to populate - * - * @return {@code true} if the ranking was properly obtained. - */ - @VisibleForTesting - protected boolean getRanking(String key, Ranking outRanking) { - return mRankingMap.getRanking(key, outRanking); - } - - // TODO: This should not be public. Instead the Environment should notify this class when - // anything changed, and this class should call back the UI so it updates itself. - public void filterAndSort() { - mSortedAndFiltered.clear(); - - synchronized (mEntries) { - final int N = mEntries.size(); - for (int i = 0; i < N; i++) { - Entry entry = mEntries.valueAt(i); - - if (mNotificationFilter.shouldFilterOut(entry)) { - continue; - } - - mSortedAndFiltered.add(entry); - } - } - - Collections.sort(mSortedAndFiltered, mRankingComparator); - } - - public void dump(PrintWriter pw, String indent) { - int N = mSortedAndFiltered.size(); - pw.print(indent); - pw.println("active notifications: " + N); - int active; - for (active = 0; active < N; active++) { - NotificationData.Entry e = mSortedAndFiltered.get(active); - dumpEntry(pw, indent, active, e); - } - synchronized (mEntries) { - int M = mEntries.size(); - pw.print(indent); - pw.println("inactive notifications: " + (M - active)); - int inactiveCount = 0; - for (int i = 0; i < M; i++) { - Entry entry = mEntries.valueAt(i); - if (!mSortedAndFiltered.contains(entry)) { - dumpEntry(pw, indent, inactiveCount, entry); - inactiveCount++; - } - } - } - } - - private void dumpEntry(PrintWriter pw, String indent, int i, Entry e) { - getRanking(e.key, mTmpRanking); - pw.print(indent); - pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon); - StatusBarNotification n = e.notification; - pw.print(indent); - pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance=" + - mTmpRanking.getImportance()); - pw.print(indent); - pw.println(" notification=" + n.getNotification()); - } - - private static boolean isSystemNotification(StatusBarNotification sbn) { - String sbnPackage = sbn.getPackageName(); - return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage); - } - - /** - * Provides access to keyguard state and user settings dependent data. - */ - public interface KeyguardEnvironment { - boolean isDeviceProvisioned(); - boolean isNotificationForCurrentProfiles(StatusBarNotification sbn); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java index 2f60f115ed53..eea44906029d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java @@ -19,6 +19,7 @@ import android.annotation.Nullable; import android.service.notification.StatusBarNotification; import com.android.internal.statusbar.NotificationVisibility; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInflater; /** @@ -29,25 +30,31 @@ public interface NotificationEntryListener { * Called when a new notification is posted. At this point, the notification is "pending": its * views haven't been inflated yet and most of the system pretends like it doesn't exist yet. */ - default void onPendingEntryAdded(NotificationData.Entry entry) { + default void onPendingEntryAdded(NotificationEntry entry) { } /** * Called when a new entry is created. */ - default void onNotificationAdded(NotificationData.Entry entry) { + default void onNotificationAdded(NotificationEntry entry) { } /** - * Called when a notification was updated. + * Called when a notification is updated, before any filtering of notifications have occurred. */ - default void onEntryUpdated(NotificationData.Entry entry) { + default void onPreEntryUpdated(NotificationEntry entry) { + } + + /** + * Called when a notification was updated, after any filtering of notifications have occurred. + */ + default void onPostEntryUpdated(NotificationEntry entry) { } /** * Called when a notification's views are inflated for the first time. */ - default void onEntryInflated(NotificationData.Entry entry, + default void onEntryInflated(NotificationEntry entry, @NotificationInflater.InflationFlag int inflatedFlags) { } @@ -57,7 +64,7 @@ public interface NotificationEntryListener { * * @param entry notification data entry that was reinflated. */ - default void onEntryReinflated(NotificationData.Entry entry) { + default void onEntryReinflated(NotificationEntry entry) { } /** @@ -77,7 +84,7 @@ public interface NotificationEntryListener { * @param removedByUser true if the notification was removed by a user action */ default void onEntryRemoved( - NotificationData.Entry entry, + NotificationEntry entry, @Nullable NotificationVisibility visibility, boolean removedByUser) { } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 5d6f60eadf1f..e698e643534b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -36,8 +36,9 @@ import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.NotificationUpdateHandler; -import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInflater; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -68,10 +69,8 @@ public class NotificationEntryManager implements public static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30); protected final Context mContext; - protected final HashMap<String, NotificationData.Entry> mPendingNotifications = new HashMap<>(); + protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>(); - private final NotificationGutsManager mGutsManager = - Dependency.get(NotificationGutsManager.class); private final DeviceProvisionedController mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class); private final ForegroundServiceController mForegroundServiceController = @@ -113,7 +112,7 @@ public class NotificationEntryManager implements if (mPendingNotifications.size() == 0) { pw.println("null"); } else { - for (NotificationData.Entry entry : mPendingNotifications.values()) { + for (NotificationEntry entry : mPendingNotifications.values()) { pw.println(entry.notification); } } @@ -205,11 +204,11 @@ public class NotificationEntryManager implements private void abortExistingInflation(String key) { if (mPendingNotifications.containsKey(key)) { - NotificationData.Entry entry = mPendingNotifications.get(key); + NotificationEntry entry = mPendingNotifications.get(key); entry.abortTask(); mPendingNotifications.remove(key); } - NotificationData.Entry addedEntry = mNotificationData.get(key); + NotificationEntry addedEntry = mNotificationData.get(key); if (addedEntry != null) { addedEntry.abortTask(); } @@ -230,7 +229,7 @@ public class NotificationEntryManager implements } } - private void maybeScheduleUpdateNotificationViews(NotificationData.Entry entry) { + private void maybeScheduleUpdateNotificationViews(NotificationEntry entry) { long audibleAlertTimeout = RECENTLY_ALERTED_THRESHOLD_MS - (System.currentTimeMillis() - entry.lastAudiblyAlertedMs); if (audibleAlertTimeout > 0) { @@ -240,7 +239,7 @@ public class NotificationEntryManager implements } @Override - public void onAsyncInflationFinished(NotificationData.Entry entry, + public void onAsyncInflationFinished(NotificationEntry entry, @InflationFlag int inflatedFlags) { mPendingNotifications.remove(entry.key); // If there was an async task started after the removal, we don't want to add it back to @@ -279,7 +278,7 @@ public class NotificationEntryManager implements @Nullable NotificationVisibility visibility, boolean forceRemove, boolean removedByUser) { - final NotificationData.Entry entry = mNotificationData.get(key); + final NotificationEntry entry = mNotificationData.get(key); abortExistingInflation(key); @@ -337,19 +336,19 @@ public class NotificationEntryManager implements * */ private void handleGroupSummaryRemoved(String key) { - NotificationData.Entry entry = mNotificationData.get(key); + NotificationEntry entry = mNotificationData.get(key); if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) { if (entry.notification.getOverrideGroupKey() != null && !entry.isRowDismissed()) { // We don't want to remove children for autobundled notifications as they are not // always cancelled. We only remove them if they were dismissed by the user. return; } - List<NotificationData.Entry> childEntries = entry.getChildren(); + List<NotificationEntry> childEntries = entry.getChildren(); if (childEntries == null) { return; } for (int i = 0; i < childEntries.size(); i++) { - NotificationData.Entry childEntry = childEntries.get(i); + NotificationEntry childEntry = childEntries.get(i); boolean isForeground = (entry.notification.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0; boolean keepForReply = @@ -368,19 +367,6 @@ public class NotificationEntryManager implements } } - public void updateNotificationsOnDensityOrFontScaleChanged() { - ArrayList<NotificationData.Entry> userNotifications = - mNotificationData.getNotificationsForCurrentUser(); - for (int i = 0; i < userNotifications.size(); i++) { - NotificationData.Entry entry = userNotifications.get(i); - entry.onDensityOrFontScaleChanged(); - boolean exposedGuts = entry.areGutsExposed(); - if (exposedGuts) { - mGutsManager.onDensityOrFontScaleChanged(entry); - } - } - } - private void addNotificationInternal(StatusBarNotification notification, NotificationListenerService.RankingMap rankingMap) throws InflationException { String key = notification.getKey(); @@ -392,7 +378,7 @@ public class NotificationEntryManager implements NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking(); rankingMap.getRanking(key, ranking); - NotificationData.Entry entry = new NotificationData.Entry(notification, ranking); + NotificationEntry entry = new NotificationEntry(notification, ranking); Dependency.get(LeakDetector.class).trackInstance(entry); // Construct the expanded view. @@ -445,7 +431,7 @@ public class NotificationEntryManager implements final String key = notification.getKey(); abortExistingInflation(key); - NotificationData.Entry entry = mNotificationData.get(key); + NotificationEntry entry = mNotificationData.get(key); if (entry == null) { return; } @@ -461,14 +447,12 @@ public class NotificationEntryManager implements getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification), mNotificationData.get(entry.key) != null); - updateNotifications(); - - if (!notification.isClearable()) { - // The user may have performed a dismiss action on the notification, since it's - // not clearable we should snap it back. - mListContainer.snapViewIfNeeded(entry); + for (NotificationEntryListener listener : mNotificationEntryListeners) { + listener.onPreEntryUpdated(entry); } + updateNotifications(); + if (DEBUG) { // Is this for you? boolean isForCurrentUser = Dependency.get(KeyguardEnvironment.class) @@ -477,7 +461,7 @@ public class NotificationEntryManager implements } for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onEntryUpdated(entry); + listener.onPostEntryUpdated(entry); } maybeScheduleUpdateNotificationViews(entry); @@ -500,14 +484,14 @@ public class NotificationEntryManager implements } public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) { - List<NotificationData.Entry> entries = new ArrayList<>(); + List<NotificationEntry> entries = new ArrayList<>(); entries.addAll(mNotificationData.getActiveNotifications()); entries.addAll(mPendingNotifications.values()); // Has a copy of the current UI adjustments. ArrayMap<String, NotificationUiAdjustment> oldAdjustments = new ArrayMap<>(); ArrayMap<String, Integer> oldImportances = new ArrayMap<>(); - for (NotificationData.Entry entry : entries) { + for (NotificationEntry entry : entries) { NotificationUiAdjustment adjustment = NotificationUiAdjustment.extractFromNotificationEntry(entry); oldAdjustments.put(entry.key, adjustment); @@ -519,7 +503,7 @@ public class NotificationEntryManager implements updateRankingOfPendingNotifications(rankingMap); // By comparing the old and new UI adjustments, reinflate the view accordingly. - for (NotificationData.Entry entry : entries) { + for (NotificationEntry entry : entries) { getRowBinder().onNotificationRankingUpdated( entry, oldImportances.get(entry.key), @@ -537,7 +521,7 @@ public class NotificationEntryManager implements return; } NotificationListenerService.Ranking tmpRanking = new NotificationListenerService.Ranking(); - for (NotificationData.Entry pendingNotification : mPendingNotifications.values()) { + for (NotificationEntry pendingNotification : mPendingNotifications.values()) { rankingMap.getRanking(pendingNotification.key, tmpRanking); pendingNotification.populateFromRanking(tmpRanking); } @@ -548,7 +532,7 @@ public class NotificationEntryManager implements * notifications whose views have not yet been inflated. In general, the system pretends like * these don't exist, although there are a couple exceptions. */ - public Iterable<NotificationData.Entry> getPendingNotificationsIterator() { + public Iterable<NotificationEntry> getPendingNotificationsIterator() { return mPendingNotifications.values(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java index 700382a103b2..e199ead18a68 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java @@ -28,6 +28,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.ForegroundServiceController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; @@ -82,7 +84,7 @@ public class NotificationFilter { /** * @return true if the provided notification should NOT be shown right now. */ - public boolean shouldFilterOut(NotificationData.Entry entry) { + public boolean shouldFilterOut(NotificationEntry entry) { final StatusBarNotification sbn = entry.notification; if (!(getEnvironment().isDeviceProvisioned() || showNotificationEvenIfUnprovisioned(sbn))) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java index 8bd0e9ad3c8b..fc7a2b37eca7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java @@ -37,6 +37,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -139,7 +140,7 @@ public class NotificationInterruptionStateProvider { * @param entry the entry to check * @return true if the entry should heads up, false otherwise */ - public boolean shouldHeadsUp(NotificationData.Entry entry) { + public boolean shouldHeadsUp(NotificationEntry entry) { StatusBarNotification sbn = entry.notification; if (getShadeController().isDozing()) { @@ -227,7 +228,7 @@ public class NotificationInterruptionStateProvider { * @param entry the entry to check * @return true if the entry should ambient pulse, false otherwise */ - public boolean shouldPulse(NotificationData.Entry entry) { + public boolean shouldPulse(NotificationEntry entry) { StatusBarNotification sbn = entry.notification; if (!getShadeController().isDozing()) { @@ -273,14 +274,14 @@ public class NotificationInterruptionStateProvider { /** * Common checks between heads up alerting and ambient pulse alerting. See - * {@link #shouldHeadsUp(NotificationData.Entry)} and - * {@link #shouldPulse(NotificationData.Entry)}. Notifications that fail any of these checks + * {@link #shouldHeadsUp(NotificationEntry)} and + * {@link #shouldPulse(NotificationEntry)}. Notifications that fail any of these checks * should not alert at all. * * @param entry the entry to check * @return true if these checks pass, false if the notification should not alert */ - protected boolean canAlertCommon(NotificationData.Entry entry) { + protected boolean canAlertCommon(NotificationEntry entry) { StatusBarNotification sbn = entry.notification; if (mNotificationFilter.shouldFilterOut(entry)) { @@ -325,7 +326,7 @@ public class NotificationInterruptionStateProvider { * @param sbn notification that might be heads upped * @return false if the notification can not be heads upped */ - boolean canHeadsUp(NotificationData.Entry entry, StatusBarNotification sbn); + boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java index 058efca51b21..cc302b16f7c1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java @@ -42,6 +42,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationUiAdjustment; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationInflater; @@ -126,7 +127,7 @@ public class NotificationRowBinder { * Inflates the views for the given entry (possibly asynchronously). */ public void inflateViews( - NotificationData.Entry entry, + NotificationEntry entry, Runnable onDismissRunnable, boolean isUpdate) throws InflationException { @@ -149,7 +150,7 @@ public class NotificationRowBinder { } } - private void bindRow(NotificationData.Entry entry, PackageManager pmUser, + private void bindRow(NotificationEntry entry, PackageManager pmUser, StatusBarNotification sbn, ExpandableNotificationRow row, Runnable onDismissRunnable) { row.setExpansionLogger(mExpansionLogger, entry.notification.getKey()); @@ -197,7 +198,7 @@ public class NotificationRowBinder { * reinflating them. */ public void onNotificationRankingUpdated( - NotificationData.Entry entry, + NotificationEntry entry, @Nullable Integer oldImportance, NotificationUiAdjustment oldAdjustment, NotificationUiAdjustment newAdjustment, @@ -224,7 +225,7 @@ public class NotificationRowBinder { //TODO: This method associates a row with an entry, but eventually needs to not do that private void updateNotification( - NotificationData.Entry entry, + NotificationEntry entry, PackageManager pmUser, StatusBarNotification sbn, ExpandableNotificationRow row, @@ -292,7 +293,7 @@ public class NotificationRowBinder { * @param sbn notification * @param row row for the notification */ - void onBindRow(NotificationData.Entry entry, PackageManager pmUser, + void onBindRow(NotificationEntry entry, PackageManager pmUser, StatusBarNotification sbn, ExpandableNotificationRow row); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java index a194eef39b6d..f09c57d786ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + /** * An object that can determine the visibility of a Notification. */ @@ -27,5 +29,5 @@ public interface VisibilityLocationProvider { * @param entry * @return true if row is in a visible location */ - boolean isInVisibleLocation(NotificationData.Entry entry); + boolean isInVisibleLocation(NotificationEntry entry); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java index 8e6a93deec69..c886685424f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java @@ -21,6 +21,7 @@ import android.view.View; import androidx.collection.ArraySet; import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -52,7 +53,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener { public VisualStabilityManager(NotificationEntryManager notificationEntryManager) { notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override - public void onEntryReinflated(NotificationData.Entry entry) { + public void onEntryReinflated(NotificationEntry entry) { if (entry.hasLowPriorityStateUpdated()) { onLowPriorityUpdated(entry); if (mPresenter != null) { @@ -163,7 +164,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener { } @Override - public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { + public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { if (isHeadsUp) { // Heads up notifications should in general be allowed to reorder if they are out of // view and stay at the current location if they aren't. @@ -171,7 +172,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener { } } - private void onLowPriorityUpdated(NotificationData.Entry entry) { + private void onLowPriorityUpdated(NotificationEntry entry) { mLowPriorityReorderingViews.add(entry.getRow()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java new file mode 100644 index 000000000000..8c29fb50f00a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2019 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.notification.collection; + +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.service.notification.NotificationListenerService.Ranking; +import android.service.notification.NotificationListenerService.RankingMap; +import android.service.notification.SnoozeCriterion; +import android.service.notification.StatusBarNotification; +import android.util.ArrayMap; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.Dependency; +import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.notification.NotificationFilter; +import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.policy.HeadsUpManager; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; + +/** + * The list of currently displaying notifications. + */ +public class NotificationData { + + private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class); + + /** + * These dependencies are late init-ed + */ + private KeyguardEnvironment mEnvironment; + private NotificationMediaManager mMediaManager; + + private HeadsUpManager mHeadsUpManager; + + private final ArrayMap<String, NotificationEntry> mEntries = new ArrayMap<>(); + private final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>(); + private final ArrayList<NotificationEntry> mFilteredForUser = new ArrayList<>(); + + private final NotificationGroupManager mGroupManager = + Dependency.get(NotificationGroupManager.class); + + private RankingMap mRankingMap; + private final Ranking mTmpRanking = new Ranking(); + + public void setHeadsUpManager(HeadsUpManager headsUpManager) { + mHeadsUpManager = headsUpManager; + } + + private final Comparator<NotificationEntry> mRankingComparator = + new Comparator<NotificationEntry>() { + private final Ranking mRankingA = new Ranking(); + private final Ranking mRankingB = new Ranking(); + + @Override + public int compare(NotificationEntry a, NotificationEntry b) { + final StatusBarNotification na = a.notification; + final StatusBarNotification nb = b.notification; + int aImportance = NotificationManager.IMPORTANCE_DEFAULT; + int bImportance = NotificationManager.IMPORTANCE_DEFAULT; + int aRank = 0; + int bRank = 0; + + if (mRankingMap != null) { + // RankingMap as received from NoMan + getRanking(a.key, mRankingA); + getRanking(b.key, mRankingB); + aImportance = mRankingA.getImportance(); + bImportance = mRankingB.getImportance(); + aRank = mRankingA.getRank(); + bRank = mRankingB.getRank(); + } + + String mediaNotification = getMediaManager().getMediaNotificationKey(); + + // IMPORTANCE_MIN media streams are allowed to drift to the bottom + final boolean aMedia = a.key.equals(mediaNotification) + && aImportance > NotificationManager.IMPORTANCE_MIN; + final boolean bMedia = b.key.equals(mediaNotification) + && bImportance > NotificationManager.IMPORTANCE_MIN; + + boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH + && isSystemNotification(na); + boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH + && isSystemNotification(nb); + + boolean isHeadsUp = a.getRow().isHeadsUp(); + if (isHeadsUp != b.getRow().isHeadsUp()) { + return isHeadsUp ? -1 : 1; + } else if (isHeadsUp) { + // Provide consistent ranking with headsUpManager + return mHeadsUpManager.compare(a, b); + } else if (a.getRow().isAmbientPulsing() != b.getRow().isAmbientPulsing()) { + return a.getRow().isAmbientPulsing() ? -1 : 1; + } else if (aMedia != bMedia) { + // Upsort current media notification. + return aMedia ? -1 : 1; + } else if (aSystemMax != bSystemMax) { + // Upsort PRIORITY_MAX system notifications + return aSystemMax ? -1 : 1; + } else if (aRank != bRank) { + return aRank - bRank; + } else { + return Long.compare(nb.getNotification().when, na.getNotification().when); + } + } + }; + + private KeyguardEnvironment getEnvironment() { + if (mEnvironment == null) { + mEnvironment = Dependency.get(KeyguardEnvironment.class); + } + return mEnvironment; + } + + private NotificationMediaManager getMediaManager() { + if (mMediaManager == null) { + mMediaManager = Dependency.get(NotificationMediaManager.class); + } + return mMediaManager; + } + + /** + * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment} + * + * <p> + * This call doesn't update the list of active notifications. Call {@link #filterAndSort()} + * when the environment changes. + * <p> + * Don't hold on to or modify the returned list. + */ + public ArrayList<NotificationEntry> getActiveNotifications() { + return mSortedAndFiltered; + } + + public ArrayList<NotificationEntry> getNotificationsForCurrentUser() { + mFilteredForUser.clear(); + + synchronized (mEntries) { + final int len = mEntries.size(); + for (int i = 0; i < len; i++) { + NotificationEntry entry = mEntries.valueAt(i); + final StatusBarNotification sbn = entry.notification; + if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) { + continue; + } + mFilteredForUser.add(entry); + } + } + return mFilteredForUser; + } + + public NotificationEntry get(String key) { + return mEntries.get(key); + } + + public void add(NotificationEntry entry) { + synchronized (mEntries) { + mEntries.put(entry.notification.getKey(), entry); + } + mGroupManager.onEntryAdded(entry); + + updateRankingAndSort(mRankingMap); + } + + public NotificationEntry remove(String key, RankingMap ranking) { + NotificationEntry removed; + synchronized (mEntries) { + removed = mEntries.remove(key); + } + if (removed == null) return null; + mGroupManager.onEntryRemoved(removed); + updateRankingAndSort(ranking); + return removed; + } + + /** Updates the given notification entry with the provided ranking. */ + public void update( + NotificationEntry entry, + RankingMap ranking, + StatusBarNotification notification) { + updateRanking(ranking); + final StatusBarNotification oldNotification = entry.notification; + entry.notification = notification; + mGroupManager.onEntryUpdated(entry, oldNotification); + } + + public void updateRanking(RankingMap ranking) { + updateRankingAndSort(ranking); + } + + public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) { + synchronized (mEntries) { + final int len = mEntries.size(); + for (int i = 0; i < len; i++) { + NotificationEntry entry = mEntries.valueAt(i); + if (uid == entry.notification.getUid() + && pkg.equals(entry.notification.getPackageName()) + && key.equals(entry.key)) { + if (showIcon) { + entry.mActiveAppOps.add(appOp); + } else { + entry.mActiveAppOps.remove(appOp); + } + } + } + } + } + + /** + * Returns true if this notification should be displayed in the high-priority notifications + * section (and on the lockscreen and status bar). + */ + public boolean isHighPriority(StatusBarNotification statusBarNotification) { + if (mRankingMap != null) { + getRanking(statusBarNotification.getKey(), mTmpRanking); + if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT + || statusBarNotification.getNotification().isForegroundService() + || statusBarNotification.getNotification().hasMediaSession()) { + return true; + } + if (mGroupManager.isSummaryOfGroup(statusBarNotification)) { + final ArrayList<NotificationEntry> logicalChildren = + mGroupManager.getLogicalChildren(statusBarNotification); + for (NotificationEntry child : logicalChildren) { + if (isHighPriority(child.notification)) { + return true; + } + } + } + } + return false; + } + + public boolean isAmbient(String key) { + if (mRankingMap != null) { + getRanking(key, mTmpRanking); + return mTmpRanking.isAmbient(); + } + return false; + } + + public int getVisibilityOverride(String key) { + if (mRankingMap != null) { + getRanking(key, mTmpRanking); + return mTmpRanking.getVisibilityOverride(); + } + return Ranking.VISIBILITY_NO_OVERRIDE; + } + + public int getImportance(String key) { + if (mRankingMap != null) { + getRanking(key, mTmpRanking); + return mTmpRanking.getImportance(); + } + return NotificationManager.IMPORTANCE_UNSPECIFIED; + } + + public String getOverrideGroupKey(String key) { + if (mRankingMap != null) { + getRanking(key, mTmpRanking); + return mTmpRanking.getOverrideGroupKey(); + } + return null; + } + + public List<SnoozeCriterion> getSnoozeCriteria(String key) { + if (mRankingMap != null) { + getRanking(key, mTmpRanking); + return mTmpRanking.getSnoozeCriteria(); + } + return null; + } + + public NotificationChannel getChannel(String key) { + if (mRankingMap != null) { + getRanking(key, mTmpRanking); + return mTmpRanking.getChannel(); + } + return null; + } + + public int getRank(String key) { + if (mRankingMap != null) { + getRanking(key, mTmpRanking); + return mTmpRanking.getRank(); + } + return 0; + } + + public boolean shouldHide(String key) { + if (mRankingMap != null) { + getRanking(key, mTmpRanking); + return mTmpRanking.isSuspended(); + } + return false; + } + + private void updateRankingAndSort(RankingMap ranking) { + if (ranking != null) { + mRankingMap = ranking; + synchronized (mEntries) { + final int len = mEntries.size(); + for (int i = 0; i < len; i++) { + NotificationEntry entry = mEntries.valueAt(i); + if (!getRanking(entry.key, mTmpRanking)) { + continue; + } + final StatusBarNotification oldSbn = entry.notification.cloneLight(); + final String overrideGroupKey = getOverrideGroupKey(entry.key); + if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) { + entry.notification.setOverrideGroupKey(overrideGroupKey); + mGroupManager.onEntryUpdated(entry, oldSbn); + } + entry.populateFromRanking(mTmpRanking); + } + } + } + filterAndSort(); + } + + /** + * Get the ranking from the current ranking map. + * + * @param key the key to look up + * @param outRanking the ranking to populate + * + * @return {@code true} if the ranking was properly obtained. + */ + @VisibleForTesting + protected boolean getRanking(String key, Ranking outRanking) { + return mRankingMap.getRanking(key, outRanking); + } + + // TODO: This should not be public. Instead the Environment should notify this class when + // anything changed, and this class should call back the UI so it updates itself. + public void filterAndSort() { + mSortedAndFiltered.clear(); + + synchronized (mEntries) { + final int len = mEntries.size(); + for (int i = 0; i < len; i++) { + NotificationEntry entry = mEntries.valueAt(i); + + if (mNotificationFilter.shouldFilterOut(entry)) { + continue; + } + + mSortedAndFiltered.add(entry); + } + } + + Collections.sort(mSortedAndFiltered, mRankingComparator); + } + + public void dump(PrintWriter pw, String indent) { + int filteredLen = mSortedAndFiltered.size(); + pw.print(indent); + pw.println("active notifications: " + filteredLen); + int active; + for (active = 0; active < filteredLen; active++) { + NotificationEntry e = mSortedAndFiltered.get(active); + dumpEntry(pw, indent, active, e); + } + synchronized (mEntries) { + int totalLen = mEntries.size(); + pw.print(indent); + pw.println("inactive notifications: " + (totalLen - active)); + int inactiveCount = 0; + for (int i = 0; i < totalLen; i++) { + NotificationEntry entry = mEntries.valueAt(i); + if (!mSortedAndFiltered.contains(entry)) { + dumpEntry(pw, indent, inactiveCount, entry); + inactiveCount++; + } + } + } + } + + private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) { + getRanking(e.key, mTmpRanking); + pw.print(indent); + pw.println(" [" + i + "] key=" + e.key + " icon=" + e.icon); + StatusBarNotification n = e.notification; + pw.print(indent); + pw.println(" pkg=" + n.getPackageName() + " id=" + n.getId() + " importance=" + + mTmpRanking.getImportance()); + pw.print(indent); + pw.println(" notification=" + n.getNotification()); + } + + private static boolean isSystemNotification(StatusBarNotification sbn) { + String sbnPackage = sbn.getPackageName(); + return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage); + } + + /** + * Provides access to keyguard state and user settings dependent data. + */ + public interface KeyguardEnvironment { + boolean isDeviceProvisioned(); + boolean isNotificationForCurrentProfiles(StatusBarNotification sbn); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java new file mode 100644 index 000000000000..58aa02ccf440 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -0,0 +1,701 @@ +/* + * Copyright (C) 2019 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.notification.collection; + +import static android.app.Notification.CATEGORY_ALARM; +import static android.app.Notification.CATEGORY_CALL; +import static android.app.Notification.CATEGORY_EVENT; +import static android.app.Notification.CATEGORY_MESSAGE; +import static android.app.Notification.CATEGORY_REMINDER; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; + +import android.annotation.NonNull; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager.Policy; +import android.app.Person; +import android.content.Context; +import android.graphics.drawable.Icon; +import android.os.Bundle; +import android.os.Parcelable; +import android.os.SystemClock; +import android.service.notification.NotificationListenerService; +import android.service.notification.SnoozeCriterion; +import android.service.notification.StatusBarNotification; +import android.util.ArraySet; +import android.view.View; +import android.widget.ImageView; + +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.ContrastColorUtil; +import com.android.systemui.statusbar.InflationTask; +import com.android.systemui.statusbar.StatusBarIconView; +import com.android.systemui.statusbar.notification.InflationException; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.NotificationGuts; +import com.android.systemui.statusbar.notification.row.NotificationInflater; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Represents a notification that the system UI knows about + * + * Whenever the NotificationManager tells us about the existence of a new notification, we wrap it + * in a NotificationEntry. Thus, every notification has an associated NotificationEntry, even if + * that notification is never displayed to the user (for example, if it's filtered out for some + * reason). + * + * Entries store information about the current state of the notification. Essentially: + * anything that needs to persist or be modifiable even when the notification's views don't + * exist. Any other state should be stored on the views/view controllers themselves. + * + * At the moment, there are many things here that shouldn't be and vice-versa. Hopefully we can + * clean this up in the future. + */ +public final class NotificationEntry { + private static final long LAUNCH_COOLDOWN = 2000; + private static final long REMOTE_INPUT_COOLDOWN = 500; + private static final long INITIALIZATION_DELAY = 400; + private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN; + private static final int COLOR_INVALID = 1; + public final String key; + public StatusBarNotification notification; + public NotificationChannel channel; + public long lastAudiblyAlertedMs; + public boolean noisy; + public boolean ambient; + public int importance; + public StatusBarIconView icon; + public StatusBarIconView expandedIcon; + private boolean interruption; + public boolean autoRedacted; // whether the redacted notification was generated by us + public int targetSdk; + private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET; + public CharSequence remoteInputText; + public List<SnoozeCriterion> snoozeCriteria; + public int userSentiment = NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; + /** Smart Actions provided by the NotificationAssistantService. */ + @NonNull + public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList(); + public CharSequence[] smartReplies = new CharSequence[0]; + @VisibleForTesting + public int suppressedVisualEffects; + public boolean suspended; + + private NotificationEntry parent; // our parent (if we're in a group) + private ArrayList<NotificationEntry> children = new ArrayList<NotificationEntry>(); + private ExpandableNotificationRow row; // the outer expanded view + + private int mCachedContrastColor = COLOR_INVALID; + private int mCachedContrastColorIsFor = COLOR_INVALID; + private InflationTask mRunningTask = null; + private Throwable mDebugThrowable; + public CharSequence remoteInputTextWhenReset; + public long lastRemoteInputSent = NOT_LAUNCHED_YET; + public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3); + public CharSequence headsUpStatusBarText; + public CharSequence headsUpStatusBarTextPublic; + + private long initializationTime = -1; + + /** + * Whether or not this row represents a system notification. Note that if this is + * {@code null}, that means we were either unable to retrieve the info or have yet to + * retrieve the info. + */ + public Boolean mIsSystemNotification; + + /** + * Has the user sent a reply through this Notification. + */ + private boolean hasSentReply; + + /** + * Whether this notification should be displayed as a bubble. + */ + private boolean mIsBubble; + + /** + * Whether the user has dismissed this notification when it was in bubble form. + */ + private boolean mUserDismissedBubble; + + public NotificationEntry(StatusBarNotification n) { + this(n, null); + } + + public NotificationEntry( + StatusBarNotification n, + @Nullable NotificationListenerService.Ranking ranking) { + this.key = n.getKey(); + this.notification = n; + if (ranking != null) { + populateFromRanking(ranking); + } + } + + public void populateFromRanking(@NonNull NotificationListenerService.Ranking ranking) { + channel = ranking.getChannel(); + lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis(); + importance = ranking.getImportance(); + ambient = ranking.isAmbient(); + snoozeCriteria = ranking.getSnoozeCriteria(); + userSentiment = ranking.getUserSentiment(); + systemGeneratedSmartActions = ranking.getSmartActions() == null + ? Collections.emptyList() : ranking.getSmartActions(); + smartReplies = ranking.getSmartReplies() == null + ? new CharSequence[0] + : ranking.getSmartReplies().toArray(new CharSequence[0]); + suppressedVisualEffects = ranking.getSuppressedVisualEffects(); + suspended = ranking.isSuspended(); + } + + public void setInterruption() { + interruption = true; + } + + public boolean hasInterrupted() { + return interruption; + } + + public void setIsBubble(boolean bubbleable) { + mIsBubble = bubbleable; + } + + public boolean isBubble() { + return mIsBubble; + } + + public void setBubbleDismissed(boolean userDismissed) { + mUserDismissedBubble = userDismissed; + } + + public boolean isBubbleDismissed() { + return mUserDismissedBubble; + } + + /** + * Resets the notification entry to be re-used. + */ + public void reset() { + if (row != null) { + row.reset(); + } + } + + public ExpandableNotificationRow getRow() { + return row; + } + + //TODO: This will go away when we have a way to bind an entry to a row + public void setRow(ExpandableNotificationRow row) { + this.row = row; + } + + @Nullable + public List<NotificationEntry> getChildren() { + if (children.size() <= 0) { + return null; + } + + return children; + } + + public void notifyFullScreenIntentLaunched() { + setInterruption(); + lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime(); + } + + public boolean hasJustLaunchedFullScreenIntent() { + return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN; + } + + public boolean hasJustSentRemoteInput() { + return SystemClock.elapsedRealtime() < lastRemoteInputSent + REMOTE_INPUT_COOLDOWN; + } + + public boolean hasFinishedInitialization() { + return initializationTime == -1 + || SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY; + } + + /** + * Create the icons for a notification + * @param context the context to create the icons with + * @param sbn the notification + * @throws InflationException Exception if required icons are not valid or specified + */ + public void createIcons(Context context, StatusBarNotification sbn) + throws InflationException { + Notification n = sbn.getNotification(); + final Icon smallIcon = n.getSmallIcon(); + if (smallIcon == null) { + throw new InflationException("No small icon in notification from " + + sbn.getPackageName()); + } + + // Construct the icon. + icon = new StatusBarIconView(context, + sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); + icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + + // Construct the expanded icon. + expandedIcon = new StatusBarIconView(context, + sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn); + expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + final StatusBarIcon ic = new StatusBarIcon( + sbn.getUser(), + sbn.getPackageName(), + smallIcon, + n.iconLevel, + n.number, + StatusBarIconView.contentDescForNotification(context, n)); + if (!icon.set(ic) || !expandedIcon.set(ic)) { + icon = null; + expandedIcon = null; + throw new InflationException("Couldn't create icon: " + ic); + } + expandedIcon.setVisibility(View.INVISIBLE); + expandedIcon.setOnVisibilityChangedListener( + newVisibility -> { + if (row != null) { + row.setIconsVisible(newVisibility != View.VISIBLE); + } + }); + } + + public void setIconTag(int key, Object tag) { + if (icon != null) { + icon.setTag(key, tag); + expandedIcon.setTag(key, tag); + } + } + + /** + * Update the notification icons. + * + * @param context the context to create the icons with. + * @param sbn the notification to read the icon from. + * @throws InflationException Exception if required icons are not valid or specified + */ + public void updateIcons(Context context, StatusBarNotification sbn) + throws InflationException { + if (icon != null) { + // Update the icon + Notification n = sbn.getNotification(); + final StatusBarIcon ic = new StatusBarIcon( + notification.getUser(), + notification.getPackageName(), + n.getSmallIcon(), + n.iconLevel, + n.number, + StatusBarIconView.contentDescForNotification(context, n)); + icon.setNotification(sbn); + expandedIcon.setNotification(sbn); + if (!icon.set(ic) || !expandedIcon.set(ic)) { + throw new InflationException("Couldn't update icon: " + ic); + } + } + } + + public int getContrastedColor(Context context, boolean isLowPriority, + int backgroundColor) { + int rawColor = isLowPriority ? Notification.COLOR_DEFAULT : + notification.getNotification().color; + if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) { + return mCachedContrastColor; + } + final int contrasted = ContrastColorUtil.resolveContrastColor(context, rawColor, + backgroundColor); + mCachedContrastColorIsFor = rawColor; + mCachedContrastColor = contrasted; + return mCachedContrastColor; + } + + /** + * Abort all existing inflation tasks + */ + public void abortTask() { + if (mRunningTask != null) { + mRunningTask.abort(); + mRunningTask = null; + } + } + + public void setInflationTask(InflationTask abortableTask) { + // abort any existing inflation + InflationTask existing = mRunningTask; + abortTask(); + mRunningTask = abortableTask; + if (existing != null && mRunningTask != null) { + mRunningTask.supersedeTask(existing); + } + } + + public void onInflationTaskFinished() { + mRunningTask = null; + } + + @VisibleForTesting + public InflationTask getRunningTask() { + return mRunningTask; + } + + /** + * Set a throwable that is used for debugging + * + * @param debugThrowable the throwable to save + */ + public void setDebugThrowable(Throwable debugThrowable) { + mDebugThrowable = debugThrowable; + } + + public Throwable getDebugThrowable() { + return mDebugThrowable; + } + + public void onRemoteInputInserted() { + lastRemoteInputSent = NOT_LAUNCHED_YET; + remoteInputTextWhenReset = null; + } + + public void setHasSentReply() { + hasSentReply = true; + } + + public boolean isLastMessageFromReply() { + if (!hasSentReply) { + return false; + } + Bundle extras = notification.getNotification().extras; + CharSequence[] replyTexts = extras.getCharSequenceArray( + Notification.EXTRA_REMOTE_INPUT_HISTORY); + if (!ArrayUtils.isEmpty(replyTexts)) { + return true; + } + Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES); + if (messages != null && messages.length > 0) { + Parcelable message = messages[messages.length - 1]; + if (message instanceof Bundle) { + Notification.MessagingStyle.Message lastMessage = + Notification.MessagingStyle.Message.getMessageFromBundle( + (Bundle) message); + if (lastMessage != null) { + Person senderPerson = lastMessage.getSenderPerson(); + if (senderPerson == null) { + return true; + } + Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON); + return Objects.equals(user, senderPerson); + } + } + } + return false; + } + + public void setInitializationTime(long time) { + if (initializationTime == -1) { + initializationTime = time; + } + } + + public void sendAccessibilityEvent(int eventType) { + if (row != null) { + row.sendAccessibilityEvent(eventType); + } + } + + /** + * Used by NotificationMediaManager to determine... things + * @return {@code true} if we are a media notification + */ + public boolean isMediaNotification() { + if (row == null) return false; + + return row.isMediaRow(); + } + + /** + * We are a top level child if our parent is the list of notifications duh + * @return {@code true} if we're a top level notification + */ + public boolean isTopLevelChild() { + return row != null && row.isTopLevelChild(); + } + + public void resetUserExpansion() { + if (row != null) row.resetUserExpansion(); + } + + public void freeContentViewWhenSafe(@NotificationInflater.InflationFlag int inflationFlag) { + if (row != null) row.freeContentViewWhenSafe(inflationFlag); + } + + public void setAmbientPulsing(boolean pulsing) { + if (row != null) row.setAmbientPulsing(pulsing); + } + + public boolean rowExists() { + return row != null; + } + + public boolean isRowDismissed() { + return row != null && row.isDismissed(); + } + + public boolean isRowRemoved() { + return row != null && row.isRemoved(); + } + + /** + * @return {@code true} if the row is null or removed + */ + public boolean isRemoved() { + //TODO: recycling invalidates this + return row == null || row.isRemoved(); + } + + /** + * @return {@code true} if the row is null or dismissed + */ + public boolean isDismissed() { + //TODO: recycling + return row == null || row.isDismissed(); + } + + public boolean isRowPinned() { + return row != null && row.isPinned(); + } + + public void setRowPinned(boolean pinned) { + if (row != null) row.setPinned(pinned); + } + + public boolean isRowAnimatingAway() { + return row != null && row.isHeadsUpAnimatingAway(); + } + + public boolean isRowHeadsUp() { + return row != null && row.isHeadsUp(); + } + + public void setHeadsUp(boolean shouldHeadsUp) { + if (row != null) row.setHeadsUp(shouldHeadsUp); + } + + public boolean mustStayOnScreen() { + return row != null && row.mustStayOnScreen(); + } + + public void setHeadsUpIsVisible() { + if (row != null) row.setHeadsUpIsVisible(); + } + + //TODO: i'm imagining a world where this isn't just the row, but I could be rwong + public ExpandableNotificationRow getHeadsUpAnimationView() { + return row; + } + + public void setUserLocked(boolean userLocked) { + if (row != null) row.setUserLocked(userLocked); + } + + public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) { + if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion); + } + + public void setGroupExpansionChanging(boolean changing) { + if (row != null) row.setGroupExpansionChanging(changing); + } + + public void notifyHeightChanged(boolean needsAnimation) { + if (row != null) row.notifyHeightChanged(needsAnimation); + } + + public void closeRemoteInput() { + if (row != null) row.closeRemoteInput(); + } + + public boolean areChildrenExpanded() { + return row != null && row.areChildrenExpanded(); + } + + public boolean keepInParent() { + return row != null && row.keepInParent(); + } + + //TODO: probably less confusing to say "is group fully visible" + public boolean isGroupNotFullyVisible() { + return row == null || row.isGroupNotFullyVisible(); + } + + public NotificationGuts getGuts() { + if (row != null) return row.getGuts(); + return null; + } + + public boolean hasLowPriorityStateUpdated() { + return row != null && row.hasLowPriorityStateUpdated(); + } + + public void removeRow() { + if (row != null) row.setRemoved(); + } + + public boolean isSummaryWithChildren() { + return row != null && row.isSummaryWithChildren(); + } + + public void setKeepInParent(boolean keep) { + if (row != null) row.setKeepInParent(keep); + } + + public void onDensityOrFontScaleChanged() { + if (row != null) row.onDensityOrFontScaleChanged(); + } + + public boolean areGutsExposed() { + return row != null && row.getGuts() != null && row.getGuts().isExposed(); + } + + public boolean isChildInGroup() { + return parent == null; + } + + public void setLowPriorityStateUpdated(boolean updated) { + if (row != null) row.setLowPriorityStateUpdated(updated); + } + + /** + * @return Can the underlying notification be cleared? This can be different from whether the + * notification can be dismissed in case notifications are sensitive on the lockscreen. + * @see #canViewBeDismissed() + */ + public boolean isClearable() { + if (notification == null || !notification.isClearable()) { + return false; + } + if (children.size() > 0) { + for (int i = 0; i < children.size(); i++) { + NotificationEntry child = children.get(i); + if (!child.isClearable()) { + return false; + } + } + } + return true; + } + + public boolean canViewBeDismissed() { + if (row == null) return true; + return row.canViewBeDismissed(); + } + + @VisibleForTesting + boolean isExemptFromDndVisualSuppression() { + if (isNotificationBlockedByPolicy(notification.getNotification())) { + return false; + } + + if ((notification.getNotification().flags + & Notification.FLAG_FOREGROUND_SERVICE) != 0) { + return true; + } + if (notification.getNotification().isMediaNotification()) { + return true; + } + if (mIsSystemNotification != null && mIsSystemNotification) { + return true; + } + return false; + } + + private boolean shouldSuppressVisualEffect(int effect) { + if (isExemptFromDndVisualSuppression()) { + return false; + } + return (suppressedVisualEffects & effect) != 0; + } + + /** + * Returns whether {@link Policy#SUPPRESSED_EFFECT_FULL_SCREEN_INTENT} + * is set for this entry. + */ + public boolean shouldSuppressFullScreenIntent() { + return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); + } + + /** + * Returns whether {@link Policy#SUPPRESSED_EFFECT_PEEK} + * is set for this entry. + */ + public boolean shouldSuppressPeek() { + return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_PEEK); + } + + /** + * Returns whether {@link Policy#SUPPRESSED_EFFECT_STATUS_BAR} + * is set for this entry. + */ + public boolean shouldSuppressStatusBar() { + return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_STATUS_BAR); + } + + /** + * Returns whether {@link Policy#SUPPRESSED_EFFECT_AMBIENT} + * is set for this entry. + */ + public boolean shouldSuppressAmbient() { + return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_AMBIENT); + } + + /** + * Returns whether {@link Policy#SUPPRESSED_EFFECT_NOTIFICATION_LIST} + * is set for this entry. + */ + public boolean shouldSuppressNotificationList() { + return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_NOTIFICATION_LIST); + } + + /** + * Categories that are explicitly called out on DND settings screens are always blocked, if + * DND has flagged them, even if they are foreground or system notifications that might + * otherwise visually bypass DND. + */ + private static boolean isNotificationBlockedByPolicy(Notification n) { + return isCategory(CATEGORY_CALL, n) + || isCategory(CATEGORY_MESSAGE, n) + || isCategory(CATEGORY_ALARM, n) + || isCategory(CATEGORY_EVENT, n) + || isCategory(CATEGORY_REMINDER, n); + } + + private static boolean isCategory(String category, Notification n) { + return Objects.equals(n.category, category); + } +} 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 43048a2c087e..3eec38e14083 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 @@ -33,9 +33,9 @@ import com.android.systemui.UiOffloadThread; 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.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -115,11 +115,11 @@ public class NotificationLogger implements StateListener { // notifications. // 3. Report newly visible and no-longer visible notifications. // 4. Keep currently visible notifications for next report. - ArrayList<NotificationData.Entry> activeNotifications = mEntryManager + ArrayList<NotificationEntry> activeNotifications = mEntryManager .getNotificationData().getActiveNotifications(); int N = activeNotifications.size(); for (int i = 0; i < N; i++) { - NotificationData.Entry entry = activeNotifications.get(i); + NotificationEntry entry = activeNotifications.get(i); String key = entry.notification.getKey(); boolean isVisible = mListContainer.isInVisibleLocation(entry); NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible); @@ -167,7 +167,7 @@ public class NotificationLogger implements StateListener { entryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override public void onEntryRemoved( - NotificationData.Entry entry, + NotificationEntry entry, NotificationVisibility visibility, boolean removedByUser) { if (removedByUser && visibility != null) { 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 a58c7cde32a7..9e0dd8461d21 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 @@ -86,10 +86,10 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.AboveShelfChangedListener; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationCounters; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; @@ -199,7 +199,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private ExpansionLogger mLogger; private String mLoggingKey; private NotificationGuts mGuts; - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; private StatusBarNotification mStatusBarNotification; private String mAppName; @@ -451,7 +451,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * * @param entry the entry this row is tied to */ - public void setEntry(@NonNull NotificationData.Entry entry) { + public void setEntry(@NonNull NotificationEntry entry) { mEntry = entry; mStatusBarNotification = entry.notification; cacheIsSystemNotification(); @@ -685,7 +685,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mStatusBarNotification; } - public NotificationData.Entry getEntry() { + public NotificationEntry getEntry() { return mEntry; } @@ -1422,7 +1422,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void performDismiss(boolean fromAccessibility) { if (isOnlyChildInGroup()) { - NotificationData.Entry groupSummary = + NotificationEntry groupSummary = mGroupManager.getLogicalGroupSummary(getStatusBarNotification()); if (groupSummary.isClearable()) { // If this is the only child in the group, dismiss the group, but don't try to show @@ -2538,7 +2538,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView /** * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as * otherwise some state might not be updated. To request about the general clearability - * see {@link NotificationData.Entry#isClearable()}. + * see {@link NotificationEntry#isClearable()}. */ public boolean canViewBeDismissed() { return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral); @@ -2969,7 +2969,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } public interface OnExpandClickListener { - void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded); + void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 02a310c29379..bf30cf9a53c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -46,8 +46,8 @@ import com.android.systemui.R; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.TransformableView; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationUtils; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -1231,7 +1231,7 @@ public class NotificationContentView extends FrameLayout { updateAllSingleLineViews(); } - public void onNotificationUpdated(NotificationData.Entry entry) { + public void onNotificationUpdated(NotificationEntry entry) { mStatusBarNotification = entry.notification; mOnContentViewInactiveListeners.clear(); mBeforeN = entry.targetSdk < Build.VERSION_CODES.N; @@ -1292,7 +1292,7 @@ public class NotificationContentView extends FrameLayout { } } - private void applyRemoteInputAndSmartReply(final NotificationData.Entry entry) { + private void applyRemoteInputAndSmartReply(final NotificationEntry entry) { if (mRemoteInputController == null) { return; } @@ -1313,7 +1313,7 @@ public class NotificationContentView extends FrameLayout { @VisibleForTesting static SmartRepliesAndActions chooseSmartRepliesAndActions( SmartReplyConstants smartReplyConstants, - final NotificationData.Entry entry) { + final NotificationEntry entry) { boolean enableAppGeneratedSmartReplies = (smartReplyConstants.isEnabled() && (!smartReplyConstants.requiresTargetingP() || entry.targetSdk >= Build.VERSION_CODES.P)); @@ -1370,7 +1370,7 @@ public class NotificationContentView extends FrameLayout { smartReplies, smartActions, freeformRemoteInputActionPair != null); } - private void applyRemoteInput(NotificationData.Entry entry, boolean hasFreeformRemoteInput) { + private void applyRemoteInput(NotificationEntry entry, boolean hasFreeformRemoteInput) { View bigContentView = mExpandedChild; if (bigContentView != null) { mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasFreeformRemoteInput, @@ -1402,7 +1402,7 @@ public class NotificationContentView extends FrameLayout { mCachedHeadsUpRemoteInput = null; } - private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry, + private RemoteInputView applyRemoteInput(View view, NotificationEntry entry, boolean hasRemoteInput, PendingIntent existingPendingIntent, RemoteInputView cachedView, NotificationViewWrapper wrapper) { View actionContainerCandidate = view.findViewById( @@ -1470,7 +1470,7 @@ public class NotificationContentView extends FrameLayout { } private void applySmartReplyView(SmartRepliesAndActions smartRepliesAndActions, - NotificationData.Entry entry) { + NotificationEntry entry) { if (mExpandedChild != null) { mExpandedSmartReplyView = applySmartReplyView(mExpandedChild, smartRepliesAndActions, entry); @@ -1496,7 +1496,7 @@ public class NotificationContentView extends FrameLayout { } private SmartReplyView applySmartReplyView(View view, - SmartRepliesAndActions smartRepliesAndActions, NotificationData.Entry entry) { + SmartRepliesAndActions smartRepliesAndActions, NotificationEntry entry) { View smartReplyContainerCandidate = view.findViewById( com.android.internal.R.id.smart_reply_container); if (!(smartReplyContainerCandidate instanceof LinearLayout)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index ac4e5830d76b..bd1dfb181afe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -48,7 +48,7 @@ import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationActivityStarter; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.StatusBar; @@ -116,7 +116,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mNotificationActivityStarter = notificationActivityStarter; } - public void onDensityOrFontScaleChanged(NotificationData.Entry entry) { + public void onDensityOrFontScaleChanged(NotificationEntry entry) { setExposedGuts(entry.getGuts()); bindGuts(entry.getRow()); } @@ -429,7 +429,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx } @Override - public boolean shouldExtendLifetime(NotificationData.Entry entry) { + public boolean shouldExtendLifetime(NotificationEntry entry) { return entry != null &&(mNotificationGutsExposed != null && entry.getGuts() != null @@ -438,7 +438,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx } @Override - public void setShouldManageLifetime(NotificationData.Entry entry, boolean shouldExtend) { + public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) { if (shouldExtend) { mKeyToRemoveOnGutsClosed = entry.key; if (Log.isLoggable(TAG, Log.DEBUG)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java index 9908049984d1..42ebfceca334 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java @@ -37,7 +37,7 @@ import com.android.internal.widget.ImageMessageConsumer; import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.MediaNotificationProcessor; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.Assert; @@ -614,7 +614,7 @@ public class NotificationInflater { @Nullable InflationCallback endListener, ExpandableNotificationRow row, boolean redactAmbient) { Assert.isMainThread(); - NotificationData.Entry entry = row.getEntry(); + NotificationEntry entry = row.getEntry(); NotificationContentView privateLayout = row.getPrivateLayout(); NotificationContentView publicLayout = row.getPublicLayout(); if (runningInflations.isEmpty()) { @@ -724,7 +724,7 @@ public class NotificationInflater { * @param entry the entry with the content views set * @param inflatedFlags the flags associated with the content views that were inflated */ - void onAsyncInflationFinished(NotificationData.Entry entry, + void onAsyncInflationFinished(NotificationEntry entry, @InflationFlag int inflatedFlags); /** @@ -782,7 +782,7 @@ public class NotificationInflater { mRedactAmbient = redactAmbient; mRemoteViewClickHandler = remoteViewClickHandler; mCallback = callback; - NotificationData.Entry entry = row.getEntry(); + NotificationEntry entry = row.getEntry(); entry.setInflationTask(this); } @@ -857,7 +857,7 @@ public class NotificationInflater { } @Override - public void onAsyncInflationFinished(NotificationData.Entry entry, + public void onAsyncInflationFinished(NotificationEntry entry, @InflationFlag int inflatedFlags) { mRow.getEntry().onInflationTaskFinished(); mRow.onNotificationUpdated(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java index 1741a0b6b37c..0160c547b336 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java @@ -25,7 +25,7 @@ import androidx.asynclayoutinflater.view.AsyncLayoutInflater; import com.android.systemui.R; import com.android.systemui.statusbar.InflationTask; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; /** * An inflater task that asynchronously inflates a ExpandableNotificationRow @@ -36,14 +36,14 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf private static final boolean TRACE_ORIGIN = true; private RowInflationFinishedListener mListener; - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; private boolean mCancelled; private Throwable mInflateOrigin; /** * Inflates a new notificationView. This should not be called twice on this object */ - public void inflate(Context context, ViewGroup parent, NotificationData.Entry entry, + public void inflate(Context context, ViewGroup parent, NotificationEntry entry, RowInflationFinishedListener listener) { if (TRACE_ORIGIN) { mInflateOrigin = new Throwable("inflate requested here"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index 670908fe175d..cbec37effe18 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -25,7 +25,7 @@ import com.android.systemui.R; import com.android.systemui.statusbar.AmbientPulseManager; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -358,7 +358,7 @@ public class AmbientState { mPulsing = hasPulsing; } - public boolean isPulsing(NotificationData.Entry entry) { + public boolean isPulsing(NotificationEntry entry) { if (!mPulsing || mAmbientPulseManager == null) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java index f0a26536d7b8..f771be043c07 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java @@ -16,15 +16,14 @@ package com.android.systemui.statusbar.notification.stack; -import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator - .ExpandAnimationParameters; +import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; import android.view.View; import android.view.ViewGroup; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.VisibilityLocationProvider; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -113,19 +112,12 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange void setMaxDisplayedNotifications(int maxNotifications); /** - * Handle snapping a non-dismissable row back if the user tried to dismiss it. - * - * @param entry the entry whose row needs to snap back - */ - void snapViewIfNeeded(NotificationData.Entry entry); - - /** * Get the view parent for a notification entry. For example, NotificationStackScrollLayout. * * @param entry entry to get the view parent for * @return the view parent for entry */ - ViewGroup getViewParentForNotification(NotificationData.Entry entry); + ViewGroup getViewParentForNotification(NotificationEntry entry); /** * Resets the currently exposed menu view. @@ -148,7 +140,7 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange * * @param entry the entry whose view's view state needs to be cleaned up (say that 5 times fast) */ - void cleanUpViewStateForEntry(NotificationData.Entry entry); + void cleanUpViewStateForEntry(NotificationEntry entry); /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index 4f0831f1043c..941860177d1b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.NUM_SECTIONS; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -49,12 +49,12 @@ class NotificationRoundnessManager implements OnHeadsUpChangedListener { } @Override - public void onHeadsUpPinned(NotificationData.Entry headsUp) { + public void onHeadsUpPinned(NotificationEntry headsUp) { updateView(headsUp.getRow(), false /* animate */); } @Override - public void onHeadsUpUnPinned(NotificationData.Entry headsUp) { + public void onHeadsUpUnPinned(NotificationEntry headsUp) { updateView(headsUp.getRow(), true /* animate */); } 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 8deb7d5e8456..80db6c11e324 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 @@ -96,12 +96,13 @@ 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.FakeShadowView; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.ShadeViewRefactor; import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -517,6 +518,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mLowPriorityBeforeSpeedBump = "1".equals(newValue); } }, LOW_PRIORITY); + + mEntryManager.addNotificationEntryListener(new NotificationEntryListener() { + @Override + public void onPostEntryUpdated(NotificationEntry entry) { + if (!entry.notification.isClearable()) { + // The user may have performed a dismiss action on the notification, since it's + // not clearable we should snap it back. + snapViewIfNeeded(entry); + } + } + }); } @Override @@ -590,14 +602,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public RemoteInputController.Delegate createDelegate() { return new RemoteInputController.Delegate() { - public void setRemoteInputActive(NotificationData.Entry entry, + public void setRemoteInputActive(NotificationEntry entry, boolean remoteInputActive) { mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive); entry.notifyHeightChanged(true /* needsAnimation */); updateFooter(); } - public void lockScrollTo(NotificationData.Entry entry) { + public void lockScrollTo(NotificationEntry entry) { NotificationStackScrollLayout.this.lockScrollTo(entry.getRow()); } @@ -910,7 +922,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM) - public boolean isInVisibleLocation(NotificationData.Entry entry) { + public boolean isInVisibleLocation(NotificationEntry entry) { ExpandableNotificationRow row = entry.getRow(); ExpandableViewState childViewState = row.getViewState(); @@ -1224,13 +1236,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd */ @ShadeViewRefactor(RefactorComponent.COORDINATOR) private int getTopHeadsUpPinnedHeight() { - NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry(); + NotificationEntry topEntry = mHeadsUpManager.getTopEntry(); if (topEntry == null) { return 0; } ExpandableNotificationRow row = topEntry.getRow(); if (row.isChildInGroup()) { - final NotificationData.Entry groupSummary + final NotificationEntry groupSummary = mGroupManager.getGroupSummary(row.getStatusBarNotification()); if (groupSummary != null) { row = groupSummary.getRow(); @@ -1405,7 +1417,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd && touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) { if (slidingChild instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild; - NotificationData.Entry entry = row.getEntry(); + NotificationEntry entry = row.getEntry(); if (!mIsExpanded && row.isHeadsUp() && row.isPinned() && mHeadsUpManager.getTopEntry().getRow() != row && mGroupManager.getGroupSummary( @@ -1538,9 +1550,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd true /* isDismissAll */); } - @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void snapViewIfNeeded(NotificationData.Entry entry) { + private void snapViewIfNeeded(NotificationEntry entry) { ExpandableNotificationRow child = entry.getRow(); boolean animate = mIsExpanded || isPinnedHeadsUp(child); // If the child is showing the notification menu snap to that @@ -1550,7 +1561,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override @ShadeViewRefactor(RefactorComponent.ADAPTER) - public ViewGroup getViewParentForNotification(NotificationData.Entry entry) { + public ViewGroup getViewParentForNotification(NotificationEntry entry) { return this; } @@ -2053,7 +2064,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - private boolean isPulsing(NotificationData.Entry entry) { + private boolean isPulsing(NotificationEntry entry) { return mAmbientState.isPulsing(entry); } @@ -2558,7 +2569,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) @Override - public void cleanUpViewStateForEntry(NotificationData.Entry entry) { + public void cleanUpViewStateForEntry(NotificationEntry entry) { View child = entry.getRow(); if (child == mSwipeHelper.getTranslatingParentView()) { mSwipeHelper.clearTranslatingParentView(); @@ -2686,7 +2697,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private boolean isChildInInvisibleGroup(View child) { if (child instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; - NotificationData.Entry groupSummary = + NotificationEntry groupSummary = mGroupManager.getGroupSummary(row.getStatusBarNotification()); if (groupSummary != null && groupSummary.getRow() != row) { return row.getVisibility() == View.INVISIBLE; @@ -4705,7 +4716,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed); } - public void generateHeadsUpAnimation(NotificationData.Entry entry, boolean isHeadsUp) { + public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) { ExpandableNotificationRow row = entry.getHeadsUpAnimationView(); generateHeadsUpAnimation(row, isHeadsUp); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index d1e488ab2b4d..876b9028a9b6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -28,7 +28,7 @@ import com.android.systemui.R; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.HeadsUpStatusBarView; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -143,7 +143,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, } @Override - public void onHeadsUpPinned(NotificationData.Entry entry) { + public void onHeadsUpPinned(NotificationEntry entry) { updateTopEntry(); updateHeader(entry); } @@ -206,11 +206,11 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, } private void updateTopEntry() { - NotificationData.Entry newEntry = null; + NotificationEntry newEntry = null; if (!mIsExpanded && mHeadsUpManager.hasPinnedHeadsUp()) { newEntry = mHeadsUpManager.getTopEntry(); } - NotificationData.Entry previousEntry = mHeadsUpStatusBarView.getShowingEntry(); + NotificationEntry previousEntry = mHeadsUpStatusBarView.getShowingEntry(); mHeadsUpStatusBarView.setEntry(newEntry); if (newEntry != previousEntry) { boolean animateIsolation = false; @@ -298,7 +298,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, } @Override - public void onHeadsUpUnPinned(NotificationData.Entry entry) { + public void onHeadsUpUnPinned(NotificationEntry entry) { updateTopEntry(); updateHeader(entry); } @@ -338,7 +338,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, }); } - public void updateHeader(NotificationData.Entry entry) { + public void updateHeader(NotificationEntry entry) { ExpandableNotificationRow row = entry.getRow(); float headerVisibleAmount = 1.0f; if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index f4cfd4197637..0fada667dd2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -41,8 +41,8 @@ import com.android.systemui.bubbles.BubbleController; 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.NotificationData; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -72,8 +72,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, private int mDisplayCutoutTouchableRegionSize; private boolean mTrackingHeadsUp; private HashSet<String> mSwipedOutKeys = new HashSet<>(); - private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>(); - private ArraySet<NotificationData.Entry> mEntriesToRemoveWhenReorderingAllowed + private HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>(); + private ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed = new ArraySet<>(); private boolean mIsExpanded; private int[] mTmpTwoArray = new int[2]; @@ -187,7 +187,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, releaseAllImmediately(); mReleaseOnExpandFinish = false; } else { - for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) { + for (NotificationEntry entry : mEntriesToRemoveAfterExpand) { if (isAlerting(entry.key)) { // Maybe the heads-up was removed already removeAlertEntry(entry.key); @@ -252,7 +252,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, * @param remoteInputActive True to notify active, False to notify inactive. */ public void setRemoteInputActive( - @NonNull NotificationData.Entry entry, boolean remoteInputActive) { + @NonNull NotificationEntry entry, boolean remoteInputActive) { HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.key); if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) { headsUpEntry.remoteInputActive = remoteInputActive; @@ -268,7 +268,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, * Sets whether an entry's menu row is exposed and therefore it should stick in the heads up * area if it's pinned until it's hidden again. */ - public void setMenuShown(@NonNull NotificationData.Entry entry, boolean menuShown) { + public void setMenuShown(@NonNull NotificationEntry entry, boolean menuShown) { HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key); if (headsUpEntry instanceof HeadsUpEntryPhone && entry.isRowPinned()) { ((HeadsUpEntryPhone) headsUpEntry).setMenuShownPinned(menuShown); @@ -315,9 +315,9 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, return; } if (hasPinnedHeadsUp()) { - NotificationData.Entry topEntry = getTopEntry(); + NotificationEntry topEntry = getTopEntry(); if (topEntry.isChildInGroup()) { - final NotificationData.Entry groupSummary + final NotificationEntry groupSummary = mGroupManager.getGroupSummary(topEntry.notification); if (groupSummary != null) { topEntry = groupSummary; @@ -374,7 +374,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, @Override public void onReorderingAllowed() { mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false); - for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) { + for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) { if (isAlerting(entry.key)) { // Maybe the heads-up was removed already removeAlertEntry(entry.key); @@ -399,7 +399,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, } @Override - protected boolean shouldHeadsUpBecomePinned(NotificationData.Entry entry) { + protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) { return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded || super.shouldHeadsUpBecomePinned(entry); } @@ -488,7 +488,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, return super.isSticky() || mMenuShownPinned; } - public void setEntry(@NonNull final NotificationData.Entry entry) { + public void setEntry(@NonNull final NotificationEntry entry) { Runnable removeHeadsUpRunnable = () -> { if (!mVisualStabilityManager.isReorderingAllowed()) { mEntriesToRemoveWhenReorderingAllowed.add(entry); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index 9c1c71a2dec8..dd200da56d20 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -21,7 +21,7 @@ import android.view.MotionEvent; import android.view.ViewConfiguration; import com.android.systemui.Gefingerpoken; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -83,7 +83,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken { } else if (child == null && !mCallback.isExpanded()) { // We might touch above the visible heads up child, but then we still would // like to capture it. - NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry(); + NotificationEntry topEntry = mHeadsUpManager.getTopEntry(); if (topEntry != null && topEntry.isRowPinned()) { mPickedChild = topEntry.getRow(); mTouchingHeadsUpView = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java index 927228eae20e..925a19d6f5eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java @@ -22,7 +22,7 @@ import android.util.Log; import com.android.systemui.Dependency; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment; +import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; import com.android.systemui.statusbar.policy.DeviceProvisionedController; public class KeyguardEnvironmentImpl implements KeyguardEnvironment { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java index af3257ae423e..d364356b19fe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java @@ -31,9 +31,9 @@ import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListen import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarStateController.StateListener; -import com.android.systemui.statusbar.notification.NotificationData.Entry; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInflater.AsyncInflationTask; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup; @@ -108,7 +108,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis * @param entry notification to check * @return true if the entry was transferred to and should inflate + alert */ - public boolean isAlertTransferPending(@NonNull Entry entry) { + public boolean isAlertTransferPending(@NonNull NotificationEntry entry) { PendingAlertInfo alertInfo = mPendingAlerts.get(entry.key); return alertInfo != null && alertInfo.isStillValid(); } @@ -172,16 +172,16 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis }; @Override - public void onAmbientStateChanged(Entry entry, boolean isAmbient) { + public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) { onAlertStateChanged(entry, isAmbient, mAmbientPulseManager); } @Override - public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) { + public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager); } - private void onAlertStateChanged(Entry entry, boolean isAlerting, + private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting, AlertingNotificationManager alertManager) { if (isAlerting && mGroupManager.isSummaryOfSuppressedGroup(entry.notification)) { handleSuppressedSummaryAlerted(entry, alertManager); @@ -193,7 +193,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis // Called when a new notification has been posted but is not inflated yet. We use this to // see as early as we can if we need to abort a transfer. @Override - public void onPendingEntryAdded(Entry entry) { + public void onPendingEntryAdded(NotificationEntry entry) { String groupKey = mGroupManager.getGroupKey(entry.notification); GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey); if (groupAlertEntry != null) { @@ -204,7 +204,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis // Called when the entry's reinflation has finished. If there is an alert pending, we // then show the alert. @Override - public void onEntryReinflated(Entry entry) { + public void onEntryReinflated(NotificationEntry entry) { PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key); if (alertInfo != null) { if (alertInfo.isStillValid()) { @@ -219,7 +219,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis @Override public void onEntryRemoved( - @Nullable Entry entry, + @Nullable NotificationEntry entry, NotificationVisibility visibility, boolean removedByUser) { // Removes any alerts pending on this entry. Note that this will not stop any inflation @@ -241,8 +241,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis return 0; } int number = 0; - Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator(); - for (Entry entry : values) { + Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator(); + for (NotificationEntry entry : values) { if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) { number++; } @@ -260,8 +260,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis if (mEntryManager == null) { return false; } - Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator(); - for (Entry entry : values) { + Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator(); + for (NotificationEntry entry : values) { if (isPendingNotificationInGroup(entry, group)) { return true; } @@ -276,7 +276,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis * @param group group to check * @return true if the notification will add to the group, false o/w */ - private boolean isPendingNotificationInGroup(@NonNull Entry entry, + private boolean isPendingNotificationInGroup(@NonNull NotificationEntry entry, @NonNull NotificationGroup group) { String groupKey = mGroupManager.getGroupKey(group.summary.notification); return mGroupManager.isGroupChild(entry.notification) @@ -293,7 +293,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis * @param summary the summary that is suppressed and alerting * @param alertManager the alert manager that manages the alerting summary */ - private void handleSuppressedSummaryAlerted(@NonNull Entry summary, + private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary, @NonNull AlertingNotificationManager alertManager) { StatusBarNotification sbn = summary.notification; GroupAlertEntry groupAlertEntry = @@ -309,7 +309,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis return; } - Entry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next(); + NotificationEntry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next(); if (child != null) { if (child.getRow().keepInParent() || child.isRowRemoved() @@ -333,7 +333,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis * @param toEntry entry to transfer to * @param alertManager alert manager for the alert type */ - private void transferAlertState(@NonNull Entry fromEntry, @NonNull Entry toEntry, + private void transferAlertState(@NonNull NotificationEntry fromEntry, @NonNull NotificationEntry toEntry, @NonNull AlertingNotificationManager alertManager) { alertManager.removeNotification(fromEntry.key, true /* releaseImmediately */); alertNotificationWhenPossible(toEntry, alertManager); @@ -353,13 +353,13 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) { if (SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime < ALERT_TRANSFER_TIMEOUT) { - Entry summary = groupAlertEntry.mGroup.summary; + NotificationEntry summary = groupAlertEntry.mGroup.summary; AlertingNotificationManager alertManager = getActiveAlertManager(); if (!onlySummaryAlerts(summary)) { return; } - ArrayList<Entry> children = mGroupManager.getLogicalChildren(summary.notification); + ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.notification); int numChildren = children.size(); int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup); numChildren += numPendingChildren; @@ -368,7 +368,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis } boolean releasedChild = false; for (int i = 0; i < children.size(); i++) { - Entry entry = children.get(i); + NotificationEntry entry = children.get(i); if (onlySummaryAlerts(entry) && alertManager.isAlerting(entry.key)) { releasedChild = true; alertManager.removeNotification(entry.key, true /* releaseImmediately */); @@ -399,7 +399,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis * @param entry entry to show * @param alertManager alert manager for the alert type */ - private void alertNotificationWhenPossible(@NonNull Entry entry, + private void alertNotificationWhenPossible(@NonNull NotificationEntry entry, @NonNull AlertingNotificationManager alertManager) { @InflationFlag int contentFlag = alertManager.getContentFlag(); if (!entry.getRow().isInflationFlagSet(contentFlag)) { @@ -419,7 +419,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis return mIsDozing ? mAmbientPulseManager : mHeadsUpManager; } - private boolean onlySummaryAlerts(Entry entry) { + private boolean onlySummaryAlerts(NotificationEntry entry) { return entry.notification.getNotification().getGroupAlertBehavior() == Notification.GROUP_ALERT_SUMMARY; } @@ -439,7 +439,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis * the transfer is still valid if the notification is updated. */ final StatusBarNotification mOriginalNotification; - final Entry mEntry; + final NotificationEntry mEntry; /** * The notification is still pending inflation but we've decided that we no longer need @@ -450,7 +450,7 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis */ boolean mAbortOnInflation; - PendingAlertInfo(Entry entry, AlertingNotificationManager alertManager) { + PendingAlertInfo(NotificationEntry entry, AlertingNotificationManager alertManager) { mOriginalNotification = entry.notification; mEntry = entry; mAlertManager = alertManager; 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 3c1c0765a3b8..bb9e4183ba76 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java @@ -27,7 +27,7 @@ import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListen 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.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -97,7 +97,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, } } - public void onEntryRemoved(NotificationData.Entry removed) { + public void onEntryRemoved(NotificationEntry removed) { onEntryRemovedInternal(removed, removed.notification); mIsolatedEntries.remove(removed.key); } @@ -109,7 +109,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * @param sbn the notification the entry has, which doesn't need to be the same as it's internal * notification */ - private void onEntryRemovedInternal(NotificationData.Entry removed, + private void onEntryRemovedInternal(NotificationEntry removed, final StatusBarNotification sbn) { String groupKey = getGroupKey(sbn); final NotificationGroup group = mGroupMap.get(groupKey); @@ -136,7 +136,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, } } - public void onEntryAdded(final NotificationData.Entry added) { + public void onEntryAdded(final NotificationEntry added) { if (added.isRowRemoved()) { added.setDebugThrowable(new Throwable()); } @@ -152,7 +152,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, } } if (isGroupChild) { - NotificationData.Entry existing = group.children.get(added.key); + NotificationEntry existing = group.children.get(added.key); if (existing != null && existing != added) { Throwable existingThrowable = existing.getDebugThrowable(); Log.wtf(TAG, "Inconsistent entries found with the same key " + added.key @@ -169,9 +169,9 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, group.expanded = added.areChildrenExpanded(); updateSuppression(group); if (!group.children.isEmpty()) { - ArrayList<NotificationData.Entry> childrenCopy + ArrayList<NotificationEntry> childrenCopy = new ArrayList<>(group.children.values()); - for (NotificationData.Entry child : childrenCopy) { + for (NotificationEntry child : childrenCopy) { onEntryBecomingChild(child); } for (OnGroupChangeListener listener : mListeners) { @@ -181,7 +181,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, } } - private void onEntryBecomingChild(NotificationData.Entry entry) { + private void onEntryBecomingChild(NotificationEntry entry) { if (shouldIsolate(entry)) { isolateNotification(entry); } @@ -221,7 +221,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, return count; } - private NotificationData.Entry getIsolatedChild(String groupKey) { + private NotificationEntry getIsolatedChild(String groupKey) { for (StatusBarNotification sbn : mIsolatedEntries.values()) { if (sbn.getGroupKey().equals(groupKey) && isIsolated(sbn)) { return mGroupMap.get(sbn.getKey()).summary; @@ -230,7 +230,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, return null; } - public void onEntryUpdated(NotificationData.Entry entry, + public void onEntryUpdated(NotificationEntry entry, StatusBarNotification oldNotification) { String oldKey = oldNotification.getGroupKey(); String newKey = entry.notification.getGroupKey(); @@ -267,7 +267,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, if (!isOnlyChild(sbn)) { return false; } - NotificationData.Entry logicalGroupSummary = getLogicalGroupSummary(sbn); + NotificationEntry logicalGroupSummary = getLogicalGroupSummary(sbn); return logicalGroupSummary != null && !logicalGroupSummary.notification.equals(sbn); } @@ -343,7 +343,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * Get the summary of a specified status bar notification. For isolated notification this return * itself. */ - public NotificationData.Entry getGroupSummary(StatusBarNotification sbn) { + public NotificationEntry getGroupSummary(StatusBarNotification sbn) { return getGroupSummary(getGroupKey(sbn)); } @@ -352,12 +352,12 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * but the logical summary, i.e when a child is isolated, it still returns the summary as if * it wasn't isolated. */ - public NotificationData.Entry getLogicalGroupSummary(StatusBarNotification sbn) { + public NotificationEntry getLogicalGroupSummary(StatusBarNotification sbn) { return getGroupSummary(sbn.getGroupKey()); } @Nullable - private NotificationData.Entry getGroupSummary(String groupKey) { + private NotificationEntry getGroupSummary(String groupKey) { NotificationGroup group = mGroupMap.get(groupKey); //TODO: see if this can become an Entry return group == null ? null @@ -371,13 +371,13 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * @param summary summary of a group * @return list of the children */ - public ArrayList<NotificationData.Entry> getLogicalChildren(StatusBarNotification summary) { + public ArrayList<NotificationEntry> getLogicalChildren(StatusBarNotification summary) { NotificationGroup group = mGroupMap.get(summary.getGroupKey()); if (group == null) { return null; } - ArrayList<NotificationData.Entry> children = new ArrayList<>(group.children.values()); - NotificationData.Entry isolatedChild = getIsolatedChild(summary.getGroupKey()); + ArrayList<NotificationEntry> children = new ArrayList<>(group.children.values()); + NotificationEntry isolatedChild = getIsolatedChild(summary.getGroupKey()); if (isolatedChild != null) { children.add(isolatedChild); } @@ -443,24 +443,24 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, } @Override - public void onHeadsUpPinned(NotificationData.Entry entry) { + public void onHeadsUpPinned(NotificationEntry entry) { } @Override - public void onHeadsUpUnPinned(NotificationData.Entry entry) { + public void onHeadsUpUnPinned(NotificationEntry entry) { } @Override - public void onAmbientStateChanged(NotificationData.Entry entry, boolean isAmbient) { + public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) { onAlertStateChanged(entry, isAmbient); } @Override - public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { + public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { onAlertStateChanged(entry, isHeadsUp); } - private void onAlertStateChanged(NotificationData.Entry entry, boolean isAlerting) { + private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting) { if (isAlerting) { if (shouldIsolate(entry)) { isolateNotification(entry); @@ -479,7 +479,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * @return true if the entry should be isolated */ - private boolean shouldIsolate(NotificationData.Entry entry) { + private boolean shouldIsolate(NotificationEntry entry) { StatusBarNotification sbn = entry.notification; NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey()); if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) { @@ -499,7 +499,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * * @param entry the notification to isolate */ - private void isolateNotification(NotificationData.Entry entry) { + private void isolateNotification(NotificationEntry entry) { StatusBarNotification sbn = entry.notification; // We will be isolated now, so lets update the groups @@ -523,7 +523,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, * * @param entry the notification to un-isolate */ - private void stopIsolatingNotification(NotificationData.Entry entry) { + private void stopIsolatingNotification(NotificationEntry entry) { StatusBarNotification sbn = entry.notification; if (mIsolatedEntries.containsKey(sbn.getKey())) { // not isolated anymore, we need to update the groups @@ -564,8 +564,8 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, } public static class NotificationGroup { - public final HashMap<String, NotificationData.Entry> children = new HashMap<>(); - public NotificationData.Entry summary; + public final HashMap<String, NotificationEntry> children = new HashMap<>(); + public NotificationEntry summary; public boolean expanded; /** * Is this notification group suppressed, i.e its summary is hidden @@ -580,7 +580,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, ? Log.getStackTraceString(summary.getDebugThrowable()) : ""); result += "\n children size: " + children.size(); - for (NotificationData.Entry child : children.values()) { + for (NotificationEntry child : children.values()) { result += "\n " + child.notification + (child.getDebugThrowable() != null ? Log.getStackTraceString(child.getDebugThrowable()) 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 056c8a7f5f5e..1fb5484196ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -23,9 +23,9 @@ import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarIconView; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationUtils; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.tuner.TunerService; @@ -182,7 +182,7 @@ public class NotificationIconAreaController implements DarkReceiver { return mStatusBar.getStatusBarHeight(); } - protected boolean shouldShowNotificationIcon(NotificationData.Entry entry, + protected boolean shouldShowNotificationIcon(NotificationEntry entry, boolean showAmbient, boolean showLowPriority, boolean hideDismissed, boolean hideRepliedMessages) { if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) { @@ -247,7 +247,7 @@ public class NotificationIconAreaController implements DarkReceiver { * @param hideDismissed should dismissed icons be hidden * @param hideRepliedMessages should messages that have been replied to be hidden */ - private void updateIconsForLayout(Function<NotificationData.Entry, StatusBarIconView> function, + private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function, NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority, boolean hideDismissed, boolean hideRepliedMessages) { ArrayList<StatusBarIconView> toShow = new ArrayList<>( @@ -257,7 +257,7 @@ public class NotificationIconAreaController implements DarkReceiver { for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) { View view = mNotificationScrollLayout.getChildAt(i); if (view instanceof ExpandableNotificationRow) { - NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry(); + NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry(); if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed, hideRepliedMessages)) { toShow.add(function.apply(ent)); 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 16576ad6e3e1..d873b0cd1f26 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -76,9 +76,9 @@ import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.AnimatableProperty; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.PropertyAnimator; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -2489,12 +2489,12 @@ public class NotificationPanelView extends PanelView implements } @Override - public void onHeadsUpPinned(NotificationData.Entry entry) { + public void onHeadsUpPinned(NotificationEntry entry) { mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(), true); } @Override - public void onHeadsUpUnPinned(NotificationData.Entry entry) { + public void onHeadsUpUnPinned(NotificationEntry entry) { // When we're unpinning the notification via active edge they remain heads-upped, // we need to make sure that an animation happens in this case, otherwise the notification @@ -2507,7 +2507,7 @@ public class NotificationPanelView extends PanelView implements } @Override - public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { + public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { mNotificationStackScroller.generateHeadsUpAnimation(entry, isHeadsUp); } 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 977e33688831..6d78f7204163 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -192,12 +192,11 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationClicker; -import com.android.systemui.statusbar.notification.NotificationData; -import com.android.systemui.statusbar.notification.NotificationData.Entry; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationRowBinder; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -489,7 +488,7 @@ public class StatusBar extends SystemUI implements DemoMode, private Runnable mLaunchTransitionEndRunnable; protected boolean mLaunchTransitionFadingAway; - private NotificationData.Entry mDraggedDownEntry; + private NotificationEntry mDraggedDownEntry; private boolean mLaunchCameraOnScreenTurningOn; private boolean mLaunchCameraOnFinishedGoingToSleep; private int mLastCameraLaunchSource; @@ -633,7 +632,7 @@ public class StatusBar extends SystemUI implements DemoMode, mBubbleController.setExpandListener(mBubbleExpandListener); KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance(); if (sliceProvider != null) { - sliceProvider.initDependencies(); + sliceProvider.initDependencies(mMediaManager, mStatusBarStateController); } else { Log.w(TAG, "Cannot init KeyguardSliceProvider dependencies"); } @@ -1510,21 +1509,21 @@ public class StatusBar extends SystemUI implements DemoMode, } @Override - public void onHeadsUpPinned(NotificationData.Entry entry) { + public void onHeadsUpPinned(NotificationEntry entry) { dismissVolumeDialog(); } @Override - public void onHeadsUpUnPinned(NotificationData.Entry entry) { + public void onHeadsUpUnPinned(NotificationEntry entry) { } @Override - public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) { + public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { mEntryManager.updateNotificationRanking(null /* rankingMap */); } @Override - public void onAmbientStateChanged(Entry entry, boolean isAmbient) { + public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) { mEntryManager.updateNotificationRanking(null); if (isAmbient) { mDozeServiceHost.fireNotificationPulse(); @@ -2551,11 +2550,11 @@ public class StatusBar extends SystemUI implements DemoMode, }; public void resetUserExpandedStates() { - ArrayList<Entry> activeNotifications = mEntryManager.getNotificationData() + ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData() .getActiveNotifications(); final int notificationCount = activeNotifications.size(); for (int i = 0; i < notificationCount; i++) { - NotificationData.Entry entry = activeNotifications.get(i); + NotificationEntry entry = activeNotifications.get(i); entry.resetUserExpansion(); } } @@ -3506,7 +3505,7 @@ public class StatusBar extends SystemUI implements DemoMode, int userId = mLockscreenUserManager.getCurrentUserId(); ExpandableNotificationRow row = null; - NotificationData.Entry entry = null; + NotificationEntry entry = null; if (expandView instanceof ExpandableNotificationRow) { entry = ((ExpandableNotificationRow) expandView).getEntry(); entry.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 8d1b911b101f..4f61009095c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -60,10 +60,10 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationActivityStarter; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.KeyguardMonitor; @@ -131,7 +131,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override - public void onPendingEntryAdded(NotificationData.Entry entry) { + public void onPendingEntryAdded(NotificationEntry entry) { handleFullScreenIntent(entry); } }); @@ -267,7 +267,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } } Intent fillInIntent = null; - NotificationData.Entry entry = row.getEntry(); + NotificationEntry entry = row.getEntry(); CharSequence remoteInputText = null; if (!TextUtils.isEmpty(entry.remoteInputText)) { remoteInputText = entry.remoteInputText; @@ -345,7 +345,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit }, null, false /* afterKeyguardGone */); } - private void handleFullScreenIntent(NotificationData.Entry entry) { + private void handleFullScreenIntent(NotificationEntry entry) { boolean isHeadsUped = mNotificationInterruptionStateProvider.shouldHeadsUp(entry); if (!isHeadsUped && entry.notification.getNotification().fullScreenIntent != null) { if (shouldSuppressFullScreenIntent(entry)) { @@ -413,7 +413,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit || !mActivityLaunchAnimator.isAnimationPending(); } - private boolean shouldSuppressFullScreenIntent(NotificationData.Entry entry) { + private boolean shouldSuppressFullScreenIntent(NotificationEntry entry) { if (mPresenter.isDeviceInVrMode()) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index fb3157a128d6..df7f53b3b63a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -60,12 +60,12 @@ import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationData.Entry; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationRowBinder; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -104,6 +104,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, Dependency.get(NotificationMediaManager.class); private final VisualStabilityManager mVisualStabilityManager = Dependency.get(VisualStabilityManager.class); + private final NotificationGutsManager mGutsManager = + Dependency.get(NotificationGutsManager.class); protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class); private final NotificationPanelView mNotificationPanel; @@ -183,19 +185,19 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, Dependency.get(InitController.class).addPostInitTask(() -> { NotificationEntryListener notificationEntryListener = new NotificationEntryListener() { @Override - public void onNotificationAdded(Entry entry) { + public void onNotificationAdded(NotificationEntry entry) { // Recalculate the position of the sliding windows and the titles. mShadeController.updateAreThereNotifications(); } @Override - public void onEntryUpdated(Entry entry) { + public void onPostEntryUpdated(NotificationEntry entry) { mShadeController.updateAreThereNotifications(); } @Override public void onEntryRemoved( - @Nullable Entry entry, + @Nullable NotificationEntry entry, NotificationVisibility visibility, boolean removedByUser) { StatusBarNotificationPresenter.this.onNotificationRemoved( @@ -206,14 +208,12 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } }; - NotificationGutsManager gutsManager = Dependency.get(NotificationGutsManager.class); - mViewHierarchyManager.setUpWithPresenter(this, notifListContainer); mEntryManager.setUpWithPresenter(this, notifListContainer, mHeadsUpManager); mEntryManager.addNotificationEntryListener(notificationEntryListener); mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager); mEntryManager.addNotificationLifetimeExtender(mAmbientPulseManager); - mEntryManager.addNotificationLifetimeExtender(gutsManager); + mEntryManager.addNotificationLifetimeExtender(mGutsManager); mEntryManager.addNotificationLifetimeExtenders( remoteInputManager.getLifetimeExtenders()); mNotificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager, @@ -223,7 +223,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mLockscreenUserManager.setUpWithPresenter(this); mMediaManager.setUpWithPresenter(this); mVisualStabilityManager.setUpWithPresenter(this); - gutsManager.setUpWithPresenter(this, + mGutsManager.setUpWithPresenter(this, notifListContainer, mCheckSaveListener, mOnSettingsClickListener); // ForegroundServiceControllerListener adds its listener in its constructor // but we need to request it here in order for it to be instantiated. @@ -242,7 +242,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, MessagingMessage.dropCache(); MessagingGroup.dropCache(); if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) { - mEntryManager.updateNotificationsOnDensityOrFontScaleChanged(); + updateNotificationsOnDensityOrFontScaleChanged(); } else { mReinflateNotificationsOnUserSwitched = true; } @@ -258,10 +258,10 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } private void updateNotificationOnUiModeChanged() { - ArrayList<Entry> userNotifications + ArrayList<NotificationEntry> userNotifications = mEntryManager.getNotificationData().getNotificationsForCurrentUser(); for (int i = 0; i < userNotifications.size(); i++) { - Entry entry = userNotifications.get(i); + NotificationEntry entry = userNotifications.get(i); ExpandableNotificationRow row = entry.getRow(); if (row != null) { row.onUiModeChanged(); @@ -269,6 +269,19 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } } + private void updateNotificationsOnDensityOrFontScaleChanged() { + ArrayList<NotificationEntry> userNotifications = + mEntryManager.getNotificationData().getNotificationsForCurrentUser(); + for (int i = 0; i < userNotifications.size(); i++) { + NotificationEntry entry = userNotifications.get(i); + entry.onDensityOrFontScaleChanged(); + boolean exposedGuts = entry.areGutsExposed(); + if (exposedGuts) { + mGutsManager.onDensityOrFontScaleChanged(entry); + } + } + } + @Override public boolean isCollapsing() { return mNotificationPanel.isCollapsing() @@ -323,7 +336,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty(); } - public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) { + public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) { if (mShadeController.isDozing()) { return false; } @@ -367,7 +380,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId); mCommandQueue.animateCollapsePanels(); if (mReinflateNotificationsOnUserSwitched) { - mEntryManager.updateNotificationsOnDensityOrFontScaleChanged(); + updateNotificationsOnDensityOrFontScaleChanged(); mReinflateNotificationsOnUserSwitched = false; } if (mDispatchUiModeChangeOnUserSwitched) { @@ -381,7 +394,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } @Override - public void onBindRow(Entry entry, PackageManager pmUser, + public void onBindRow(NotificationEntry entry, PackageManager pmUser, StatusBarNotification sbn, ExpandableNotificationRow row) { row.setAboveShelfChangedListener(mAboveShelfObserver); row.setSecureStateProvider(mUnlockMethodCache::canSkipBouncer); @@ -439,7 +452,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } @Override - public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) { + public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) { mHeadsUpManager.setExpanded(clickedEntry, nowExpanded); if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) { mShadeController.goToLockedShade(clickedEntry.getRow()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index a02c9d51fecf..fd3f680e5e77 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -30,7 +30,7 @@ import android.util.Log; import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.statusbar.AlertingNotificationManager; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import java.io.FileDescriptor; @@ -108,11 +108,11 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { } } - protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationData.Entry entry) { + protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationEntry entry) { return hasFullScreenIntent(entry); } - protected boolean hasFullScreenIntent(@NonNull NotificationData.Entry entry) { + protected boolean hasFullScreenIntent(@NonNull NotificationEntry entry) { return entry.notification.getNotification().fullScreenIntent != null; } @@ -121,7 +121,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "setEntryPinned: " + isPinned); } - NotificationData.Entry entry = headsUpEntry.mEntry; + NotificationEntry entry = headsUpEntry.mEntry; if (entry.isRowPinned() != isPinned) { entry.setRowPinned(isPinned); updatePinnedMode(); @@ -141,7 +141,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { @Override protected void onAlertEntryAdded(AlertEntry alertEntry) { - NotificationData.Entry entry = alertEntry.mEntry; + NotificationEntry entry = alertEntry.mEntry; entry.setHeadsUp(true); setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry)); for (OnHeadsUpChangedListener listener : mListeners) { @@ -151,7 +151,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { @Override protected void onAlertEntryRemoved(AlertEntry alertEntry) { - NotificationData.Entry entry = alertEntry.mEntry; + NotificationEntry entry = alertEntry.mEntry; entry.setHeadsUp(false); setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */); for (OnHeadsUpChangedListener listener : mListeners) { @@ -222,7 +222,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { * Returns the top Heads Up Notification, which appears to show at first. */ @Nullable - public NotificationData.Entry getTopEntry() { + public NotificationEntry getTopEntry() { HeadsUpEntry topEntry = getTopHeadsUpEntry(); return (topEntry != null) ? topEntry.mEntry : null; } @@ -323,7 +323,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { * @return -1 if the first argument should be ranked higher than the second, 1 if the second * one should be ranked higher and 0 if they are equal. */ - public int compare(@NonNull NotificationData.Entry a, @NonNull NotificationData.Entry b) { + public int compare(@NonNull NotificationEntry a, @NonNull NotificationEntry b) { AlertEntry aEntry = getHeadsUpEntry(a.key); AlertEntry bEntry = getHeadsUpEntry(b.key); if (aEntry == null || bEntry == null) { @@ -336,7 +336,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager { * Set an entry to be expanded and therefore stick in the heads up area if it's pinned * until it's collapsed again. */ - public void setExpanded(@NonNull NotificationData.Entry entry, boolean expanded) { + public void setExpanded(@NonNull NotificationEntry entry, boolean expanded) { HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key); if (headsUpEntry != null && entry.isRowPinned()) { headsUpEntry.setExpanded(expanded); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java index 7ad547afdb53..438226ae082d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java @@ -16,8 +16,7 @@ package com.android.systemui.statusbar.policy; -import com.android.systemui.statusbar.notification.NotificationData; -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; /** * A listener to heads up changes @@ -33,12 +32,12 @@ public interface OnHeadsUpChangedListener { /** * A notification was just pinned to the top. */ - default void onHeadsUpPinned(NotificationData.Entry entry) {} + default void onHeadsUpPinned(NotificationEntry entry) {} /** * A notification was just unpinned from the top. */ - default void onHeadsUpUnPinned(NotificationData.Entry entry) {} + default void onHeadsUpUnPinned(NotificationEntry entry) {} /** * A notification just became a heads up or turned back to its normal state. @@ -46,5 +45,5 @@ public interface OnHeadsUpChangedListener { * @param entry the entry of the changed notification * @param isHeadsUp whether the notification is now a headsUp notification */ - default void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {} + default void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {} } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index 866015e84af0..dfb02cffc6e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -56,7 +56,7 @@ import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.RemoteInputController; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; @@ -83,7 +83,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene private RemoteInputController mController; private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; private boolean mRemoved; @@ -180,7 +180,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene } public static RemoteInputView inflate(Context context, ViewGroup root, - NotificationData.Entry entry, + NotificationEntry entry, RemoteInputController controller) { RemoteInputView v = (RemoteInputView) LayoutInflater.from(context).inflate(R.layout.remote_input, root, false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java index f85d8038ab3f..68b172d397c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java @@ -36,8 +36,8 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.SmartReplyController; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationUtils; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import java.text.BreakIterator; @@ -194,7 +194,7 @@ public class SmartReplyView extends ViewGroup { */ public void addRepliesFromRemoteInput( SmartReplies smartReplies, - SmartReplyController smartReplyController, NotificationData.Entry entry) { + SmartReplyController smartReplyController, NotificationEntry entry) { if (smartReplies.remoteInput != null && smartReplies.pendingIntent != null) { if (smartReplies.choices != null) { for (int i = 0; i < smartReplies.choices.length; ++i) { @@ -212,7 +212,7 @@ public class SmartReplyView extends ViewGroup { * notification are shown. */ public void addSmartActions(SmartActions smartActions, - SmartReplyController smartReplyController, NotificationData.Entry entry, + SmartReplyController smartReplyController, NotificationEntry entry, HeadsUpManager headsUpManager) { int numSmartActions = smartActions.actions.size(); for (int n = 0; n < numSmartActions; n++) { @@ -235,7 +235,7 @@ public class SmartReplyView extends ViewGroup { @VisibleForTesting Button inflateReplyButton(Context context, ViewGroup root, int replyIndex, SmartReplies smartReplies, SmartReplyController smartReplyController, - NotificationData.Entry entry) { + NotificationEntry entry) { Button b = (Button) LayoutInflater.from(context).inflate( R.layout.smart_reply_button, root, false); CharSequence choice = smartReplies.choices[replyIndex]; @@ -289,7 +289,7 @@ public class SmartReplyView extends ViewGroup { @VisibleForTesting Button inflateActionButton(Context context, ViewGroup root, int actionIndex, SmartActions smartActions, SmartReplyController smartReplyController, - NotificationData.Entry entry, HeadsUpManager headsUpManager) { + NotificationEntry entry, HeadsUpManager headsUpManager) { Notification.Action action = smartActions.actions.get(actionIndex); Button button = (Button) LayoutInflater.from(context).inflate( R.layout.smart_action_button, root, false); @@ -428,9 +428,9 @@ public class SmartReplyView extends ViewGroup { markButtonsWithPendingSqueezeStatusAs( LayoutParams.SQUEEZE_STATUS_FAILED, coveredSuggestions); - // The current button doesn't fit, so there's no point in measuring further - // buttons. - break; + // The current button doesn't fit, keep on adding lower-priority buttons in case + // any of those fit. + continue; } // The current button fits, so mark all squeezed buttons as "successfully squeezed" diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index 415060244243..1844df5c070a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -35,6 +35,8 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.text.TextPaint; import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.TextClock; @@ -42,6 +44,8 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateController; import org.junit.Before; import org.junit.Test; @@ -60,6 +64,7 @@ import org.mockito.MockitoAnnotations; public class KeyguardClockSwitchTest extends SysuiTestCase { private PluginManager mPluginManager; private FrameLayout mClockContainer; + private StatusBarStateController.StateListener mStateListener; @Mock TextClock mClockView; @@ -75,6 +80,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view); MockitoAnnotations.initMocks(this); when(mClockView.getPaint()).thenReturn(mock(TextPaint.class)); + mStateListener = mKeyguardClockSwitch.getStateListener(); } @Test @@ -272,4 +278,28 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { verify(plugin).setStyle(style); } + + @Test + public void onStateChanged_InvisibleInShade() { + // GIVEN that the big clock container is visible + ViewGroup container = mock(ViewGroup.class); + when(container.getVisibility()).thenReturn(View.VISIBLE); + mKeyguardClockSwitch.setBigClockContainer(container); + // WHEN transitioned to SHADE state + mStateListener.onStateChanged(StatusBarState.SHADE); + // THEN the container is invisible. + verify(container).setVisibility(View.INVISIBLE); + } + + @Test + public void onStateChanged_VisibleInKeyguard() { + // GIVEN that the big clock container is invisible + ViewGroup container = mock(ViewGroup.class); + when(container.getVisibility()).thenReturn(View.INVISIBLE); + mKeyguardClockSwitch.setBigClockContainer(container); + // WHEN transitioned to KEYGUARD state + mStateListener.onStateChanged(StatusBarState.KEYGUARD); + // THEN the container is visible. + verify(container).setVisibility(View.VISIBLE); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index f8912bcca302..31e8071f5677 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -36,9 +36,9 @@ import android.support.test.runner.AndroidJUnit4; import android.widget.RemoteViews; import com.android.internal.messages.nano.SystemMessageProto; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import org.junit.Before; import org.junit.Test; @@ -391,19 +391,19 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { } private void entryRemoved(StatusBarNotification notification) { - mEntryListener.onEntryRemoved(new NotificationData.Entry(notification), + mEntryListener.onEntryRemoved(new NotificationEntry(notification), null, false); } private void entryAdded(StatusBarNotification notification, int importance) { - NotificationData.Entry entry = new NotificationData.Entry(notification); + NotificationEntry entry = new NotificationEntry(notification); entry.importance = importance; mEntryListener.onPendingEntryAdded(entry); } private void entryUpdated(StatusBarNotification notification, int importance) { - NotificationData.Entry entry = new NotificationData.Entry(notification); + NotificationEntry entry = new NotificationEntry(notification); entry.importance = importance; - mEntryListener.onEntryUpdated(entry); + mEntryListener.onPostEntryUpdated(entry); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 31df4a3fc766..21d3652adca7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -33,9 +33,9 @@ import android.widget.FrameLayout; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationTestHelper; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.StatusBarWindowController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index a8ff0b21bab9..cfc19ef28c92 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -44,6 +45,7 @@ import androidx.slice.core.SliceQuery; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.StatusBarStateController; import org.junit.Assert; import org.junit.Before; @@ -67,6 +69,8 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { private AlarmManager mAlarmManager; @Mock private NotificationMediaManager mNotificationMediaManager; + @Mock + private StatusBarStateController mStatusBarStateController; private TestableKeyguardSliceProvider mProvider; private boolean mIsZenMode; @@ -76,7 +80,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { mIsZenMode = false; mProvider = new TestableKeyguardSliceProvider(); mProvider.attachInfo(getContext(), null); - mProvider.initDependencies(); + mProvider.initDependencies(mNotificationMediaManager, mStatusBarStateController); SliceProvider.setSpecs(new HashSet<>(Arrays.asList(SliceSpecs.LIST))); } @@ -98,6 +102,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { @Test public void onBindSlice_readsMedia() { MediaMetadata metadata = mock(MediaMetadata.class); + mProvider.onDozingChanged(true); mProvider.onMetadataChanged(metadata); mProvider.onBindSlice(mProvider.getUri()); verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_TITLE)); @@ -162,7 +167,31 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { @Test public void onMetadataChanged_updatesSlice() { mProvider.onMetadataChanged(mock(MediaMetadata.class)); + mProvider.onDozingChanged(true); + verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); + + // Hides after waking up + reset(mContentResolver); + mProvider.onDozingChanged(false); + verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); + + // And won't update slice if device is awake + reset(mContentResolver); + mProvider.onMetadataChanged(mock(MediaMetadata.class)); + verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null)); + } + + @Test + public void onDozingChanged_updatesSliceIfMedia() { + // Show media when dozing + mProvider.onMetadataChanged(mock(MediaMetadata.class)); + mProvider.onDozingChanged(true); verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); + + // Do not notify again if nothing changed + reset(mContentResolver); + mProvider.onDozingChanged(true); + verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null)); } private class TestableKeyguardSliceProvider extends KeyguardSliceProvider { @@ -201,11 +230,6 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { protected String getFormattedDateLocked() { return super.getFormattedDateLocked() + mCounter++; } - - @Override - public void initDependencies() { - mMediaManager = mNotificationMediaManager; - } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java index 9d0556f61398..f8957b204021 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java @@ -36,7 +36,7 @@ import android.testing.TestableLooper; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -67,7 +67,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase { private AlertingNotificationManager mAlertingNotificationManager; - protected NotificationData.Entry mEntry; + protected NotificationEntry mEntry; protected Handler mTestHandler; private StatusBarNotification mSbn; protected boolean mTimedOut = false; @@ -119,7 +119,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase { public void setUp() { mTestHandler = Handler.createAsync(Looper.myLooper()); mSbn = createNewNotification(0 /* id */); - mEntry = new NotificationData.Entry(mSbn); + mEntry = new NotificationEntry(mSbn); mEntry.setRow(mRow); mAlertingNotificationManager = createAlertingNotificationManager(); @@ -170,7 +170,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase { public void testReleaseAllImmediately() { for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) { StatusBarNotification sbn = createNewNotification(i); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); entry.setRow(mRow); mAlertingNotificationManager.showNotification(entry); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java index 65c04fe4bcd3..c880172e775a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java @@ -31,8 +31,9 @@ import android.testing.TestableLooper; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import org.junit.Before; import org.junit.Test; @@ -85,7 +86,7 @@ public class NotificationListenerTest extends SysuiTestCase { @Test public void testNotificationUpdateCallsUpdateNotification() { - when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationData.Entry(mSbn)); + when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationEntry(mSbn)); mListener.onNotificationPosted(mSbn, mRanking); TestableLooper.get(this).processAllMessages(); verify(mEntryManager).updateNotification(mSbn, mRanking); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index f168a490acf4..d7ca5b410e56 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar; -import static android.content.Intent.ACTION_DEVICE_LOCKED_CHANGED; import static android.content.Intent.ACTION_USER_SWITCHED; import static junit.framework.Assert.assertFalse; @@ -42,8 +41,8 @@ import android.testing.TestableLooper; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.DeviceProvisionedController; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java index 150dcb9f841c..c159516d5bde 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -24,8 +24,8 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputActiveExtender; import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputHistoryExtender; import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.ShadeController; @@ -60,7 +60,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { private TestableNotificationRemoteInputManager mRemoteInputManager; private StatusBarNotification mSbn; - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; private RemoteInputHistoryExtender mRemoteInputHistoryExtender; private SmartReplyHistoryExtender mSmartReplyHistoryExtender; private RemoteInputActiveExtender mRemoteInputActiveExtender; @@ -75,7 +75,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { Handler.createAsync(Looper.myLooper())); mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, new Notification(), UserHandle.CURRENT, null, 0); - mEntry = new NotificationData.Entry(mSbn); + mEntry = new NotificationEntry(mSbn); mEntry.setRow(mRow); mRemoteInputManager.setUpWithPresenterForTest(mCallback, @@ -170,7 +170,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { // Setup a notification entry with 1 remote input. StatusBarNotification newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", false); - NotificationData.Entry entry = new NotificationData.Entry(newSbn); + NotificationEntry entry = new NotificationEntry(newSbn); // Try rebuilding to add another reply. newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(entry, "Reply 2", true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index fb5e8753c935..529da8251c57 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -32,7 +32,7 @@ import android.view.LayoutInflater; import android.widget.RemoteViews; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import com.android.systemui.statusbar.notification.row.NotificationInflaterTest; @@ -238,7 +238,7 @@ public class NotificationTestHelper { mUser, null /* overrideGroupKey */, System.currentTimeMillis()); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); entry.setRow(row); entry.createIcons(mContext, sbn); entry.channel = new NotificationChannel( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index e716421a1e69..bf91305137e2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -38,10 +38,10 @@ import com.android.systemui.InitController; import com.android.systemui.SysuiTestCase; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; -import com.android.systemui.statusbar.notification.NotificationData; -import com.android.systemui.statusbar.notification.NotificationData.Entry; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -102,9 +102,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer); } - private NotificationData.Entry createEntry() throws Exception { + private NotificationEntry createEntry() throws Exception { ExpandableNotificationRow row = mHelper.createRow(); - NotificationData.Entry entry = new NotificationData.Entry(row.getStatusBarNotification()); + NotificationEntry entry = new NotificationEntry(row.getStatusBarNotification()); entry.setRow(row); return entry; } @@ -113,9 +113,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { public void testNotificationsBecomingBundled() throws Exception { // Tests 3 top level notifications becoming a single bundled notification with |entry0| as // the summary. - NotificationData.Entry entry0 = createEntry(); - NotificationData.Entry entry1 = createEntry(); - NotificationData.Entry entry2 = createEntry(); + NotificationEntry entry0 = createEntry(); + NotificationEntry entry1 = createEntry(); + NotificationEntry entry2 = createEntry(); // Set up the prior state to look like three top level notifications. mListContainer.addContainerView(entry0.getRow()); @@ -142,9 +142,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { @Test public void testNotificationsBecomingUnbundled() throws Exception { // Tests a bundled notification becoming three top level notifications. - NotificationData.Entry entry0 = createEntry(); - NotificationData.Entry entry1 = createEntry(); - NotificationData.Entry entry2 = createEntry(); + NotificationEntry entry0 = createEntry(); + NotificationEntry entry1 = createEntry(); + NotificationEntry entry2 = createEntry(); entry0.getRow().addChildNotification(entry1.getRow()); entry0.getRow().addChildNotification(entry2.getRow()); @@ -173,8 +173,8 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { @Test public void testNotificationsBecomingSuppressed() throws Exception { // Tests two top level notifications becoming a suppressed summary and a child. - NotificationData.Entry entry0 = createEntry(); - NotificationData.Entry entry1 = createEntry(); + NotificationEntry entry0 = createEntry(); + NotificationEntry entry1 = createEntry(); entry0.getRow().addChildNotification(entry1.getRow()); // Set up the prior state to look like a top level notification. @@ -199,7 +199,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { @Test public void testUpdateNotificationViews_appOps() throws Exception { - NotificationData.Entry entry0 = createEntry(); + NotificationEntry entry0 = createEntry(); entry0.setRow(spy(entry0.getRow())); when(mNotificationData.getActiveNotifications()).thenReturn( Lists.newArrayList(entry0)); @@ -264,10 +264,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { public void setMaxDisplayedNotifications(int maxNotifications) {} @Override - public void snapViewIfNeeded(Entry entry) {} - - @Override - public ViewGroup getViewParentForNotification(NotificationData.Entry entry) { + public ViewGroup getViewParentForNotification(NotificationEntry entry) { return null; } @@ -283,10 +280,10 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { } @Override - public void cleanUpViewStateForEntry(Entry entry) { } + public void cleanUpViewStateForEntry(NotificationEntry entry) { } @Override - public boolean isInVisibleLocation(Entry entry) { + public boolean isInVisibleLocation(NotificationEntry entry) { return true; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java index e7a1f051a6df..6cca434bd8cb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java @@ -36,8 +36,8 @@ import android.testing.TestableLooper; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.ShadeController; import org.junit.Before; @@ -58,7 +58,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { private static final int TEST_ACTION_COUNT = 3; private Notification mNotification; - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; private SmartReplyController mSmartReplyController; private NotificationRemoteInputManager mRemoteInputManager; @@ -92,7 +92,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, mNotification, new UserHandle(ActivityManager.getCurrentUser()), null, 0); - mEntry = new NotificationData.Entry(mSbn); + mEntry = new NotificationEntry(mSbn); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 6197341acda5..d937f93482d5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -26,6 +26,7 @@ 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.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -65,7 +66,9 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.StatusBarIconView; -import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationInflater; @@ -82,6 +85,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -123,7 +127,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private RowInflaterTask mAsyncInflationTask; @Mock private NotificationRowBinder mMockedRowBinder; - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; private StatusBarNotification mSbn; private TestableNotificationEntryManager mEntryManager; private CountDownLatch mCountDownLatch; @@ -136,8 +140,12 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mCountDownLatch = new CountDownLatch(1); } + public void setNotificationData(NotificationData data) { + mNotificationData = data; + } + @Override - public void onAsyncInflationFinished(NotificationData.Entry entry, + public void onAsyncInflationFinished(NotificationEntry entry, @NotificationInflater.InflationFlag int inflatedFlags) { super.onAsyncInflationFinished(entry, inflatedFlags); @@ -222,7 +230,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { .setContentText("Text"); mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, n.build(), new UserHandle(ActivityManager.getCurrentUser()), null, 0); - mEntry = new NotificationData.Entry(mSbn); + mEntry = new NotificationEntry(mSbn); mEntry.expandedIcon = mock(StatusBarIconView.class); mEntryManager = new TestableNotificationEntryManager(mContext); @@ -259,10 +267,10 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(mEntryListener, never()).onInflationError(any(), any()); // Row inflation: - ArgumentCaptor<NotificationData.Entry> entryCaptor = ArgumentCaptor.forClass( - NotificationData.Entry.class); + ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass( + NotificationEntry.class); verify(mBindCallback).onBindRow(entryCaptor.capture(), any(), eq(mSbn), any()); - NotificationData.Entry entry = entryCaptor.getValue(); + NotificationEntry entry = entryCaptor.getValue(); verify(mRemoteInputManager).bindRow(entry.getRow()); // Row content inflation: @@ -291,14 +299,43 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(mEntryListener, never()).onInflationError(any(), any()); + verify(mEntryListener).onPreEntryUpdated(mEntry); verify(mPresenter).updateNotificationViews(); - verify(mEntryListener).onEntryUpdated(mEntry); + verify(mEntryListener).onPostEntryUpdated(mEntry); + assertNotNull(mEntry.getRow()); assertEquals(mEntry.userSentiment, NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE); } @Test + public void testUpdateNotification_prePostEntryOrder() throws Exception { + com.android.systemui.util.Assert.isNotMainThread(); + TestableLooper.get(this).processAllMessages(); + + NotificationData notifData = mock(NotificationData.class); + when(notifData.get(mEntry.key)).thenReturn(mEntry); + + mEntryManager.setNotificationData(notifData); + + mEntryManager.updateNotification(mSbn, mRankingMap); + TestableLooper.get(this).processMessages(1); + // Wait for content update. + assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS)); + + verify(mEntryListener, never()).onInflationError(any(), any()); + + // Ensure that update callbacks happen in correct order + InOrder order = inOrder(mEntryListener, notifData, mPresenter, mEntryListener); + order.verify(mEntryListener).onPreEntryUpdated(mEntry); + order.verify(notifData).filterAndSort(); + order.verify(mPresenter).updateNotificationViews(); + order.verify(mEntryListener).onPostEntryUpdated(mEntry); + + assertNotNull(mEntry.getRow()); + } + + @Test public void testRemoveNotification() throws Exception { com.android.systemui.util.Assert.isNotMainThread(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java index da8bc01dc29d..387475f79cc2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java @@ -40,6 +40,8 @@ import android.testing.TestableLooper.RunWithLooper; import com.android.systemui.ForegroundServiceController; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationTestHelper; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; @@ -191,12 +193,12 @@ public class NotificationFilterTest extends SysuiTestCase { // test should filter out hidden notifications: // hidden - NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); + NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); entry.suspended = true; assertTrue(mNotificationFilter.shouldFilterOut(entry)); // not hidden - entry = new NotificationData.Entry(mMockStatusBarNotification); + entry = new NotificationEntry(mMockStatusBarNotification); entry.suspended = false; assertFalse(mNotificationFilter.shouldFilterOut(entry)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java index 6fbd8c751285..813fc9d308e5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java @@ -29,6 +29,7 @@ import android.test.suitebuilder.annotation.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import org.junit.Before; @@ -44,13 +45,13 @@ public class VisualStabilityManagerTest extends SysuiTestCase { private VisualStabilityManager.Callback mCallback = mock(VisualStabilityManager.Callback.class); private VisibilityLocationProvider mLocationProvider = mock(VisibilityLocationProvider.class); private ExpandableNotificationRow mRow = mock(ExpandableNotificationRow.class); - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; @Before public void setUp() { mVisualStabilityManager.setUpWithPresenter(mock(NotificationPresenter.class)); mVisualStabilityManager.setVisibilityLocationProvider(mLocationProvider); - mEntry = new NotificationData.Entry(mock(StatusBarNotification.class)); + mEntry = new NotificationEntry(mock(StatusBarNotification.class)); mEntry.setRow(mRow); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java index 871ff8998c20..193f483058d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.systemui.statusbar.notification; +package com.android.systemui.statusbar.notification.collection; import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER; import static android.app.AppOpsManager.OP_CAMERA; @@ -59,7 +59,9 @@ import com.android.systemui.ForegroundServiceController; import com.android.systemui.InitController; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationTestHelper; -import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.ShadeController; @@ -203,7 +205,7 @@ public class NotificationDataTest extends SysuiTestCase { mRow.getEntry().notification)).thenReturn(false); when(mEnvironment.isNotificationForCurrentProfiles( row2.getEntry().notification)).thenReturn(true); - ArrayList<NotificationData.Entry> result = + ArrayList<NotificationEntry> result = mNotificationData.getNotificationsForCurrentUser(); assertEquals(result.size(), 1); @@ -217,7 +219,7 @@ public class NotificationDataTest extends SysuiTestCase { TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); Notification n = mMockStatusBarNotification.getNotification(); n.flags = Notification.FLAG_FOREGROUND_SERVICE; - NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); + NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); mNotificationData.add(entry); assertTrue(entry.isExemptFromDndVisualSuppression()); @@ -234,7 +236,7 @@ public class NotificationDataTest extends SysuiTestCase { nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); n = nb.build(); when(mMockStatusBarNotification.getNotification()).thenReturn(n); - NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); + NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); mNotificationData.add(entry); assertTrue(entry.isExemptFromDndVisualSuppression()); @@ -246,7 +248,7 @@ public class NotificationDataTest extends SysuiTestCase { initStatusBarNotification(false); when(mMockStatusBarNotification.getKey()).thenReturn( TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); - NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); + NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); entry.mIsSystemNotification = true; mNotificationData.add(entry); @@ -259,7 +261,7 @@ public class NotificationDataTest extends SysuiTestCase { initStatusBarNotification(false); when(mMockStatusBarNotification.getKey()).thenReturn( TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY); - NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification); + NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification); entry.mIsSystemNotification = true; mNotificationData.add(entry); @@ -313,8 +315,8 @@ public class NotificationDataTest extends SysuiTestCase { snoozeCriterions.add(snoozeCriterion); when(ranking.getSnoozeCriteria()).thenReturn(snoozeCriterions); - NotificationData.Entry entry = - new NotificationData.Entry(mMockStatusBarNotification, ranking); + NotificationEntry entry = + new NotificationEntry(mMockStatusBarNotification, ranking); assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions); assertEquals(NOTIFICATION_CHANNEL, entry.channel); @@ -343,7 +345,7 @@ public class NotificationDataTest extends SysuiTestCase { StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0, notification, mContext.getUser(), "", 0); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); entry.setHasSentReply(); assertTrue(entry.isLastMessageFromReply()); @@ -400,8 +402,7 @@ public class NotificationDataTest extends SysuiTestCase { Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon), title, PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)) - .setSemanticAction( - Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) + .setContextual(true) .build(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java index afdeb62a8f28..64725896cce5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java @@ -41,9 +41,10 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.UiOffloadThread; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -77,7 +78,7 @@ public class NotificationLoggerTest extends SysuiTestCase { @Mock private NotificationListener mListener; @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor; - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; private TestableNotificationLogger mLogger; private NotificationEntryListener mNotificationEntryListener; private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>(); @@ -93,7 +94,7 @@ public class NotificationLoggerTest extends SysuiTestCase { StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, new Notification(), UserHandle.CURRENT, null, 0); - mEntry = new NotificationData.Entry(sbn); + mEntry = new NotificationEntry(sbn); mEntry.setRow(mRow); mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java index 82b42c51622d..d94bf845ca5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java @@ -47,7 +47,7 @@ import android.view.View; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.policy.SmartReplyConstants; import org.junit.Before; @@ -73,7 +73,7 @@ public class NotificationContentViewTest extends SysuiTestCase { StatusBarNotification mStatusBarNotification; @Mock Notification mNotification; - NotificationData.Entry mEntry; + NotificationEntry mEntry; @Mock RemoteInput mRemoteInput; @Mock @@ -107,7 +107,7 @@ public class NotificationContentViewTest extends SysuiTestCase { // Smart replies and actions when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(true); when(mStatusBarNotification.getNotification()).thenReturn(mNotification); - mEntry = new NotificationData.Entry(mStatusBarNotification); + mEntry = new NotificationEntry(mStatusBarNotification); when(mSmartReplyConstants.isEnabled()).thenReturn(true); mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index ad43bea74089..0899c73ab07b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -60,7 +60,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.NotificationActivityStarter; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -183,8 +183,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getGuts()).thenReturn(guts); doNothing().when(row).inflateGuts(); - NotificationData.Entry realEntry = realRow.getEntry(); - NotificationData.Entry entry = spy(realEntry); + NotificationEntry realEntry = realRow.getEntry(); + NotificationEntry entry = spy(realEntry); when(entry.getRow()).thenReturn(row); when(entry.getGuts()).thenReturn(guts); @@ -443,7 +443,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { NotificationGuts guts = new NotificationGuts(mContext); ExpandableNotificationRow row = spy(createTestNotificationRow()); doReturn(guts).when(row).getGuts(); - NotificationData.Entry entry = row.getEntry(); + NotificationEntry entry = row.getEntry(); entry.setRow(row); mGutsManager.setExposedGuts(guts); @@ -452,7 +452,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Test public void testSetShouldManageLifetime_setShouldManage() { - NotificationData.Entry entry = createTestNotificationRow().getEntry(); + NotificationEntry entry = createTestNotificationRow().getEntry(); mGutsManager.setShouldManageLifetime(entry, true /* shouldManage */); assertTrue(entry.key.equals(mGutsManager.mKeyToRemoveOnGutsClosed)); @@ -460,7 +460,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Test public void testSetShouldManageLifetime_setShouldNotManage() { - NotificationData.Entry entry = createTestNotificationRow().getEntry(); + NotificationEntry entry = createTestNotificationRow().getEntry(); mGutsManager.mKeyToRemoveOnGutsClosed = entry.key; mGutsManager.setShouldManageLifetime(entry, false /* shouldManage */); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java index d6b706d73827..648df3cab33c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java @@ -48,7 +48,7 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.NotificationTestHelper; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import org.junit.Assert; import org.junit.Before; @@ -88,7 +88,7 @@ public class NotificationInflaterTest extends SysuiTestCase { } @Override - public void onAsyncInflationFinished(NotificationData.Entry entry, + public void onAsyncInflationFinished(NotificationEntry entry, @NotificationInflater.InflationFlag int inflatedFlags) { } }); @@ -174,7 +174,7 @@ public class NotificationInflaterTest extends SysuiTestCase { } @Override - public void onAsyncInflationFinished(NotificationData.Entry entry, + public void onAsyncInflationFinished(NotificationEntry entry, @NotificationInflater.InflationFlag int inflatedFlags) { countDownLatch.countDown(); } @@ -256,7 +256,7 @@ public class NotificationInflaterTest extends SysuiTestCase { } @Override - public void onAsyncInflationFinished(NotificationData.Entry entry, + public void onAsyncInflationFinished(NotificationEntry entry, @NotificationInflater.InflationFlag int inflatedFlags) { if (expectingException) { exceptionHolder.setException(new RuntimeException( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java index e4d019656072..04d7509f760f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java @@ -35,7 +35,7 @@ import android.testing.ViewUtils; import android.view.ViewGroup; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.utils.leaks.LeakCheckedTest; import org.junit.Before; @@ -54,7 +54,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest { public void setup() { injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); mRow = mock(ExpandableNotificationRow.class); - NotificationData.Entry entry = new NotificationData.Entry( + NotificationEntry entry = new NotificationEntry( mock(StatusBarNotification.class)); entry.channel = mock(NotificationChannel.class); when(mRow.getEntry()).thenReturn(entry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index b66d0ab78fd8..214404c8c295 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -53,9 +53,9 @@ import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.notification.NotificationData; -import com.android.systemui.statusbar.notification.NotificationData.Entry; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.FooterView; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; @@ -265,8 +265,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_remoteInput() { setBarStateForTest(StatusBarState.SHADE); - ArrayList<Entry> entries = new ArrayList<>(); - entries.add(mock(Entry.class)); + ArrayList<NotificationEntry> entries = new ArrayList<>(); + entries.add(mock(NotificationEntry.class)); when(mNotificationData.getActiveNotifications()).thenReturn(entries); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); @@ -282,8 +282,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_oneClearableNotification() { setBarStateForTest(StatusBarState.SHADE); - ArrayList<Entry> entries = new ArrayList<>(); - entries.add(mock(Entry.class)); + ArrayList<NotificationEntry> entries = new ArrayList<>(); + entries.add(mock(NotificationEntry.class)); when(mNotificationData.getActiveNotifications()).thenReturn(entries); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); @@ -298,8 +298,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testUpdateFooter_oneNonClearableNotification() { setBarStateForTest(StatusBarState.SHADE); - ArrayList<Entry> entries = new ArrayList<>(); - entries.add(mock(Entry.class)); + ArrayList<NotificationEntry> entries = new ArrayList<>(); + entries.add(mock(NotificationEntry.class)); when(mEntryManager.getNotificationData().getActiveNotifications()).thenReturn(entries); assertTrue(mEntryManager.getNotificationData().getActiveNotifications().size() != 0); @@ -314,7 +314,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { // add notification ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); - NotificationData.Entry entry = mock(NotificationData.Entry.class); + NotificationEntry entry = mock(NotificationEntry.class); when(row.getEntry()).thenReturn(entry); when(entry.isClearable()).thenReturn(true); mStackScroller.addContainerView(row); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index 44deb10941ec..9ceb325204fe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -16,15 +16,20 @@ package com.android.systemui.statusbar.phone; -import android.view.View; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Mockito.when; + import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.view.View; import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.AlertingNotificationManagerTest; -import com.android.systemui.statusbar.notification.NotificationData; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import org.junit.Before; import org.junit.Rule; @@ -34,11 +39,6 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.assertFalse; - -import static org.mockito.Mockito.when; - @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -96,7 +96,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { @Test public void testCanRemoveImmediately_notTopEntry() { - NotificationData.Entry laterEntry = new NotificationData.Entry(createNewNotification(1)); + NotificationEntry laterEntry = new NotificationEntry(createNewNotification(1)); laterEntry.setRow(mRow); mHeadsUpManager.showNotification(mEntry); mHeadsUpManager.showNotification(laterEntry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java index 79695fd6d38d..cefd4acbfb5a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java @@ -32,10 +32,9 @@ import android.testing.TestableLooper; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.AmbientPulseManager; -import com.android.systemui.statusbar.notification.NotificationData; -import com.android.systemui.statusbar.notification.NotificationData.Entry; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.policy.HeadsUpManager; import org.junit.Before; @@ -64,7 +63,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Captor private ArgumentCaptor<NotificationEntryListener> mListenerCaptor; private NotificationEntryListener mNotificationEntryListener; - private final HashMap<String, Entry> mPendingEntries = new HashMap<>(); + private final HashMap<String, NotificationEntry> mPendingEntries = new HashMap<>(); private final NotificationGroupTestHelper mGroupTestHelper = new NotificationGroupTestHelper(mContext); @@ -94,9 +93,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Test public void testSuppressedSummaryHeadsUpTransfersToChild() { - Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mHeadsUpManager.showNotification(summaryEntry); - Entry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); // Summary will be suppressed because there is only one child. mGroupManager.onEntryAdded(summaryEntry); @@ -109,11 +108,11 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Test public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() { - NotificationData.Entry summaryEntry = + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationData.Entry childEntry = + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationData.Entry childEntry2 = + NotificationEntry childEntry2 = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); mHeadsUpManager.showNotification(summaryEntry); // Trigger a transfer of alert state from summary to child. @@ -133,11 +132,11 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Test public void testSuppressedSummaryHeadsUpDoesntTransferBackOnDozingChanged() { - NotificationData.Entry summaryEntry = + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationData.Entry childEntry = + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationData.Entry childEntry2 = + NotificationEntry childEntry2 = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); mHeadsUpManager.showNotification(summaryEntry); // Trigger a transfer of alert state from summary to child. @@ -158,9 +157,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Test public void testSuppressedSummaryHeadsUpTransferDoesNotAlertChildIfUninflated() { - Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mHeadsUpManager.showNotification(summaryEntry); - Entry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) .thenReturn(false); @@ -176,9 +175,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Test public void testSuppressedSummaryHeadsUpTransferAlertsChildOnInflation() { - Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mHeadsUpManager.showNotification(summaryEntry); - Entry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) .thenReturn(false); @@ -196,13 +195,13 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Test public void testSuppressedSummaryHeadsUpTransferBackAbortsChildInflation() { - NotificationData.Entry summaryEntry = + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationData.Entry childEntry = + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) .thenReturn(false); - NotificationData.Entry childEntry2 = + NotificationEntry childEntry2 = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); mHeadsUpManager.showNotification(summaryEntry); // Trigger a transfer of alert state from summary to child. @@ -226,9 +225,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Test public void testCleanUpPendingAlertInfo() { - NotificationData.Entry summaryEntry = + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationData.Entry childEntry = + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) .thenReturn(false); @@ -244,9 +243,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Test public void testUpdateGroupChangeDoesNotTransfer() { - NotificationData.Entry summaryEntry = + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationData.Entry childEntry = + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) .thenReturn(false); @@ -267,9 +266,9 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Test public void testUpdateChildToSummaryDoesNotTransfer() { - NotificationData.Entry summaryEntry = + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY); - NotificationData.Entry childEntry = + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY); when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag())) .thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java index b0bd1fba3760..ecb3e4d8067c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java @@ -29,7 +29,7 @@ import android.testing.TestableLooper; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.AmbientPulseManager; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.policy.HeadsUpManager; import org.junit.Before; @@ -69,8 +69,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { @Test public void testIsOnlyChildInGroup() { - NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(); - NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); @@ -80,8 +80,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { @Test public void testIsChildInGroupWithSummary() { - NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(); - NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); @@ -92,8 +92,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { @Test public void testIsSummaryOfGroupWithChildren() { - NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(); - NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); @@ -105,8 +105,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { @Test public void testRemoveChildFromGroupWithSummary() { - NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(); - NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); @@ -118,8 +118,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { @Test public void testRemoveSummaryFromGroupWithSummary() { - NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(); - NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); @@ -132,8 +132,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { @Test public void testHeadsUpEntryIsIsolated() { - NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(); - NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); @@ -149,8 +149,8 @@ public class NotificationGroupManagerTest extends SysuiTestCase { @Test public void testAmbientPulseEntryIsIsolated() { - NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification(); - NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification(); + NotificationEntry childEntry = mGroupTestHelper.createChildNotification(); + NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(); mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java index 7ad68eb1c9a3..e6b9778eb59f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java @@ -27,7 +27,7 @@ import android.os.UserHandle; import android.service.notification.StatusBarNotification; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; /** @@ -44,23 +44,23 @@ public final class NotificationGroupTestHelper { mContext = context; } - public NotificationData.Entry createSummaryNotification() { + public NotificationEntry createSummaryNotification() { return createSummaryNotification(Notification.GROUP_ALERT_ALL); } - public NotificationData.Entry createSummaryNotification(int groupAlertBehavior) { + public NotificationEntry createSummaryNotification(int groupAlertBehavior) { return createEntry(true, groupAlertBehavior); } - public NotificationData.Entry createChildNotification() { + public NotificationEntry createChildNotification() { return createChildNotification(Notification.GROUP_ALERT_ALL); } - public NotificationData.Entry createChildNotification(int groupAlertBehavior) { + public NotificationEntry createChildNotification(int groupAlertBehavior) { return createEntry(false, groupAlertBehavior); } - public NotificationData.Entry createEntry(boolean isSummary, int groupAlertBehavior) { + public NotificationEntry createEntry(boolean isSummary, int groupAlertBehavior) { Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID) .setContentTitle("Title") .setSmallIcon(R.drawable.ic_person) @@ -79,7 +79,7 @@ public final class NotificationGroupTestHelper { new UserHandle(ActivityManager.getCurrentUser()), null /* overrideGroupKey */, 0 /* postTime */); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); entry.setRow(row); when(row.getEntry()).thenReturn(entry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 2bbfd7d8bb8d..12cb99575fb6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -40,7 +40,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -82,7 +82,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { Notification n = new Notification.Builder(getContext(), "a").build(); StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n, UserHandle.of(0), null, 0); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0, false /* animate */); TestableLooper.get(this).processAllMessages(); @@ -96,7 +96,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { Notification n = new Notification.Builder(getContext(), "a").build(); StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n, UserHandle.of(0), null, 0); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */); TestableLooper.get(this).processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index a45a5c4c3a0e..0d4046b6147b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -95,13 +95,13 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationData; -import com.android.systemui.statusbar.notification.NotificationData.Entry; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -135,7 +135,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private IDreamManager mDreamManager; @Mock private ScrimController mScrimController; @Mock private DozeScrimController mDozeScrimController; - @Mock private ArrayList<Entry> mNotificationList; + @Mock private ArrayList<NotificationEntry> mNotificationList; @Mock private BiometricUnlockController mBiometricUnlockController; @Mock private NotificationData mNotificationData; @Mock @@ -409,7 +409,7 @@ public class StatusBarTest extends SysuiTestCase { .build(); StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n, UserHandle.of(0), null, 0); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); entry.importance = IMPORTANCE_HIGH; assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry)); @@ -430,7 +430,7 @@ public class StatusBarTest extends SysuiTestCase { .build(); StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n, UserHandle.of(0), null, 0); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); entry.importance = IMPORTANCE_HIGH; assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry)); @@ -447,7 +447,7 @@ public class StatusBarTest extends SysuiTestCase { Notification n = new Notification.Builder(getContext(), "a").build(); StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n, UserHandle.of(0), null, 0); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); entry.suppressedVisualEffects = SUPPRESSED_EFFECT_PEEK; entry.importance = IMPORTANCE_HIGH; @@ -465,7 +465,7 @@ public class StatusBarTest extends SysuiTestCase { Notification n = new Notification.Builder(getContext(), "a").build(); StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n, UserHandle.of(0), null, 0); - NotificationData.Entry entry = new NotificationData.Entry(sbn); + NotificationEntry entry = new NotificationEntry(sbn); entry.importance = IMPORTANCE_HIGH; assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java index c5bac9242b8b..1066bc1a04df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java @@ -50,7 +50,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.statusbar.SmartReplyController; -import com.android.systemui.statusbar.notification.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import com.android.systemui.statusbar.phone.ShadeController; @@ -94,7 +94,7 @@ public class SmartReplyViewTest extends SysuiTestCase { private int mSpacing; @Mock private SmartReplyController mLogger; - private NotificationData.Entry mEntry; + private NotificationEntry mEntry; private Notification mNotification; @Mock ActivityStarter mActivityStarter; @@ -127,7 +127,7 @@ public class SmartReplyViewTest extends SysuiTestCase { StatusBarNotification sbn = mock(StatusBarNotification.class); when(sbn.getNotification()).thenReturn(mNotification); when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY); - mEntry = new NotificationData.Entry(sbn); + mEntry = new NotificationEntry(sbn); mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person); } @@ -855,4 +855,92 @@ public class SmartReplyViewTest extends SysuiTestCase { assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2)); assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3)); } + + /** + * Test to ensure that we try to add all possible actions - if we find one action that's too + * long we just skip that one rather than quitting altogether. + */ + @Test + public void testMeasure_skipTooLongActions() { + String[] choices = new String[] {}; + String[] actions = new String[] { + "a1", "a2", "this action is soooooooo long it's ridiculous", "a4"}; + + // All actions should be displayed as DOUBLE-line smart action buttons. + ViewGroup expectedView = buildExpectedView(new String[] {}, 1 /* lineCount */, + createActions(new String[] {"a1", "a2", "a4"})); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + setSmartRepliesAndActions(choices, actions); + mView.measure( + MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST), + MeasureSpec.UNSPECIFIED); + + assertEqualMeasures(expectedView, mView); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1)); + assertReplyButtonHidden(mView.getChildAt(2)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3)); + } + + /** + * Test to ensure that we try to add all possible replies - if we find one reply that's too + * long we just skip that one rather than quitting altogether. + */ + @Test + public void testMeasure_skipTooLongReplies() { + String[] choices = new String[] { + "r1", "r2", "this reply is soooooooo long it's ridiculous", "r4"}; + String[] actions = new String[] {}; + + // All replies should be displayed as single-line smart reply buttons. + ViewGroup expectedView = buildExpectedView(new String[] {"r1", "r2", "r4"}, + 1 /* lineCount */, Collections.emptyList()); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + setSmartRepliesAndActions(choices, actions); + mView.measure( + MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST), + MeasureSpec.UNSPECIFIED); + + assertEqualMeasures(expectedView, mView); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1)); + assertReplyButtonHidden(mView.getChildAt(2)); + assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3)); + } + + /** + * Test to ensure that we try to add all possible replies and actions - if we find a reply or + * action that's too long we just skip that one rather than quitting altogether. + */ + @Test + public void testMeasure_skipTooLongRepliesAndActions() { + String[] choices = new String[] { + "r1", "r2", "this reply is soooooooo long it's ridiculous", "r4"}; + String[] actions = new String[] { + "a1", "ThisActionIsSooooooooLongItsRidiculousIPromise"}; + + // All replies should be displayed as single-line smart reply buttons. + ViewGroup expectedView = buildExpectedView(new String[] {"r1", "r2", "r4"}, + 1 /* lineCount */, createActions(new String[] {"a1"})); + expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + setSmartRepliesAndActions(choices, actions); + mView.measure( + MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST), + MeasureSpec.UNSPECIFIED); + + assertEqualMeasures(expectedView, mView); + assertReplyButtonShownWithEqualMeasures( + expectedView.getChildAt(0), mView.getChildAt(0)); // r1 + assertReplyButtonShownWithEqualMeasures( + expectedView.getChildAt(1), mView.getChildAt(1)); // r2 + assertReplyButtonHidden(mView.getChildAt(2)); // long reply + assertReplyButtonShownWithEqualMeasures( + expectedView.getChildAt(2), mView.getChildAt(3)); // r4 + assertReplyButtonShownWithEqualMeasures( + expectedView.getChildAt(3), mView.getChildAt(4)); // a1 + assertReplyButtonHidden(mView.getChildAt(5)); // long action + } } diff --git a/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml b/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml index 165aab21c2e8..a6aa64c03c50 100644 --- a/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml +++ b/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml @@ -19,7 +19,7 @@ <!-- Name of a font family to use for body text. --> <string name="config_bodyFontFamily" translatable="false">source-sans-pro</string> <!-- Name of a font family to use for medium body text. --> - <string name="config_bodyFontFamilyMedium" translatable="false">source-sans-pro-medium</string> + <string name="config_bodyFontFamilyMedium" translatable="false">source-sans-pro-semi-bold</string> <!-- Name of a font family to use for headlines. If empty, falls back to platform default --> <string name="config_headlineFontFamily" translatable="false">arbutus-slab</string> <!-- Name of the font family used for system surfaces where the font should use medium weight --> diff --git a/packages/overlays/FontArvoLatoOverlay/res/values/config.xml b/packages/overlays/FontArvoLatoOverlay/res/values/config.xml index 229c578b22da..4e70d72aaae8 100644 --- a/packages/overlays/FontArvoLatoOverlay/res/values/config.xml +++ b/packages/overlays/FontArvoLatoOverlay/res/values/config.xml @@ -19,10 +19,10 @@ <!-- Name of a font family to use for body text. --> <string name="config_bodyFontFamily" translatable="false">lato</string> <!-- Name of a font family to use for medium body text. --> - <string name="config_bodyFontFamilyMedium" translatable="false">lato-medium</string> + <string name="config_bodyFontFamilyMedium" translatable="false">lato-bold</string> <!-- Name of a font family to use for headlines. If empty, falls back to platform default --> <string name="config_headlineFontFamily" translatable="false">arvo</string> <!-- Name of the font family used for system surfaces where the font should use medium weight --> - <string name="config_headlineFontFamilyMedium" translatable="false">arvo-medium</string> + <string name="config_headlineFontFamilyMedium" translatable="false">arvo-bold</string> </resources> diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp index 846ff2517d12..a40cf1c06d07 100644 --- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp +++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp @@ -27,23 +27,7 @@ namespace android { -class ProxyErrorLogger : public net::ProxyErrorListener { -public: - ~ProxyErrorLogger() { - - } - void AlertMessage(String16 message) { - String8 str(message); - ALOGD("Alert: %s", str.string()); - } - void ErrorMessage(String16 message) { - String8 str(message); - ALOGE("Error: %s", str.string()); - } -}; - net::ProxyResolverV8* proxyResolver = NULL; -ProxyErrorLogger* logger = NULL; bool pacSet = false; String16 jstringToString16(JNIEnv* env, jstring jstr) { @@ -64,9 +48,7 @@ jstring string16ToJstring(JNIEnv* env, String16 string) { static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* /* env */, jobject) { if (proxyResolver == NULL) { - logger = new ProxyErrorLogger(); - proxyResolver = new net::ProxyResolverV8(net::ProxyResolverJSBindings::CreateDefault(), - logger); + proxyResolver = new net::ProxyResolverV8(net::ProxyResolverJSBindings::CreateDefault()); pacSet = false; return JNI_FALSE; } @@ -76,9 +58,7 @@ static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JN static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* /* env */, jobject) { if (proxyResolver != NULL) { - delete logger; delete proxyResolver; - logger = NULL; proxyResolver = NULL; return JNI_FALSE; } diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index 3379b1b6d15a..665773c28235 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -3684,7 +3684,7 @@ message MetricsEvent { ACTION_SETTINGS_TILE_CLICK = 830; // OPEN: Notification unsnoozed. CLOSE: Notification snoozed. UPDATE: snoozed notification - // updated + // updated. TYPE_DISMISS: snoozing canceled due to data being cleared on package // CATEGORY: NOTIFICATION // OS: O NOTIFICATION_SNOOZED = 831; @@ -6735,6 +6735,34 @@ message MetricsEvent { // OS: Q SETTINGS_GUP_DASHBOARD = 1613; + // CATEGORY: The category for all actions relating to language detection logging. + // OS: Q + LANGUAGE_DETECTION = 1614; + + // CATEGORY: The category for all actions relating to conversation actions logging. + // OS: Q + CONVERSATION_ACTIONS = 1615; + + // ACTION: Actions from a text classifier are shown to user. + // CATEGORY: CONVERSATION_ACTIONS + // OS: Q + ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN = 1616; + + // ACTION: Event time of a text classifier event in unix timestamp. + // CATEGORY: CONVERSATION_ACTIONS, LANGUAGE_DETECTION + // OS: Q + FIELD_TEXT_CLASSIFIER_EVENT_TIME = 1617; + + // ACTION: Users compose their own replies instead of using suggested ones. + // CATEGORY: CONVERSATION_ACTIONS + // OS: Q + ACTION_TEXT_CLASSIFIER_MANUAL_REPLY = 1618; + + // ACTION: Text classifier generates an action. + // CATEGORY: CONVERSATION_ACTIONS + // OS: Q + ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED = 1619; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/Android.bp b/services/Android.bp index 58a09977596f..01734f4051d3 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -28,6 +28,7 @@ java_library { "services.net", "services.print", "services.restrictions", + "services.startop", "services.usage", "services.usb", "services.voiceinteraction", diff --git a/services/art-profile b/services/art-profile index af9d7a91ad60..7e4884b2c016 100644 --- a/services/art-profile +++ b/services/art-profile @@ -6970,6 +6970,7 @@ PLcom/android/server/am/ActivityManagerService$LocalService;->enforceCallerIsRec PLcom/android/server/am/ActivityManagerService$LocalService;->getMemoryStateForProcesses()Ljava/util/List; PLcom/android/server/am/ActivityManagerService$LocalService;->getTopVisibleActivities()Ljava/util/List; PLcom/android/server/am/ActivityManagerService$LocalService;->getUidProcessState(I)I +PLcom/android/server/am/ActivityManagerService$LocalService;->isAppForeground(I)Z PLcom/android/server/am/ActivityManagerService$LocalService;->isCallerRecents(I)Z PLcom/android/server/am/ActivityManagerService$LocalService;->isRuntimeRestarted()Z PLcom/android/server/am/ActivityManagerService$LocalService;->isSystemReady()Z @@ -7125,7 +7126,6 @@ PLcom/android/server/am/ActivityManagerService;->hasUsageStatsPermission(Ljava/l PLcom/android/server/am/ActivityManagerService;->installEncryptionUnawareProviders(I)V PLcom/android/server/am/ActivityManagerService;->installSystemProviders()V PLcom/android/server/am/ActivityManagerService;->isAllowedWhileBooting(Landroid/content/pm/ApplicationInfo;)Z -PLcom/android/server/am/ActivityManagerService;->isAppForeground(I)Z PLcom/android/server/am/ActivityManagerService;->isAssistDataAllowedOnCurrentActivity()Z PLcom/android/server/am/ActivityManagerService;->isGetTasksAllowed(Ljava/lang/String;II)Z PLcom/android/server/am/ActivityManagerService;->isInLockTaskMode()Z diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 1a6bee9daaf3..6cccd62d563f 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -70,6 +70,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IResultReceiver; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; +import com.android.internal.util.SyncResultReceiver; import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.autofill.ui.AutoFillUI; @@ -606,15 +607,15 @@ public final class AutofillManagerService } private void send(@NonNull IResultReceiver receiver, @Nullable String value) { - send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value)); + send(receiver, SyncResultReceiver.bundleFor(value)); } private void send(@NonNull IResultReceiver receiver, @Nullable String[] value) { - send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value)); + send(receiver, SyncResultReceiver.bundleFor(value)); } private void send(@NonNull IResultReceiver receiver, @Nullable Parcelable value) { - send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value)); + send(receiver, SyncResultReceiver.bundleFor(value)); } private void send(@NonNull IResultReceiver receiver, boolean value) { diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 4b7efe1dfa71..a6bb049602a0 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -870,8 +870,11 @@ final class AutofillManagerServiceImpl } pw.print(prefix); pw.print("Default component: "); pw.println(getContext() .getString(R.string.config_defaultAutofillService)); - pw.print(prefix); pw.print("mAugmentedAutofillNamer: "); - mAugmentedAutofillResolver.dumpShort(pw); pw.println(); + + pw.print(prefix); pw.println("mAugmentedAutofillNamer: "); + pw.print(prefix2); mAugmentedAutofillResolver.dumpShort(pw); pw.println(); + pw.print(prefix2); mAugmentedAutofillResolver.dumpShort(pw, mUserId); pw.println(); + if (mRemoteAugmentedAutofillService != null) { pw.print(prefix); pw.println("RemoteAugmentedAutofillService: "); mRemoteAugmentedAutofillService.dump(prefix2, pw); diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 8b07db7fc32d..12db4f37da58 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -39,7 +39,6 @@ import android.os.Binder; import android.os.HandlerThread; import android.os.IBinder; import android.os.ParcelFileDescriptor; -import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; import android.util.Slog; @@ -127,7 +126,7 @@ public class BackupManagerService { protected void startServiceForUser(int userId) { UserBackupManagerService userBackupManagerService = UserBackupManagerService.createAndInitializeService( - userId, mContext, mTrampoline, mBackupThread, mTransportWhitelist); + userId, mContext, mTrampoline, mTransportWhitelist); startServiceForUser(userId, userBackupManagerService); } @@ -139,20 +138,18 @@ public class BackupManagerService { mServiceUsers.put(userId, userBackupManagerService); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable"); - try { - // TODO(b/121198604): Make enable file per-user and clean up indirection. - mTrampoline.setBackupEnabledForUser( - userId, UserBackupManagerFilePersistedSettings.readBackupEnableState(userId)); - } catch (RemoteException e) { - // Can't happen, it's a local object. - } + userBackupManagerService.initializeBackupEnableState(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } /** Stops the backup service for user {@code userId} when the user is stopped. */ @VisibleForTesting protected void stopServiceForUser(int userId) { - mServiceUsers.remove(userId); + UserBackupManagerService userBackupManagerService = mServiceUsers.removeReturnOld(userId); + + if (userBackupManagerService != null) { + userBackupManagerService.tearDownService(); + } } SparseArray<UserBackupManagerService> getServiceUsers() { diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java index 82638b4ecee4..5708b1c36822 100644 --- a/services/backup/java/com/android/server/backup/FullBackupJob.java +++ b/services/backup/java/com/android/server/backup/FullBackupJob.java @@ -24,15 +24,12 @@ import android.content.ComponentName; import android.content.Context; public class FullBackupJob extends JobService { - private static final String TAG = "FullBackupJob"; - private static final boolean DEBUG = true; - private static ComponentName sIdleService = new ComponentName("android", FullBackupJob.class.getName()); private static final int JOB_ID = 0x5038; - JobParameters mParams; + private JobParameters mParams; public static void schedule(Context ctx, long minDelay, BackupManagerConstants constants) { JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE); diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java index bed520e9f068..3184bd87601a 100644 --- a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java @@ -13,8 +13,6 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Slog; -import com.android.server.backup.restore.PerformAdbRestoreTask; - import libcore.io.IoUtils; import java.io.File; @@ -42,11 +40,10 @@ public class KeyValueAdbRestoreEngine implements Runnable { private final UserBackupManagerService mBackupManagerService; private final File mDataDir; - FileMetadata mInfo; - PerformAdbRestoreTask mRestoreTask; - ParcelFileDescriptor mInFD; - IBackupAgent mAgent; - int mToken; + private final FileMetadata mInfo; + private final ParcelFileDescriptor mInFD; + private final IBackupAgent mAgent; + private final int mToken; public KeyValueAdbRestoreEngine(UserBackupManagerService backupManagerService, File dataDir, FileMetadata info, ParcelFileDescriptor inFD, IBackupAgent agent, diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java index a0feaf9c8d15..aabd41a611a1 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java @@ -17,29 +17,35 @@ package com.android.server.backup; import android.os.Environment; +import android.os.UserHandle; import java.io.File; /** Directories used for user specific backup/restore persistent state and book-keeping. */ -public final class UserBackupManagerFiles { +final class UserBackupManagerFiles { // Name of the directories the service stores bookkeeping data under. private static final String BACKUP_PERSISTENT_DIR = "backup"; private static final String BACKUP_STAGING_DIR = "backup_stage"; + private static File getBaseDir(int userId) { + return Environment.getDataSystemCeDirectory(userId); + } + static File getBaseStateDir(int userId) { - // TODO (b/120424138) this should be per user + if (userId != UserHandle.USER_SYSTEM) { + return new File(getBaseDir(userId), BACKUP_PERSISTENT_DIR); + } + // TODO (b/120424138) remove if clause above and use same logic for system user. + // simultaneously, copy below dir to new system user dir return new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR); } static File getDataDir(int userId) { - // TODO (b/120424138) this should be per user - // This dir on /cache is managed directly in init.rc + if (userId != UserHandle.USER_SYSTEM) { + return new File(getBaseDir(userId), BACKUP_STAGING_DIR); + } + // TODO (b/120424138) remove if clause above and use same logic for system user. Since this + // is a staging dir, we dont need to copy below dir to new system user dir return new File(Environment.getDownloadCacheDirectory(), BACKUP_STAGING_DIR); } - - /** Directory used by full backup engine to store state. */ - public static File getFullBackupEngineFilesDir(int userId) { - // TODO (b/120424138) this should be per user - return new File("/data/system"); - } } diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 6425508829ce..d7a23650d811 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -39,6 +39,7 @@ import static com.android.server.backup.internal.BackupHandler.MSG_SCHEDULE_BACK import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; +import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.AppGlobals; import android.app.IActivityManager; @@ -103,6 +104,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.backup.fullbackup.FullBackupEntry; import com.android.server.backup.fullbackup.PerformFullTransportBackupTask; import com.android.server.backup.internal.BackupHandler; @@ -110,9 +112,9 @@ import com.android.server.backup.internal.ClearDataObserver; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.internal.Operation; import com.android.server.backup.internal.PerformInitializeTask; -import com.android.server.backup.internal.ProvisionedObserver; import com.android.server.backup.internal.RunBackupReceiver; import com.android.server.backup.internal.RunInitializeReceiver; +import com.android.server.backup.internal.SetupObserver; import com.android.server.backup.keyvalue.BackupRequest; import com.android.server.backup.params.AdbBackupParams; import com.android.server.backup.params.AdbParams; @@ -208,8 +210,8 @@ public class UserBackupManagerService { public static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN"; public static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT"; - public static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED"; - public static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName"; + private static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED"; + private static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName"; // Bookkeeping of in-flight operations. The operation token is the index of the entry in the // pending operations list. @@ -245,26 +247,28 @@ public class UserBackupManagerService { private final @UserIdInt int mUserId; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; private final TransportManager mTransportManager; + private final HandlerThread mUserBackupThread; private Context mContext; private PackageManager mPackageManager; private IPackageManager mPackageManagerBinder; private IActivityManager mActivityManager; + private ActivityManagerInternal mActivityManagerInternal; private PowerManager mPowerManager; - private AlarmManager mAlarmManager; - private IStorageManager mStorageManager; - private BackupManagerConstants mConstants; - private PowerManager.WakeLock mWakelock; - private BackupHandler mBackupHandler; + private final AlarmManager mAlarmManager; + private final IStorageManager mStorageManager; + private final BackupManagerConstants mConstants; + private final PowerManager.WakeLock mWakelock; + private final BackupHandler mBackupHandler; - private IBackupManager mBackupManagerBinder; + private final IBackupManager mBackupManagerBinder; private boolean mEnabled; // access to this is synchronized on 'this' - private boolean mProvisioned; + private boolean mSetupComplete; private boolean mAutoRestore; - private PendingIntent mRunBackupIntent; - private PendingIntent mRunInitIntent; + private final PendingIntent mRunBackupIntent; + private final PendingIntent mRunInitIntent; private final ArraySet<String> mPendingInits = new ArraySet<>(); // transport names @@ -272,7 +276,7 @@ public class UserBackupManagerService { private final SparseArray<HashSet<String>> mBackupParticipants = new SparseArray<>(); // Backups that we haven't started yet. Keys are package names. - private HashMap<String, BackupRequest> mPendingBackups = new HashMap<>(); + private final HashMap<String, BackupRequest> mPendingBackups = new HashMap<>(); // locking around the pending-backup management private final Object mQueueLock = new Object(); @@ -314,9 +318,6 @@ public class UserBackupManagerService { private ActiveRestoreSession mActiveRestoreSession; - // Watch the device provisioning operation during setup - private ContentObserver mProvisionedObserver; - /** * mCurrentOperations contains the list of currently active operations. * @@ -342,7 +343,7 @@ public class UserBackupManagerService { private final SparseArray<Operation> mCurrentOperations = new SparseArray<>(); private final Object mCurrentOpLock = new Object(); private final Random mTokenGenerator = new Random(); - final AtomicInteger mNextToken = new AtomicInteger(); + private final AtomicInteger mNextToken = new AtomicInteger(); // Where we keep our journal files and other bookkeeping. private final File mBaseStateDir; @@ -350,7 +351,7 @@ public class UserBackupManagerService { private final File mJournalDir; @Nullable private DataChangedJournal mJournal; - private File mFullBackupScheduleFile; + private final File mFullBackupScheduleFile; // Keep a log of all the apps we've ever backed up. private ProcessedPackagesJournal mProcessedPackagesJournal; @@ -371,11 +372,10 @@ public class UserBackupManagerService { @UserIdInt int userId, Context context, Trampoline trampoline, - HandlerThread backupThread, Set<ComponentName> transportWhitelist) { String currentTransport = - Settings.Secure.getString( - context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT); + Settings.Secure.getStringForUser( + context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT, userId); if (TextUtils.isEmpty(currentTransport)) { currentTransport = null; } @@ -389,8 +389,21 @@ public class UserBackupManagerService { File baseStateDir = UserBackupManagerFiles.getBaseStateDir(userId); File dataDir = UserBackupManagerFiles.getDataDir(userId); + HandlerThread userBackupThread = + new HandlerThread("backup-" + userId, Process.THREAD_PRIORITY_BACKGROUND); + userBackupThread.start(); + if (DEBUG) { + Slog.d(TAG, "Started thread " + userBackupThread.getName() + " for user " + userId); + } + return createAndInitializeService( - userId, context, trampoline, backupThread, baseStateDir, dataDir, transportManager); + userId, + context, + trampoline, + userBackupThread, + baseStateDir, + dataDir, + transportManager); } /** @@ -399,7 +412,7 @@ public class UserBackupManagerService { * @param userId The user which this service is for. * @param context The system server context. * @param trampoline A reference to the proxy to {@link BackupManagerService}. - * @param backupThread The thread running backup/restore operations for the user. + * @param userBackupThread The thread running backup/restore operations for the user. * @param baseStateDir The directory we store the user's persistent bookkeeping data. * @param dataDir The directory we store the user's temporary staging data. * @param transportManager The {@link TransportManager} responsible for handling the user's @@ -410,19 +423,38 @@ public class UserBackupManagerService { @UserIdInt int userId, Context context, Trampoline trampoline, - HandlerThread backupThread, + HandlerThread userBackupThread, File baseStateDir, File dataDir, TransportManager transportManager) { return new UserBackupManagerService( - userId, context, trampoline, backupThread, baseStateDir, dataDir, transportManager); + userId, + context, + trampoline, + userBackupThread, + baseStateDir, + dataDir, + transportManager); + } + + /** + * Returns the value of {@link Settings.Secure#USER_SETUP_COMPLETE} for the specified user + * {@code userId} as a {@code boolean}. + */ + public static boolean getSetupCompleteSettingForUser(Context context, int userId) { + return Settings.Secure.getIntForUser( + context.getContentResolver(), + Settings.Secure.USER_SETUP_COMPLETE, + 0, + userId) + != 0; } private UserBackupManagerService( @UserIdInt int userId, Context context, Trampoline parent, - HandlerThread backupThread, + HandlerThread userBackupThread, File baseStateDir, File dataDir, TransportManager transportManager) { @@ -431,6 +463,7 @@ public class UserBackupManagerService { mPackageManager = context.getPackageManager(); mPackageManagerBinder = AppGlobals.getPackageManager(); mActivityManager = ActivityManager.getService(); + mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); @@ -443,21 +476,22 @@ public class UserBackupManagerService { BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver()); mAgentTimeoutParameters.start(); - // spin up the backup/restore handler thread - checkNotNull(backupThread, "backupThread cannot be null"); - mBackupHandler = new BackupHandler(this, backupThread.getLooper()); + checkNotNull(userBackupThread, "userBackupThread cannot be null"); + mUserBackupThread = userBackupThread; + mBackupHandler = new BackupHandler(this, userBackupThread.getLooper()); // Set up our bookkeeping final ContentResolver resolver = context.getContentResolver(); - mProvisioned = Settings.Global.getInt(resolver, - Settings.Global.DEVICE_PROVISIONED, 0) != 0; - mAutoRestore = Settings.Secure.getInt(resolver, - Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0; + mSetupComplete = getSetupCompleteSettingForUser(context, userId); + mAutoRestore = Settings.Secure.getIntForUser(resolver, + Settings.Secure.BACKUP_AUTO_RESTORE, 1, userId) != 0; - mProvisionedObserver = new ProvisionedObserver(this, mBackupHandler); + ContentObserver setupObserver = new SetupObserver(this, mBackupHandler); resolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), - false, mProvisionedObserver); + Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), + /* notifyForDescendents */ false, + setupObserver, + mUserId); mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null"); mBaseStateDir.mkdirs(); @@ -469,26 +503,46 @@ public class UserBackupManagerService { mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng); - // Alarm receivers for scheduled backups & initialization operations - BroadcastReceiver mRunBackupReceiver = new RunBackupReceiver(this); + // Receivers for scheduled backups and transport initialization operations. + BroadcastReceiver runBackupReceiver = new RunBackupReceiver(this); IntentFilter filter = new IntentFilter(); filter.addAction(RUN_BACKUP_ACTION); - context.registerReceiver(mRunBackupReceiver, filter, - android.Manifest.permission.BACKUP, null); - - BroadcastReceiver mRunInitReceiver = new RunInitializeReceiver(this); + context.registerReceiverAsUser( + runBackupReceiver, + UserHandle.of(userId), + filter, + android.Manifest.permission.BACKUP, + /* scheduler */ null); + + BroadcastReceiver runInitReceiver = new RunInitializeReceiver(this); filter = new IntentFilter(); filter.addAction(RUN_INITIALIZE_ACTION); - context.registerReceiver(mRunInitReceiver, filter, - android.Manifest.permission.BACKUP, null); + context.registerReceiverAsUser( + runInitReceiver, + UserHandle.of(userId), + filter, + android.Manifest.permission.BACKUP, + /* scheduler */ null); Intent backupIntent = new Intent(RUN_BACKUP_ACTION); backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mRunBackupIntent = PendingIntent.getBroadcast(context, 0, backupIntent, 0); + mRunBackupIntent = + PendingIntent.getBroadcastAsUser( + context, + /* requestCode */ 0, + backupIntent, + /* flags */ 0, + UserHandle.of(userId)); Intent initIntent = new Intent(RUN_INITIALIZE_ACTION); initIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mRunInitIntent = PendingIntent.getBroadcast(context, 0, initIntent, 0); + mRunInitIntent = + PendingIntent.getBroadcastAsUser( + context, + /* requestCode */ 0, + initIntent, + /* flags */ 0, + UserHandle.of(userId)); // Set up the backup-request journaling mJournalDir = new File(mBaseStateDir, "pending"); @@ -526,6 +580,20 @@ public class UserBackupManagerService { mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"); } + void initializeBackupEnableState() { + boolean isEnabled = UserBackupManagerFilePersistedSettings.readBackupEnableState(mUserId); + setBackupEnabled(isEnabled); + } + + /** Cleans up state when the user of this service is stopped. */ + void tearDownService() { + mUserBackupThread.quit(); + } + + public @UserIdInt int getUserId() { + return mUserId; + } + public BackupManagerConstants getConstants() { return mConstants; } @@ -538,51 +606,27 @@ public class UserBackupManagerService { return mContext; } - public void setContext(Context context) { - mContext = context; - } - public PackageManager getPackageManager() { return mPackageManager; } - public void setPackageManager(PackageManager packageManager) { - mPackageManager = packageManager; - } - public IPackageManager getPackageManagerBinder() { return mPackageManagerBinder; } - public void setPackageManagerBinder(IPackageManager packageManagerBinder) { - mPackageManagerBinder = packageManagerBinder; - } - public IActivityManager getActivityManager() { return mActivityManager; } - public void setActivityManager(IActivityManager activityManager) { - mActivityManager = activityManager; - } - public AlarmManager getAlarmManager() { return mAlarmManager; } - public void setAlarmManager(AlarmManager alarmManager) { - mAlarmManager = alarmManager; - } - @VisibleForTesting void setPowerManager(PowerManager powerManager) { mPowerManager = powerManager; } - public void setBackupManagerBinder(IBackupManager backupManagerBinder) { - mBackupManagerBinder = backupManagerBinder; - } - public TransportManager getTransportManager() { return mTransportManager; } @@ -595,12 +639,12 @@ public class UserBackupManagerService { mEnabled = enabled; } - public boolean isProvisioned() { - return mProvisioned; + public boolean isSetupComplete() { + return mSetupComplete; } - public void setProvisioned(boolean provisioned) { - mProvisioned = provisioned; + public void setSetupComplete(boolean setupComplete) { + mSetupComplete = setupComplete; } public PowerManager.WakeLock getWakelock() { @@ -617,35 +661,18 @@ public class UserBackupManagerService { mWakelock.setWorkSource(workSource); } - public void setWakelock(PowerManager.WakeLock wakelock) { - mWakelock = wakelock; - } - public Handler getBackupHandler() { return mBackupHandler; } - public void setBackupHandler(BackupHandler backupHandler) { - mBackupHandler = backupHandler; - } - public PendingIntent getRunInitIntent() { return mRunInitIntent; } - public void setRunInitIntent(PendingIntent runInitIntent) { - mRunInitIntent = runInitIntent; - } - public HashMap<String, BackupRequest> getPendingBackups() { return mPendingBackups; } - public void setPendingBackups( - HashMap<String, BackupRequest> pendingBackups) { - mPendingBackups = pendingBackups; - } - public Object getQueueLock() { return mQueueLock; } @@ -658,10 +685,6 @@ public class UserBackupManagerService { mBackupRunning = backupRunning; } - public long getLastBackupPass() { - return mLastBackupPass; - } - public void setLastBackupPass(long lastBackupPass) { mLastBackupPass = lastBackupPass; } @@ -670,10 +693,6 @@ public class UserBackupManagerService { return mClearDataLock; } - public boolean isClearingData() { - return mClearingData; - } - public void setClearingData(boolean clearingData) { mClearingData = clearingData; } @@ -694,11 +713,6 @@ public class UserBackupManagerService { return mActiveRestoreSession; } - public void setActiveRestoreSession( - ActiveRestoreSession activeRestoreSession) { - mActiveRestoreSession = activeRestoreSession; - } - public SparseArray<Operation> getCurrentOperations() { return mCurrentOperations; } @@ -732,18 +746,10 @@ public class UserBackupManagerService { return mRng; } - public Set<String> getAncestralPackages() { - return mAncestralPackages; - } - public void setAncestralPackages(Set<String> ancestralPackages) { mAncestralPackages = ancestralPackages; } - public long getAncestralToken() { - return mAncestralToken; - } - public void setAncestralToken(long ancestralToken) { mAncestralToken = ancestralToken; } @@ -1553,11 +1559,16 @@ public class UserBackupManagerService { throw new IllegalArgumentException("No packages are provided for backup"); } - if (!mEnabled || !mProvisioned) { - Slog.i(TAG, "Backup requested but e=" + mEnabled + " p=" + mProvisioned); + if (!mEnabled || !mSetupComplete) { + Slog.i( + TAG, + "Backup requested but enabled=" + + mEnabled + + " setupComplete=" + + mSetupComplete); BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_BACKUP_NOT_ALLOWED); - final int logTag = mProvisioned + final int logTag = mSetupComplete ? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED : BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED; monitor = BackupManagerMonitorUtils.monitorEvent(monitor, logTag, null, @@ -1992,13 +2003,13 @@ public class UserBackupManagerService { FullBackupEntry entry = null; long latency = fullBackupInterval; - if (!mEnabled || !mProvisioned) { + if (!mEnabled || !mSetupComplete) { // Backups are globally disabled, so don't proceed. We also don't reschedule // the job driving automatic backups; that job will be scheduled again when // the user enables backup. if (MORE_DEBUG) { - Slog.i(TAG, "beginFullBackup but e=" + mEnabled - + " p=" + mProvisioned + "; ignoring"); + Slog.i(TAG, "beginFullBackup but enabled=" + mEnabled + + " setupComplete=" + mSetupComplete + "; ignoring"); } return false; } @@ -2087,7 +2098,8 @@ public class UserBackupManagerService { final int privFlags = appInfo.applicationInfo.privateFlags; headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0 - && mActivityManager.isAppForeground(appInfo.applicationInfo.uid); + && mActivityManagerInternal.isAppForeground( + appInfo.applicationInfo.uid); if (headBusy) { final long nextEligible = System.currentTimeMillis() @@ -2110,8 +2122,6 @@ public class UserBackupManagerService { // queue entirely and move on, but if there's nothing else in the queue // we should bail entirely. headBusy cannot have been set to true yet. runBackup = (mFullBackupQueue.size() > 1); - } catch (RemoteException e) { - // Cannot happen; the Activity Manager is in the same process } } } while (headBusy); @@ -2399,12 +2409,6 @@ public class UserBackupManagerService { } } - /** Returns {@code true} if the system user has gone through SUW. */ - public boolean deviceIsProvisioned() { - final ContentResolver resolver = mContext.getContentResolver(); - return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0); - } - /** * Used by 'adb backup' to run a backup pass for packages supplied via the command line, writing * the resulting data stream to the supplied {@code fd}. This method is synchronous and does not @@ -2437,8 +2441,7 @@ public class UserBackupManagerService { long oldId = Binder.clearCallingIdentity(); try { - // Doesn't make sense to do a full backup prior to setup - if (!deviceIsProvisioned()) { + if (!mSetupComplete) { Slog.i(TAG, "Backup not supported before setup"); return; } @@ -2564,9 +2567,7 @@ public class UserBackupManagerService { long oldId = Binder.clearCallingIdentity(); try { - // Check whether the device has been provisioned -- we don't handle - // full restores prior to completing the setup process. - if (!deviceIsProvisioned()) { + if (!mSetupComplete) { Slog.i(TAG, "Full restore not permitted before setup"); return; } @@ -2721,7 +2722,7 @@ public class UserBackupManagerService { } synchronized (mQueueLock) { - if (enable && !wasEnabled && mProvisioned) { + if (enable && !wasEnabled && mSetupComplete) { // if we've just been enabled, start scheduling backup passes KeyValueBackupJob.schedule(mContext, mConstants); scheduleNextFullBackupJob(0); @@ -2734,7 +2735,7 @@ public class UserBackupManagerService { // This also constitutes an opt-out, so we wipe any data for // this device from the backend. We start that process with // an alarm in order to guarantee wakelock states. - if (wasEnabled && mProvisioned) { + if (wasEnabled && mSetupComplete) { // NOTE: we currently flush every registered transport, not just // the currently-active one. List<String> transportNames = new ArrayList<>(); @@ -2782,8 +2783,8 @@ public class UserBackupManagerService { final long oldId = Binder.clearCallingIdentity(); try { synchronized (this) { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0); + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0, mUserId); mAutoRestore = doAutoRestore; } } finally { @@ -2996,8 +2997,8 @@ public class UserBackupManagerService { private void updateStateForTransport(String newTransportName) { // Publish the name change - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.BACKUP_TRANSPORT, newTransportName); + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.BACKUP_TRANSPORT, newTransportName, mUserId); // And update our current-dataset bookkeeping String callerLogString = "BMS.updateStateForTransport()"; @@ -3112,8 +3113,7 @@ public class UserBackupManagerService { synchronized (mAgentConnectLock) { if (Binder.getCallingUid() == Process.SYSTEM_UID) { Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder); - IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder); - mConnectedAgent = agent; + mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder); mConnecting = false; } else { Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() @@ -3431,7 +3431,7 @@ public class UserBackupManagerService { private void dumpInternal(PrintWriter pw) { synchronized (mQueueLock) { pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled") - + " / " + (!mProvisioned ? "not " : "") + "provisioned / " + + " / " + (!mSetupComplete ? "not " : "") + "setup complete / " + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init"); pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled")); if (mBackupRunning) pw.println("Backup currently running"); diff --git a/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java index bace1aa638ec..d13f71116c81 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java +++ b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java @@ -7,6 +7,7 @@ import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA import static com.android.server.backup.UserBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.backup.FullBackup; import android.app.backup.FullBackupDataOutput; import android.content.pm.PackageInfo; @@ -15,7 +16,6 @@ import android.content.pm.Signature; import android.content.pm.SigningInfo; import android.os.Build; import android.os.Environment; -import android.os.UserHandle; import android.util.Log; import android.util.StringBuilderPrinter; @@ -254,12 +254,11 @@ public class AppMetadataBackupWriter { * for 'adb backup'. */ // TODO(b/113807190): Investigate and potentially remove. - public void backupObb(PackageInfo packageInfo) { + public void backupObb(@UserIdInt int userId, PackageInfo packageInfo) { // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM doesn't have access to // external storage. - // TODO: http://b/22388012 Environment.UserEnvironment userEnv = - new Environment.UserEnvironment(UserHandle.USER_SYSTEM); + new Environment.UserEnvironment(userId); File obbDir = userEnv.buildExternalStorageAppObbDirs(packageInfo.packageName)[0]; if (obbDir != null) { if (MORE_DEBUG) { diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java index 45ca2af54b52..7ea1892727e3 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java @@ -34,14 +34,12 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.os.UserHandle; import android.util.Slog; import com.android.internal.util.Preconditions; import com.android.server.AppWidgetBackupBridge; import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; -import com.android.server.backup.UserBackupManagerFiles; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.remote.RemoteCall; import com.android.server.backup.utils.FullBackupUtils; @@ -56,12 +54,12 @@ import java.io.OutputStream; */ public class FullBackupEngine { private UserBackupManagerService backupManagerService; - OutputStream mOutput; - FullBackupPreflight mPreflightHook; - BackupRestoreTask mTimeoutMonitor; - IBackupAgent mAgent; - boolean mIncludeApks; - PackageInfo mPkg; + private OutputStream mOutput; + private FullBackupPreflight mPreflightHook; + private BackupRestoreTask mTimeoutMonitor; + private IBackupAgent mAgent; + private boolean mIncludeApks; + private PackageInfo mPkg; private final long mQuota; private final int mOpToken; private final int mTransportFlags; @@ -78,21 +76,21 @@ public class FullBackupEngine { private final File mFilesDir; FullBackupRunner( + UserBackupManagerService userBackupManagerService, PackageInfo packageInfo, IBackupAgent agent, ParcelFileDescriptor pipe, int token, boolean includeApks) throws IOException { - // TODO: http://b/22388012 - mUserId = UserHandle.USER_SYSTEM; + mUserId = userBackupManagerService.getUserId(); mPackageManager = backupManagerService.getPackageManager(); mPackage = packageInfo; mAgent = agent; mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor()); mToken = token; mIncludeApks = includeApks; - mFilesDir = UserBackupManagerFiles.getFullBackupEngineFilesDir(mUserId); + mFilesDir = userBackupManagerService.getDataDir(); } @Override @@ -132,7 +130,7 @@ public class FullBackupEngine { // TODO(b/113807190): Look into removing, only used for 'adb backup'. if (writeApk) { appMetadataBackupWriter.backupApk(mPackage); - appMetadataBackupWriter.backupObb(mPackage); + appMetadataBackupWriter.backupObb(mUserId, mPackage); } if (DEBUG) { @@ -155,9 +153,12 @@ public class FullBackupEngine { backupManagerService.getBackupManagerBinder(), mTransportFlags); } catch (IOException e) { - Slog.e(TAG, "Error running full backup for " + mPackage.packageName); + Slog.e(TAG, "Error running full backup for " + mPackage.packageName, e); } catch (RemoteException e) { - Slog.e(TAG, "Remote agent vanished during full backup of " + mPackage.packageName); + Slog.e( + TAG, + "Remote agent vanished during full backup of " + mPackage.packageName, + e); } finally { try { mPipe.close(); @@ -233,7 +234,13 @@ public class FullBackupEngine { pipes = ParcelFileDescriptor.createPipe(); FullBackupRunner runner = - new FullBackupRunner(mPkg, mAgent, pipes[1], mOpToken, mIncludeApks); + new FullBackupRunner( + backupManagerService, + mPkg, + mAgent, + pipes[1], + mOpToken, + mIncludeApks); pipes[1].close(); // the runner has dup'd it pipes[1] = null; Thread t = new Thread(runner, "app-data-runner"); diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java index 43a80c45d6f7..31786d749f0a 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java @@ -66,24 +66,22 @@ import javax.crypto.spec.SecretKeySpec; */ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask { - private UserBackupManagerService backupManagerService; - FullBackupEngine mBackupEngine; - final AtomicBoolean mLatch; - - ParcelFileDescriptor mOutputFile; - DeflaterOutputStream mDeflater; - boolean mIncludeApks; - boolean mIncludeObbs; - boolean mIncludeShared; - boolean mDoWidgets; - boolean mAllApps; - boolean mIncludeSystem; - boolean mCompress; - boolean mKeyValue; - ArrayList<String> mPackages; - PackageInfo mCurrentTarget; - String mCurrentPassword; - String mEncryptPassword; + private final UserBackupManagerService mUserBackupManagerService; + private final AtomicBoolean mLatch; + + private final ParcelFileDescriptor mOutputFile; + private final boolean mIncludeApks; + private final boolean mIncludeObbs; + private final boolean mIncludeShared; + private final boolean mDoWidgets; + private final boolean mAllApps; + private final boolean mIncludeSystem; + private final boolean mCompress; + private final boolean mKeyValue; + private final ArrayList<String> mPackages; + private PackageInfo mCurrentTarget; + private final String mCurrentPassword; + private final String mEncryptPassword; private final int mCurrentOpToken; public PerformAdbBackupTask(UserBackupManagerService backupManagerService, @@ -92,7 +90,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor String curPassword, String encryptPassword, boolean doAllApps, boolean doSystem, boolean doCompress, boolean doKeyValue, String[] packages, AtomicBoolean latch) { super(observer); - this.backupManagerService = backupManagerService; + mUserBackupManagerService = backupManagerService; mCurrentOpToken = backupManagerService.generateRandomIntegerToken(); mLatch = latch; @@ -104,7 +102,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor mAllApps = doAllApps; mIncludeSystem = doSystem; mPackages = (packages == null) - ? new ArrayList<String>() + ? new ArrayList<>() : new ArrayList<>(Arrays.asList(packages)); mCurrentPassword = curPassword; // when backing up, if there is a current backup password, we require that @@ -123,11 +121,11 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor mKeyValue = doKeyValue; } - void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) { + private void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) { for (String pkgName : pkgNames) { if (!set.containsKey(pkgName)) { try { - PackageInfo info = backupManagerService.getPackageManager().getPackageInfo( + PackageInfo info = mUserBackupManagerService.getPackageManager().getPackageInfo( pkgName, PackageManager.GET_SIGNING_CERTIFICATES); set.put(pkgName, info); @@ -141,7 +139,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor private OutputStream emitAesBackupHeader(StringBuilder headerbuf, OutputStream ofstream) throws Exception { // User key will be used to encrypt the master key. - byte[] newUserSalt = backupManagerService + byte[] newUserSalt = mUserBackupManagerService .randomBytes(PasswordUtils.PBKDF2_SALT_SIZE); SecretKey userKey = PasswordUtils .buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, @@ -150,8 +148,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor // the master key is random for each backup byte[] masterPw = new byte[256 / 8]; - backupManagerService.getRng().nextBytes(masterPw); - byte[] checksumSalt = backupManagerService + mUserBackupManagerService.getRng().nextBytes(masterPw); + byte[] checksumSalt = mUserBackupManagerService .randomBytes(PasswordUtils.PBKDF2_SALT_SIZE); // primary encryption of the datastream with the random key @@ -232,11 +230,11 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<>(); FullBackupObbConnection obbConnection = new FullBackupObbConnection( - backupManagerService); + mUserBackupManagerService); obbConnection.establish(); // we'll want this later sendStartBackup(); - PackageManager pm = backupManagerService.getPackageManager(); + PackageManager pm = mUserBackupManagerService.getPackageManager(); // doAllApps supersedes the package set if any if (mAllApps) { @@ -245,7 +243,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor for (int i = 0; i < allPackages.size(); i++) { PackageInfo pkg = allPackages.get(i); // Exclude system apps if we've been asked to do so - if (mIncludeSystem == true + if (mIncludeSystem || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) { packagesToBackup.put(pkg.packageName, pkg); } @@ -316,7 +314,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0); // Only allow encrypted backups of encrypted devices - if (backupManagerService.deviceIsEncrypted() && !encrypting) { + if (mUserBackupManagerService.deviceIsEncrypted() && !encrypting) { Slog.e(TAG, "Unencrypted backup of encrypted device; aborting"); return; } @@ -325,7 +323,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor // Verify that the given password matches the currently-active // backup password, if any - if (!backupManagerService.backupPasswordMatches(mCurrentPassword)) { + if (!mUserBackupManagerService.backupPasswordMatches(mCurrentPassword)) { if (DEBUG) { Slog.w(TAG, "Backup password mismatch; aborting"); } @@ -390,7 +388,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor // Shared storage if requested if (mIncludeShared) { try { - pkg = backupManagerService.getPackageManager().getPackageInfo( + pkg = mUserBackupManagerService.getPackageManager().getPackageInfo( SHARED_BACKUP_AGENT_PACKAGE, 0); backupQueue.add(pkg); } catch (NameNotFoundException e) { @@ -410,9 +408,17 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor pkg.packageName.equals( SHARED_BACKUP_AGENT_PACKAGE); - mBackupEngine = new FullBackupEngine(backupManagerService, out, - null, pkg, mIncludeApks, this, Long.MAX_VALUE, - mCurrentOpToken, /*transportFlags=*/ 0); + FullBackupEngine mBackupEngine = + new FullBackupEngine( + mUserBackupManagerService, + out, + null, + pkg, + mIncludeApks, + this, + Long.MAX_VALUE, + mCurrentOpToken, + /*transportFlags=*/ 0); sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName); // Don't need to check preflight result as there is no preflight hook. @@ -437,10 +443,10 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor } KeyValueAdbBackupEngine kvBackupEngine = new KeyValueAdbBackupEngine(out, keyValuePackage, - backupManagerService, - backupManagerService.getPackageManager(), - backupManagerService.getBaseStateDir(), - backupManagerService.getDataDir()); + mUserBackupManagerService, + mUserBackupManagerService.getPackageManager(), + mUserBackupManagerService.getBaseStateDir(), + mUserBackupManagerService.getDataDir()); sendOnBackupPackage(keyValuePackage.packageName); kvBackupEngine.backupOnePackage(); } @@ -471,7 +477,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor if (DEBUG) { Slog.d(TAG, "Full backup pass complete."); } - backupManagerService.getWakelock().release(); + mUserBackupManagerService.getWakelock().release(); } } @@ -493,8 +499,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor Slog.w(TAG, "adb backup cancel of " + target); } if (target != null) { - backupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo); + mUserBackupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo); } - backupManagerService.removeOperation(mCurrentOpToken); + mUserBackupManagerService.removeOperation(mCurrentOpToken); } } diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index 5b449c5b400e..2ee96d190f90 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -317,16 +317,16 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba int backupRunStatus = BackupManager.SUCCESS; try { - if (!backupManagerService.isEnabled() || !backupManagerService.isProvisioned()) { + if (!backupManagerService.isEnabled() || !backupManagerService.isSetupComplete()) { // Backups are globally disabled, so don't proceed. if (DEBUG) { Slog.i(TAG, "full backup requested but enabled=" + backupManagerService .isEnabled() - + " provisioned=" + backupManagerService.isProvisioned() + + " setupComplete=" + backupManagerService.isSetupComplete() + "; ignoring"); } int monitoringEvent; - if (backupManagerService.isProvisioned()) { + if (backupManagerService.isSetupComplete()) { monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED; } else { monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED; diff --git a/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java b/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java deleted file mode 100644 index 7e2ac796d343..000000000000 --- a/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.backup.internal; - -import static com.android.server.backup.BackupManagerService.MORE_DEBUG; -import static com.android.server.backup.BackupManagerService.TAG; - -import android.database.ContentObserver; -import android.os.Handler; -import android.util.Slog; - -import com.android.server.backup.KeyValueBackupJob; -import com.android.server.backup.UserBackupManagerService; - -public class ProvisionedObserver extends ContentObserver { - - private UserBackupManagerService backupManagerService; - - public ProvisionedObserver( - UserBackupManagerService backupManagerService, Handler handler) { - super(handler); - this.backupManagerService = backupManagerService; - } - - public void onChange(boolean selfChange) { - final boolean wasProvisioned = backupManagerService.isProvisioned(); - final boolean isProvisioned = backupManagerService.deviceIsProvisioned(); - // latch: never unprovision - backupManagerService.setProvisioned(wasProvisioned || isProvisioned); - if (MORE_DEBUG) { - Slog.d(TAG, "Provisioning change: was=" + wasProvisioned - + " is=" + isProvisioned + " now=" + backupManagerService.isProvisioned()); - } - - synchronized (backupManagerService.getQueueLock()) { - if (backupManagerService.isProvisioned() && !wasProvisioned - && backupManagerService.isEnabled()) { - // we're now good to go, so start the backup alarms - if (MORE_DEBUG) { - Slog.d(TAG, "Now provisioned, so starting backups"); - } - KeyValueBackupJob.schedule(backupManagerService.getContext(), - backupManagerService.getConstants()); - backupManagerService.scheduleNextFullBackupJob(0); - } - } - } -} diff --git a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java index 2a5d913226b9..d37b106c2b26 100644 --- a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java +++ b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java @@ -26,61 +26,84 @@ import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.os.Handler; import android.os.Message; import android.util.Slog; import com.android.server.backup.UserBackupManagerService; +/** + * A {@link BroadcastReceiver} for the action {@link UserBackupManagerService#RUN_BACKUP_ACTION} + * that runs an immediate backup operation if eligible. + */ public class RunBackupReceiver extends BroadcastReceiver { + private final UserBackupManagerService mUserBackupManagerService; - private UserBackupManagerService backupManagerService; - - public RunBackupReceiver(UserBackupManagerService backupManagerService) { - this.backupManagerService = backupManagerService; + public RunBackupReceiver(UserBackupManagerService userBackupManagerService) { + mUserBackupManagerService = userBackupManagerService; } + /** + * Run a backup pass if we're eligible. We're eligible if the following conditions are met: + * + * <ul> + * <li>No transports are pending initialization (otherwise we kick off an initialization + * operation instead). + * <li>Backup is enabled for the user. + * <li>The user has completed setup. + * <li>No backup operation is currently running for the user. + * </ul> + */ public void onReceive(Context context, Intent intent) { - if (RUN_BACKUP_ACTION.equals(intent.getAction())) { - synchronized (backupManagerService.getQueueLock()) { - if (backupManagerService.getPendingInits().size() > 0) { - // If there are pending init operations, we process those - // and then settle into the usual periodic backup schedule. - if (MORE_DEBUG) { - Slog.v(TAG, "Init pending at scheduled backup"); - } - try { - backupManagerService.getAlarmManager().cancel( - backupManagerService.getRunInitIntent()); - backupManagerService.getRunInitIntent().send(); - } catch (PendingIntent.CanceledException ce) { - Slog.e(TAG, "Run init intent cancelled"); - // can't really do more than bail here - } - } else { - // Don't run backups now if we're disabled or not yet - // fully set up. - if (backupManagerService.isEnabled() && backupManagerService.isProvisioned()) { - if (!backupManagerService.isBackupRunning()) { - if (DEBUG) { - Slog.v(TAG, "Running a backup pass"); - } + if (!RUN_BACKUP_ACTION.equals(intent.getAction())) { + return; + } + + synchronized (mUserBackupManagerService.getQueueLock()) { + if (mUserBackupManagerService.getPendingInits().size() > 0) { + // If there are pending init operations, we process those and then settle into the + // usual periodic backup schedule. + if (MORE_DEBUG) { + Slog.v(TAG, "Init pending at scheduled backup"); + } + try { + PendingIntent runInitIntent = mUserBackupManagerService.getRunInitIntent(); + mUserBackupManagerService.getAlarmManager().cancel(runInitIntent); + runInitIntent.send(); + } catch (PendingIntent.CanceledException ce) { + Slog.w(TAG, "Run init intent cancelled"); + } + } else { + // Don't run backups if we're disabled or not yet set up. + if (!mUserBackupManagerService.isEnabled() + || !mUserBackupManagerService.isSetupComplete()) { + Slog.w( + TAG, + "Backup pass but enabled=" + + mUserBackupManagerService.isEnabled() + + " setupComplete=" + + mUserBackupManagerService.isSetupComplete()); + return; + } - // Acquire the wakelock and pass it to the backup thread. it will - // be released once backup concludes. - backupManagerService.setBackupRunning(true); - backupManagerService.getWakelock().acquire(); + // Don't run backups if one is already running. + if (mUserBackupManagerService.isBackupRunning()) { + Slog.i(TAG, "Backup time but one already running"); + return; + } - Message msg = backupManagerService.getBackupHandler().obtainMessage( - MSG_RUN_BACKUP); - backupManagerService.getBackupHandler().sendMessage(msg); - } else { - Slog.i(TAG, "Backup time but one already running"); - } - } else { - Slog.w(TAG, "Backup pass but e=" + backupManagerService.isEnabled() + " p=" - + backupManagerService.isProvisioned()); - } + if (DEBUG) { + Slog.v(TAG, "Running a backup pass"); } + + // Acquire the wakelock and pass it to the backup thread. It will be released once + // backup concludes. + mUserBackupManagerService.setBackupRunning(true); + mUserBackupManagerService.getWakelock().acquire(); + + Handler backupHandler = mUserBackupManagerService.getBackupHandler(); + Message message = backupHandler.obtainMessage(MSG_RUN_BACKUP); + backupHandler.sendMessage(message); } } } diff --git a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java index 38870cba4812..97711e3c27ed 100644 --- a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java +++ b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java @@ -24,41 +24,50 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.PowerManager; -import android.util.ArraySet; import android.util.Slog; import com.android.server.backup.UserBackupManagerService; +import java.util.Set; + +/** + * A {@link BroadcastReceiver} for the action {@link UserBackupManagerService#RUN_INITIALIZE_ACTION} + * that runs an initialization operation on all pending transports. + */ public class RunInitializeReceiver extends BroadcastReceiver { - private final UserBackupManagerService mBackupManagerService; + private final UserBackupManagerService mUserBackupManagerService; - public RunInitializeReceiver(UserBackupManagerService backupManagerService) { - mBackupManagerService = backupManagerService; + public RunInitializeReceiver(UserBackupManagerService userBackupManagerService) { + mUserBackupManagerService = userBackupManagerService; } public void onReceive(Context context, Intent intent) { - if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) { - synchronized (mBackupManagerService.getQueueLock()) { - final ArraySet<String> pendingInits = mBackupManagerService.getPendingInits(); - if (DEBUG) { - Slog.v(TAG, "Running a device init; " + pendingInits.size() + " pending"); - } + if (!RUN_INITIALIZE_ACTION.equals(intent.getAction())) { + return; + } + + synchronized (mUserBackupManagerService.getQueueLock()) { + Set<String> pendingInits = mUserBackupManagerService.getPendingInits(); + if (DEBUG) { + Slog.v(TAG, "Running a device init; " + pendingInits.size() + " pending"); + } - if (pendingInits.size() > 0) { - final String[] transports = - pendingInits.toArray(new String[pendingInits.size()]); + if (pendingInits.size() > 0) { + String[] transports = pendingInits.toArray(new String[pendingInits.size()]); - mBackupManagerService.clearPendingInits(); + mUserBackupManagerService.clearPendingInits(); - PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock(); - wakelock.acquire(); - OnTaskFinishedListener listener = caller -> wakelock.release(); + PowerManager.WakeLock wakelock = mUserBackupManagerService.getWakelock(); + wakelock.acquire(); + OnTaskFinishedListener listener = caller -> wakelock.release(); - Runnable task = - new PerformInitializeTask( - mBackupManagerService, transports, null, listener); - mBackupManagerService.getBackupHandler().post(task); - } + Runnable task = + new PerformInitializeTask( + mUserBackupManagerService, + transports, + /* observer */ null, + listener); + mUserBackupManagerService.getBackupHandler().post(task); } } } diff --git a/services/backup/java/com/android/server/backup/internal/SetupObserver.java b/services/backup/java/com/android/server/backup/internal/SetupObserver.java new file mode 100644 index 000000000000..62ae3eb8e192 --- /dev/null +++ b/services/backup/java/com/android/server/backup/internal/SetupObserver.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2019 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.backup.internal; + +import static com.android.server.backup.BackupManagerService.MORE_DEBUG; +import static com.android.server.backup.BackupManagerService.TAG; +import static com.android.server.backup.UserBackupManagerService.getSetupCompleteSettingForUser; + +import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings; +import android.util.Slog; + +import com.android.server.backup.KeyValueBackupJob; +import com.android.server.backup.UserBackupManagerService; + +/** + * A {@link ContentObserver} for changes to the setting {@link Settings.Secure#USER_SETUP_COMPLETE} + * for a particular user. + */ +public class SetupObserver extends ContentObserver { + private final UserBackupManagerService mUserBackupManagerService; + private final Context mContext; + private final int mUserId; + + public SetupObserver(UserBackupManagerService userBackupManagerService, Handler handler) { + super(handler); + mUserBackupManagerService = userBackupManagerService; + mContext = userBackupManagerService.getContext(); + mUserId = userBackupManagerService.getUserId(); + } + + /** + * Callback that executes when the setting {@link Settings.Secure#USER_SETUP_COMPLETE} changes + * for the user {@link #mUserId}. If the user is newly setup and backup is enabled, then we + * schedule a key value and full backup job for the user. If the user was previously setup and + * now the setting has changed to {@code false}, we don't reset the state as having gone through + * setup is a non-reversible action. + */ + public void onChange(boolean selfChange) { + boolean previousSetupComplete = mUserBackupManagerService.isSetupComplete(); + boolean newSetupComplete = getSetupCompleteSettingForUser(mContext, mUserId); + + boolean resolvedSetupComplete = previousSetupComplete || newSetupComplete; + mUserBackupManagerService.setSetupComplete(resolvedSetupComplete); + if (MORE_DEBUG) { + Slog.d( + TAG, + "Setup complete change: was=" + + previousSetupComplete + + " new=" + + newSetupComplete + + " resolved=" + + resolvedSetupComplete); + } + + synchronized (mUserBackupManagerService.getQueueLock()) { + // Start backup if the user is newly setup and backup is enabled. + if (resolvedSetupComplete + && !previousSetupComplete + && mUserBackupManagerService.isEnabled()) { + if (MORE_DEBUG) { + Slog.d(TAG, "Setup complete so starting backups"); + } + KeyValueBackupJob.schedule(mContext, mUserBackupManagerService.getConstants()); + mUserBackupManagerService.scheduleNextFullBackupJob(0); + } + } + } +} diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index 0d26ea56faa2..45a398f80351 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -678,12 +678,13 @@ public class FullRestoreEngine extends RestoreEngine { * Returns whether the package is in the list of the packages for which clear app data should * be called despite the fact that they have backup agent. * - * <p>The list is read from {@link Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE}. + * <p>The list is read from {@link Settings.Secure#PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE}. */ private boolean shouldForceClearAppDataOnFullRestore(String packageName) { - String packageListString = Settings.Secure.getString( + String packageListString = Settings.Secure.getStringForUser( mBackupManagerService.getContext().getContentResolver(), - Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE); + Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE, + mBackupManagerService.getUserId()); if (TextUtils.isEmpty(packageListString)) { return false; } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index c467935f1996..09aa4212654e 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -95,7 +95,7 @@ final class ContentCapturePerUserService final ComponentName serviceComponentName = updateServiceInfoLocked(); if (serviceComponentName == null) { - Slog.w(TAG, "updateRemoteService(): no service componennt name"); + if (mMaster.debug) Slog.d(TAG, "updateRemoteService(): no service component name"); return; } @@ -163,7 +163,10 @@ final class ContentCapturePerUserService @NonNull String sessionId, int uid, int flags, @NonNull IResultReceiver clientReceiver) { if (!isEnabledLocked()) { - setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED, /* binder=*/ null); + // TODO: it would be better to split in differet reasons, like + // STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY + setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_NO_SERVICE, + /* binder= */ null); return; } final ComponentName serviceComponentName = getServiceComponentName(); @@ -195,8 +198,8 @@ final class ContentCapturePerUserService Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken + ": ignoring because service is not set"); // TODO(b/111276913): use a new disabled state? - setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED, - /* binder=*/ null); + setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_NO_SERVICE, + /* binder= */ null); return; } @@ -285,7 +288,7 @@ final class ContentCapturePerUserService final int numSessions = mSessions.size(); for (int i = 0; i < numSessions; i++) { final ContentCaptureServerSession session = mSessions.valueAt(i); - session.destroyLocked(true); + session.destroyLocked(/* notifyRemoteService= */ true); } mSessions.clear(); } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index e10e0d6ef1ce..cbf6d04c9975 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -34,6 +34,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.telephony.CellInfo; import android.telephony.CellLocation; +import android.telephony.DataFailCause; import android.telephony.DisconnectCause; import android.telephony.LocationAccessPolicy; import android.telephony.PhoneCapability; @@ -47,6 +48,7 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; import android.telephony.emergency.EmergencyNumber; import android.util.LocalLog; import android.util.StatsLog; @@ -1366,7 +1368,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataConnectionNetworkType[phoneId] = networkType; } mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType, - apnType, apn, linkProperties, ""); + ApnSetting.getApnTypesBitmaskFromString(apnType), apn, + linkProperties, DataFailCause.NONE); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) { @@ -1384,7 +1387,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { broadcastDataConnectionStateChanged(state, isDataAllowed, apn, apnType, linkProperties, networkCapabilities, roaming, subId); broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, - linkProperties, ""); + linkProperties, DataFailCause.NONE); } public void notifyDataConnectionFailed(String apnType) { @@ -1403,7 +1406,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { mPreciseDataConnectionState = new PreciseDataConnectionState( TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN, - apnType, "", null, ""); + ApnSetting.getApnTypesBitmaskFromString(apnType), "", null, + DataFailCause.NONE); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) { @@ -1418,7 +1422,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } broadcastDataConnectionFailed(apnType, subId); broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN, - TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", null, ""); + TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", null, + DataFailCause.NONE); } public void notifyCellLocation(Bundle cellLocation) { @@ -1528,14 +1533,15 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - public void notifyPreciseDataConnectionFailed(String apnType, String apn, String failCause) { + public void notifyPreciseDataConnectionFailed(String apnType, + String apn, @DataFailCause.FailCause int failCause) { if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) { return; } synchronized (mRecords) { mPreciseDataConnectionState = new PreciseDataConnectionState( TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN, - apnType, apn, null, failCause); + ApnSetting.getApnTypesBitmaskFromString(apnType), apn, null, failCause); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) { @@ -1928,9 +1934,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } private void broadcastPreciseDataConnectionStateChanged(int state, int networkType, - String apnType, String apn, - LinkProperties linkProperties, - String failCause) { + String apnType, String apn, LinkProperties linkProperties, + @DataFailCause.FailCause int failCause) { Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED); intent.putExtra(PhoneConstants.STATE_KEY, state); intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType); @@ -1939,7 +1944,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (linkProperties != null) { intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties); } - if (failCause != null) intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause); + intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause); mContext.sendBroadcastAsUser(intent, UserHandle.ALL, android.Manifest.permission.READ_PRECISE_PHONE_STATE); diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 9f353a80a5be..5d4c5c359a2b 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -149,6 +149,8 @@ public class VibratorService extends IVibratorService.Stub native static boolean vibratorSupportsAmplitudeControl(); native static void vibratorSetAmplitude(int amplitude); native static long vibratorPerformEffect(long effect, long strength); + static native boolean vibratorSupportsExternalControl(); + static native void vibratorSetExternalControl(boolean enabled); private final IUidObserver mUidObserver = new IUidObserver.Stub() { @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index a94fa12e4f35..ed39d8302bf7 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -2503,6 +2503,9 @@ public final class ActiveServices { && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) { hostingType = "webview_service"; } + if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) { + hostingType = "app_zygote"; + } } // Not running -- get it started, and enqueue this service record diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b053979f1fcd..4f21ee8d8624 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -235,6 +235,7 @@ import android.media.audiofx.AudioEffect; import android.net.Proxy; import android.net.ProxyInfo; import android.net.Uri; +import android.os.AppZygote; import android.os.BatteryStats; import android.os.Binder; import android.os.BinderProxy; @@ -452,6 +453,9 @@ public class ActivityManagerService extends IActivityManager.Stub // before we decide it must be hung. static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000; + // How long we wait to kill an application zygote, after the last process using + // it has gone away. + static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000; /** * How long we wait for an provider to be published. Should be longer than * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}. @@ -1441,6 +1445,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; + static final int KILL_APP_ZYGOTE_MSG = 71; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1644,6 +1649,12 @@ public class ActivityManagerService extends IActivityManager.Stub false, userId, reason); } } break; + case KILL_APP_ZYGOTE_MSG: { + synchronized (ActivityManagerService.this) { + final AppZygote appZygote = (AppZygote) msg.obj; + mProcessList.killAppZygoteIfNeededLocked(appZygote); + } + } break; case CHECK_EXCESSIVE_POWER_USE_MSG: { synchronized (ActivityManagerService.this) { checkExcessivePowerUsageLocked(); @@ -1932,7 +1943,8 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName, false, - 0); + 0, + false); app.setPersistent(true); app.pid = MY_PID; app.getWindowProcessController().setPid(MY_PID); @@ -2417,16 +2429,21 @@ public class ActivityManagerService extends IActivityManager.Stub return mBackgroundLaunchBroadcasts; } + /** + * Returns true if the package {@code pkg1} running under user handle {@code uid1} is + * allowed association with the package {@code pkg2} running under user handle {@code uid2}. + * <p> If either of the packages are running as part of the core system, then the + * association is implicitly allowed. + */ boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) { if (mAllowedAssociations == null) { mAllowedAssociations = SystemConfig.getInstance().getAllowedAssociations(); } // Interactions with the system uid are always allowed, since that is the core system - // that everyone needs to be able to interact with. - if (UserHandle.getAppId(uid1) == SYSTEM_UID) { - return true; - } - if (UserHandle.getAppId(uid2) == SYSTEM_UID) { + // that everyone needs to be able to interact with. Also allow reflexive associations + // within the same uid. + if (uid1 == uid2 || UserHandle.getAppId(uid1) == SYSTEM_UID + || UserHandle.getAppId(uid2) == SYSTEM_UID) { return true; } // We won't allow this association if either pkg1 or pkg2 has a limit on the @@ -2442,6 +2459,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (pkgs != null) { return pkgs.contains(pkg1); } + // If no explicit associations are provided in the manifest, then assume the app is + // allowed associations with any package. return true; } @@ -5310,16 +5329,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - @Override - public boolean isAppForeground(int uid) { - int callerUid = Binder.getCallingUid(); - if (UserHandle.isCore(callerUid) || callerUid == uid) { - return isAppForegroundInternal(uid); - } - return false; - } - - private boolean isAppForegroundInternal(int uid) { + private boolean isAppForeground(int uid) { synchronized (this) { UidRecord uidRec = mActiveUids.get(uid); if (uidRec == null || uidRec.idle) { @@ -7396,7 +7406,7 @@ public class ActivityManagerService extends IActivityManager.Stub } if (app == null) { - app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0); + app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0, false); mProcessList.updateLruProcessLocked(app, false, null); updateOomAdjLocked(); } @@ -19675,6 +19685,11 @@ public class ActivityManagerService extends IActivityManager.Stub return pr == null ? Zygote.MOUNT_EXTERNAL_NONE : pr.mountMode; } } + + @Override + public boolean isAppForeground(int uid) { + return ActivityManagerService.this.isAppForeground(uid); + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java index f9a77af631af..d7cb2bd36bde 100644 --- a/services/core/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java @@ -68,6 +68,7 @@ final class CoreSettingsObserver extends ContentObserver { sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class); sGlobalSettingToTypeMap.put(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, int.class); sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_IN_APPS, String.class); + sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_OUT_APPS, String.class); sGlobalSettingToTypeMap.put(Settings.Global.GUP_BLACK_LIST, String.class); // add other global settings here... } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 895a86ba9fc7..9898d06837be 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -19,8 +19,6 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; import static android.app.ActivityThread.PROC_START_SEQ_IDENT; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO; -import static android.os.Process.FIRST_ISOLATED_UID; -import static android.os.Process.LAST_ISOLATED_UID; import static android.os.Process.SYSTEM_UID; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static android.os.Process.getFreeMemory; @@ -34,6 +32,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_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.ActivityManagerService.KILL_APP_ZYGOTE_DELAY_MS; +import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_MSG; import static com.android.server.am.ActivityManagerService.PERSISTENT_MASK; import static com.android.server.am.ActivityManagerService.PROC_START_TIMEOUT; import static com.android.server.am.ActivityManagerService.PROC_START_TIMEOUT_MSG; @@ -58,6 +58,7 @@ import android.graphics.Point; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.net.Uri; +import android.os.AppZygote; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -75,10 +76,12 @@ import android.os.UserHandle; import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.EventLog; import android.util.LongSparseArray; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.util.StatsLog; import android.view.Display; @@ -108,6 +111,7 @@ import java.io.PrintWriter; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.List; /** @@ -354,10 +358,136 @@ public final class ProcessList { final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>(); /** - * Counter for assigning isolated process uids, to avoid frequently reusing the - * same ones. + * The currently running application zygotes. */ - int mNextIsolatedProcessUid = 0; + final ProcessMap<AppZygote> mAppZygotes = new ProcessMap<AppZygote>(); + + /** + * The processes that are forked off an application zygote. + */ + final ArrayMap<AppZygote, ArrayList<ProcessRecord>> mAppZygoteProcesses = + new ArrayMap<AppZygote, ArrayList<ProcessRecord>>(); + + final class IsolatedUidRange { + @VisibleForTesting + public final int mFirstUid; + @VisibleForTesting + public final int mLastUid; + + @GuardedBy("ProcessList.this.mService") + private final SparseBooleanArray mUidUsed = new SparseBooleanArray(); + + @GuardedBy("ProcessList.this.mService") + private int mNextUid; + + IsolatedUidRange(int firstUid, int lastUid) { + mFirstUid = firstUid; + mLastUid = lastUid; + mNextUid = firstUid; + } + + @GuardedBy("ProcessList.this.mService") + int allocateIsolatedUidLocked(int userId) { + int uid; + int stepsLeft = (mLastUid - mFirstUid + 1); + for (int i = 0; i < stepsLeft; ++i) { + if (mNextUid < mFirstUid || mNextUid > mLastUid) { + mNextUid = mFirstUid; + } + uid = UserHandle.getUid(userId, mNextUid); + mNextUid++; + if (!mUidUsed.get(uid, false)) { + mUidUsed.put(uid, true); + return uid; + } + } + return -1; + } + + @GuardedBy("ProcessList.this.mService") + void freeIsolatedUidLocked(int uid) { + // Strip out userId + final int appId = UserHandle.getAppId(uid); + mUidUsed.delete(appId); + } + }; + + /** + * A class that allocates ranges of isolated UIDs per application, and keeps track of them. + */ + final class IsolatedUidRangeAllocator { + private final int mFirstUid; + private final int mNumUidRanges; + private final int mNumUidsPerRange; + /** + * We map the uid range [mFirstUid, mFirstUid + mNumUidRanges * mNumUidsPerRange) + * back to an underlying bitset of [0, mNumUidRanges) and allocate out of that. + */ + @GuardedBy("ProcessList.this.mService") + private final BitSet mAvailableUidRanges; + @GuardedBy("ProcessList.this.mService") + private final ProcessMap<IsolatedUidRange> mAppRanges = new ProcessMap<IsolatedUidRange>(); + + IsolatedUidRangeAllocator(int firstUid, int lastUid, int numUidsPerRange) { + mFirstUid = firstUid; + mNumUidsPerRange = numUidsPerRange; + mNumUidRanges = (lastUid - firstUid + 1) / numUidsPerRange; + mAvailableUidRanges = new BitSet(mNumUidRanges); + // Mark all as available + mAvailableUidRanges.set(0, mNumUidRanges); + } + + @GuardedBy("ProcessList.this.mService") + IsolatedUidRange getIsolatedUidRangeLocked(ApplicationInfo info) { + return mAppRanges.get(info.processName, info.uid); + } + + @GuardedBy("ProcessList.this.mService") + IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info) { + IsolatedUidRange range = getIsolatedUidRangeLocked(info); + if (range == null) { + int uidRangeIndex = mAvailableUidRanges.nextSetBit(0); + if (uidRangeIndex < 0) { + // No free range + return null; + } + mAvailableUidRanges.clear(uidRangeIndex); + int actualUid = mFirstUid + uidRangeIndex * mNumUidsPerRange; + range = new IsolatedUidRange(actualUid, actualUid + mNumUidsPerRange - 1); + mAppRanges.put(info.processName, info.uid, range); + } + return range; + } + + @GuardedBy("ProcessList.this.mService") + void freeUidRangeLocked(ApplicationInfo info) { + // Find the UID range + IsolatedUidRange range = mAppRanges.get(info.processName, info.uid); + if (range != null) { + // Map back to starting uid + final int uidRangeIndex = (range.mFirstUid - mFirstUid) / mNumUidsPerRange; + // Mark it as available in the underlying bitset + mAvailableUidRanges.set(uidRangeIndex); + // And the map + mAppRanges.remove(info.processName, info.uid); + } + } + } + + /** + * The available isolated UIDs for processes that are not spawned from an application zygote. + */ + @VisibleForTesting + IsolatedUidRange mGlobalIsolatedUids = new IsolatedUidRange(Process.FIRST_ISOLATED_UID, + Process.LAST_ISOLATED_UID); + + /** + * An allocator for isolated UID ranges for apps that use an application zygote. + */ + @VisibleForTesting + IsolatedUidRangeAllocator mAppIsolatedUidRangeAllocator = + new IsolatedUidRangeAllocator(Process.FIRST_APP_ZYGOTE_ISOLATED_UID, + Process.LAST_APP_ZYGOTE_ISOLATED_UID, Process.NUM_UIDS_PER_APP_ZYGOTE); /** * Processes that are being forcibly torn down. @@ -1505,6 +1635,67 @@ public final class ProcessList { } } + @GuardedBy("mService") + public void killAppZygoteIfNeededLocked(AppZygote appZygote) { + final ApplicationInfo appInfo = appZygote.getAppInfo(); + ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote); + if (zygoteProcesses.size() == 0) { // Only remove if no longer in use now + mAppZygotes.remove(appInfo.processName, appInfo.uid); + mAppZygoteProcesses.remove(appZygote); + mAppIsolatedUidRangeAllocator.freeUidRangeLocked(appInfo); + appZygote.stopZygote(); + } + } + + @GuardedBy("mService") + private void removeProcessFromAppZygoteLocked(final ProcessRecord app) { + // Free the isolated uid for this process + final IsolatedUidRange appUidRange = + mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info); + if (appUidRange != null) { + appUidRange.freeIsolatedUidLocked(app.uid); + } + + final AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid); + if (appZygote != null) { + ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote); + zygoteProcesses.remove(app); + if (zygoteProcesses.size() == 0) { + Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG); + msg.obj = appZygote; + mService.mHandler.sendMessageDelayed(msg, KILL_APP_ZYGOTE_DELAY_MS); + } + } + } + + private AppZygote createAppZygoteForProcessIfNeeded(final ProcessRecord app) { + synchronized (mService) { + AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid); + final ArrayList<ProcessRecord> zygoteProcessList; + if (appZygote == null) { + final int userId = UserHandle.getUserId(app.info.uid); + final IsolatedUidRange uidRange = + mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info); + // Allocate an isolated UID out of this range for the Zygote itself + final int zygoteIsolatedUid = uidRange.allocateIsolatedUidLocked(userId); + appZygote = new AppZygote(app.info, zygoteIsolatedUid); + mAppZygotes.put(app.info.processName, app.info.uid, appZygote); + zygoteProcessList = new ArrayList<ProcessRecord>(); + mAppZygoteProcesses.put(appZygote, zygoteProcessList); + } else { + mService.mHandler.removeMessages(KILL_APP_ZYGOTE_MSG, appZygote); + zygoteProcessList = mAppZygoteProcesses.get(appZygote); + } + // Note that we already add the app to mAppZygoteProcesses here; + // this is so that another thread can't come in and kill the zygote + // before we've even tried to start the process. If the process launch + // goes wrong, we'll clean this up in removeProcessNameLocked() + zygoteProcessList.add(app); + + return appZygote; + } + } + private Process.ProcessStartResult startProcess(String hostingType, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, @@ -1525,6 +1716,15 @@ public final class ProcessList { app.info.dataDir, null, app.info.packageName, packageNames, visibleVolIds, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); + } else if (hostingType.equals("app_zygote")) { + final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); + + startResult = appZygote.getProcess().start(entryPoint, + app.processName, uid, uid, gids, runtimeFlags, mountExternal, + app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, + app.info.dataDir, null, app.info.packageName, + packageNames, visibleVolIds, + new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } else { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, @@ -1629,8 +1829,9 @@ public final class ProcessList { ? hostingName.flattenToShortString() : null; if (app == null) { + final boolean fromAppZygote = "app_zygote".equals(hostingType); checkSlow(startTime, "startProcess: creating new process record"); - app = newProcessRecordLocked(info, processName, isolated, isolatedUid); + app = newProcessRecordLocked(info, processName, isolated, isolatedUid, fromAppZygote); if (app == null) { Slog.w(TAG, "Failed making new process record for " + processName + "/" + info.uid + " isolated=" + isolated); @@ -2003,29 +2204,31 @@ public final class ProcessList { } @GuardedBy("mService") + private IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info, + boolean fromAppZygote) { + if (!fromAppZygote) { + // Allocate an isolated UID from the global range + return mGlobalIsolatedUids; + } else { + return mAppIsolatedUidRangeAllocator.getOrCreateIsolatedUidRangeLocked(info); + } + } + + @GuardedBy("mService") final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess, - boolean isolated, int isolatedUid) { + boolean isolated, int isolatedUid, boolean fromAppZygote) { String proc = customProcess != null ? customProcess : info.processName; final int userId = UserHandle.getUserId(info.uid); int uid = info.uid; if (isolated) { if (isolatedUid == 0) { - int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1; - while (true) { - if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID - || mNextIsolatedProcessUid > LAST_ISOLATED_UID) { - mNextIsolatedProcessUid = FIRST_ISOLATED_UID; - } - uid = UserHandle.getUid(userId, mNextIsolatedProcessUid); - mNextIsolatedProcessUid++; - if (mIsolatedProcesses.indexOfKey(uid) < 0) { - // No process for this uid, use it. - break; - } - stepsLeft--; - if (stepsLeft <= 0) { - return null; - } + IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, fromAppZygote); + if (uidRange == null) { + return null; + } + uid = uidRange.allocateIsolatedUidLocked(userId); + if (uid == -1) { + return null; } } else { // Special case for startIsolatedProcess (internal only), where @@ -2093,6 +2296,13 @@ public final class ProcessList { old.uidRecord = null; } mIsolatedProcesses.remove(uid); + mGlobalIsolatedUids.freeIsolatedUidLocked(uid); + // Remove the (expected) ProcessRecord from the app zygote + final ProcessRecord record = expecting != null ? expecting : old; + if (record != null && record.appZygote) { + removeProcessFromAppZygoteLocked(record); + } + return old; } diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 6f0a562eb819..0d0824a74cdd 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -76,6 +76,7 @@ final class ProcessRecord implements WindowProcessListener { private final ActivityManagerService mService; // where we came from final ApplicationInfo info; // all about the first app in the process final boolean isolated; // true if this is a special isolated process + final boolean appZygote; // true if this is forked from the app zygote final int uid; // uid of process; may be different from 'info' if isolated final int userId; // user of process. final String processName; // name of the process @@ -559,6 +560,8 @@ final class ProcessRecord implements WindowProcessListener { mService = _service; info = _info; isolated = _info.uid != _uid; + appZygote = (UserHandle.getAppId(_uid) >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID + && UserHandle.getAppId(_uid) <= Process.LAST_APP_ZYGOTE_ISOLATED_UID); uid = _uid; userId = UserHandle.getUserId(_uid); processName = _processName; diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING index 48b414581d45..c84b5c74c1e7 100644 --- a/services/core/java/com/android/server/am/TEST_MAPPING +++ b/services/core/java/com/android/server/am/TEST_MAPPING @@ -7,7 +7,7 @@ "include-annotation": "android.platform.test.annotations.Presubmit" }, { - "exclude-annotation": "android.support.test.filters.FlakyTest" + "exclude-annotation": "androidx.test.filters.FlakyTest" } ] }, @@ -21,7 +21,7 @@ "include-annotation": "android.platform.test.annotations.Presubmit" }, { - "exclude-annotation": "android.support.test.filters.FlakyTest" + "exclude-annotation": "androidx.test.filters.FlakyTest" } ] }, diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 9684f4c4ae19..2a000252d6f4 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -126,21 +126,21 @@ public class NetworkMonitor extends StateMachine { private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES = (1 << DATA_STALL_EVALUATION_TYPE_DNS); - static enum EvaluationResult { + enum EvaluationResult { VALIDATED(true), CAPTIVE_PORTAL(false); - final boolean isValidated; + final boolean mIsValidated; EvaluationResult(boolean isValidated) { - this.isValidated = isValidated; + this.mIsValidated = isValidated; } } - static enum ValidationStage { + enum ValidationStage { FIRST_VALIDATION(true), REVALIDATION(false); - final boolean isFirstValidation; + final boolean mIsFirstValidation; ValidationStage(boolean isFirstValidation) { - this.isFirstValidation = isFirstValidation; + this.mIsFirstValidation = isFirstValidation; } } @@ -251,7 +251,7 @@ public class NetworkMonitor extends StateMachine { // Start mReevaluateDelayMs at this value and double. private static final int INITIAL_REEVALUATE_DELAY_MS = 1000; - private static final int MAX_REEVALUATE_DELAY_MS = 10*60*1000; + private static final int MAX_REEVALUATE_DELAY_MS = 10 * 60 * 1000; // Before network has been evaluated this many times, ignore repeated reevaluate requests. private static final int IGNORE_REEVALUATE_ATTEMPTS = 5; private int mReevaluateToken = 0; @@ -261,7 +261,7 @@ public class NetworkMonitor extends StateMachine { // Stop blaming UID that requested re-evaluation after this many attempts. private static final int BLAME_FOR_EVALUATION_ATTEMPTS = 5; // Delay between reevaluations once a captive portal has been found. - private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 10*60*1000; + private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 10 * 60 * 1000; private static final int NUM_VALIDATION_LOG_LINES = 20; @@ -393,10 +393,17 @@ public class NetworkMonitor extends StateMachine { start(); } + /** + * Request the NetworkMonitor to reevaluate the network. + */ public void forceReevaluation(int responsibleUid) { sendMessage(CMD_FORCE_REEVALUATION, responsibleUid, 0); } + /** + * Send a notification to NetworkMonitor indicating that private DNS settings have changed. + * @param newCfg The new private DNS configuration. + */ public void notifyPrivateDnsSettingsChanged(PrivateDnsConfig newCfg) { // Cancel any outstanding resolutions. removeMessages(CMD_PRIVATE_DNS_SETTINGS_CHANGED); @@ -655,8 +662,9 @@ public class NetworkMonitor extends StateMachine { public boolean processMessage(Message message) { switch (message.what) { case CMD_REEVALUATE: - if (message.arg1 != mReevaluateToken || mUserDoesNotWant) + if (message.arg1 != mReevaluateToken || mUserDoesNotWant) { return HANDLED; + } // Don't bother validating networks that don't satisfy the default request. // This includes: // - VPNs which can be considered explicitly desired by the user and the @@ -813,9 +821,9 @@ public class NetworkMonitor extends StateMachine { } private boolean isStrictModeHostnameResolved() { - return (mPrivateDnsConfig != null) && - mPrivateDnsConfig.hostname.equals(mPrivateDnsProviderHostname) && - (mPrivateDnsConfig.ips.length > 0); + return (mPrivateDnsConfig != null) + && mPrivateDnsConfig.hostname.equals(mPrivateDnsProviderHostname) + && (mPrivateDnsConfig.ips.length > 0); } private void resolveStrictModeHostname() { @@ -852,9 +860,9 @@ public class NetworkMonitor extends StateMachine { private boolean sendPrivateDnsProbe() { // q.v. system/netd/server/dns/DnsTlsTransport.cpp - final String ONE_TIME_HOSTNAME_SUFFIX = "-dnsotls-ds.metric.gstatic.com"; - final String host = UUID.randomUUID().toString().substring(0, 8) + - ONE_TIME_HOSTNAME_SUFFIX; + final String oneTimeHostnameSuffix = "-dnsotls-ds.metric.gstatic.com"; + final String host = UUID.randomUUID().toString().substring(0, 8) + + oneTimeHostnameSuffix; final Stopwatch watch = new Stopwatch().start(); try { final InetAddress[] ips = mNetworkAgentInfo.network().getAllByName(host); @@ -966,7 +974,7 @@ public class NetworkMonitor extends StateMachine { // most one per address family. This ensures we only wait up to 20 seconds for TCP connections // to complete, regardless of how many IP addresses a host has. private static class OneAddressPerFamilyNetwork extends Network { - public OneAddressPerFamilyNetwork(Network network) { + OneAddressPerFamilyNetwork(Network network) { // Always bypass Private DNS. super(network.getPrivateDnsBypassingCopy()); } @@ -1000,7 +1008,8 @@ public class NetworkMonitor extends StateMachine { } public boolean getWifiScansAlwaysAvailableDisabled() { - return mDependencies.getSetting(mContext, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0; + return mDependencies.getSetting( + mContext, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0; } private String getCaptivePortalServerHttpsUrl() { @@ -1246,10 +1255,10 @@ public class NetworkMonitor extends StateMachine { // Time how long it takes to get a response to our request long responseTimestamp = SystemClock.elapsedRealtime(); - validationLog(probeType, url, "time=" + (responseTimestamp - requestTimestamp) + "ms" + - " ret=" + httpResponseCode + - " request=" + requestHeader + - " headers=" + urlConnection.getHeaderFields()); + validationLog(probeType, url, "time=" + (responseTimestamp - requestTimestamp) + "ms" + + " ret=" + httpResponseCode + + " request=" + requestHeader + + " headers=" + urlConnection.getHeaderFields()); // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive // portal. The only example of this seen so far was a captive portal. For // the time being go with prior behavior of assuming it's not a captive @@ -1267,7 +1276,7 @@ public class NetworkMonitor extends StateMachine { // sign-in to an empty page. Probably the result of a broken transparent proxy. // See http://b/9972012. validationLog(probeType, url, - "200 response with Content-length=0 interpreted as 204 response."); + "200 response with Content-length=0 interpreted as 204 response."); httpResponseCode = CaptivePortalProbeResult.SUCCESS_CODE; } else if (urlConnection.getContentLengthLong() == -1) { // When no Content-length (default value == -1), attempt to read a byte from the @@ -1309,7 +1318,7 @@ public class NetworkMonitor extends StateMachine { private final boolean mIsHttps; private volatile CaptivePortalProbeResult mResult = CaptivePortalProbeResult.FAILED; - public ProbeThread(boolean isHttps) { + ProbeThread(boolean isHttps) { mIsHttps = isHttps; } @@ -1443,8 +1452,10 @@ public class NetworkMonitor extends StateMachine { if (cellInfo.isRegistered()) { numRegisteredCellInfo++; if (numRegisteredCellInfo > 1) { - if (VDBG) logw("more than one registered CellInfo." + - " Can't tell which is active. Bailing."); + if (VDBG) { + logw("more than one registered CellInfo." + + " Can't tell which is active. Bailing."); + } return; } if (cellInfo instanceof CellInfoCdma) { @@ -1492,14 +1503,14 @@ public class NetworkMonitor extends StateMachine { } private int networkEventType(ValidationStage s, EvaluationResult r) { - if (s.isFirstValidation) { - if (r.isValidated) { + if (s.mIsFirstValidation) { + if (r.mIsValidated) { return NetworkEvent.NETWORK_FIRST_VALIDATION_SUCCESS; } else { return NetworkEvent.NETWORK_FIRST_VALIDATION_PORTAL_FOUND; } } else { - if (r.isValidated) { + if (r.mIsValidated) { return NetworkEvent.NETWORK_REVALIDATION_SUCCESS; } else { return NetworkEvent.NETWORK_REVALIDATION_PORTAL_FOUND; @@ -1517,7 +1528,7 @@ public class NetworkMonitor extends StateMachine { private void logValidationProbe(long durationMs, int probeType, int probeResult) { int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes(); - boolean isFirstValidation = validationStage().isFirstValidation; + boolean isFirstValidation = validationStage().mIsFirstValidation; ValidationProbeEvent ev = new ValidationProbeEvent(); ev.probeType = ValidationProbeEvent.makeProbeType(probeType, isFirstValidation); ev.returnCode = probeResult; @@ -1535,10 +1546,20 @@ public class NetworkMonitor extends StateMachine { return new Random(); } + /** + * Get the value of a global integer setting. + * @param symbol Name of the setting + * @param defaultValue Value to return if the setting is not defined. + */ public int getSetting(Context context, String symbol, int defaultValue) { return Settings.Global.getInt(context.getContentResolver(), symbol, defaultValue); } + /** + * Get the value of a global String setting. + * @param symbol Name of the setting + * @param defaultValue Value to return if the setting is not defined. + */ public String getSetting(Context context, String symbol, String defaultValue) { final String value = Settings.Global.getString(context.getContentResolver(), symbol); return value != null ? value : defaultValue; diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 9dfdddbea18a..eb5be77e4a33 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -1837,7 +1837,7 @@ public class Tethering extends BaseNetworkObserver { final TetherState tetherState = new TetherState( new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService, makeControlCallback(), mConfig.enableLegacyDhcpServer, - mDeps.getIpServerDependencies())); + mDeps.getIpServerDependencies(mContext))); mTetherStates.put(iface, tetherState); tetherState.ipServer.start(); } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java index d56b167b9a75..a42efe960ff9 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -34,32 +34,53 @@ import java.util.ArrayList; * @hide */ public class TetheringDependencies { + /** + * Get a reference to the offload hardware interface to be used by tethering. + */ public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) { return new OffloadHardwareInterface(h, log); } + /** + * Get a reference to the UpstreamNetworkMonitor to be used by tethering. + */ public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target, SharedLog log, int what) { return new UpstreamNetworkMonitor(ctx, target, log, what); } + /** + * Get a reference to the IPv6TetheringCoordinator to be used by tethering. + */ public IPv6TetheringCoordinator getIPv6TetheringCoordinator( ArrayList<IpServer> notifyList, SharedLog log) { return new IPv6TetheringCoordinator(notifyList, log); } - public IpServer.Dependencies getIpServerDependencies() { - return new IpServer.Dependencies(); + /** + * Get dependencies to be used by IpServer. + */ + public IpServer.Dependencies getIpServerDependencies(Context context) { + return new IpServer.Dependencies(context); } + /** + * Indicates whether tethering is supported on the device. + */ public boolean isTetheringSupported() { return true; } + /** + * Get the NetworkRequest that should be fulfilled by the default network. + */ public NetworkRequest getDefaultNetworkRequest() { return null; } + /** + * Get a reference to the EntitlementManager to be used by tethering. + */ public EntitlementManager getEntitlementManager(Context ctx, SharedLog log, MockableSystemProperties systemProperties) { return new EntitlementManager(ctx, log, systemProperties); diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index 78b3c15500ea..d57431e6b58b 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -17,6 +17,12 @@ package com.android.server.display; import android.annotation.Nullable; +import android.app.ActivityManager.StackInfo; +import android.app.ActivityTaskManager; +import android.app.IActivityTaskManager; +import android.app.TaskStackListener; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; @@ -27,6 +33,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PowerManager; +import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.util.EventLog; @@ -34,6 +41,7 @@ import android.util.MathUtils; import android.util.Slog; import android.util.TimeUtils; +import com.android.internal.os.BackgroundThread; import com.android.server.EventLogTags; import java.io.PrintWriter; @@ -41,7 +49,6 @@ import java.io.PrintWriter; class AutomaticBrightnessController { private static final String TAG = "AutomaticBrightnessController"; - private static final boolean DEBUG = false; private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false; // If true, enables the use of the screen auto-brightness adjustment setting. @@ -56,16 +63,11 @@ class AutomaticBrightnessController { // the user is satisfied with the result before storing the sample. private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000; - // Timeout after which we remove the effects any user interactions might've had on the - // brightness mapping. This timeout doesn't start until we transition to a non-interactive - // display policy so that we don't reset while users are using their devices, but also so that - // we don't erroneously keep the short-term model if the device is dozing but the display is - // fully on. - private static final int SHORT_TERM_MODEL_TIMEOUT_MILLIS = 30000; - private static final int MSG_UPDATE_AMBIENT_LUX = 1; private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2; private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3; + private static final int MSG_UPDATE_FOREGROUND_APP = 4; + private static final int MSG_UPDATE_FOREGROUND_APP_SYNC = 5; // Length of the ambient light horizon used to calculate the long term estimate of ambient // light. @@ -126,6 +128,15 @@ class AutomaticBrightnessController { private final HysteresisLevels mAmbientBrightnessThresholds; private final HysteresisLevels mScreenBrightnessThresholds; + private boolean mLoggingEnabled; + + // Timeout after which we remove the effects any user interactions might've had on the + // brightness mapping. This timeout doesn't start until we transition to a non-interactive + // display policy so that we don't reset while users are using their devices, but also so that + // we don't erroneously keep the short-term model if the device is dozing but the display is + // fully on. + private long mShortTermModelTimeout; + // Amount of time to delay auto-brightness after screen on while waiting for // the light sensor to warm-up in milliseconds. // May be 0 if no warm-up is required. @@ -192,13 +203,26 @@ class AutomaticBrightnessController { private float mShortTermModelAnchor; private float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f; + // Context-sensitive brightness configurations require keeping track of the foreground app's + // package name and category, which is done by registering a TaskStackListener to call back to + // us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's + // package namd and PackageManager to get its category (so might as well cache them). + private String mForegroundAppPackageName; + private String mPendingForegroundAppPackageName; + private @ApplicationInfo.Category int mForegroundAppCategory; + private @ApplicationInfo.Category int mPendingForegroundAppCategory; + private TaskStackListenerImpl mTaskStackListener; + private IActivityTaskManager mActivityTaskManager; + private PackageManager mPackageManager; + public AutomaticBrightnessController(Callbacks callbacks, Looper looper, SensorManager sensorManager, BrightnessMappingStrategy mapper, int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, - HysteresisLevels screenBrightnessThresholds) { + HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout, + PackageManager packageManager) { mCallbacks = callbacks; mSensorManager = sensorManager; mBrightnessMapper = mapper; @@ -216,6 +240,7 @@ class AutomaticBrightnessController { mWeightingIntercept = AMBIENT_LIGHT_LONG_HORIZON_MILLIS; mAmbientBrightnessThresholds = ambientBrightnessThresholds; mScreenBrightnessThresholds = screenBrightnessThresholds; + mShortTermModelTimeout = shortTermModelTimeout; mShortTermModelValid = true; mShortTermModelAnchor = -1; @@ -226,6 +251,31 @@ class AutomaticBrightnessController { if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) { mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); } + + mActivityTaskManager = ActivityTaskManager.getService(); + mPackageManager = packageManager; + mTaskStackListener = new TaskStackListenerImpl(); + mForegroundAppPackageName = null; + mPendingForegroundAppPackageName = null; + mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; + mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; + } + + /** + * Enable/disable logging. + * + * @param loggingEnabled + * Whether logging should be on/off. + * + * @return Whether the method succeeded or not. + */ + public boolean setLoggingEnabled(boolean loggingEnabled) { + if (mLoggingEnabled == loggingEnabled) { + return false; + } + mBrightnessMapper.setLoggingEnabled(loggingEnabled); + mLoggingEnabled = loggingEnabled; + return true; } public int getAutomaticScreenBrightness() { @@ -290,12 +340,12 @@ class AutomaticBrightnessController { } final int oldPolicy = mDisplayPolicy; mDisplayPolicy = policy; - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy); } if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) { mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL, - SHORT_TERM_MODEL_TIMEOUT_MILLIS); + mShortTermModelTimeout); } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) { mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL); } @@ -317,7 +367,7 @@ class AutomaticBrightnessController { mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness); mShortTermModelValid = true; mShortTermModelAnchor = mAmbientLux; - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor); } return true; @@ -330,7 +380,7 @@ class AutomaticBrightnessController { } private void invalidateShortTermModel() { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "ShortTermModel: invalidate user data"); } mShortTermModelValid = false; @@ -377,13 +427,17 @@ class AutomaticBrightnessController { pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer); pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness); pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy)); + pw.println(" mShortTermModelTimeout=" + mShortTermModelTimeout); pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor); pw.println(" mShortTermModelValid=" + mShortTermModelValid); pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending); pw.println(" mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux); pw.println(" mBrightnessAdjustmentSampleOldBrightness=" + mBrightnessAdjustmentSampleOldBrightness); - pw.println(" mShortTermModelValid=" + mShortTermModelValid); + pw.println(" mForegroundAppPackageName=" + mForegroundAppPackageName); + pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName); + pw.println(" mForegroundAppCategory=" + mForegroundAppCategory); + pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory); pw.println(); mBrightnessMapper.dump(pw); @@ -399,6 +453,7 @@ class AutomaticBrightnessController { mLightSensorEnabled = true; mLightSensorEnableTime = SystemClock.uptimeMillis(); mCurrentLightSensorRate = mInitialLightSensorRate; + registerForegroundAppUpdater(); mSensorManager.registerListener(mLightSensorListener, mLightSensor, mCurrentLightSensorRate * 1000, mHandler); return true; @@ -411,6 +466,7 @@ class AutomaticBrightnessController { mAmbientLightRingBuffer.clear(); mCurrentLightSensorRate = -1; mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX); + unregisterForegroundAppUpdater(); mSensorManager.unregisterListener(mLightSensorListener); } return false; @@ -441,7 +497,7 @@ class AutomaticBrightnessController { private void adjustLightSensorRate(int lightSensorRate) { // if the light sensor rate changed, update the sensor listener if (lightSensorRate != mCurrentLightSensorRate) { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "adjustLightSensorRate: " + "previousRate=" + mCurrentLightSensorRate + ", " + "currentRate=" + lightSensorRate); @@ -458,7 +514,7 @@ class AutomaticBrightnessController { } private void setAmbientLux(float lux) { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "setAmbientLux(" + lux + ")"); } if (lux < 0) { @@ -476,7 +532,7 @@ class AutomaticBrightnessController { final float maxAmbientLux = mShortTermModelAnchor + mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO; if (minAmbientLux < mAmbientLux && mAmbientLux < maxAmbientLux) { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is " + minAmbientLux + " < " + mAmbientLux + " < " + maxAmbientLux); } @@ -490,7 +546,7 @@ class AutomaticBrightnessController { } private float calculateAmbientLux(long now, long horizon) { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")"); } final int N = mAmbientLightRingBuffer.size(); @@ -509,7 +565,7 @@ class AutomaticBrightnessController { break; } } - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" + mAmbientLightRingBuffer.getTime(endIndex) + ", " + mAmbientLightRingBuffer.getLux(endIndex) + ")"); @@ -527,7 +583,7 @@ class AutomaticBrightnessController { final long startTime = eventTime - now; float weight = calculateWeight(startTime, endTime); float lux = mAmbientLightRingBuffer.getLux(i); - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " + "lux=" + lux + ", " + "weight=" + weight); @@ -536,7 +592,7 @@ class AutomaticBrightnessController { sum += lux * weight; endTime = startTime; } - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "calculateAmbientLux: " + "totalWeight=" + totalWeight + ", " + "newAmbientLux=" + (sum / totalWeight)); @@ -591,7 +647,7 @@ class AutomaticBrightnessController { final long timeWhenSensorWarmedUp = mLightSensorWarmUpTimeConfig + mLightSensorEnableTime; if (time < timeWhenSensorWarmedUp) { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: " + "time=" + time + ", " + "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp); @@ -602,7 +658,7 @@ class AutomaticBrightnessController { } setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS)); mAmbientLuxValid = true; - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "updateAmbientLux: Initializing: " + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " + "mAmbientLux=" + mAmbientLux); @@ -630,10 +686,10 @@ class AutomaticBrightnessController { && fastAmbientLux <= mAmbientDarkeningThreshold && nextDarkenTransition <= time)) { setAmbientLux(fastAmbientLux); - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "updateAmbientLux: " + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": " - + "mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold + ", " + + "mBrighteningLuxThreshold=" + mAmbientBrighteningThreshold + ", " + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " + "mAmbientLux=" + mAmbientLux); } @@ -650,7 +706,7 @@ class AutomaticBrightnessController { // weighted ambient lux or not. nextTransitionTime = nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate; - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime)); } @@ -662,7 +718,8 @@ class AutomaticBrightnessController { return; } - float value = mBrightnessMapper.getBrightness(mAmbientLux); + float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName, + mForegroundAppCategory); int newScreenAutoBrightness = clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON)); @@ -673,7 +730,7 @@ class AutomaticBrightnessController { if (mScreenAutoBrightness != -1 && newScreenAutoBrightness > mScreenDarkeningThreshold && newScreenAutoBrightness < mScreenBrighteningThreshold) { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "ignoring newScreenAutoBrightness: " + mScreenDarkeningThreshold + " < " + newScreenAutoBrightness + " < " + mScreenBrighteningThreshold); } @@ -681,8 +738,7 @@ class AutomaticBrightnessController { } if (mScreenAutoBrightness != newScreenAutoBrightness) { - - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "updateAutoBrightness: " + "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " + "newScreenAutoBrightness=" + newScreenAutoBrightness); @@ -729,7 +785,7 @@ class AutomaticBrightnessController { if (mBrightnessAdjustmentSamplePending) { mBrightnessAdjustmentSamplePending = false; if (mAmbientLuxValid && mScreenAutoBrightness >= 0) { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "Auto-brightness adjustment changed by user: " + "lux=" + mAmbientLux + ", " + "brightness=" + mScreenAutoBrightness + ", " + @@ -745,6 +801,83 @@ class AutomaticBrightnessController { } } + // Register a TaskStackListener to call back to us onTaskStackChanged, so we can update the + // foreground app's package name and category and correct the brightness accordingly. + private void registerForegroundAppUpdater() { + try { + mActivityTaskManager.registerTaskStackListener(mTaskStackListener); + // This will not get called until the foreground app changes for the first time, so + // call it explicitly to get the current foreground app's info. + updateForegroundApp(); + } catch (RemoteException e) { + if (mLoggingEnabled) { + Slog.e(TAG, "Failed to register foreground app updater: " + e); + } + // Nothing to do. + } + } + + private void unregisterForegroundAppUpdater() { + try { + mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); + } catch (RemoteException e) { + // Nothing to do. + } + mForegroundAppPackageName = null; + mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; + } + + // Set the foreground app's package name and category, so brightness can be corrected per app. + private void updateForegroundApp() { + if (mLoggingEnabled) { + Slog.d(TAG, "Attempting to update foreground app"); + } + // The ActivityTaskManager's lock tends to get contended, so this is done in a background + // thread and applied via this thread's handler synchronously. + BackgroundThread.getHandler().post(new Runnable() { + public void run() { + try { + // The foreground app is the top activity of the focused tasks stack. + final StackInfo info = mActivityTaskManager.getFocusedStackInfo(); + if (info == null || info.topActivity == null) { + return; + } + final String packageName = info.topActivity.getPackageName(); + // If the app didn't change, there's nothing to do. Otherwise, we have to + // update the category and re-apply the brightness correction. + if (mForegroundAppPackageName != null + && mForegroundAppPackageName.equals(packageName)) { + return; + } + mPendingForegroundAppPackageName = packageName; + mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; + try { + ApplicationInfo app = mPackageManager.getApplicationInfo(packageName, + PackageManager.MATCH_ANY_USER); + mPendingForegroundAppCategory = app.category; + } catch (PackageManager.NameNotFoundException e) { + // Nothing to do + } + mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP_SYNC); + } catch (RemoteException e) { + // Nothing to do + } + } + }); + } + + private void updateForegroundAppSync() { + if (mLoggingEnabled) { + Slog.d(TAG, "Updating foreground app: packageName=" + mPendingForegroundAppPackageName + + ", category=" + mPendingForegroundAppCategory); + } + mForegroundAppPackageName = mPendingForegroundAppPackageName; + mPendingForegroundAppPackageName = null; + mForegroundAppCategory = mPendingForegroundAppCategory; + mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; + updateAutoBrightness(true /* sendUpdate */); + } + private final class AutomaticBrightnessHandler extends Handler { public AutomaticBrightnessHandler(Looper looper) { super(looper, null, true /*async*/); @@ -764,6 +897,14 @@ class AutomaticBrightnessController { case MSG_INVALIDATE_SHORT_TERM_MODEL: invalidateShortTermModel(); break; + + case MSG_UPDATE_FOREGROUND_APP: + updateForegroundApp(); + break; + + case MSG_UPDATE_FOREGROUND_APP_SYNC: + updateForegroundAppSync(); + break; } } } @@ -784,6 +925,15 @@ class AutomaticBrightnessController { } }; + // Call back whenever the tasks stack changes, which includes tasks being created, removed, and + // moving to top. + class TaskStackListenerImpl extends TaskStackListener { + @Override + public void onTaskStackChanged() { + mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP); + } + } + /** Callbacks to request updates to the display's power state. */ interface Callbacks { void updateBrightness(); diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index 76c191d5e9ea..9fce644d6c4b 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -17,9 +17,11 @@ package com.android.server.display; import android.annotation.Nullable; +import android.content.pm.ApplicationInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.hardware.display.BrightnessConfiguration; +import android.hardware.display.BrightnessCorrection; import android.os.PowerManager; import android.util.MathUtils; import android.util.Pair; @@ -42,11 +44,12 @@ import java.util.Arrays; */ public abstract class BrightnessMappingStrategy { private static final String TAG = "BrightnessMappingStrategy"; - private static final boolean DEBUG = false; private static final float LUX_GRAD_SMOOTHING = 0.25f; private static final float MAX_GRAD = 1.0f; + protected boolean mLoggingEnabled; + private static final Plog PLOG = Plog.createSystemPlog(TAG); @Nullable @@ -161,6 +164,22 @@ public abstract class BrightnessMappingStrategy { } /** + * Enable/disable logging. + * + * @param loggingEnabled + * Whether logging should be on/off. + * + * @return Whether the method succeeded or not. + */ + public boolean setLoggingEnabled(boolean loggingEnabled) { + if (mLoggingEnabled == loggingEnabled) { + return false; + } + mLoggingEnabled = loggingEnabled; + return true; + } + + /** * Sets the {@link BrightnessConfiguration}. * * @param config The new configuration. If {@code null} is passed, the default configuration is @@ -170,15 +189,33 @@ public abstract class BrightnessMappingStrategy { public abstract boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config); /** - * Returns the desired brightness of the display based on the current ambient lux. + * Returns the desired brightness of the display based on the current ambient lux, including + * any context-related corrections. * * The returned brightness will be in the range [0, 1.0], where 1.0 is the display at max * brightness and 0 is the display at minimum brightness. * * @param lux The current ambient brightness in lux. + * @param packageName the foreground app package name. + * @param category the foreground app package category. * @return The desired brightness of the display normalized to the range [0, 1.0]. */ - public abstract float getBrightness(float lux); + public abstract float getBrightness(float lux, String packageName, + @ApplicationInfo.Category int category); + + /** + * Returns the desired brightness of the display based on the current ambient lux. + * + * The returned brightness wil be in the range [0, 1.0], where 1.0 is the display at max + * brightness and 0 is the display at minimum brightness. + * + * @param lux The current ambient brightness in lux. + * + * @return The desired brightness of the display normalized to the range [0, 1.0]. + */ + public float getBrightness(float lux) { + return getBrightness(lux, null /* packageName */, ApplicationInfo.CATEGORY_UNDEFINED); + } /** * Returns the current auto-brightness adjustment. @@ -239,13 +276,13 @@ public abstract class BrightnessMappingStrategy { public abstract void dump(PrintWriter pw); - private static float normalizeAbsoluteBrightness(int brightness) { + protected float normalizeAbsoluteBrightness(int brightness) { brightness = MathUtils.constrain(brightness, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON); return (float) brightness / PowerManager.BRIGHTNESS_ON; } - private static Pair<float[], float[]> insertControlPoint( + private Pair<float[], float[]> insertControlPoint( float[] luxLevels, float[] brightnessLevels, float lux, float brightness) { final int idx = findInsertionPoint(luxLevels, lux); final float[] newLuxLevels; @@ -278,7 +315,7 @@ public abstract class BrightnessMappingStrategy { * This assumes that {@code arr} is sorted. If all values in {@code arr} are greater * than val, then it will return the length of arr as the insertion point. */ - private static int findInsertionPoint(float[] arr, float val) { + private int findInsertionPoint(float[] arr, float val) { for (int i = 0; i < arr.length; i++) { if (val <= arr[i]) { return i; @@ -287,8 +324,8 @@ public abstract class BrightnessMappingStrategy { return arr.length; } - private static void smoothCurve(float[] lux, float[] brightness, int idx) { - if (DEBUG) { + private void smoothCurve(float[] lux, float[] brightness, int idx) { + if (mLoggingEnabled) { PLOG.logCurve("unsmoothed curve", lux, brightness); } float prevLux = lux[idx]; @@ -323,19 +360,19 @@ public abstract class BrightnessMappingStrategy { prevBrightness = newBrightness; brightness[i] = newBrightness; } - if (DEBUG) { + if (mLoggingEnabled) { PLOG.logCurve("smoothed curve", lux, brightness); } } - private static float permissibleRatio(float currLux, float prevLux) { + private float permissibleRatio(float currLux, float prevLux) { return MathUtils.exp(MAX_GRAD * (MathUtils.log(currLux + LUX_GRAD_SMOOTHING) - MathUtils.log(prevLux + LUX_GRAD_SMOOTHING))); } - private static float inferAutoBrightnessAdjustment(float maxGamma, - float desiredBrightness, float currentBrightness) { + protected float inferAutoBrightnessAdjustment(float maxGamma, float desiredBrightness, + float currentBrightness) { float adjustment = 0; float gamma = Float.NaN; // Extreme edge cases: use a simpler heuristic, as proper gamma correction around the edges @@ -355,7 +392,7 @@ public abstract class BrightnessMappingStrategy { adjustment = -MathUtils.log(gamma) / MathUtils.log(maxGamma); } adjustment = MathUtils.constrain(adjustment, -1, +1); - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "inferAutoBrightnessAdjustment: " + maxGamma + "^" + -adjustment + "=" + MathUtils.pow(maxGamma, -adjustment) + " == " + gamma); Slog.d(TAG, "inferAutoBrightnessAdjustment: " + currentBrightness + "^" + gamma + "=" + @@ -364,16 +401,16 @@ public abstract class BrightnessMappingStrategy { return adjustment; } - private static Pair<float[], float[]> getAdjustedCurve(float[] lux, float[] brightness, + protected Pair<float[], float[]> getAdjustedCurve(float[] lux, float[] brightness, float userLux, float userBrightness, float adjustment, float maxGamma) { float[] newLux = lux; float[] newBrightness = Arrays.copyOf(brightness, brightness.length); - if (DEBUG) { + if (mLoggingEnabled) { PLOG.logCurve("unadjusted curve", newLux, newBrightness); } adjustment = MathUtils.constrain(adjustment, -1, 1); float gamma = MathUtils.pow(maxGamma, -adjustment); - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "getAdjustedCurve: " + maxGamma + "^" + -adjustment + "=" + MathUtils.pow(maxGamma, -adjustment) + " == " + gamma); } @@ -382,7 +419,7 @@ public abstract class BrightnessMappingStrategy { newBrightness[i] = MathUtils.pow(newBrightness[i], gamma); } } - if (DEBUG) { + if (mLoggingEnabled) { PLOG.logCurve("gamma adjusted curve", newLux, newBrightness); } if (userLux != -1) { @@ -390,7 +427,7 @@ public abstract class BrightnessMappingStrategy { userBrightness); newLux = curve.first; newBrightness = curve.second; - if (DEBUG) { + if (mLoggingEnabled) { PLOG.logCurve("gamma and user adjusted curve", newLux, newBrightness); // This is done for comparison. curve = insertControlPoint(lux, brightness, userLux, userBrightness); @@ -440,7 +477,7 @@ public abstract class BrightnessMappingStrategy { mAutoBrightnessAdjustment = 0; mUserLux = -1; mUserBrightness = -1; - if (DEBUG) { + if (mLoggingEnabled) { PLOG.start("simple mapping strategy"); } computeSpline(); @@ -452,7 +489,8 @@ public abstract class BrightnessMappingStrategy { } @Override - public float getBrightness(float lux) { + public float getBrightness(float lux, String packageName, + @ApplicationInfo.Category int category) { return mSpline.interpolate(lux); } @@ -467,7 +505,7 @@ public abstract class BrightnessMappingStrategy { if (adjustment == mAutoBrightnessAdjustment) { return false; } - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " + adjustment); PLOG.start("auto-brightness adjustment"); @@ -485,7 +523,7 @@ public abstract class BrightnessMappingStrategy { @Override public void addUserDataPoint(float lux, float brightness) { float unadjustedBrightness = getUnadjustedBrightness(lux); - if (DEBUG){ + if (mLoggingEnabled) { Slog.d(TAG, "addUserDataPoint: (" + lux + "," + brightness + ")"); PLOG.start("add user data point") .logPoint("user data point", lux, brightness) @@ -494,7 +532,7 @@ public abstract class BrightnessMappingStrategy { float adjustment = inferAutoBrightnessAdjustment(mMaxGamma, brightness /* desiredBrightness */, unadjustedBrightness /* currentBrightness */); - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "addUserDataPoint: " + mAutoBrightnessAdjustment + " => " + adjustment); } @@ -507,7 +545,7 @@ public abstract class BrightnessMappingStrategy { @Override public void clearUserDataPoints() { if (mUserLux != -1) { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "clearUserDataPoints: " + mAutoBrightnessAdjustment + " => 0"); PLOG.start("clear user data points") .logPoint("user data point", mUserLux, mUserBrightness); @@ -614,7 +652,7 @@ public abstract class BrightnessMappingStrategy { mBacklightToNitsSpline = Spline.createSpline(normalizedBacklight, nits); mDefaultConfig = config; - if (DEBUG) { + if (mLoggingEnabled) { PLOG.start("physical mapping strategy"); } mConfig = config; @@ -629,7 +667,7 @@ public abstract class BrightnessMappingStrategy { if (config.equals(mConfig)) { return false; } - if (DEBUG) { + if (mLoggingEnabled) { PLOG.start("brightness configuration"); } mConfig = config; @@ -638,9 +676,17 @@ public abstract class BrightnessMappingStrategy { } @Override - public float getBrightness(float lux) { + public float getBrightness(float lux, String packageName, + @ApplicationInfo.Category int category) { float nits = mBrightnessSpline.interpolate(lux); float backlight = mNitsToBacklightSpline.interpolate(nits); + // Correct the brightness according to the current application and its category, but + // only if no user data point is set (as this will oevrride the user setting). + if (mUserLux == -1) { + backlight = correctBrightness(backlight, packageName, category); + } else if (mLoggingEnabled) { + Slog.d(TAG, "user point set, correction not applied"); + } return backlight; } @@ -655,7 +701,7 @@ public abstract class BrightnessMappingStrategy { if (adjustment == mAutoBrightnessAdjustment) { return false; } - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " + adjustment); PLOG.start("auto-brightness adjustment"); @@ -673,7 +719,7 @@ public abstract class BrightnessMappingStrategy { @Override public void addUserDataPoint(float lux, float brightness) { float unadjustedBrightness = getUnadjustedBrightness(lux); - if (DEBUG){ + if (mLoggingEnabled) { Slog.d(TAG, "addUserDataPoint: (" + lux + "," + brightness + ")"); PLOG.start("add user data point") .logPoint("user data point", lux, brightness) @@ -682,7 +728,7 @@ public abstract class BrightnessMappingStrategy { float adjustment = inferAutoBrightnessAdjustment(mMaxGamma, brightness /* desiredBrightness */, unadjustedBrightness /* currentBrightness */); - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "addUserDataPoint: " + mAutoBrightnessAdjustment + " => " + adjustment); } @@ -695,7 +741,7 @@ public abstract class BrightnessMappingStrategy { @Override public void clearUserDataPoints() { if (mUserLux != -1) { - if (DEBUG) { + if (mLoggingEnabled) { Slog.d(TAG, "clearUserDataPoints: " + mAutoBrightnessAdjustment + " => 0"); PLOG.start("clear user data points") .logPoint("user data point", mUserLux, mUserBrightness); @@ -758,5 +804,21 @@ public abstract class BrightnessMappingStrategy { Spline spline = Spline.createSpline(curve.first, curve.second); return mNitsToBacklightSpline.interpolate(spline.interpolate(lux)); } + + private float correctBrightness(float brightness, String packageName, int category) { + if (packageName != null) { + BrightnessCorrection correction = mConfig.getCorrectionByPackageName(packageName); + if (correction != null) { + return correction.apply(brightness); + } + } + if (category != ApplicationInfo.CATEGORY_UNDEFINED) { + BrightnessCorrection correction = mConfig.getCorrectionByCategory(category); + if (correction != null) { + return correction.apply(brightness); + } + } + return brightness; + } } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 0a1a9a20e0da..b1ba05c035b3 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -2144,6 +2144,14 @@ public final class DisplayManagerService extends SystemService { mContext.getPackageName()); } + void setAutoBrightnessLoggingEnabled(boolean enabled) { + if (mDisplayPowerController != null) { + synchronized (mSyncRoot) { + mDisplayPowerController.setAutoBrightnessLoggingEnabled(enabled); + } + } + } + private boolean validatePackageName(int uid, String packageName) { if (packageName != null) { String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java index 27cad1eece09..abbfc7b18f94 100644 --- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java +++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java @@ -17,14 +17,9 @@ package com.android.server.display; import android.content.Intent; -import android.os.RemoteException; -import android.os.ResultReceiver; -import android.os.ShellCallback; import android.os.ShellCommand; -import android.util.Slog; import java.io.PrintWriter; -import java.lang.NumberFormatException; class DisplayManagerShellCommand extends ShellCommand { private static final String TAG = "DisplayManagerShellCommand"; @@ -46,6 +41,10 @@ class DisplayManagerShellCommand extends ShellCommand { return setBrightness(); case "reset-brightness-configuration": return resetBrightnessConfiguration(); + case "ab-logging-enable": + return setAutoBrightnessLoggingEnabled(true); + case "ab-logging-disable": + return setAutoBrightnessLoggingEnabled(false); default: return handleDefaultCommands(cmd); } @@ -62,6 +61,10 @@ class DisplayManagerShellCommand extends ShellCommand { pw.println(" Sets the current brightness to BRIGHTNESS (a number between 0 and 1)."); pw.println(" reset-brightness-configuration"); pw.println(" Reset the brightness to its default configuration."); + pw.println(" ab-logging-enable"); + pw.println(" Enable auto-brightness logging."); + pw.println(" ab-logging-disable"); + pw.println(" Disable auto-brightness logging."); pw.println(); Intent.printIntentArgsHelp(pw , ""); } @@ -89,4 +92,9 @@ class DisplayManagerShellCommand extends ShellCommand { mService.resetBrightnessConfiguration(); return 0; } + + private int setAutoBrightnessLoggingEnabled(boolean enabled) { + mService.setAutoBrightnessLoggingEnabled(enabled); + return 0; + } } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 249270bfda7e..db3928ec5fde 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -461,6 +461,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call + initialLightSensorRate + ") to be less than or equal to " + "config_autoBrightnessLightSensorRate (" + lightSensorRate + ")."); } + int shortTermModelTimeout = resources.getInteger( + com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout); mBrightnessMapper = BrightnessMappingStrategy.create(resources); if (mBrightnessMapper != null) { @@ -470,7 +472,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds, - screenBrightnessThresholds); + screenBrightnessThresholds, shortTermModelTimeout, + context.getPackageManager()); } else { mUseSoftwareAutoBrightnessConfig = false; } @@ -1836,4 +1839,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mHandler.sendMessage(msg); } } + + void setAutoBrightnessLoggingEnabled(boolean enabled) { + if (mAutomaticBrightnessController != null) { + mAutomaticBrightnessController.setLoggingEnabled(enabled); + } + } } diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java index 89cef621a55d..9aec43b6eaed 100644 --- a/services/core/java/com/android/server/display/PersistentDataStore.java +++ b/services/core/java/com/android/server/display/PersistentDataStore.java @@ -16,13 +16,6 @@ package com.android.server.display; -import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.XmlUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - import android.annotation.Nullable; import android.graphics.Point; import android.hardware.display.BrightnessConfiguration; @@ -30,13 +23,20 @@ import android.hardware.display.WifiDisplay; import android.util.AtomicFile; import android.util.Slog; import android.util.SparseArray; -import android.util.Pair; import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; import android.view.Display; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.XmlUtils; + +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -50,12 +50,9 @@ import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; -import libcore.io.IoUtils; - /** * Manages persistent state recorded by the display manager service as an XML file. * Caller must acquire lock on the data store before accessing it. @@ -110,14 +107,9 @@ final class PersistentDataStore { private static final String TAG_BRIGHTNESS_CONFIGURATIONS = "brightness-configurations"; private static final String TAG_BRIGHTNESS_CONFIGURATION = "brightness-configuration"; - private static final String TAG_BRIGHTNESS_CURVE = "brightness-curve"; - private static final String TAG_BRIGHTNESS_POINT = "brightness-point"; private static final String ATTR_USER_SERIAL = "user-serial"; private static final String ATTR_PACKAGE_NAME = "package-name"; private static final String ATTR_TIME_STAMP = "timestamp"; - private static final String ATTR_LUX = "lux"; - private static final String ATTR_NITS = "nits"; - private static final String ATTR_DESCRIPTION = "description"; // Remembered Wifi display devices. private ArrayList<WifiDisplay> mRememberedWifiDisplays = new ArrayList<WifiDisplay>(); @@ -646,7 +638,8 @@ final class PersistentDataStore { } try { - BrightnessConfiguration config = loadConfigurationFromXml(parser); + BrightnessConfiguration config = + BrightnessConfiguration.loadFromXml(parser); if (userSerial >= 0 && config != null) { mConfigurations.put(userSerial, config); if (timeStamp != -1) { @@ -663,56 +656,6 @@ final class PersistentDataStore { } } - private static BrightnessConfiguration loadConfigurationFromXml(XmlPullParser parser) - throws IOException, XmlPullParserException { - final int outerDepth = parser.getDepth(); - String description = null; - Pair<float[], float[]> curve = null; - while (XmlUtils.nextElementWithin(parser, outerDepth)) { - if (TAG_BRIGHTNESS_CURVE.equals(parser.getName())) { - description = parser.getAttributeValue(null, ATTR_DESCRIPTION); - curve = loadCurveFromXml(parser); - } - } - if (curve == null) { - return null; - } - final BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder( - curve.first, curve.second); - builder.setDescription(description); - return builder.build(); - } - - private static Pair<float[], float[]> loadCurveFromXml(XmlPullParser parser) - throws IOException, XmlPullParserException { - final int outerDepth = parser.getDepth(); - List<Float> luxLevels = new ArrayList<>(); - List<Float> nitLevels = new ArrayList<>(); - while (XmlUtils.nextElementWithin(parser, outerDepth)) { - if (TAG_BRIGHTNESS_POINT.equals(parser.getName())) { - luxLevels.add(loadFloat(parser.getAttributeValue(null, ATTR_LUX))); - nitLevels.add(loadFloat(parser.getAttributeValue(null, ATTR_NITS))); - } - } - final int N = luxLevels.size(); - float[] lux = new float[N]; - float[] nits = new float[N]; - for (int i = 0; i < N; i++) { - lux[i] = luxLevels.get(i); - nits[i] = nitLevels.get(i); - } - return Pair.create(lux, nits); - } - - private static float loadFloat(String val) { - try { - return Float.parseFloat(val); - } catch (NullPointerException | NumberFormatException e) { - Slog.e(TAG, "Failed to parse float loading brightness config", e); - return Float.NEGATIVE_INFINITY; - } - } - public void saveToXml(XmlSerializer serializer) throws IOException { for (int i = 0; i < mConfigurations.size(); i++) { final int userSerial = mConfigurations.keyAt(i); @@ -728,27 +671,11 @@ final class PersistentDataStore { if (timestamp != -1) { serializer.attribute(null, ATTR_TIME_STAMP, Long.toString(timestamp)); } - saveConfigurationToXml(serializer, config); + config.saveToXml(serializer); serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATION); } } - private static void saveConfigurationToXml(XmlSerializer serializer, - BrightnessConfiguration config) throws IOException { - serializer.startTag(null, TAG_BRIGHTNESS_CURVE); - if (config.getDescription() != null) { - serializer.attribute(null, ATTR_DESCRIPTION, config.getDescription()); - } - final Pair<float[], float[]> curve = config.getCurve(); - for (int i = 0; i < curve.first.length; i++) { - serializer.startTag(null, TAG_BRIGHTNESS_POINT); - serializer.attribute(null, ATTR_LUX, Float.toString(curve.first[i])); - serializer.attribute(null, ATTR_NITS, Float.toString(curve.second[i])); - serializer.endTag(null, TAG_BRIGHTNESS_POINT); - } - serializer.endTag(null, TAG_BRIGHTNESS_CURVE); - } - public void dump(final PrintWriter pw, final String prefix) { for (int i = 0; i < mConfigurations.size(); i++) { final int userSerial = mConfigurations.keyAt(i); diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index ba05b49b7698..bffa8f486db7 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -18,13 +18,6 @@ package com.android.server.dreams; import static android.Manifest.permission.BIND_DREAM_SERVICE; -import com.android.internal.hardware.AmbientDisplayConfiguration; -import com.android.internal.util.DumpUtils; -import com.android.server.FgThread; -import com.android.server.LocalServices; -import com.android.server.SystemService; - -import android.Manifest; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -53,6 +46,12 @@ import android.service.dreams.IDreamManager; import android.util.Slog; import android.view.Display; +import com.android.internal.hardware.AmbientDisplayConfiguration; +import com.android.internal.util.DumpUtils; +import com.android.server.FgThread; +import com.android.server.LocalServices; +import com.android.server.SystemService; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -84,6 +83,7 @@ public final class DreamManagerService extends SystemService { private boolean mCurrentDreamCanDoze; private boolean mCurrentDreamIsDozing; private boolean mCurrentDreamIsWaking; + private boolean mForceAmbientDisplayEnabled; private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN; private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT; @@ -139,6 +139,7 @@ public final class DreamManagerService extends SystemService { pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze); pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing); pw.println("mCurrentDreamIsWaking=" + mCurrentDreamIsWaking); + pw.println("mForceAmbientDisplayEnabled=" + mForceAmbientDisplayEnabled); pw.println("mCurrentDreamDozeScreenState=" + Display.stateToString(mCurrentDreamDozeScreenState)); pw.println("mCurrentDreamDozeScreenBrightness=" + mCurrentDreamDozeScreenBrightness); @@ -257,6 +258,16 @@ public final class DreamManagerService extends SystemService { } } + private void forceAmbientDisplayEnabledInternal(boolean enabled) { + if (DEBUG) { + Slog.d(TAG, "Force ambient display enabled: " + enabled); + } + + synchronized (mLock) { + mForceAmbientDisplayEnabled = enabled; + } + } + private ComponentName chooseDreamForUser(boolean doze, int userId) { if (doze) { ComponentName dozeComponent = getDozeComponent(userId); @@ -328,7 +339,7 @@ public final class DreamManagerService extends SystemService { } private ComponentName getDozeComponent(int userId) { - if (mDozeConfig.enabled(userId)) { + if (mForceAmbientDisplayEnabled || mDozeConfig.enabled(userId)) { return ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent()); } else { return null; @@ -631,6 +642,18 @@ public final class DreamManagerService extends SystemService { Binder.restoreCallingIdentity(ident); } } + + @Override // Binder call + public void forceAmbientDisplayEnabled(boolean enabled) { + checkPermission(android.Manifest.permission.DEVICE_POWER); + + final long ident = Binder.clearCallingIdentity(); + try { + forceAmbientDisplayEnabledInternal(enabled); + } finally { + Binder.restoreCallingIdentity(ident); + } + } } private final class LocalService extends DreamManagerInternal { diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java index 1f0f94a7bf0b..ea01a0b4253e 100644 --- a/services/core/java/com/android/server/hdmi/Constants.java +++ b/services/core/java/com/android/server/hdmi/Constants.java @@ -273,6 +273,16 @@ final class Constants { // TODO(OEM): Set this to true to enable 'Set Menu Language' feature. False by default. static final String PROPERTY_SET_MENU_LANGUAGE = "ro.hdmi.set_menu_language"; + /** + * Property to disable muting logic in System Audio Control handling. Default is true. + * + * <p>True means enabling muting logic. + * <p>False means never mute device. + */ + // TODO(OEM): set to true to disable muting. + static final String PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE = + "ro.hdmi.property_system_audio_mode_muting_enable"; + // Set to false to allow playback device to go to suspend mode even // when it's an active source. True by default. static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake"; @@ -300,7 +310,7 @@ final class Constants { * <p>Default is true. */ static final String PROPERTY_ARC_SUPPORT = - "persist.sys.hdmi.property_arc_support"; + "persist.sys.hdmi.property_arc_support"; /** * Property to save the audio port to switch to when system audio control is on. @@ -310,7 +320,7 @@ final class Constants { * <p>Default is ARC port. */ static final String PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT = - "persist.sys.hdmi.property_sytem_audio_mode_audio_port"; + "persist.sys.hdmi.property_sytem_audio_mode_audio_port"; /** * Property to save the ARC port id on system audio device. @@ -320,6 +330,15 @@ final class Constants { "persist.sys.hdmi.property_sytem_audio_device_arc_port"; /** + * Property to indicate if a CEC audio device should forward volume keys when system audio mode + * is off. + * + * <p>Default is false. + */ + static final String PROPERTY_CEC_AUDIO_DEVICE_FORWARD_VOLUME_KEYS_SYSTEM_AUDIO_MODE_OFF = + "persist.sys.hdmi.property_cec_audio_device_forward_volume_keys_system_audio_mode_off"; + + /** * Property to strip local audio of amplifier and use local speaker * when TV does not support system audio mode. * diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 9690ba877c1e..7358eaa587e3 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -25,6 +25,7 @@ import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.media.AudioSystem; import android.os.SystemProperties; +import android.provider.Settings.Global; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -50,16 +51,38 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { private boolean mTvSystemAudioModeSupport; + // Whether the auido system will turn TV off when it's powering off + private boolean mAutoTvOff; + // Whether the auido system will broadcast standby to the system when it's powering off + private boolean mAutoDeviceOff; + // Whether ARC is available or not. "true" means that ARC is established between TV and // AVR as audio receiver. @ServiceThreadOnly private boolean mArcEstablished = false; + /** + * Return value of {@link #getLocalPortFromPhysicalAddress(int)} + */ + private static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1; + private static final int TARGET_SAME_PHYSICAL_ADDRESS = 0; + + // Local active port number used for Routing Control. + // Default 0 means HOME is the current active path. Temp solution only. + // TODO(amyjojo): adding system constants for Atom inputs port and TIF mapping. + private int mLocalActivePath = 0; + protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); mSystemAudioControlFeatureEnabled = true; // TODO(amyjojo) make System Audio Control controllable by users /*mSystemAudioControlFeatureEnabled = mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/ + // TODO(b/80297700): set read-only property in config instead of setting here + SystemProperties.set(Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, "false"); + mAutoDeviceOff = mService.readBooleanSetting( + Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, true); + mAutoTvOff = mService.readBooleanSetting( + Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED, true); } @Override @@ -74,6 +97,21 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mSystemAudioActivated ? "true" : "false"); } terminateSystemAudioMode(); + + HdmiLogger.debug(TAG + " onStandby, initiatedByCec:" + initiatedByCec + + ", mAutoDeviceOff: " + mAutoDeviceOff + ", mAutoTvOff: " + mAutoTvOff); + if (!mService.isControlEnabled() || initiatedByCec) { + return; + } + if (mAutoDeviceOff) { + mService.sendCecCommand( + HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_BROADCAST)); + } else if (mAutoTvOff) { + mService.sendCecCommand( + HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV)); + } + return; + } @Override @@ -124,6 +162,20 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { @Override @ServiceThreadOnly + protected boolean handleSetStreamPath(HdmiCecMessage message) { + assertRunOnServiceThread(); + int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); + // If current device is the target path, playback device should handle it. + // If the path is under the current device, should switch + int port = getLocalPortFromPhysicalAddress(physicalAddress); + if (port > 0) { + routeToPort(port); + } + return true; + } + + @Override + @ServiceThreadOnly protected int getPreferredAddress() { assertRunOnServiceThread(); return SystemProperties.getInt( @@ -371,10 +423,25 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { mService.wakeUp(); } int targetPhysicalAddress = getActiveSource().physicalAddress; - if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) { + int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress); + if (newSystemAudioMode && port >= 0) { switchToAudioInput(); } - // TODO(b/80297700): Mute device when TV terminates the system audio control + // Mute device when feature is turned off and unmute device when feature is turned on. + // PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE is false when device never needs to be muted. + boolean currentMuteStatus = + mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC); + if (SystemProperties.getBoolean( + Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true) + && currentMuteStatus == newSystemAudioMode) { + mService.getAudioManager() + .adjustStreamVolume( + AudioManager.STREAM_MUSIC, + newSystemAudioMode + ? AudioManager.ADJUST_UNMUTE + : AudioManager.ADJUST_MUTE, + 0); + } updateAudioManagerForSystemAudio(newSystemAudioMode); synchronized (mLock) { if (mSystemAudioActivated != newSystemAudioMode) { @@ -386,27 +453,44 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { } /** - * Method to check if the target device belongs to the subtree of the current device or not. + * Method to parse target physical address to the port number on the current device. * - * <p>Return true if it does or if the two devices share the same physical address. + * <p>This check assumes target address is valid. + * @param targetPhysicalAddress is the physical address of the target device + * @return + * <p>If the target device is under the current device, return the port number of current device + * that the target device is connected to. * - * <p>This check assumes both device physical address and target address are valid. + * <p>If the target device has the same physical address as the current device, return + * {@link #TARGET_SAME_PHYSICAL_ADDRESS}. * - * @param targetPhysicalAddress is the physical address of the target device + * <p>If the target device is not under the current device, return + * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}. */ - protected boolean isPhysicalAddressMeOrBelow(int targetPhysicalAddress) { + protected int getLocalPortFromPhysicalAddress(int targetPhysicalAddress) { int myPhysicalAddress = mService.getPhysicalAddress(); - int xor = targetPhysicalAddress ^ myPhysicalAddress; - // Return true if two addresses are the same - // or if they only differs for one byte, but not the first byte, - // and myPhysicalAddress is 0 after that byte - if (xor == 0 - || ((xor & 0x0f00) == xor && (myPhysicalAddress & 0x0fff) == 0) - || ((xor & 0x00f0) == xor && (myPhysicalAddress & 0x00ff) == 0) - || ((xor & 0x000f) == xor && (myPhysicalAddress & 0x000f) == 0)) { - return true; + if (myPhysicalAddress == targetPhysicalAddress) { + return TARGET_SAME_PHYSICAL_ADDRESS; } - return false; + int finalMask = 0xF000; + int mask; + int port = 0; + for (mask = 0x0F00; mask > 0x000F; mask >>= 4) { + if ((myPhysicalAddress & mask) == 0) { + port = mask & targetPhysicalAddress; + break; + } else { + finalMask |= mask; + } + } + if (finalMask != 0xFFFF && (finalMask & targetPhysicalAddress) == myPhysicalAddress) { + while (mask != 0x000F) { + mask >>= 4; + port >>= 4; + } + return port; + } + return TARGET_NOT_UNDER_LOCAL_DEVICE; } protected void switchToAudioInput() { @@ -491,4 +575,27 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice { return mArcEstablished; } } + + @ServiceThreadOnly + protected void setAutoTvOff(boolean autoTvOff) { + assertRunOnServiceThread(); + mAutoTvOff = autoTvOff; + } + + @Override + @ServiceThreadOnly + void setAutoDeviceOff(boolean autoDeviceOff) { + assertRunOnServiceThread(); + mAutoDeviceOff = autoDeviceOff; + } + + private void routeToPort(int portId) { + // TODO(AMYJOJO): route to specific input of the port + mLocalActivePath = portId; + } + + @VisibleForTesting + protected int getLocalActivePath() { + return mLocalActivePath; + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 3420b263eac5..e3a4084ab7f3 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -592,6 +592,11 @@ public class HdmiControlService extends SystemService { } // No need to propagate to HAL. break; + case Global.HDMI_CONTROL_AUTO_TV_OFF_ENABLED: + if (isAudioSystemDevice()) { + audioSystem().setAutoTvOff(enabled); + } + break; case Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED: if (isTvDeviceEnabled()) { tv().setSystemAudioControlFeatureEnabled(enabled); diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java index a3ebe2408fa3..8e26097cd55d 100644 --- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java @@ -274,10 +274,14 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem } synchronized (mLock) { - final S service = getServiceForUserLocked(userId); - if (service != null) { - service.setTemporaryServiceLocked(componentName, durationMs); + final S oldService = peekServiceForUserLocked(userId); + if (oldService != null) { + oldService.removeSelfFromCacheLocked(); } + mServiceNameResolver.setTemporaryService(userId, componentName, durationMs); + + // Must update the service on cache so its initialization code is triggered + updateCachedServiceLocked(userId); } } @@ -500,6 +504,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) { boolean realDebug = debug; boolean realVerbose = verbose; + final String prefix2 = " "; try { // Temporarily turn on full logging; @@ -510,6 +515,13 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem if (mServiceNameResolver != null) { pw.print(prefix); pw.print("Name resolver: "); mServiceNameResolver.dumpShort(pw); pw.println(); + final UserManager um = getContext().getSystemService(UserManager.class); + final List<UserInfo> users = um.getUsers(); + for (int i = 0; i < users.size(); i++) { + final int userId = users.get(i).id; + pw.print(prefix2); pw.print(userId); pw.print(": "); + mServiceNameResolver.dumpShort(pw, userId); pw.println(); + } } pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers); pw.print(prefix); pw.print("Allow instant service: "); pw.println(mAllowInstantService); @@ -522,7 +534,6 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem 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); diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java index 556e4892807c..cd9ebcda009c 100644 --- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java @@ -214,7 +214,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst /** * Gets the current name of the service, which is either the default service or the - * {@link #setTemporaryServiceLocked(String, int) temporary one}. + * {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}. */ protected final @Nullable String getComponentNameLocked() { return mMaster.mServiceNameResolver.getServiceName(mUserId); @@ -228,17 +228,6 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst } /** - * Temporary sets the service implementation. - * - * @param componentName name of the new component - * @param durationMs how long the change will be valid (the service will be automatically reset - * to the default component after this timeout expires). - */ - protected final void setTemporaryServiceLocked(@NonNull String componentName, int durationMs) { - mMaster.mServiceNameResolver.setTemporaryService(mUserId, componentName, durationMs); - } - - /** * Resets the temporary service implementation to the default component. */ protected final void resetTemporaryServiceLocked() { diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java index 7027246a1bbe..7f198acfd743 100644 --- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java @@ -159,7 +159,7 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR @Override public String toString() { - return "FrameworkResourcesServiceNamer: temps=" + mTemporaryServiceNames; + return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNames + "]"; } // TODO(b/117779333): support proto diff --git a/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java b/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java index bcaa9188ca62..cac7f53aad66 100644 --- a/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java +++ b/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java @@ -56,4 +56,9 @@ public final class SecureSettingsServiceNameResolver implements ServiceNameResol public void dumpShort(@NonNull PrintWriter pw, @UserIdInt int userId) { pw.print("defaultService="); pw.print(getDefaultServiceName(userId)); } + + @Override + public String toString() { + return "SecureSettingsServiceNameResolver[" + mProperty + "]"; + } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 5a7739c49b42..d45869e07586 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -291,6 +291,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub new DebugFlag("debug.optimize_startinput", false); } + @UserIdInt + private int mLastSwitchUserId; final Context mContext; final Resources mRes; @@ -1436,6 +1438,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e); } + mLastSwitchUserId = userId; + // mSettings should be created before buildInputMethodListLocked mSettings = new InputMethodSettings( mRes, context.getContentResolver(), mMethodMap, mMethodList, userId, !mSystemReady); @@ -1523,6 +1527,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId + " selectedIme=" + mSettings.getSelectedInputMethod()); + + mLastSwitchUserId = newUserId; } void updateCurrentProfileIds() { @@ -4424,6 +4430,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return refreshDebugProperties(); } + if ("get-last-switch-user-id".equals(cmd)) { + return mService.getLastSwitchUserId(this); + } + // For existing "adb shell ime <command>". if ("ime".equals(cmd)) { final String imeCommand = getNextArg(); @@ -4516,6 +4526,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // ---------------------------------------------------------------------- // Shell command handlers: + @BinderThread + @ShellCommandResult + private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) { + synchronized (mMethodMap) { + shellCommand.getOutPrintWriter().println(mLastSwitchUserId); + return ShellCommandResult.SUCCESS; + } + } + /** * Handles {@code adb shell ime list}. * @param shellCommand {@link ShellCommand} object that is handling this command. diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 3f9d928e1986..2464ca782b6e 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -332,6 +332,44 @@ public class JobSchedulerService extends com.android.server.SystemService } } + private static class MaxJobCounts { + private final KeyValueListParser.IntValue mTotal; + private final KeyValueListParser.IntValue mBg; + + private MaxJobCounts(int totalDefault, String totalKey, int bgDefault, String bgKey) { + mTotal = new KeyValueListParser.IntValue(totalKey, totalDefault); + mBg = new KeyValueListParser.IntValue(bgKey, bgDefault); + } + + public void parse(KeyValueListParser parser) { + mTotal.parse(parser); + mBg.parse(parser); + + if (mBg.getValue() > mTotal.getValue()) { + mBg.setValue(mTotal.getValue()); + } + + } + + public int getTotalMax() { + return mTotal.getValue(); + } + + public int getBgMax() { + return mBg.getValue(); + } + + public void dump(PrintWriter pw, String prefix) { + mTotal.dump(pw, prefix); + mBg.dump(pw, prefix); + } + + public void dumpProto(ProtoOutputStream proto, long tagTotal, long tagBg) { + mTotal.dumpProto(proto, tagTotal); + mBg.dumpProto(proto, tagBg); + } + } + /** * All times are in milliseconds. These constants are kept synchronized with the system * global Settings. Any access to this class or its fields should be done while @@ -492,6 +530,43 @@ public class JobSchedulerService extends com.android.server.SystemService * memory state. */ int BG_CRITICAL_JOB_COUNT = DEFAULT_BG_CRITICAL_JOB_COUNT; + + // Max job counts for screen on / off, for each memory trim level. + // TODO Remove the old configs such as FG_JOB_COUNT and BG_*_COUNT, once the code switches + // to the below configs. + + final MaxJobCounts MAX_JOB_COUNTS_ON_NORMAL = new MaxJobCounts( + 4, "max_job_total_on_normal", + 2, "max_job_bg_on_normal"); + + final MaxJobCounts MAX_JOB_COUNTS_ON_MODERATE = new MaxJobCounts( + 4, "max_job_total_on_moderate", + 1, "max_job_bg_on_moderate"); + + final MaxJobCounts MAX_JOB_COUNTS_ON_LOW = new MaxJobCounts( + 4, "max_job_total_on_low", + 1, "max_job_bg_on_low"); + + final MaxJobCounts MAX_JOB_COUNTS_ON_CRITICAL = new MaxJobCounts( + 2, "max_job_total_on_critical", + 1, "max_job_bg_on_critical"); + + final MaxJobCounts MAX_JOB_COUNTS_OFF_NORMAL = new MaxJobCounts( + 8, "max_job_total_off_normal", + 4, "max_job_bg_off_normal"); + + final MaxJobCounts MAX_JOB_COUNTS_OFF_MODERATE = new MaxJobCounts( + 6, "max_job_total_off_moderate", + 4, "max_job_bg_off_moderate"); + + final MaxJobCounts MAX_JOB_COUNTS_OFF_LOW = new MaxJobCounts( + 4, "max_job_total_off_low", + 1, "max_job_bg_off_low"); + + final MaxJobCounts MAX_JOB_COUNTS_OFF_CRITICAL = new MaxJobCounts( + 2, "max_job_total_off_critical", + 1, "max_job_bg_off_critical"); + /** * The maximum number of times we allow a job to have itself rescheduled before * giving up on it, for standard jobs. @@ -566,7 +641,7 @@ public class JobSchedulerService extends com.android.server.SystemService /** * The quota window size of the particular standby bucket. Apps in this standby bucket are - * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past + * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past * WINDOW_SIZE_MS. */ public long QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = @@ -574,7 +649,7 @@ public class JobSchedulerService extends com.android.server.SystemService /** * The quota window size of the particular standby bucket. Apps in this standby bucket are - * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past + * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past * WINDOW_SIZE_MS. */ public long QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = @@ -582,7 +657,7 @@ public class JobSchedulerService extends com.android.server.SystemService /** * The quota window size of the particular standby bucket. Apps in this standby bucket are - * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past + * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past * WINDOW_SIZE_MS. */ public long QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = @@ -590,7 +665,7 @@ public class JobSchedulerService extends com.android.server.SystemService /** * The quota window size of the particular standby bucket. Apps in this standby bucket are - * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past + * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past * WINDOW_SIZE_MS. */ public long QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = @@ -653,6 +728,17 @@ public class JobSchedulerService extends com.android.server.SystemService if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) { BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT; } + + MAX_JOB_COUNTS_ON_NORMAL.parse(mParser); + MAX_JOB_COUNTS_ON_MODERATE.parse(mParser); + MAX_JOB_COUNTS_ON_LOW.parse(mParser); + MAX_JOB_COUNTS_ON_CRITICAL.parse(mParser); + + MAX_JOB_COUNTS_OFF_NORMAL.parse(mParser); + MAX_JOB_COUNTS_OFF_MODERATE.parse(mParser); + MAX_JOB_COUNTS_OFF_LOW.parse(mParser); + MAX_JOB_COUNTS_OFF_CRITICAL.parse(mParser); + MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT, DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT); MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT, @@ -717,6 +803,17 @@ public class JobSchedulerService extends com.android.server.SystemService pw.printPair(KEY_BG_MODERATE_JOB_COUNT, BG_MODERATE_JOB_COUNT).println(); pw.printPair(KEY_BG_LOW_JOB_COUNT, BG_LOW_JOB_COUNT).println(); pw.printPair(KEY_BG_CRITICAL_JOB_COUNT, BG_CRITICAL_JOB_COUNT).println(); + + MAX_JOB_COUNTS_ON_NORMAL.dump(pw, ""); + MAX_JOB_COUNTS_ON_MODERATE.dump(pw, ""); + MAX_JOB_COUNTS_ON_LOW.dump(pw, ""); + MAX_JOB_COUNTS_ON_CRITICAL.dump(pw, ""); + + MAX_JOB_COUNTS_OFF_NORMAL.dump(pw, ""); + MAX_JOB_COUNTS_OFF_MODERATE.dump(pw, ""); + MAX_JOB_COUNTS_OFF_LOW.dump(pw, ""); + MAX_JOB_COUNTS_OFF_CRITICAL.dump(pw, ""); + pw.printPair(KEY_MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT).println(); pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println(); pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println(); @@ -767,6 +864,9 @@ public class JobSchedulerService extends com.android.server.SystemService proto.write(ConstantsProto.BG_MODERATE_JOB_COUNT, BG_MODERATE_JOB_COUNT); proto.write(ConstantsProto.BG_LOW_JOB_COUNT, BG_LOW_JOB_COUNT); proto.write(ConstantsProto.BG_CRITICAL_JOB_COUNT, BG_CRITICAL_JOB_COUNT); + + // TODO Dump max job counts. + proto.write(ConstantsProto.MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT); proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT); proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME); diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java new file mode 100644 index 000000000000..29465ad366f4 --- /dev/null +++ b/services/core/java/com/android/server/location/GnssConfiguration.java @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2019 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.location; + +import android.content.Context; +import android.os.PersistableBundle; +import android.os.SystemProperties; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.text.TextUtils; +import android.util.Log; + +import libcore.io.IoUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + +/** + * A utility class to hold GNSS configuration properties. + * + * The trigger to load/reload the configuration parameters should be managed by the class + * that owns an instance of this class. + * + * Instances of this class are not thread-safe and should either be used from a single thread + * or with external synchronization when used by multiple threads. + */ +class GnssConfiguration { + private static final String TAG = "GnssConfiguration"; + + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + //TODO(b/33112647): Create gps_debug.conf with commented career parameters. + private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf"; + + // config.xml properties + private static final String CONFIG_SUPL_HOST = "SUPL_HOST"; + private static final String CONFIG_SUPL_PORT = "SUPL_PORT"; + private static final String CONFIG_C2K_HOST = "C2K_HOST"; + private static final String CONFIG_C2K_PORT = "C2K_PORT"; + private static final String CONFIG_SUPL_VER = "SUPL_VER"; + private static final String CONFIG_SUPL_MODE = "SUPL_MODE"; + private static final String CONFIG_SUPL_ES = "SUPL_ES"; + private static final String CONFIG_LPP_PROFILE = "LPP_PROFILE"; + private static final String CONFIG_A_GLONASS_POS_PROTOCOL_SELECT = + "A_GLONASS_POS_PROTOCOL_SELECT"; + private static final String CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL = + "USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL"; + private static final String CONFIG_GPS_LOCK = "GPS_LOCK"; + private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC"; + + // Limit on NI emergency mode time extension after emergency sessions ends + private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300; // 5 minute maximum + + // Persist property for LPP_PROFILE + static final String LPP_PROFILE = "persist.sys.gps.lpp"; + + // Represents an HAL interface version. Instances of this class are created in the JNI layer + // and returned through native methods. + private static class HalInterfaceVersion { + final int mMajor; + final int mMinor; + + HalInterfaceVersion(int major, int minor) { + mMajor = major; + mMinor = minor; + } + } + + /** + * Properties loaded from PROPERTIES_FILE. + */ + private Properties mProperties; + + private int mEsExtensionSec = 0; + + private final Context mContext; + + GnssConfiguration(Context context) { + mContext = context; + mProperties = new Properties(); + } + + /** + * Returns the full set of properties loaded. + */ + Properties getProperties() { + return mProperties; + } + + /** + * Returns the value of config parameter ES_EXTENSION_SEC. The value is range checked + * and constrained to min/max limits. + */ + int getEsExtensionSec() { + return mEsExtensionSec; + } + + /** + * Returns the value of config parameter SUPL_HOST or {@code null} if no value is + * provided. + */ + String getSuplHost() { + return mProperties.getProperty(CONFIG_SUPL_HOST); + } + + /** + * Returns the value of config parameter SUPL_PORT or {@code defaultPort} if no value is + * provided or if there is an error parsing the configured value. + */ + int getSuplPort(int defaultPort) { + return getIntConfig(CONFIG_SUPL_PORT, defaultPort); + } + + /** + * Returns the value of config parameter C2K_HOST or {@code null} if no value is + * provided. + */ + String getC2KHost() { + return mProperties.getProperty(CONFIG_C2K_HOST); + } + + /** + * Returns the value of config parameter C2K_PORT or {@code defaultPort} if no value is + * provided or if there is an error parsing the configured value. + */ + int getC2KPort(int defaultPort) { + return getIntConfig(CONFIG_C2K_PORT, defaultPort); + } + + /** + * Returns the value of config parameter SUPL_MODE or {@code defaultMode} if no value is + * provided or if there is an error parsing the configured value. + */ + int getSuplMode(int defaultMode) { + return getIntConfig(CONFIG_SUPL_MODE, defaultMode); + } + + /** + * Returns the value of config parameter SUPL_ES or {@code defaultSuplEs} if no value is + * provided or if there is an error parsing the configured value. + */ + int getSuplEs(int defaulSuplEs) { + return getIntConfig(CONFIG_SUPL_ES, defaulSuplEs); + } + + /** + * Returns the value of config parameter LPP_PROFILE or {@code null} if no value is + * provided. + */ + String getLppProfile() { + return mProperties.getProperty(CONFIG_LPP_PROFILE); + } + + /** + * Updates the GNSS HAL satellite blacklist. + */ + void setSatelliteBlacklist(int[] constellations, int[] svids) { + native_set_satellite_blacklist(constellations, svids); + } + + interface SetCarrierProperty { + boolean set(int value); + } + + /** + * Loads the GNSS properties from carrier config file followed by the properties from + * gps debug config file. + */ + void reloadGpsProperties() { + if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + mProperties.size()); + loadPropertiesFromCarrierConfig(); + + String lpp_prof = SystemProperties.get(LPP_PROFILE); + if (!TextUtils.isEmpty(lpp_prof)) { + // override default value of this if lpp_prof is not empty + mProperties.setProperty(CONFIG_LPP_PROFILE, lpp_prof); + } + /* + * Overlay carrier properties from a debug configuration file. + */ + loadPropertiesFromGpsDebugConfig(mProperties); + + mEsExtensionSec = getRangeCheckedConfigEsExtensionSec(); + + final HalInterfaceVersion gnssConfigurationIfaceVersion = + native_get_gnss_configuration_version(); + if (gnssConfigurationIfaceVersion != null) { + // Set to a range checked value. + if (isConfigEsExtensionSecSupported(gnssConfigurationIfaceVersion) + && !native_set_es_extension_sec(mEsExtensionSec)) { + Log.e(TAG, "Unable to set " + CONFIG_ES_EXTENSION_SEC + ": " + mEsExtensionSec); + } + + Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() { + { + put(CONFIG_SUPL_VER, GnssConfiguration::native_set_supl_version); + put(CONFIG_SUPL_MODE, GnssConfiguration::native_set_supl_mode); + + if (isConfigSuplEsSupported(gnssConfigurationIfaceVersion)) { + put(CONFIG_SUPL_ES, GnssConfiguration::native_set_supl_es); + } + + put(CONFIG_LPP_PROFILE, GnssConfiguration::native_set_lpp_profile); + put(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT, + GnssConfiguration::native_set_gnss_pos_protocol_select); + put(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL, + GnssConfiguration::native_set_emergency_supl_pdn); + + if (isConfigGpsLockSupported(gnssConfigurationIfaceVersion)) { + put(CONFIG_GPS_LOCK, GnssConfiguration::native_set_gps_lock); + } + } + }; + + for (Entry<String, SetCarrierProperty> entry : map.entrySet()) { + String propertyName = entry.getKey(); + String propertyValueString = mProperties.getProperty(propertyName); + if (propertyValueString != null) { + try { + int propertyValueInt = Integer.decode(propertyValueString); + boolean result = entry.getValue().set(propertyValueInt); + if (!result) { + Log.e(TAG, "Unable to set " + propertyName); + } + } catch (NumberFormatException e) { + Log.e(TAG, "Unable to parse propertyName: " + propertyValueString); + } + } + } + } else if (DEBUG) { + Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not" + + " supported"); + } + } + + /** + * Loads GNSS properties from carrier config file. + */ + void loadPropertiesFromCarrierConfig() { + CarrierConfigManager configManager = (CarrierConfigManager) + mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager == null) { + return; + } + PersistableBundle configs = configManager.getConfigForSubId( + SubscriptionManager.getDefaultDataSubscriptionId()); + if (configs == null) { + if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config."); + configs = CarrierConfigManager.getDefaultConfig(); + } + for (String configKey : configs.keySet()) { + if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) { + String key = configKey + .substring(CarrierConfigManager.Gps.KEY_PREFIX.length()) + .toUpperCase(); + Object value = configs.get(configKey); + if (value instanceof String) { + // All GPS properties are of String type; convert so. + if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value); + mProperties.setProperty(key, (String) value); + } + } + } + } + + private void loadPropertiesFromGpsDebugConfig(Properties properties) { + try { + File file = new File(DEBUG_PROPERTIES_FILE); + FileInputStream stream = null; + try { + stream = new FileInputStream(file); + properties.load(stream); + } finally { + IoUtils.closeQuietly(stream); + } + } catch (IOException e) { + if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE); + } + } + + private int getRangeCheckedConfigEsExtensionSec() { + int emergencyExtensionSeconds = getIntConfig(CONFIG_ES_EXTENSION_SEC, 0); + if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) { + Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds + + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS); + emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS; + } else if (emergencyExtensionSeconds < 0) { + Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds + + " is negative, reset to zero."); + emergencyExtensionSeconds = 0; + } + return emergencyExtensionSeconds; + } + + private int getIntConfig(String configParameter, int defaultValue) { + String valueString = mProperties.getProperty(configParameter); + if (TextUtils.isEmpty(valueString)) { + return defaultValue; + } + try { + return Integer.parseInt(valueString); + } catch (NumberFormatException e) { + Log.e(TAG, "Unable to parse config parameter " + configParameter + " value: " + + valueString + ". Using default value: " + defaultValue); + return defaultValue; + } + } + + private static boolean isConfigEsExtensionSecSupported( + HalInterfaceVersion gnssConfiguartionIfaceVersion) { + // ES_EXTENSION_SEC is introduced in @2.0::IGnssConfiguration.hal + return gnssConfiguartionIfaceVersion.mMajor >= 2; + } + + private static boolean isConfigSuplEsSupported( + HalInterfaceVersion gnssConfiguartionIfaceVersion) { + // SUPL_ES is deprecated in @2.0::IGnssConfiguration.hal + return gnssConfiguartionIfaceVersion.mMajor < 2; + } + + private static boolean isConfigGpsLockSupported( + HalInterfaceVersion gnssConfiguartionIfaceVersion) { + // GPS_LOCK is deprecated in @2.0::IGnssConfiguration.hal + return gnssConfiguartionIfaceVersion.mMajor < 2; + } + + private static native HalInterfaceVersion native_get_gnss_configuration_version(); + + private static native boolean native_set_supl_version(int version); + + private static native boolean native_set_supl_mode(int mode); + + private static native boolean native_set_supl_es(int es); + + private static native boolean native_set_lpp_profile(int lppProfile); + + private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect); + + private static native boolean native_set_gps_lock(int gpsLock); + + private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn); + + private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds); + + private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds); +} diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 05d77ab5867e..3c81a4569407 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -74,12 +74,7 @@ import com.android.internal.location.gnssmetrics.GnssMetrics; import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback; import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback; -import libcore.io.IoUtils; - -import java.io.File; import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -87,11 +82,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; /** * A GNSS implementation of LocationProvider used by LocationManager. @@ -147,7 +138,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private static final int LOCATION_HAS_SPEED_ACCURACY = 64; private static final int LOCATION_HAS_BEARING_ACCURACY = 128; - // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal private static final int GPS_DELETE_EPHEMERIS = 0x0001; private static final int GPS_DELETE_ALMANAC = 0x0002; @@ -200,9 +190,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; - //TODO(b/33112647): Create gps_debug.conf with commented career parameters. - private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf"; - // ref. location info private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1; private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2; @@ -375,7 +362,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements * Properties loaded from PROPERTIES_FILE. * It must be accessed only inside {@link #mHandler}. */ - private Properties mProperties; + private GnssConfiguration mGnssConfiguration; private String mSuplServerHost; private int mSuplServerPort = TCP_MIN_PORT; @@ -411,10 +398,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP"; private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT"; - // Persist property for LPP_PROFILE - private final static String LPP_PROFILE = "persist.sys.gps.lpp"; - - private final PowerManager mPowerManager; private final AlarmManager mAlarmManager; private final PendingIntent mWakeupIntent; @@ -502,7 +485,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements */ @Override public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) { - mHandler.post(() -> native_set_satellite_blacklist(constellations, svids)); + mHandler.post(() -> mGnssConfiguration.setSatelliteBlacklist(constellations, svids)); } private void subscriptionOrCarrierConfigChanged(Context context) { @@ -525,17 +508,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } if (isKeepLppProfile) { // load current properties for the carrier - loadPropertiesFromCarrierConfig(context, mProperties); - String lpp_profile = mProperties.getProperty("LPP_PROFILE"); + mGnssConfiguration.loadPropertiesFromCarrierConfig(); + String lpp_profile = mGnssConfiguration.getLppProfile(); // set the persist property LPP_PROFILE for the value if (lpp_profile != null) { - SystemProperties.set(LPP_PROFILE, lpp_profile); + SystemProperties.set(GnssConfiguration.LPP_PROFILE, lpp_profile); } } else { // reset the persist property - SystemProperties.set(LPP_PROFILE, ""); + SystemProperties.set(GnssConfiguration.LPP_PROFILE, ""); } - reloadGpsProperties(context, mProperties); + reloadGpsProperties(); mNIHandler.setSuplEsEnabled(mSuplEsEnabled); } } else { @@ -564,133 +547,14 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return native_is_supported(); } - interface SetCarrierProperty { - boolean set(int value); - } - - private void reloadGpsProperties(Context context, Properties properties) { - if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size()); - loadPropertiesFromCarrierConfig(context, properties); - - String lpp_prof = SystemProperties.get(LPP_PROFILE); - if (!TextUtils.isEmpty(lpp_prof)) { - // override default value of this if lpp_prof is not empty - properties.setProperty("LPP_PROFILE", lpp_prof); - } - /* - * Overlay carrier properties from a debug configuration file. - */ - loadPropertiesFromGpsDebugConfig(properties); + private void reloadGpsProperties() { + mGnssConfiguration.reloadGpsProperties(); + setSuplHostPort(); // TODO: we should get rid of C2K specific setting. - setSuplHostPort(properties.getProperty("SUPL_HOST"), - properties.getProperty("SUPL_PORT")); - mC2KServerHost = properties.getProperty("C2K_HOST"); - String portString = properties.getProperty("C2K_PORT"); - if (mC2KServerHost != null && portString != null) { - try { - mC2KServerPort = Integer.parseInt(portString); - } catch (NumberFormatException e) { - Log.e(TAG, "unable to parse C2K_PORT: " + portString); - } - } - if (native_is_gnss_configuration_supported()) { - Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() { - { - put("SUPL_VER", GnssLocationProvider::native_set_supl_version); - put("SUPL_MODE", GnssLocationProvider::native_set_supl_mode); - put("SUPL_ES", GnssLocationProvider::native_set_supl_es); - put("LPP_PROFILE", GnssLocationProvider::native_set_lpp_profile); - put("A_GLONASS_POS_PROTOCOL_SELECT", - GnssLocationProvider::native_set_gnss_pos_protocol_select); - put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", - GnssLocationProvider::native_set_emergency_supl_pdn); - put("GPS_LOCK", GnssLocationProvider::native_set_gps_lock); - } - }; - - for (Entry<String, SetCarrierProperty> entry : map.entrySet()) { - String propertyName = entry.getKey(); - String propertyValueString = properties.getProperty(propertyName); - if (propertyValueString != null) { - try { - int propertyValueInt = Integer.decode(propertyValueString); - boolean result = entry.getValue().set(propertyValueInt); - if (!result) { - Log.e(TAG, "Unable to set " + propertyName); - } - } catch (NumberFormatException e) { - Log.e(TAG, "unable to parse propertyName: " + propertyValueString); - } - } - } - } else if (DEBUG) { - Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not" - + " supported"); - } - - // SUPL_ES configuration. - String suplESProperty = mProperties.getProperty("SUPL_ES"); - if (suplESProperty != null) { - try { - mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1); - } catch (NumberFormatException e) { - Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty); - } - } - - String emergencyExtensionSecondsString - = properties.getProperty("ES_EXTENSION_SEC", "0"); - try { - int emergencyExtensionSeconds = - Integer.parseInt(emergencyExtensionSecondsString); - mNIHandler.setEmergencyExtensionSeconds(emergencyExtensionSeconds); - } catch (NumberFormatException e) { - Log.e(TAG, "unable to parse ES_EXTENSION_SEC: " - + emergencyExtensionSecondsString); - } - } - - private void loadPropertiesFromCarrierConfig(Context context, Properties properties) { - CarrierConfigManager configManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager == null) { - return; - } - PersistableBundle configs = configManager.getConfigForSubId( - SubscriptionManager.getDefaultDataSubscriptionId()); - if (configs == null) { - if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config."); - configs = CarrierConfigManager.getDefaultConfig(); - } - for (String configKey : configs.keySet()) { - if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) { - String key = configKey - .substring(CarrierConfigManager.Gps.KEY_PREFIX.length()) - .toUpperCase(); - Object value = configs.get(configKey); - if (value instanceof String) { - // All GPS properties are of String type; convert so. - if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value); - properties.setProperty(key, (String) value); - } - } - } - } - - private void loadPropertiesFromGpsDebugConfig(Properties properties) { - try { - File file = new File(DEBUG_PROPERTIES_FILE); - FileInputStream stream = null; - try { - stream = new FileInputStream(file); - properties.load(stream); - } finally { - IoUtils.closeQuietly(stream); - } - - } catch (IOException e) { - if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE); - } + mC2KServerHost = mGnssConfiguration.getC2KHost(); + mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT); + mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec()); + mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1; } public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager, @@ -733,7 +597,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // relative long time, so the ctor() is kept to create objects needed by this instance, // while IO initialization and registration is delegated to our internal handler // this approach is just fine because events are posted to our handler anyway - mProperties = new Properties(); + mGnssConfiguration = new GnssConfiguration(mContext); sendMessage(INITIALIZE_HANDLER, 0, null); // Create a GPS net-initiated handler. @@ -918,7 +782,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS); Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()"); AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { - GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties); + GpsXtraDownloader xtraDownloader = new GpsXtraDownloader( + mGnssConfiguration.getProperties()); byte[] data = xtraDownloader.downloadXtraData(); if (data != null) { if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data"); @@ -963,17 +828,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } - private void setSuplHostPort(String hostString, String portString) { - if (hostString != null) { - mSuplServerHost = hostString; - } - if (portString != null) { - try { - mSuplServerPort = Integer.parseInt(portString); - } catch (NumberFormatException e) { - Log.e(TAG, "unable to parse SUPL_PORT: " + portString); - } - } + private void setSuplHostPort() { + mSuplServerHost = mGnssConfiguration.getSuplHost(); + mSuplServerPort = mGnssConfiguration.getSuplPort(TCP_MIN_PORT); if (mSuplServerHost != null && mSuplServerPort > TCP_MIN_PORT && mSuplServerPort <= TCP_MAX_PORT) { @@ -986,23 +843,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements * Checks what SUPL mode to use, according to the AGPS mode as well as the * allowed mode from properties. * - * @param properties GPS properties * @param agpsEnabled whether AGPS is enabled by settings value * @param singleShot whether "singleshot" is needed * @return SUPL mode (MSA vs MSB vs STANDALONE) */ - private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) { + private int getSuplMode(boolean agpsEnabled, boolean singleShot) { if (agpsEnabled) { - String modeString = properties.getProperty("SUPL_MODE"); - int suplMode = 0; - if (!TextUtils.isEmpty(modeString)) { - try { - suplMode = Integer.parseInt(modeString); - } catch (NumberFormatException e) { - Log.e(TAG, "unable to parse SUPL_MODE: " + modeString); - return GPS_POSITION_MODE_STANDALONE; - } + int suplMode = mGnssConfiguration.getSuplMode(0); + if (suplMode == 0) { + return GPS_POSITION_MODE_STANDALONE; } + // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor // such mode when it is available if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { @@ -1307,7 +1158,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements boolean agpsEnabled = (Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0); - mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot); + mPositionMode = getSuplMode(agpsEnabled, singleShot); if (DEBUG) { String mode; @@ -1670,7 +1521,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // re-calls native_init() and other setup. handleEnable(); // resend configuration into the restarted HAL service. - reloadGpsProperties(mContext, mProperties); + reloadGpsProperties(); } }); } @@ -2072,7 +1923,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // load default GPS configuration // (this configuration might change in the future based on SIM changes) - reloadGpsProperties(mContext, mProperties); + reloadGpsProperties(); // TODO: When this object "finishes" we should unregister by invoking // SubscriptionManager.getInstance(mContext).unregister @@ -2227,8 +2078,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private static native boolean native_is_supported(); - private static native boolean native_is_gnss_configuration_supported(); - private static native void native_init_once(); private native boolean native_init(); @@ -2284,21 +2133,4 @@ public class GnssLocationProvider extends AbstractLocationProvider implements int lac, int cid); private native void native_agps_set_id(int type, String setid); - - // GNSS Configuration - private static native boolean native_set_supl_version(int version); - - private static native boolean native_set_supl_mode(int mode); - - private static native boolean native_set_supl_es(int es); - - private static native boolean native_set_lpp_profile(int lppProfile); - - private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect); - - private static native boolean native_set_gps_lock(int gpsLock); - - private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn); - - private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds); -} +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 139d8ac6a8d5..b70c64edc2cc 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -34,7 +34,6 @@ import android.media.session.ISessionControllerCallback; import android.media.session.MediaController; import android.media.session.MediaController.PlaybackInfo; import android.media.session.MediaSession; -import android.media.session.ParcelableVolumeInfo; import android.media.session.PlaybackState; import android.net.Uri; import android.os.Binder; @@ -628,7 +627,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { if (mDestroyed) { return; } - ParcelableVolumeInfo info = mController.getVolumeAttributes(); + PlaybackInfo info = mController.getVolumeAttributes(); for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) { ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i); try { @@ -1233,14 +1232,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } @Override - public ParcelableVolumeInfo getVolumeAttributes() { + public PlaybackInfo getVolumeAttributes() { int volumeType; AudioAttributes attributes; synchronized (mLock) { if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) { int current = mOptimisticVolume != -1 ? mOptimisticVolume : mCurrentVolume; - return new ParcelableVolumeInfo( - mVolumeType, mAudioAttrs, mVolumeControlType, mMaxVolume, current); + return new PlaybackInfo(mVolumeType, mVolumeControlType, mMaxVolume, current, + mAudioAttrs); } volumeType = mVolumeType; attributes = mAudioAttrs; @@ -1248,8 +1247,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { int stream = AudioAttributes.toLegacyStreamType(attributes); int max = mAudioManager.getStreamMaxVolume(stream); int current = mAudioManager.getStreamVolume(stream); - return new ParcelableVolumeInfo( - volumeType, attributes, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max, current); + return new PlaybackInfo(volumeType, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max, + current, attributes); } @Override diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 0d6dadfb1ad8..af55605975ca 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -270,14 +270,12 @@ import java.util.concurrent.TimeUnit; * enforcement. * * <p> - * This class uses 2-3 locks to synchronize state: + * This class uses 2 locks to synchronize state: * <ul> * <li>{@code mUidRulesFirstLock}: used to guard state related to individual UIDs (such as firewall * rules). * <li>{@code mNetworkPoliciesSecondLock}: used to guard state related to network interfaces (such * as network policies). - * <li>{@code allLocks}: not a "real" lock, but an indication (through @GuardedBy) that all locks - * must be held. * </ul> * * <p> @@ -419,7 +417,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final Object mUidRulesFirstLock = new Object(); final Object mNetworkPoliciesSecondLock = new Object(); - @GuardedBy("allLocks") volatile boolean mSystemReady; + @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"}) + volatile boolean mSystemReady; @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackground; @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictPower; @@ -558,7 +557,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private final ServiceThread mUidEventThread; - @GuardedBy("allLocks") + @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"}) private final AtomicFile mPolicyFile; private final AppOpsManager mAppOps; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index dc3bfbca893c..8c274e42c930 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -368,7 +368,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers"); mSystemDir = checkNotNull(systemDir, "missing systemDir"); mBaseDir = checkNotNull(baseDir, "missing baseDir"); - mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); + mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists(); } private void registerLocalService() { diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 88d73fb10902..c222e6948a3d 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -767,6 +767,23 @@ abstract public class ManagedServices { return installed; } + protected Set<String> getAllowedPackages() { + final Set<String> allowedPackages = new ArraySet<>(); + for (int k = 0; k < mApproved.size(); k++) { + ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k); + for (int i = 0; i < allowedByType.size(); i++) { + final ArraySet<String> allowed = allowedByType.valueAt(i); + for (int j = 0; j < allowed.size(); j++) { + String pkgName = getPackageName(allowed.valueAt(j)); + if (!TextUtils.isEmpty(pkgName)) { + allowedPackages.add(pkgName); + } + } + } + } + return allowedPackages; + } + private void trimApprovedListsAccordingToInstalledServices() { int N = mApproved.size(); for (int i = 0 ; i < N; i++) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index c2c88258b067..c68e0f98325e 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -765,8 +765,7 @@ public class NotificationManagerService extends SystemService { .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank) .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count) .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART, - (Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION - == action.getSemanticAction()) ? 1 : 0) + action.isContextual() ? 1 : 0) .addTaggedData( MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, generatedByAssistant ? 1 : 0)); @@ -970,7 +969,7 @@ public class NotificationManagerService extends SystemService { r.getNumSmartActionsAdded()) .addTaggedData( MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED, - r.getSuggestionsGeneratedByAssistant()); + r.getSuggestionsGeneratedByAssistant() ? 1 : 0); mMetricsLogger.write(logMaker); } } @@ -1702,8 +1701,16 @@ public class NotificationManagerService extends SystemService { } private void sendRegisteredOnlyBroadcast(String action) { - getContext().sendBroadcastAsUser(new Intent(action) - .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null); + Intent intent = new Intent(action); + getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), + UserHandle.ALL, null); + // explicitly send the broadcast to all DND packages, even if they aren't currently running + intent.setFlags(0); + final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages(); + for (String pkg : dndApprovedPackages) { + intent.setPackage(pkg); + getContext().sendBroadcastAsUser(intent, UserHandle.ALL); + } } @Override @@ -2642,6 +2649,9 @@ public class NotificationManagerService extends SystemService { // Zen mConditionProviders.onPackagesChanged(true, packages, uids); + // Snoozing + mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName); + // Reset notification preferences if (!fromApp) { mPreferencesHelper.onPackagesChanged( @@ -5698,19 +5708,17 @@ public class NotificationManagerService extends SystemService { } int indexBefore = findNotificationRecordIndexLocked(record); boolean interceptBefore = record.isIntercepted(); - float contactAffinityBefore = record.getContactAffinity(); int visibilityBefore = record.getPackageVisibilityOverride(); recon.applyChangesLocked(record); applyZenModeLocked(record); mRankingHelper.sort(mNotificationList); int indexAfter = findNotificationRecordIndexLocked(record); boolean interceptAfter = record.isIntercepted(); - float contactAffinityAfter = record.getContactAffinity(); int visibilityAfter = record.getPackageVisibilityOverride(); changed = indexBefore != indexAfter || interceptBefore != interceptAfter || visibilityBefore != visibilityAfter; if (interceptBefore && !interceptAfter - && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) { + && record.isNewEnoughForAlerting(System.currentTimeMillis())) { buzzBeepBlinkLocked(record); } } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index e2c64ca459a8..9942f5920c9e 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -92,6 +92,8 @@ public final class NotificationRecord { static final String TAG = "NotificationRecord"; static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); private static final int MAX_LOGTAG_LENGTH = 35; + // the period after which a notification is updated where it can make sound + private static final int MAX_SOUND_DELAY_MS = 2000; final StatusBarNotification sbn; IActivityManager mAm; UriGrantsManagerInternal mUgmInternal; @@ -125,7 +127,8 @@ public final class NotificationRecord { private long mVisibleSinceMs; // The most recent update time, or the creation time if no updates. - private long mUpdateTimeMs; + @VisibleForTesting + final long mUpdateTimeMs; // The most recent interruption time, or the creation time if no updates. Differs from the // above value because updates are filtered based on whether they actually interrupted the @@ -165,7 +168,7 @@ public final class NotificationRecord { private String mChannelIdLogTag; /** * This list contains system generated smart actions from NAS, app-generated smart actions are - * stored in Notification.actions marked as SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION. + * stored in Notification.actions with isContextual() set to true. */ private ArrayList<Notification.Action> mSystemGeneratedSmartActions; private ArrayList<CharSequence> mSmartReplies; @@ -826,6 +829,10 @@ public final class NotificationRecord { return mIntercept; } + public boolean isNewEnoughForAlerting(long now) { + return getFreshnessMs(now) <= MAX_SOUND_DELAY_MS; + } + public void setHidden(boolean hidden) { mHidden = hidden; } diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java index 2b581d601ad5..abc98412e126 100644 --- a/services/core/java/com/android/server/notification/SnoozeHelper.java +++ b/services/core/java/com/android/server/notification/SnoozeHelper.java @@ -17,6 +17,7 @@ package com.android.server.notification; import android.annotation.NonNull; import android.app.AlarmManager; +import android.app.Notification; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; @@ -163,7 +164,6 @@ public class SnoozeHelper { mSnoozedNotifications.get(userId).get(pkg); if (recordsForPkg != null) { final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet(); - String key = null; for (Map.Entry<String, NotificationRecord> record : records) { final StatusBarNotification sbn = record.getValue().sbn; if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) { @@ -305,6 +305,30 @@ public class SnoozeHelper { } } + protected void clearData(int userId, String pkg) { + ArrayMap<String, ArrayMap<String, NotificationRecord>> records = + mSnoozedNotifications.get(userId); + if (records == null) { + return; + } + ArrayMap<String, NotificationRecord> pkgRecords = records.get(pkg); + if (pkgRecords == null) { + return; + } + for (int i = pkgRecords.size() - 1; i >= 0; i--) { + final NotificationRecord r = pkgRecords.removeAt(i); + if (r != null) { + mPackages.remove(r.getKey()); + mUsers.remove(r.getKey()); + final PendingIntent pi = createPendingIntent(pkg, r.getKey(), userId); + mAm.cancel(pi); + MetricsLogger.action(r.getLogMaker() + .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) + .setType(MetricsProto.MetricsEvent.TYPE_DISMISS)); + } + } + } + private PendingIntent createPendingIntent(String pkg, String key, int userId) { return PendingIntent.getBroadcast(mContext, REQUEST_CODE_REPOST, diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index e5b1878650d3..afc0b7230e27 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -375,8 +375,7 @@ public class ZenModeHelper { newConfig = mConfig.copy(); for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) { ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i)); - if (rule.component.getPackageName().equals(packageName) - && canManageAutomaticZenRule(rule)) { + if (rule.pkg.equals(packageName) && canManageAutomaticZenRule(rule)) { newConfig.automaticRules.removeAt(i); } } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index f9e31aed1174..5412e9425adf 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -85,9 +85,6 @@ public class PackageDexOptimizer { // One minute over PM WATCHDOG_TIMEOUT private static final long WAKELOCK_TIMEOUT_MS = WATCHDOG_TIMEOUT + 1000 * 60; - /** Special library name that skips shared libraries check during compilation. */ - public static final String SKIP_SHARED_LIBRARY_CHECK = "&"; - @GuardedBy("mInstallLock") private final Installer mInstaller; private final Object mInstallLock; @@ -397,23 +394,23 @@ public class PackageDexOptimizer { Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName); return DEX_OPT_FAILED; } - Log.d(TAG, "Running dexopt on: " + path - + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas() - + " dexoptFlags=" + printDexoptFlags(dexoptFlags) - + " target-filter=" + compilerFilter); - - String classLoaderContext; + String classLoaderContext = null; if (dexUseInfo.isUnknownClassLoaderContext() || dexUseInfo.isVariableClassLoaderContext()) { - // If we have an unknown (not yet set), or a variable class loader chain, compile - // without a context and mark the oat file with SKIP_SHARED_LIBRARY_CHECK. Note that - // this might lead to a incorrect compilation. - // TODO(calin): We should just extract in this case. - classLoaderContext = SKIP_SHARED_LIBRARY_CHECK; + // If we have an unknown (not yet set), or a variable class loader chain. Just extract + // the dex file. + compilerFilter = "extract"; } else { classLoaderContext = dexUseInfo.getClassLoaderContext(); } int reason = options.getCompilationReason(); + Log.d(TAG, "Running dexopt on: " + path + + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas() + + " reason=" + getReasonName(reason) + + " dexoptFlags=" + printDexoptFlags(dexoptFlags) + + " target-filter=" + compilerFilter + + " class-loader-context=" + classLoaderContext); + try { for (String isa : dexUseInfo.getLoaderIsas()) { // Reuse the same dexopt path as for the primary apks. We don't need all the diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 982daa5df2d5..5cb6c342e5e3 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -57,6 +57,7 @@ import android.content.pm.IPackageInstallerSession; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; import android.content.pm.PackageParser; @@ -982,9 +983,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mSealed = true; // Read transfers from the original owner stay open, but as the session's data - // cannot be modified anymore, there is no leak of information. - // For staged sessions, the validation is performed by StagingManager. - if (!params.isMultiPackage && !params.isStaged) { + // cannot be modified anymore, there is no leak of information. For staged sessions, + // further validation may be performed by the staging manager. + if (!params.isMultiPackage) { final PackageInfo pkgInfo = mPm.getPackageInfo( params.appPackageName, PackageManager.GET_SIGNATURES | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId); @@ -1328,18 +1329,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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"); - } + // STOPSHIP: Ensure that we remove the non-staged version of APEX installs in production + // because we currently do not verify that signatures are consistent with the previously + // installed version in that case. + // + // When that happens, this hack can be reverted and we can rely on APEXd to map between + // APEX files and their package names instead of parsing it out of the AndroidManifest + // such as here. + if (params.appPackageName == null) { + params.appPackageName = mPackageName; } } @@ -1374,7 +1372,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "Missing existing base package"); } // Default to require only if existing base has fs-verity. - mVerityFound = params.mode == SessionParams.MODE_INHERIT_EXISTING + mVerityFound = PackageManagerServiceUtils.isApkVerityEnabled() + && params.mode == SessionParams.MODE_INHERIT_EXISTING && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath()); try { @@ -2011,6 +2010,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** {@hide} */ + void setStagedSessionFailed(@StagedSessionErrorCode int errorCode) { + synchronized (mLock) { + mStagedSessionReady = false; + mStagedSessionApplied = false; + mStagedSessionFailed = true; + mStagedSessionErrorCode = errorCode; + } + } + private void destroyInternal() { synchronized (mLock) { mSealed = true; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index fe89be6f73c4..33019627efda 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8572,7 +8572,7 @@ public class PackageManagerService extends IPackageManager.Stub * match one in a trusted source, and should be done separately. */ private boolean canSkipForcedApkVerification(String apkPath) { - if (!PackageManagerServiceUtils.isLegacyApkVerityMode()) { + if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) { return VerityUtils.hasFsverity(apkPath); } @@ -15618,13 +15618,25 @@ public class PackageManagerService extends IPackageManager.Stub if (!hasDynamicLibraries) { return null; } + final boolean isUpdatedSystemApp = pkg.isUpdatedSystemApp(); + // We may not yet have disabled the updated package yet, so be sure to grab the + // current setting if that's the case. + final PackageSetting updatedSystemPs = isUpdatedSystemApp + ? scanResult.request.disabledPkgSetting == null + ? scanResult.request.oldPkgSetting + : scanResult.request.disabledPkgSetting + : null; + if (isUpdatedSystemApp && (updatedSystemPs.pkg == null + || updatedSystemPs.pkg.libraryNames == null)) { + Slog.w(TAG, "Package " + pkg.packageName + " declares libraries that are not " + + "declared on the system image; skipping"); + return null; + } final ArrayList<SharedLibraryInfo> infos = new ArrayList<>(scanResult.dynamicSharedLibraryInfos.size()); - final boolean updatedSystemApp = pkg.isUpdatedSystemApp(); for (SharedLibraryInfo info : scanResult.dynamicSharedLibraryInfos) { - String name = info.getName(); - boolean allowed = false; - if (updatedSystemApp) { + final String name = info.getName(); + if (isUpdatedSystemApp) { // New library entries can only be added through the // system image. This is important to get rid of a lot // of nasty edge cases: for example if we allowed a non- @@ -15634,36 +15646,20 @@ public class PackageManagerService extends IPackageManager.Stub // have allowed apps on the device which aren't compatible // with it. Better to just have the restriction here, be // conservative, and create many fewer cases that can negatively - // impact the user experience. We may not yet have disabled the - // updated package yet, so be sure to grab the current setting if - // that's the case. - final PackageSetting sysPs = scanResult.request.disabledPkgSetting == null - ? scanResult.request.oldPkgSetting - : scanResult.request.disabledPkgSetting; - if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) { - for (int j = 0; j < sysPs.pkg.libraryNames.size(); j++) { - if (name.equals(sysPs.pkg.libraryNames.get(j))) { - allowed = true; - break; - } - } - } - } else { - allowed = true; - } - if (allowed) { - if (sharedLibExists( - name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) { - Slog.w(TAG, "Package " + pkg.packageName + " library " - + name + " already exists; skipping"); + // impact the user experience. + if (!updatedSystemPs.pkg.libraryNames.contains(name)) { + Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name + + " that is not declared on system image; skipping"); continue; } - infos.add(info); - } else { - Slog.w(TAG, "Package " + pkg.packageName + " declares lib " - + name + " that is not declared on system image; skipping"); + } + if (sharedLibExists( + name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) { + Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name + + " that already exists; skipping"); continue; } + infos.add(info); } return infos; } @@ -16866,10 +16862,11 @@ public class PackageManagerService extends IPackageManager.Stub */ private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException, PrepareFailure, IOException, DigestException, NoSuchAlgorithmException { - if (!PackageManagerServiceUtils.isApkVerityEnabled()) { + final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled(); + final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled(); + if (!standardMode && !legacyMode) { return; } - final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityMode(); // Collect files we care for fs-verity setup. ArrayMap<String, String> fsverityCandidates = new ArrayMap<>(); diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 25169a24d932..6134d3098e3b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -555,19 +555,19 @@ public class PackageManagerServiceUtils { /** Standard fs-verity. */ private static final int FSVERITY_ENABLED = 2; - /** Returns true if APK Verity is enabled. */ + /** Returns true if standard APK Verity is enabled. */ static boolean isApkVerityEnabled() { - int mode = SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED); - return mode == FSVERITY_LEGACY || mode == FSVERITY_ENABLED; + return SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED) == FSVERITY_ENABLED; } - static boolean isLegacyApkVerityMode() { + static boolean isLegacyApkVerityEnabled() { return SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED) == FSVERITY_LEGACY; } /** Returns true to force apk verification if the updated package (in /data) is a priv app. */ static boolean isApkVerificationForced(@Nullable PackageSetting disabledPs) { - return disabledPs != null && disabledPs.isPrivileged() && isApkVerityEnabled(); + return disabledPs != null && disabledPs.isPrivileged() && ( + isApkVerityEnabled() || isLegacyApkVerityEnabled()); } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 2e9d26a0a0ca..c9d298cc28c2 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -2293,9 +2293,7 @@ class PackageManagerShellCommand extends ShellCommand { break; case "--apex": sessionParams.installFlags |= PackageManager.INSTALL_APEX; - // TODO(b/118865310): APEX packages should always imply - // sessionParams.isStaged(). Enforce this when the staged - // install workflow is complete. + sessionParams.setStaged(); break; case "--multi-package": sessionParams.setMultiPackage(); diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java index b47d96622e96..b4154c7476a1 100644 --- a/services/core/java/com/android/server/pm/SELinuxMMAC.java +++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java @@ -17,8 +17,8 @@ package com.android.server.pm; import android.content.pm.PackageParser; -import android.content.pm.Signature; import android.content.pm.PackageParser.SigningDetails; +import android.content.pm.Signature; import android.os.Environment; import android.util.Slog; import android.util.Xml; @@ -81,6 +81,13 @@ public final class SELinuxMMAC { sMacPermissions.add(new File( Environment.getRootDirectory(), "/etc/selinux/plat_mac_permissions.xml")); + // Product mac permissions (optional). + final File productMacPermission = new File( + Environment.getProductDirectory(), "/etc/selinux/product_mac_permissions.xml"); + if (productMacPermission.exists()) { + sMacPermissions.add(productMacPermission); + } + // Vendor mac permissions. // The filename has been renamed from nonplat_mac_permissions to // vendor_mac_permissions. Either of them should exist. diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 3beda6a3f92b..23293567be46 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -17,10 +17,23 @@ package com.android.server.pm; import android.annotation.NonNull; +import android.apex.ApexInfo; +import android.apex.IApexService; import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.PackageParser.SigningDetails; +import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.ParceledListSlice; +import android.content.pm.Signature; import android.os.Handler; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.TextUtils; +import android.util.Slog; import android.util.SparseArray; +import android.util.apk.ApkSignatureVerifier; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; @@ -71,14 +84,70 @@ public class StagingManager { return new ParceledListSlice<>(result); } + private static boolean validateApexSignatureLocked(String apexPath, String packageName) { + final SigningDetails signingDetails; + try { + signingDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR); + } catch (PackageParserException e) { + Slog.e(TAG, "Unable to parse APEX package: " + apexPath, e); + return false; + } + + final IApexService apex = IApexService.Stub.asInterface( + ServiceManager.getService("apexservice")); + final ApexInfo apexInfo; + try { + apexInfo = apex.getActivePackage(packageName); + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact APEXD", re); + return false; + } + + if (apexInfo == null || TextUtils.isEmpty(apexInfo.packageName)) { + // TODO: What is the right thing to do here ? This implies there's no active package + // with the given name. This should never be the case in production (where we only + // accept updates to existing APEXes) but may be required for testing. + return true; + } + + final SigningDetails existingSigningDetails; + try { + existingSigningDetails = ApkSignatureVerifier.verify( + apexInfo.packagePath, SignatureSchemeVersion.JAR); + } catch (PackageParserException e) { + Slog.e(TAG, "Unable to parse APEX package: " + apexInfo.packagePath, e); + return false; + } + + // Now that we have both sets of signatures, demand that they're an exact match. + if (Signature.areExactMatch(existingSigningDetails.signatures, signingDetails.signatures)) { + return true; + } + + return false; + } + void commitSession(@NonNull PackageInstallerSession sessionInfo) { updateStoredSession(sessionInfo); mBgHandler.post(() -> { - // TODO(b/118865310): Dispatch the session to apexd/PackageManager for verification. For - // now we directly mark it as ready. sessionInfo.setStagedSessionReady(); - mPm.sendSessionUpdatedBroadcast(sessionInfo.generateInfo(), sessionInfo.userId); + + SessionInfo session = sessionInfo.generateInfo(false); + // For APEXes, we validate the signature here before we write the package to the + // staging directory. For APKs, the signature verification will be done by the package + // manager at the point at which it applies the staged install. + // + // TODO: Decide whether we want to fail fast by detecting signature mismatches right + // away. + if ((sessionInfo.params.installFlags & PackageManager.INSTALL_APEX) != 0) { + if (!validateApexSignatureLocked(session.resolvedBaseCodePath, + session.appPackageName)) { + sessionInfo.setStagedSessionFailed(SessionInfo.VERIFICATION_FAILED); + } + } + + mPm.sendSessionUpdatedBroadcast(sessionInfo.generateInfo(false), sessionInfo.userId); }); } diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java index 93ee44cdf0ce..91ad11e53538 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java +++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java @@ -22,7 +22,6 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.os.ClassLoaderFactory; -import com.android.server.pm.PackageDexOptimizer; import java.io.File; import java.util.List; @@ -275,15 +274,11 @@ public final class DexoptUtils { /** * Encodes a single class loader dependency starting from {@param path} and * {@param classLoaderName}. - * When classpath is {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns - * the same. This special property is used only during OTA. * NOTE: Keep this in sync with the dexopt expectations! Right now that is either "PCL[path]" * for a PathClassLoader or "DLC[path]" for a DelegateLastClassLoader. */ /*package*/ static String encodeClassLoader(String classpath, String classLoaderName) { - if (classpath.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK)) { - return classpath; - } + classpath.getClass(); // Throw NPE if classpath is null String classLoaderDexoptEncoding = classLoaderName; if (ClassLoaderFactory.isPathClassLoaderName(classLoaderName)) { classLoaderDexoptEncoding = "PCL"; @@ -306,16 +301,10 @@ public final class DexoptUtils { /** * Links to dependencies together in a format accepted by dexopt. * For the special case when either of cl1 or cl2 equals - * {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns the same. This - * property is used only during OTA. * NOTE: Keep this in sync with the dexopt expectations! Right now that is a list of split * dependencies {@see encodeClassLoader} separated by ';'. */ /*package*/ static String encodeClassLoaderChain(String cl1, String cl2) { - if (cl1.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK) || - cl2.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK)) { - return PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK; - } if (cl1.isEmpty()) return cl2; if (cl2.isEmpty()) return cl1; return cl1 + ";" + cl2; diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 5adc248cee79..c3f20aab568e 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -755,9 +755,10 @@ public class Notifier { }; /** - * Plays the wireless charging sound for both wireless and non-wireless charging + * If enabled, plays a sound and/or vibration when wireless or non-wireless charging has started */ - private void playChargingStartedSound(@UserIdInt int userId) { + private void playChargingStartedFeedback(@UserIdInt int userId) { + playChargingStartedVibration(userId); final String soundPath = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.CHARGING_STARTED_SOUND); if (isChargingFeedbackEnabled(userId) && soundPath != null) { @@ -773,8 +774,7 @@ public class Notifier { } private void showWirelessChargingStarted(int batteryLevel, @UserIdInt int userId) { - playWirelessChargingVibration(userId); - playChargingStartedSound(userId); + playChargingStartedFeedback(userId); if (mStatusBarManagerInternal != null) { mStatusBarManagerInternal.showChargingAnimation(batteryLevel); } @@ -782,7 +782,7 @@ public class Notifier { } private void showWiredChargingStarted(@UserIdInt int userId) { - playChargingStartedSound(userId); + playChargingStartedFeedback(userId); mSuspendBlocker.release(); } @@ -790,7 +790,7 @@ public class Notifier { mTrustManager.setDeviceLockedForUser(userId, true /*locked*/); } - private void playWirelessChargingVibration(@UserIdInt int userId) { + private void playChargingStartedVibration(@UserIdInt int userId) { final boolean vibrateEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0; if (vibrateEnabled && isChargingFeedbackEnabled(userId)) { diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java index f262f6dabbe0..a60f16d7ca27 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java @@ -15,8 +15,14 @@ */ package com.android.server.power.batterysaver; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; import android.database.ContentObserver; import android.os.Handler; import android.os.PowerManager; @@ -26,6 +32,7 @@ import android.provider.Settings.Global; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; @@ -46,6 +53,8 @@ import java.io.PrintWriter; */ public class BatterySaverStateMachine { private static final String TAG = "BatterySaverStateMachine"; + private static final String DYNAMIC_MODE_NOTIF_CHANNEL_ID = "dynamic_mode_notification"; + private static final int DYNAMIC_MODE_NOTIFICATION_ID = 1992; private final Object mLock; private static final boolean DEBUG = BatterySaverPolicy.DEBUG; @@ -484,6 +493,13 @@ public class BatterySaverStateMachine { } mBatterySaverController.enableBatterySaver(enable, intReason); + // Handle triggering the notification to show/hide when appropriate + if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON) { + runOnBgThread(this::triggerDynamicModeNotification); + } else if (!enable) { + runOnBgThread(this::hideDynamicModeNotification); + } + if (DEBUG) { Slog.d(TAG, "Battery saver: Enabled=" + enable + " manual=" + manual @@ -491,6 +507,44 @@ public class BatterySaverStateMachine { } } + private void triggerDynamicModeNotification() { + NotificationManager manager = mContext.getSystemService(NotificationManager.class); + ensureNotificationChannelExists(manager); + + manager.notify(DYNAMIC_MODE_NOTIFICATION_ID, buildNotification()); + } + + private void ensureNotificationChannelExists(NotificationManager manager) { + NotificationChannel channel = new NotificationChannel( + DYNAMIC_MODE_NOTIF_CHANNEL_ID, + mContext.getText( + R.string.dynamic_mode_notification_channel_name), + NotificationManager.IMPORTANCE_DEFAULT); + channel.setSound(null, null); + manager.createNotificationChannel(channel); + } + + private Notification buildNotification() { + Resources res = mContext.getResources(); + Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + PendingIntent batterySaverIntent = PendingIntent.getActivity( + mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT); + + return new Notification.Builder(mContext, DYNAMIC_MODE_NOTIF_CHANNEL_ID) + .setSmallIcon(R.drawable.ic_battery) + .setContentTitle(res.getString(R.string.dynamic_mode_notification_title)) + .setContentText(res.getString(R.string.dynamic_mode_notification_summary)) + .setContentIntent(batterySaverIntent) + .setOnlyAlertOnce(true) + .build(); + } + + private void hideDynamicModeNotification() { + NotificationManager manager = mContext.getSystemService(NotificationManager.class); + manager.cancel(DYNAMIC_MODE_NOTIFICATION_ID); + } + @GuardedBy("mLock") private void updateSnoozingLocked(boolean snoozing, String reason) { if (mBatterySaverSnoozing == snoozing) { diff --git a/services/core/java/com/android/server/rollback/RollbackManagerService.java b/services/core/java/com/android/server/rollback/RollbackManagerService.java index 8c3f04f3b8a8..4b5e76497f62 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerService.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerService.java @@ -17,8 +17,6 @@ package com.android.server.rollback; import android.content.Context; -import android.os.SELinux; -import android.util.Log; import com.android.server.SystemService; @@ -30,8 +28,6 @@ import com.android.server.SystemService; */ public final class RollbackManagerService extends SystemService { - private static final String TAG = "RollbackManager"; - private RollbackManagerServiceImpl mService; public RollbackManagerService(Context context) { @@ -41,12 +37,6 @@ public final class RollbackManagerService extends SystemService { @Override public void onStart() { mService = new RollbackManagerServiceImpl(getContext()); - - // TODO: Set up sepolicy to allow publishing the service. - if (SELinux.isSELinuxEnforced()) { - Log.w(TAG, "RollbackManager disabled pending selinux policy updates"); - } else { - publishBinderService(Context.ROLLBACK_SERVICE, mService); - } + publishBinderService(Context.ROLLBACK_SERVICE, mService); } } diff --git a/services/core/java/com/android/server/rollback/TEST_MAPPING b/services/core/java/com/android/server/rollback/TEST_MAPPING new file mode 100644 index 000000000000..c1d95ac85c23 --- /dev/null +++ b/services/core/java/com/android/server/rollback/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "RollbackTest" + } + ] +} diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index f00877030145..410f864b5893 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -89,6 +89,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.Xml; import android.view.Display; +import android.view.DisplayInfo; import android.view.IWindowManager; import com.android.internal.R; @@ -350,12 +351,34 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) { + if (wallpaper.connection != null) { + wallpaper.connection.forEachDisplayConnector(connector -> { + notifyWallpaperColorsChangedOnDisplay(wallpaper, which, connector.mDisplayId); + }); + } else { // Lock wallpaper does not have WallpaperConnection. + notifyWallpaperColorsChangedOnDisplay(wallpaper, which, DEFAULT_DISPLAY); + } + } + + private RemoteCallbackList<IWallpaperManagerCallback> getWallpaperCallbacks(int userId, + int displayId) { + RemoteCallbackList<IWallpaperManagerCallback> listeners = null; + final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> displayListeners = + mColorsChangedListeners.get(userId); + if (displayListeners != null) { + listeners = displayListeners.get(displayId); + } + return listeners; + } + + private void notifyWallpaperColorsChangedOnDisplay(@NonNull WallpaperData wallpaper, int which, + int displayId) { boolean needsExtraction; synchronized (mLock) { final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners = - mColorsChangedListeners.get(wallpaper.userId); + getWallpaperCallbacks(wallpaper.userId, displayId); final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners = - mColorsChangedListeners.get(UserHandle.USER_ALL); + getWallpaperCallbacks(UserHandle.USER_ALL, displayId); // No-op until someone is listening to it. if (emptyCallbackList(currentUserColorListeners) && emptyCallbackList(userAllColorListeners)) { @@ -363,7 +386,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } if (DEBUG) { - Slog.v(TAG, "notifyWallpaperColorsChanged " + which); + Slog.v(TAG, "notifyWallpaperColorsChangedOnDisplay " + which); } needsExtraction = wallpaper.primaryColors == null; @@ -371,7 +394,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Let's notify the current values, it's fine if it's null, it just means // that we don't know yet. - notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId); + notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId); if (needsExtraction) { extractColors(wallpaper); @@ -381,7 +404,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return; } } - notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId); + notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId); } } @@ -390,14 +413,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which, - int userId) { + int userId, int displayId) { final IWallpaperManagerCallback keyguardListener; final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>(); synchronized (mLock) { final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners = - mColorsChangedListeners.get(userId); + getWallpaperCallbacks(userId, displayId); final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners = - mColorsChangedListeners.get(UserHandle.USER_ALL); + getWallpaperCallbacks(UserHandle.USER_ALL, displayId); keyguardListener = mKeyguardListener; if (currentUserColorListeners != null) { @@ -427,7 +450,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - if (keyguardListener != null) { + // Only shows Keyguard on default display + if (keyguardListener != null && displayId == DEFAULT_DISPLAY) { try { keyguardListener.onWallpaperColorsChanged(wallpaperColors, which, userId); } catch (RemoteException e) { @@ -446,6 +470,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub String cropFile = null; int wallpaperId; + if (wallpaper.equals(mFallbackWallpaper)) { + extractDefaultImageWallpaperColors(); + return; + } + synchronized (mLock) { // Not having a wallpaperComponent means it's a lock screen wallpaper. final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent) @@ -482,6 +511,39 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + private void extractDefaultImageWallpaperColors() { + synchronized (mLock) { + if (mFallbackWallpaper.primaryColors != null) return; + } + + if (DEBUG) Slog.d(TAG, "Extract default image wallpaper colors"); + WallpaperColors colors = null; + final InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM); + if (is != null) { + try { + final BitmapFactory.Options options = new BitmapFactory.Options(); + final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); + if (bitmap != null) { + colors = WallpaperColors.fromBitmap(bitmap); + bitmap.recycle(); + } + } catch (OutOfMemoryError e) { + Slog.w(TAG, "Can't decode default wallpaper stream", e); + } finally { + IoUtils.closeQuietly(is); + } + } + + if (colors == null) { + Slog.e(TAG, "Extract default image wallpaper colors failed"); + return; + } + + synchronized (mLock) { + mFallbackWallpaper.primaryColors = colors; + } + } + /** * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped * for display. @@ -539,6 +601,20 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // scale if the crop height winds up not matching the recommended metrics needScale = (wpData.mHeight != cropHint.height()); + //make sure screen aspect ratio is preserved if width is scaled under screen size + if (needScale) { + final DisplayInfo displayInfo = new DisplayInfo(); + mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); + final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height(); + final int newWidth = (int) (cropHint.width() * scaleByHeight); + if (newWidth < displayInfo.logicalWidth) { + final float screenAspectRatio = + (float) displayInfo.logicalHeight / (float) displayInfo.logicalWidth; + cropHint.bottom = (int) (cropHint.width() * screenAspectRatio); + needCrop = true; + } + } + if (DEBUG) { Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height()); Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight); @@ -696,6 +772,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub targetWallpaper.connection.removeDisplayConnector(displayId); removeDisplayData(displayId); } + for (int i = mColorsChangedListeners.size() - 1; i >= 0; i--) { + final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> callbacks = + mColorsChangedListeners.valueAt(i); + callbacks.delete(displayId); + } } } @@ -706,9 +787,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub /** * Map of color listeners per user id. - * The key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners. + * The first key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners. + * The secondary key will be the display id, which means which display the listener is + * interested in. */ - private final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> + private final SparseArray<SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>> mColorsChangedListeners; private WallpaperData mLastWallpaper; private IWallpaperManagerCallback mKeyguardListener; @@ -1228,9 +1311,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub /** * Called by a live wallpaper if its colors have changed. * @param primaryColors representation of wallpaper primary colors + * @param displayId for which display */ @Override - public void onWallpaperColorsChanged(WallpaperColors primaryColors) { + public void onWallpaperColorsChanged(WallpaperColors primaryColors, int displayId) { int which; synchronized (mLock) { // Do not broadcast changes on ImageWallpaper since it's handled @@ -1243,14 +1327,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Live wallpapers always are system wallpapers. which = FLAG_SYSTEM; - // It's also the lock screen wallpaper when we don't have a bitmap in there - WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId); - if (lockedWallpaper == null) { - which |= FLAG_LOCK; + // It's also the lock screen wallpaper when we don't have a bitmap in there. + if (displayId == DEFAULT_DISPLAY) { + final WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId); + if (lockedWallpaper == null) { + which |= FLAG_LOCK; + } } } if (which != 0) { - notifyWallpaperColorsChanged(mWallpaper, which); + notifyWallpaperColorsChangedOnDisplay(mWallpaper, which, displayId); } } @@ -1277,16 +1363,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub Slog.w(TAG, "Failed to set ambient mode state", e); } } - // TODO(multi-display) So far, we have shared the same wallpaper on each display. - // Once we have multiple wallpapers on multiple displays, please complete here. - if (displayId == DEFAULT_DISPLAY) { - try { - // This will trigger onComputeColors in the wallpaper engine. - // It's fine to be locked in here since the binder is oneway. - connector.mEngine.requestWallpaperColors(); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to request wallpaper colors", e); - } + try { + // This will trigger onComputeColors in the wallpaper engine. + // It's fine to be locked in here since the binder is oneway. + connector.mEngine.requestWallpaperColors(); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to request wallpaper colors", e); } } } @@ -1681,6 +1763,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub FgThread.getHandler().post(() -> { notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM); notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK); + notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM); }); } @@ -1743,6 +1826,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // When clearing a wallpaper, broadcast new valid colors if (data != null) { notifyWallpaperColorsChanged(data, which); + notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM); } } @@ -2084,35 +2168,47 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } @Override - public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) { + public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, + int displayId) { userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "registerWallpaperColorsCallback", null); synchronized (mLock) { - RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners = - mColorsChangedListeners.get(userId); - if (userColorsChangedListeners == null) { - userColorsChangedListeners = new RemoteCallbackList<>(); - mColorsChangedListeners.put(userId, userColorsChangedListeners); + SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> + userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId); + if (userDisplayColorsChangedListeners == null) { + userDisplayColorsChangedListeners = new SparseArray<>(); + mColorsChangedListeners.put(userId, userDisplayColorsChangedListeners); + } + RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners = + userDisplayColorsChangedListeners.get(displayId); + if (displayChangedListeners == null) { + displayChangedListeners = new RemoteCallbackList<>(); + userDisplayColorsChangedListeners.put(displayId, displayChangedListeners); } - userColorsChangedListeners.register(cb); + displayChangedListeners.register(cb); } } @Override - public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) { + public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, + int displayId) { userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "unregisterWallpaperColorsCallback", null); synchronized (mLock) { - final RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners = - mColorsChangedListeners.get(userId); - if (userColorsChangedListeners != null) { - userColorsChangedListeners.unregister(cb); + SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> + userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId); + if (userDisplayColorsChangedListeners != null) { + RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners = + userDisplayColorsChangedListeners.get(displayId); + if (displayChangedListeners != null) { + displayChangedListeners.unregister(cb); + } } } } /** - * TODO(b/115486823) Extends this method with specific display. + * TODO(multi-display) Extends this method with specific display. * Propagate ambient state to wallpaper engine. * * @param inAmbientMode {@code true} when in ambient mode, {@code false} otherwise. @@ -2125,7 +2221,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub final WallpaperData data = mWallpaperMap.get(mCurrentUserId); if (data != null && data.connection != null && data.connection.mInfo != null && data.connection.mInfo.supportsAmbientMode()) { - // TODO(b/115486823) Extends this method with specific display. + // TODO(multi-display) Extends this method with specific display. engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine; } else { engine = null; @@ -2151,7 +2247,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } @Override - public WallpaperColors getWallpaperColors(int which, int userId) throws RemoteException { + public WallpaperColors getWallpaperColors(int which, int userId, int displayId) + throws RemoteException { if (which != FLAG_LOCK && which != FLAG_SYSTEM) { throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM"); } @@ -2169,7 +2266,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Try to get the system wallpaper anyway since it might // also be the lock screen wallpaper if (wallpaperData == null) { - wallpaperData = mWallpaperMap.get(userId); + wallpaperData = findWallpaperAtDisplay(userId, displayId); } if (wallpaperData == null) { @@ -2187,6 +2284,15 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + private WallpaperData findWallpaperAtDisplay(int userId, int displayId) { + if (mFallbackWallpaper != null && mFallbackWallpaper.connection != null + && mFallbackWallpaper.connection.containsDisplay(displayId)) { + return mFallbackWallpaper; + } else { + return mWallpaperMap.get(userId); + } + } + @Override public ParcelFileDescriptor setWallpaper(String name, String callingPackage, Rect cropHint, boolean allowBackup, Bundle extras, int which, @@ -2382,6 +2488,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (shouldNotifyColors) { notifyWallpaperColorsChanged(wallpaper, which); + notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM); } } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index fe0b5c250da8..caebf1528270 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -1066,93 +1066,19 @@ final class AccessibilityController { final int visibleWindowCount = visibleWindows.size(); HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>(); - for (int i = visibleWindowCount - 1; i >= 0; i--) { - final WindowState windowState = visibleWindows.valueAt(i); - final int flags = windowState.mAttrs.flags; - final Task task = windowState.getTask(); - // If the window is part of a task that we're finished with - ignore. - if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) { - continue; - } - - // Ignore non-touchable windows, except the split-screen divider, which is - // occasionally non-touchable but still useful for identifying split-screen - // mode. - if (((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) - && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) { - continue; - } + // Iterate until we figure out what is touchable for the entire screen. + for (int i = visibleWindowCount - 1; i >= 0 && !unaccountedSpace.isEmpty(); i--) { + final WindowState windowState = visibleWindows.valueAt(i); - // Compute the bounds in the screen. final Rect boundsInScreen = mTempRect; computeWindowBoundsInScreen(windowState, boundsInScreen); - // If the window is completely covered by other windows - ignore. - if (unaccountedSpace.quickReject(boundsInScreen)) { - continue; - } - - // Add windows of certain types not covered by modal windows. - if (isReportedWindowType(windowState.mAttrs.type)) { - // Add the window to the ones to be reported. + if (windowMattersToAccessibility(windowState, boundsInScreen, unaccountedSpace, + skipRemainingWindowsForTasks)) { addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows); - if (windowState.isFocused()) { - focusedWindowAdded = true; - } - } - - if (windowState.mAttrs.type != - WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) { - - // Account for the space this window takes if the window - // is not an accessibility overlay which does not change - // the reported windows. - unaccountedSpace.op(boundsInScreen, unaccountedSpace, - Region.Op.REVERSE_DIFFERENCE); - - // If a window is modal it prevents other windows from being touched - if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) { - // Account for all space in the task, whether the windows in it are - // touchable or not. The modal window blocks all touches from the task's - // area. - unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace, - Region.Op.REVERSE_DIFFERENCE); - - if (task != null) { - // If the window is associated with a particular task, we can skip the - // rest of the windows for that task. - skipRemainingWindowsForTasks.add(task.mTaskId); - continue; - } else { - // If the window is not associated with a particular task, then it is - // globally modal. In this case we can skip all remaining windows. - break; - } - } - } - - // We figured out what is touchable for the entire screen - done. - if (unaccountedSpace.isEmpty()) { - break; - } - } - - // Always report the focused window. - if (!focusedWindowAdded) { - for (int i = visibleWindowCount - 1; i >= 0; i--) { - WindowState windowState = visibleWindows.valueAt(i); - if (windowState.isFocused()) { - // Compute the bounds in the screen. - Rect boundsInScreen = mTempRect; - computeWindowBoundsInScreen(windowState, boundsInScreen); - - // Add the window to the ones to be reported. - addPopulatedWindowInfo( - windowState, boundsInScreen, windows, addedWindows); - break; - } + updateUnaccountedSpace(windowState, boundsInScreen, unaccountedSpace, + skipRemainingWindowsForTasks); } } @@ -1221,6 +1147,73 @@ final class AccessibilityController { clearAndRecycleWindows(windows); } + private boolean windowMattersToAccessibility(WindowState windowState, Rect boundsInScreen, + Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) { + if (windowState.isFocused()) { + return true; + } + + // If the window is part of a task that we're finished with - ignore. + final Task task = windowState.getTask(); + if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) { + return false; + } + + // Ignore non-touchable windows, except the split-screen divider, which is + // occasionally non-touchable but still useful for identifying split-screen + // mode. + if (((windowState.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) + && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) { + return false; + } + + // If the window is completely covered by other windows - ignore. + if (unaccountedSpace.quickReject(boundsInScreen)) { + return false; + } + + // Add windows of certain types not covered by modal windows. + if (isReportedWindowType(windowState.mAttrs.type)) { + return true; + } + + return false; + } + + private void updateUnaccountedSpace(WindowState windowState, Rect boundsInScreen, + Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) { + if (windowState.mAttrs.type + != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) { + + // Account for the space this window takes if the window + // is not an accessibility overlay which does not change + // the reported windows. + unaccountedSpace.op(boundsInScreen, unaccountedSpace, + Region.Op.REVERSE_DIFFERENCE); + + // If a window is modal it prevents other windows from being touched + if ((windowState.mAttrs.flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) { + // Account for all space in the task, whether the windows in it are + // touchable or not. The modal window blocks all touches from the task's + // area. + unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace, + Region.Op.REVERSE_DIFFERENCE); + + final Task task = windowState.getTask(); + if (task != null) { + // If the window is associated with a particular task, we can skip the + // rest of the windows for that task. + skipRemainingWindowsForTasks.add(task.mTaskId); + } else { + // If the window is not associated with a particular task, then it is + // globally modal. In this case we can skip all remaining windows. + unaccountedSpace.setEmpty(); + } + } + } + } + private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) { // Get the touchable frame. Region touchableRegion = mTempRegion1; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 8884615d2fe1..6f8f85f1af26 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -728,9 +728,10 @@ final class ActivityRecord extends ConfigurationContainer { mLastReportedMultiWindowMode = inPictureInPictureMode; final Configuration newConfig = new Configuration(); if (targetStackBounds != null && !targetStackBounds.isEmpty()) { - task.computeResolvedOverrideConfiguration(newConfig, - task.getParent().getConfiguration(), - task.getRequestedOverrideConfiguration()); + newConfig.setTo(task.getRequestedOverrideConfiguration()); + Rect outBounds = newConfig.windowConfiguration.getBounds(); + task.adjustForMinimalTaskDimensions(outBounds, outBounds); + task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration()); } schedulePictureInPictureModeChanged(newConfig); scheduleMultiWindowModeChanged(newConfig); @@ -2503,7 +2504,8 @@ final class ActivityRecord extends ConfigurationContainer { return; } - final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null; + final IBinder binder = + (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null; mAppWindowToken.setOrientation(requestedOrientation, binder, this); } @@ -2547,7 +2549,6 @@ final class ActivityRecord extends ConfigurationContainer { // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. private void updateOverrideConfiguration() { - mTmpConfig.unset(); computeBounds(mTmpBounds); if (mTmpBounds.equals(getRequestedOverrideBounds())) { @@ -2558,8 +2559,10 @@ final class ActivityRecord extends ConfigurationContainer { // Bounds changed...update configuration to match. if (!matchParentBounds()) { - task.computeResolvedOverrideConfiguration(mTmpConfig, - task.getParent().getConfiguration(), getRequestedOverrideConfiguration()); + mTmpConfig.setTo(getRequestedOverrideConfiguration()); + task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration()); + } else { + mTmpConfig.unset(); } onRequestedOverrideConfigurationChanged(mTmpConfig); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index a5341ca11784..801c1e727483 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1714,7 +1714,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (mLetterbox == null) { mLetterbox = new Letterbox(() -> makeChildSurface(null)); } - mLetterbox.layout(getParent().getBounds(), w.getFrameLw()); + getPosition(mTmpPoint); + mLetterbox.layout(getParent().getBounds(), w.getFrameLw(), mTmpPoint); } else if (mLetterbox != null) { mLetterbox.hide(); } @@ -2355,7 +2356,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree public void onAnimationLeashDestroyed(Transaction t) { super.onAnimationLeashDestroyed(t); if (mAnimationBoundsLayer != null) { - t.destroy(mAnimationBoundsLayer); + t.reparent(mAnimationBoundsLayer, null); mAnimationBoundsLayer = null; } diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index ded45c9e3079..650d0be76dc5 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -37,6 +37,7 @@ import static com.android.server.wm.ConfigurationContainerProto.OVERRIDE_CONFIGU import android.annotation.CallSuper; import android.app.WindowConfiguration; import android.content.res.Configuration; +import android.graphics.Point; import android.graphics.Rect; import android.util.proto.ProtoOutputStream; @@ -243,6 +244,14 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { } /** + * Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}. + */ + public void getPosition(Point out) { + Rect bounds = getBounds(); + out.set(bounds.left, bounds.top); + } + + /** * Returns the bounds requested on this container. These may not be the actual bounds the * container ends up with due to policy constraints. The {@link Rect} handed back is * shared for all calls to this method and should not be modified. diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index aea071f94ba2..c39060ee1922 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -129,7 +129,7 @@ class Dimmer { final DimAnimatable dimAnimatable = new DimAnimatable(dimLayer); mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, () -> { if (!mDimming) { - dimAnimatable.getPendingTransaction().destroy(mDimLayer); + dimAnimatable.getPendingTransaction().reparent(mDimLayer, null); } }, mHost.mWmService); } @@ -300,7 +300,7 @@ class Dimmer { if (!mDimState.mDimming) { if (!mDimState.mAnimateExit) { - t.destroy(mDimState.mDimLayer); + t.reparent(mDimState.mDimLayer, null); } else { startDimExit(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index fecc8da3d645..740d47240bd0 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3656,6 +3656,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + /** @returns the orientation of the display when it's rotation is ROTATION_0. */ + int getNaturalOrientation() { + return mBaseDisplayWidth < mBaseDisplayHeight + ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; + } + void performLayout(boolean initial, boolean updateInputWindows) { if (!isLayoutNeeded()) { return; diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 607ee767869f..786a3064ab4e 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -127,6 +127,7 @@ class DragState { * {@code true} when {@link #closeLocked()} is called. */ private boolean mIsClosing; + IBinder mTransferTouchFromToken; DragState(WindowManagerService service, DragDropController controller, IBinder token, SurfaceControl surface, int flags, IBinder localWin) { @@ -177,6 +178,8 @@ class DragState { mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); t.setWindowCrop(mInputSurface, mTmpClipRect); + t.transferTouchFocus(mTransferTouchFromToken, h.token); + mTransferTouchFromToken = null; } /** diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index fbb9e2905697..d6f161645327 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -25,6 +25,7 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.InsetsSource; import android.view.InsetsSourceControl; +import android.view.ViewRootImpl; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.pooled.PooledLambda; @@ -158,7 +159,7 @@ class InsetsSourceProvider { } boolean isClientVisible() { - return mClientVisible; + return !ViewRootImpl.USE_NEW_INSETS || mClientVisible; } private class ControlAdapter implements AnimationAdapter { diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index cc57b932092c..bc01f7c2595d 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -202,6 +202,9 @@ class InsetsStateController { } private void notifyPendingInsetsControlChanged() { + if (mPendingControlChanged.isEmpty()) { + return; + } mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { for (int i = mPendingControlChanged.size() - 1; i >= 0; i--) { final WindowState controllingWin = mPendingControlChanged.valueAt(i); diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 1a2aa2f252e6..33ff19415089 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.view.SurfaceControl.HIDDEN; +import android.graphics.Point; import android.graphics.Rect; import android.view.SurfaceControl; @@ -30,6 +31,7 @@ import java.util.function.Supplier; public class Letterbox { private static final Rect EMPTY_RECT = new Rect(); + private static final Point ZERO_POINT = new Point(0, 0); private final Supplier<SurfaceControl.Builder> mFactory; private final Rect mOuter = new Rect(); @@ -53,14 +55,19 @@ public class Letterbox { * frames will be covered by black color surfaces. * * The caller must use {@link #applySurfaceChanges} to apply the new layout to the surface. - * * @param outer the outer frame of the letterbox (this frame will be black, except the area - * that intersects with the {code inner} frame). - * @param inner the inner frame of the letterbox (this frame will be clear) + * that intersects with the {code inner} frame), in global coordinates + * @param inner the inner frame of the letterbox (this frame will be clear), in global + * coordinates + * @param surfaceOrigin the origin of the surface factory in global coordinates */ - public void layout(Rect outer, Rect inner) { + public void layout(Rect outer, Rect inner, Point surfaceOrigin) { mOuter.set(outer); mInner.set(inner); + mOuter.offset(-surfaceOrigin.x, -surfaceOrigin.y); + mInner.offset(-surfaceOrigin.x, -surfaceOrigin.y); + outer = mOuter; + inner = mInner; mTop.layout(outer.left, outer.top, inner.right, inner.top); mLeft.layout(outer.left, inner.top, inner.left, outer.bottom); @@ -94,7 +101,7 @@ public class Letterbox { * The caller must use {@link #applySurfaceChanges} to apply the new layout to the surface. */ public void hide() { - layout(EMPTY_RECT, EMPTY_RECT); + layout(EMPTY_RECT, EMPTY_RECT, ZERO_POINT); } /** diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index d85fdb03e4a6..937c9d9fc809 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -187,7 +187,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, - Surface outSurface, InsetsState outInsetsState) { + SurfaceControl outSurfaceControl, InsetsState outInsetsState) { if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag); @@ -195,7 +195,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { requestedWidth, requestedHeight, viewFlags, flags, frameNumber, outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, outStableInsets, outsets, outBackdropFrame, cutout, - mergedConfiguration, outSurface, outInsetsState); + mergedConfiguration, outSurfaceControl, outInsetsState); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 11068ce8bace..9d9b48a5b36a 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -280,7 +280,7 @@ class SurfaceAnimator { } mService.mAnimationTransferMap.remove(mAnimation); if (mLeash != null && destroyLeash) { - t.destroy(mLeash); + t.reparent(mLeash, null); scheduleAnim = true; } mLeash = null; diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index e15bf5b9a6f0..916316549f39 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -24,6 +24,7 @@ import android.app.IActivityTaskManager; import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Slog; @@ -50,6 +51,7 @@ class TaskPositioningController { private @Nullable TaskPositioner mTaskPositioner; private final Rect mTmpClipRect = new Rect(); + private IBinder mTransferTouchFromToken; boolean isPositioningLocked() { return mTaskPositioner != null; @@ -102,6 +104,8 @@ class TaskPositioningController { mTmpClipRect.set(0, 0, p.x, p.y); t.setWindowCrop(mInputSurface, mTmpClipRect); + t.transferTouchFocus(mTransferTouchFromToken, h.token); + mTransferTouchFromToken = null; } boolean startMovingTask(IWindow window, float startX, float startY) { @@ -170,7 +174,6 @@ class TaskPositioningController { mPositioningDisplay = displayContent; mTaskPositioner = TaskPositioner.create(mService); - mTaskPositioner.register(displayContent); // We need to grab the touch focus so that the touch events during the // resizing/scrolling are not sent to the app. 'win' is the main window @@ -181,12 +184,8 @@ class TaskPositioningController { && displayContent.mCurrentFocus.mAppToken == win.mAppToken) { transferFocusFromWin = displayContent.mCurrentFocus; } - if (!mInputManager.transferTouchFocus( - transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) { - Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus"); - cleanUpTaskPositioner(); - return false; - } + mTransferTouchFromToken = transferFocusFromWin.mInputChannel.getToken(); + mTaskPositioner.register(displayContent); mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY); return true; diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java index e3433228f2de..4a553cf59bc9 100644 --- a/services/core/java/com/android/server/wm/TaskRecord.java +++ b/services/core/java/com/android/server/wm/TaskRecord.java @@ -44,6 +44,9 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.content.res.Configuration.ORIENTATION_UNDEFINED; 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; @@ -971,10 +974,11 @@ class TaskRecord extends ConfigurationContainer { */ boolean isSameIntentFilter(ActivityRecord r) { final Intent intent = new Intent(r.intent); - // Correct the activity intent for aliasing. The task record intent will always be based on - // the real activity that will be launched not the alias, so we need to use an intent with - // the component name pointing to the real activity not the alias in the activity record. - intent.setComponent(r.mActivityComponent); + // Make sure the component are the same if the input activity has the same real activity + // as the one in the task because either one of them could be the alias activity. + if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) { + intent.setComponent(this.intent.getComponent()); + } return intent.filterEquals(this.intent); } @@ -1259,10 +1263,6 @@ class TaskRecord extends ConfigurationContainer { setFrontOfTask(); } - void addActivityAtBottom(ActivityRecord r) { - addActivityAtIndex(0, r); - } - void addActivityToTop(ActivityRecord r) { addActivityAtIndex(mActivities.size(), r); } @@ -1278,6 +1278,34 @@ class TaskRecord extends ConfigurationContainer { } /** + * Checks if the root activity requires a particular orientation (either by override or + * activityInfo) and returns that. Otherwise, this returns ORIENTATION_UNDEFINED. + */ + private int getRootActivityRequestedOrientation() { + ActivityRecord root = getRootActivity(); + if (getRequestedOverrideConfiguration().orientation != ORIENTATION_UNDEFINED + || root == null) { + return getRequestedOverrideConfiguration().orientation; + } + int rootScreenOrientation = root.getOrientation(); + if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { + // NOSENSOR means the display's "natural" orientation, so return that. + ActivityDisplay display = mStack != null ? mStack.getDisplay() : null; + if (display != null && display.mDisplayContent != null) { + return mStack.getDisplay().mDisplayContent.getNaturalOrientation(); + } + } else if (rootScreenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { + // LOCKED means the activity's orientation remains unchanged, so return existing value. + return root.getConfiguration().orientation; + } else if (ActivityInfo.isFixedOrientationLandscape(rootScreenOrientation)) { + return ORIENTATION_LANDSCAPE; + } else if (ActivityInfo.isFixedOrientationPortrait(rootScreenOrientation)) { + return ORIENTATION_PORTRAIT; + } + return ORIENTATION_UNDEFINED; + } + + /** * Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either * be in the current task or unparented to any task. */ @@ -1741,7 +1769,7 @@ class TaskRecord extends ConfigurationContainer { updateTaskDescription(); } - private void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) { + void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) { if (bounds == null) { return; } @@ -1853,11 +1881,27 @@ class TaskRecord extends ConfigurationContainer { @Override public void onConfigurationChanged(Configuration newParentConfig) { + // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so + // restore the last recorded non-fullscreen bounds. + final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds(); + final boolean nextPersistTaskBounds = + getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds() + || newParentConfig.windowConfiguration.persistTaskBounds(); + if (!prevPersistTaskBounds && nextPersistTaskBounds + && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) { + // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop. + getRequestedOverrideConfiguration().windowConfiguration + .setBounds(mLastNonFullscreenBounds); + } + final boolean wasInMultiWindowMode = inMultiWindowMode(); super.onConfigurationChanged(newParentConfig); if (wasInMultiWindowMode != inMultiWindowMode()) { mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this); } + + // If the configuration supports persistent bounds (eg. Freeform), keep track of the + // current (non-fullscreen) bounds for persistence. if (getWindowConfiguration().persistTaskBounds()) { final Rect currentBounds = getRequestedOverrideBounds(); if (!currentBounds.isEmpty()) { @@ -2047,7 +2091,7 @@ class TaskRecord extends ConfigurationContainer { * configuring an "inherit-bounds" window which means that all configuration settings would * just be inherited from the parent configuration. **/ - void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Rect bounds, + void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Configuration parentConfig) { int windowingMode = inOutConfig.windowConfiguration.getWindowingMode(); if (windowingMode == WINDOWING_MODE_UNDEFINED) { @@ -2060,6 +2104,7 @@ class TaskRecord extends ConfigurationContainer { } density *= DisplayMetrics.DENSITY_DEFAULT_SCALE; + final Rect bounds = inOutConfig.windowConfiguration.getBounds(); Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); if (outAppBounds == null || outAppBounds.isEmpty()) { inOutConfig.windowConfiguration.setAppBounds(bounds); @@ -2107,13 +2152,14 @@ class TaskRecord extends ConfigurationContainer { // Iterating across all screen orientations, and return the minimum of the task // width taking into account that the bounds might change because the snap // algorithm snaps to a different value - getSmallestScreenWidthDpForDockedBounds(bounds); + inOutConfig.smallestScreenWidthDp = + getSmallestScreenWidthDpForDockedBounds(bounds); } // otherwise, it will just inherit } } - if (inOutConfig.orientation == Configuration.ORIENTATION_UNDEFINED) { + if (inOutConfig.orientation == ORIENTATION_UNDEFINED) { inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp) ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; } @@ -2134,36 +2180,56 @@ class TaskRecord extends ConfigurationContainer { } } - // TODO(b/113900640): remove this once ActivityRecord is changed to not need it anymore. - void computeResolvedOverrideConfiguration(Configuration inOutConfig, Configuration parentConfig, - Configuration overrideConfig) { - // Save previous bounds because adjustForMinimalTaskDimensions uses that to determine if it - // changes left bound vs. right bound, or top bound vs. bottom bound. - mTmpBounds.set(inOutConfig.windowConfiguration.getBounds()); - - inOutConfig.setTo(overrideConfig); - - Rect outOverrideBounds = inOutConfig.windowConfiguration.getBounds(); - if (outOverrideBounds != null && !outOverrideBounds.isEmpty()) { - adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds); - - int windowingMode = overrideConfig.windowConfiguration.getWindowingMode(); - if (windowingMode == WINDOWING_MODE_UNDEFINED) { - windowingMode = parentConfig.windowConfiguration.getWindowingMode(); - } - if (windowingMode == WINDOWING_MODE_FREEFORM) { - // by policy, make sure the window remains within parent - fitWithinBounds(outOverrideBounds, parentConfig.windowConfiguration.getBounds()); + @Override + void resolveOverrideConfiguration(Configuration newParentConfig) { + mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); + super.resolveOverrideConfiguration(newParentConfig); + int windowingMode = + getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode(); + if (windowingMode == WINDOWING_MODE_UNDEFINED) { + windowingMode = newParentConfig.windowConfiguration.getWindowingMode(); + } + Rect outOverrideBounds = + getResolvedOverrideConfiguration().windowConfiguration.getBounds(); + + if (windowingMode == WINDOWING_MODE_FULLSCREEN) { + // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent" + outOverrideBounds.setEmpty(); + + // If the task or its root activity require a different orientation, make it fit the + // available bounds by scaling down its bounds. + int forcedOrientation = getRootActivityRequestedOrientation(); + if (forcedOrientation != ORIENTATION_UNDEFINED + && forcedOrientation != newParentConfig.orientation) { + final Rect parentBounds = newParentConfig.windowConfiguration.getBounds(); + final int parentWidth = parentBounds.width(); + final int parentHeight = parentBounds.height(); + final float aspect = ((float) parentHeight) / parentWidth; + if (forcedOrientation == ORIENTATION_LANDSCAPE) { + final int height = (int) (parentWidth / aspect); + final int top = parentBounds.centerY() - height / 2; + outOverrideBounds.set( + parentBounds.left, top, parentBounds.right, top + height); + } else { + final int width = (int) (parentHeight * aspect); + final int left = parentBounds.centerX() - width / 2; + outOverrideBounds.set( + left, parentBounds.top, left + width, parentBounds.bottom); + } } + } - computeConfigResourceOverrides(inOutConfig, outOverrideBounds, parentConfig); + if (outOverrideBounds.isEmpty()) { + // If the task fills the parent, just inherit all the other configs from parent. + return; } - } - @Override - void resolveOverrideConfiguration(Configuration newParentConfig) { - computeResolvedOverrideConfiguration(getResolvedOverrideConfiguration(), newParentConfig, - getRequestedOverrideConfiguration()); + adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds); + if (windowingMode == WINDOWING_MODE_FREEFORM) { + // by policy, make sure the window remains within parent somewhere + fitWithinBounds(outOverrideBounds, newParentConfig.windowConfiguration.getBounds()); + } + computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); } Rect updateOverrideConfigurationFromLaunchBounds() { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 9a56606aee7f..2d3e3aee4b7f 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -111,6 +111,7 @@ class TaskSnapshotSurface implements StartingSurface { private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s"; private final Window mWindow; private final Surface mSurface; + private SurfaceControl mSurfaceControl; private SurfaceControl mChildSurfaceControl; private final IWindowSession mSession; private final WindowManagerService mService; @@ -136,7 +137,7 @@ class TaskSnapshotSurface implements StartingSurface { final Window window = new Window(); final IWindowSession session = WindowManagerGlobal.getWindowSession(); window.setSession(session); - final Surface surface = new Surface(); + final SurfaceControl surfaceControl = new SurfaceControl(); final Rect tmpRect = new Rect(); final DisplayCutout.ParcelableWrapper tmpCutout = new DisplayCutout.ParcelableWrapper(); final Rect tmpFrame = new Rect(); @@ -213,14 +214,14 @@ class TaskSnapshotSurface implements StartingSurface { // Local call. } final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window, - surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor, + surfaceControl, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor, navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds, currentOrientation); window.setOuter(snapshotSurface); try { session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1, tmpFrame, tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect, - tmpCutout, tmpMergedConfiguration, surface, mTmpInsetsState); + tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState); } catch (RemoteException e) { // Local call. } @@ -230,15 +231,16 @@ class TaskSnapshotSurface implements StartingSurface { } @VisibleForTesting - TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface, + TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl, TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor, int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags, Rect taskBounds, int currentOrientation) { mService = service; + mSurface = new Surface(); mHandler = new Handler(mService.mH.getLooper()); mSession = WindowManagerGlobal.getWindowSession(); mWindow = window; - mSurface = surface; + mSurfaceControl = surfaceControl; mSnapshot = snapshot; mTitle = title; mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE); @@ -281,6 +283,8 @@ class TaskSnapshotSurface implements StartingSurface { private void drawSnapshot() { final GraphicBuffer buffer = mSnapshot.getSnapshot(); + mSurface.copyFrom(mSurfaceControl); + if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch=" + mSizeMismatch); if (mSizeMismatch) { @@ -310,13 +314,14 @@ class TaskSnapshotSurface implements StartingSurface { if (!mSurface.isValid()) { throw new IllegalStateException("mSurface does not hold a valid surface."); } - final SurfaceSession session = new SurfaceSession(mSurface); + final SurfaceSession session = new SurfaceSession(); // Keep a reference to it such that it doesn't get destroyed when finalized. mChildSurfaceControl = new SurfaceControl.Builder(session) .setName(mTitle + " - task-snapshot-surface") .setBufferSize(buffer.getWidth(), buffer.getHeight()) .setFormat(buffer.getFormat()) + .setParent(mSurfaceControl) .build(); Surface surface = new Surface(); surface.copyFrom(mChildSurfaceControl); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 32c5a3b8688e..25e61f876722 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -326,7 +326,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } if (mSurfaceControl != null) { - mPendingTransaction.destroy(mSurfaceControl); + mPendingTransaction.reparent(mSurfaceControl, null); // Merge to parent transaction to ensure the transactions on this WindowContainer are // applied in native even if WindowContainer is removed. diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 646fdd960adc..1691dc0e3806 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -158,8 +158,9 @@ public abstract class WindowManagerInternal { default boolean registerInputChannel( DragState state, Display display, InputManagerService service, InputChannel source) { + state.mTransferTouchFromToken = source.getToken(); state.register(display); - return service.transferTouchFocus(source, state.getInputChannel()); + return true; } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f5f55e2ebf73..91aac7e0e8aa 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1874,7 +1874,7 @@ public class WindowManagerService extends IWindowManager.Stub long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration, - Surface outSurface, InsetsState outInsetsState) { + SurfaceControl outSurfaceControl, InsetsState outInsetsState) { int result = 0; boolean configChanged; final boolean hasStatusBarPermission = @@ -2047,7 +2047,7 @@ public class WindowManagerService extends IWindowManager.Stub result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility); try { - result = createSurfaceControl(outSurface, result, win, winAnimator); + result = createSurfaceControl(outSurfaceControl, result, win, winAnimator); } catch (Exception e) { displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); @@ -2078,7 +2078,7 @@ public class WindowManagerService extends IWindowManager.Stub // handled yet, or it might want to draw a last frame. If we already have a // surface, let the client use that, but don't create new surface at this point. Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface"); - winAnimator.mSurfaceController.getSurface(outSurface); + winAnimator.mSurfaceController.getSurfaceControl(outSurfaceControl); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } else { if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win); @@ -2086,7 +2086,7 @@ public class WindowManagerService extends IWindowManager.Stub try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_" + win.mAttrs.getTitle()); - outSurface.release(); + outSurfaceControl.release(); } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } @@ -2182,7 +2182,7 @@ public class WindowManagerService extends IWindowManager.Stub + ", requestedHeight=" + requestedHeight + ", viewVisibility=" + viewVisibility + "\nRelayout returning frame=" + outFrame - + ", surface=" + outSurface); + + ", surface=" + outSurfaceControl); if (localLOGV || DEBUG_FOCUS) Slog.v( TAG_WM, "Relayout of " + win + ": focusMayChange=" + focusMayChange); @@ -2252,7 +2252,7 @@ public class WindowManagerService extends IWindowManager.Stub return focusMayChange; } - private int createSurfaceControl(Surface outSurface, int result, WindowState win, + private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, WindowState win, WindowStateAnimator winAnimator) { if (!win.mHasSurface) { result |= RELAYOUT_RES_SURFACE_CHANGED; @@ -2266,13 +2266,13 @@ public class WindowManagerService extends IWindowManager.Stub Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } if (surfaceController != null) { - surfaceController.getSurface(outSurface); - if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurface + ": copied"); + surfaceController.getSurfaceControl(outSurfaceControl); + if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurfaceControl + ": copied"); } else { // For some reason there isn't a surface. Clear the // caller's object so they see the same state. Slog.w(TAG_WM, "Failed to create surface control for " + win); - outSurface.release(); + outSurfaceControl.release(); } return result; @@ -6166,7 +6166,7 @@ public class WindowManagerService extends IWindowManager.Stub dumpWindowsLocked(pw, true, null); } return; - } else if ("all".equals(cmd) || "a".equals(cmd)) { + } else if ("all".equals(cmd)) { synchronized (mGlobalLock) { dumpWindowsLocked(pw, true, null); } diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index ce627e23e6ee..c2a8e7efb5a5 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -478,8 +478,8 @@ class WindowSurfaceController { return mSurfaceControl.getHandle(); } - void getSurface(Surface outSurface) { - outSurface.copyFrom(mSurfaceControl); + void getSurfaceControl(SurfaceControl outSurfaceControl) { + outSurfaceControl.copyFrom(mSurfaceControl); } int getLayer() { diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index b4fe83704ff2..9ecafb3c70d6 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -119,6 +119,7 @@ cc_defaults { "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", + "android.hardware.vibrator@1.3", "android.hardware.vr@1.0", "android.frameworks.schedulerservice@1.0", "android.frameworks.sensorservice@1.0", diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index defcfd9a3370..63dca62104a1 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -22,6 +22,7 @@ #include <android/hardware/vibrator/1.1/types.h> #include <android/hardware/vibrator/1.2/IVibrator.h> #include <android/hardware/vibrator/1.2/types.h> +#include <android/hardware/vibrator/1.3/IVibrator.h> #include "jni.h" #include <nativehelper/JNIHelp.h> @@ -42,6 +43,7 @@ using android::hardware::vibrator::V1_1::Effect_1_1; namespace V1_0 = android::hardware::vibrator::V1_0; namespace V1_1 = android::hardware::vibrator::V1_1; namespace V1_2 = android::hardware::vibrator::V1_2; +namespace V1_3 = android::hardware::vibrator::V1_3; namespace android { @@ -136,6 +138,19 @@ static void vibratorSetAmplitude(JNIEnv*, jobject, jint amplitude) { } } +static jboolean vibratorSupportsExternalControl(JNIEnv*, jobject) { + return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false); +} + +static void vibratorSetExternalControl(JNIEnv*, jobject, jboolean enabled) { + Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled)) + .withDefault(Status::UNKNOWN_ERROR); + if (status != Status::OK) { + ALOGE("Failed to set vibrator external control (%" PRIu32 ").", + static_cast<uint32_t>(status)); + } +} + static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength) { Status status; uint32_t lengthMs; @@ -187,7 +202,9 @@ static const JNINativeMethod method_table[] = { { "vibratorOff", "()V", (void*)vibratorOff }, { "vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl}, { "vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude}, - { "vibratorPerformEffect", "(JJ)J", (void*)vibratorPerformEffect} + { "vibratorPerformEffect", "(JJ)J", (void*)vibratorPerformEffect}, + { "vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl}, + { "vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl}, }; int register_android_server_VibratorService(JNIEnv *env) diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 6d8fc1c88307..b290bc516320 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -135,6 +135,7 @@ using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss; using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss; using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration; using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration; +using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration; using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement; @@ -179,6 +180,7 @@ sp<IGnssBatching> gnssBatchingIface = nullptr; sp<IGnssDebug> gnssDebugIface = nullptr; sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr; sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr; +sp<IGnssConfiguration_V2_0> gnssConfigurationIface_V2_0 = nullptr; sp<IGnssNi> gnssNiIface = nullptr; sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr; sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr; @@ -313,6 +315,15 @@ static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodNa } } +static jobject createHalInterfaceVersionJavaObject(JNIEnv* env, jint major, jint minor) { + jclass versionClass = + env->FindClass("com/android/server/location/GnssConfiguration$HalInterfaceVersion"); + jmethodID versionCtor = env->GetMethodID(versionClass, "<init>", "(II)V"); + jobject version = env->NewObject(versionClass, versionCtor, major, minor); + env->DeleteLocalRef(versionClass); + return version; +} + struct ScopedJniString { ScopedJniString(JNIEnv* env, jstring javaString) : mEnv(env), mJavaString(javaString) { mNativeString = mEnv->GetStringUTFChars(mJavaString, nullptr); @@ -1421,10 +1432,19 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass gnssNiIface = gnssNi; } - if (gnssHal_V1_1 != nullptr) { + if (gnssHal_V2_0 != nullptr) { + auto gnssConfiguration = gnssHal_V2_0->getExtensionGnssConfiguration_2_0(); + if (!gnssConfiguration.isOk()) { + ALOGD("Unable to get a handle to GnssConfiguration_V2_0"); + } else { + gnssConfigurationIface_V2_0 = gnssConfiguration; + gnssConfigurationIface_V1_1 = gnssConfigurationIface_V2_0; + gnssConfigurationIface = gnssConfigurationIface_V2_0; + } + } else if (gnssHal_V1_1 != nullptr) { auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1(); if (!gnssConfiguration.isOk()) { - ALOGD("Unable to get a handle to GnssConfiguration"); + ALOGD("Unable to get a handle to GnssConfiguration_V1_1"); } else { gnssConfigurationIface_V1_1 = gnssConfiguration; gnssConfigurationIface = gnssConfigurationIface_V1_1; @@ -1463,9 +1483,23 @@ static jboolean android_location_GnssNetworkConnectivityHandler_is_agps_ril_supp return (agnssRilIface != nullptr) ? JNI_TRUE : JNI_FALSE; } -static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported( - JNIEnv* /* env */, jclass /* jclazz */) { - return (gnssConfigurationIface != nullptr) ? JNI_TRUE : JNI_FALSE; +static jobject android_location_GnssConfiguration_get_gnss_configuration_version( + JNIEnv* env, jclass /* jclazz */) { + jint major, minor; + if (gnssConfigurationIface_V2_0 != nullptr) { + major = 2; + minor = 0; + } else if (gnssConfigurationIface_V1_1 != nullptr) { + major = 1; + minor = 1; + } else if (gnssConfigurationIface != nullptr) { + major = 1; + minor = 0; + } else { + return nullptr; + } + + return createHalInterfaceVersionJavaObject(env, major, minor); } static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj) { @@ -2278,9 +2312,9 @@ static jboolean android_location_GnssNavigationMessageProvider_stop_navigation_m return boolToJbool(result.isOk()); } -static jboolean android_location_GnssLocationProvider_set_emergency_supl_pdn(JNIEnv*, - jobject, - jint emergencySuplPdn) { +static jboolean android_location_GnssConfiguration_set_emergency_supl_pdn(JNIEnv*, + jobject, + jint emergencySuplPdn) { if (gnssConfigurationIface == nullptr) { ALOGE("no GNSS configuration interface available"); return JNI_FALSE; @@ -2294,7 +2328,7 @@ static jboolean android_location_GnssLocationProvider_set_emergency_supl_pdn(JNI } } -static jboolean android_location_GnssLocationProvider_set_supl_version(JNIEnv*, +static jboolean android_location_GnssConfiguration_set_supl_version(JNIEnv*, jobject, jint version) { if (gnssConfigurationIface == nullptr) { @@ -2309,9 +2343,14 @@ static jboolean android_location_GnssLocationProvider_set_supl_version(JNIEnv*, } } -static jboolean android_location_GnssLocationProvider_set_supl_es(JNIEnv*, - jobject, - jint suplEs) { +static jboolean android_location_GnssConfiguration_set_supl_es(JNIEnv*, + jobject, + jint suplEs) { + if (gnssConfigurationIface_V2_0 != nullptr) { + ALOGI("Config parameter SUPL_ES is deprecated in IGnssConfiguration.hal version 2.0."); + return JNI_FALSE; + } + if (gnssConfigurationIface == nullptr) { ALOGE("no GNSS configuration interface available"); return JNI_FALSE; @@ -2325,9 +2364,9 @@ static jboolean android_location_GnssLocationProvider_set_supl_es(JNIEnv*, } } -static jboolean android_location_GnssLocationProvider_set_supl_mode(JNIEnv*, - jobject, - jint mode) { +static jboolean android_location_GnssConfiguration_set_supl_mode(JNIEnv*, + jobject, + jint mode) { if (gnssConfigurationIface == nullptr) { ALOGE("no GNSS configuration interface available"); return JNI_FALSE; @@ -2341,9 +2380,14 @@ static jboolean android_location_GnssLocationProvider_set_supl_mode(JNIEnv*, } } -static jboolean android_location_GnssLocationProvider_set_gps_lock(JNIEnv*, - jobject, - jint gpsLock) { +static jboolean android_location_GnssConfiguration_set_gps_lock(JNIEnv*, + jobject, + jint gpsLock) { + if (gnssConfigurationIface_V2_0 != nullptr) { + ALOGI("Config parameter GPS_LOCK is deprecated in IGnssConfiguration.hal version 2.0."); + return JNI_FALSE; + } + if (gnssConfigurationIface == nullptr) { ALOGE("no GNSS configuration interface available"); return JNI_FALSE; @@ -2357,7 +2401,7 @@ static jboolean android_location_GnssLocationProvider_set_gps_lock(JNIEnv*, } } -static jboolean android_location_GnssLocationProvider_set_lpp_profile(JNIEnv*, +static jboolean android_location_GnssConfiguration_set_lpp_profile(JNIEnv*, jobject, jint lppProfile) { if (gnssConfigurationIface == nullptr) { @@ -2374,9 +2418,9 @@ static jboolean android_location_GnssLocationProvider_set_lpp_profile(JNIEnv*, } } -static jboolean android_location_GnssLocationProvider_set_gnss_pos_protocol_select(JNIEnv*, - jobject, - jint gnssPosProtocol) { +static jboolean android_location_GnssConfiguration_set_gnss_pos_protocol_select(JNIEnv*, + jobject, + jint gnssPosProtocol) { if (gnssConfigurationIface == nullptr) { ALOGE("no GNSS configuration interface available"); return JNI_FALSE; @@ -2390,7 +2434,7 @@ static jboolean android_location_GnssLocationProvider_set_gnss_pos_protocol_sele } } -static jboolean android_location_GnssLocationProvider_set_satellite_blacklist( +static jboolean android_location_GnssConfiguration_set_satellite_blacklist( JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) { if (gnssConfigurationIface_V1_1 == nullptr) { ALOGI("No GNSS Satellite Blacklist interface available"); @@ -2431,6 +2475,27 @@ static jboolean android_location_GnssLocationProvider_set_satellite_blacklist( } } +static jboolean android_location_GnssConfiguration_set_es_extension_sec( + JNIEnv*, jobject, jint emergencyExtensionSeconds) { + if (gnssConfigurationIface == nullptr) { + ALOGE("no GNSS configuration interface available"); + return JNI_FALSE; + } + + if (gnssConfigurationIface_V2_0 == nullptr) { + ALOGI("Config parameter ES_EXTENSION_SEC is not supported in IGnssConfiguration.hal" + " versions earlier than 2.0."); + return JNI_FALSE; + } + + auto result = gnssConfigurationIface_V2_0->setEsExtensionSec(emergencyExtensionSeconds); + if (result.isOk()) { + return result; + } else { + return JNI_FALSE; + } +} + static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass) { if (gnssBatchingIface == nullptr) { return 0; // batching not supported, size = 0 @@ -2498,17 +2563,14 @@ static const JNINativeMethod sMethods[] = { android_location_GnssLocationProvider_class_init_native)}, {"native_is_supported", "()Z", reinterpret_cast<void *>( android_location_GnssLocationProvider_is_supported)}, - {"native_is_gnss_configuration_supported", "()Z", - reinterpret_cast<void *>( - android_location_gpsLocationProvider_is_gnss_configuration_supported)}, {"native_init_once", "()V", reinterpret_cast<void *>( android_location_GnssLocationProvider_init_once)}, {"native_init", "()Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_init)}, {"native_cleanup", "()V", reinterpret_cast<void *>( android_location_GnssLocationProvider_cleanup)}, {"native_set_position_mode", - "(IIIIIZ)Z", - reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)}, + "(IIIIIZ)Z", + reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)}, {"native_start", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_start)}, {"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)}, {"native_delete_aiding_data", @@ -2545,31 +2607,6 @@ static const JNINativeMethod sMethods[] = { {"native_get_internal_state", "()Ljava/lang/String;", reinterpret_cast<void *>(android_location_GnssLocationProvider_get_internal_state)}, - {"native_set_supl_es", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_es)}, - {"native_set_supl_version", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_version)}, - {"native_set_supl_mode", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_mode)}, - {"native_set_lpp_profile", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_set_lpp_profile)}, - {"native_set_gnss_pos_protocol_select", - "(I)Z", - reinterpret_cast<void *>( - android_location_GnssLocationProvider_set_gnss_pos_protocol_select)}, - {"native_set_gps_lock", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_set_gps_lock)}, - {"native_set_emergency_supl_pdn", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_set_emergency_supl_pdn)}, - {"native_set_satellite_blacklist", - "([I[I)Z", - reinterpret_cast<void *>(android_location_GnssLocationProvider_set_satellite_blacklist)}, }; static const JNINativeMethod sMethodsBatching[] = { @@ -2663,6 +2700,42 @@ static const JNINativeMethod sNetworkConnectivityMethods[] = { reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)}, }; +static const JNINativeMethod sConfigurationMethods[] = { + /* name, signature, funcPtr */ + {"native_get_gnss_configuration_version", + "()Lcom/android/server/location/GnssConfiguration$HalInterfaceVersion;", + reinterpret_cast<void *>( + android_location_GnssConfiguration_get_gnss_configuration_version)}, + {"native_set_supl_es", + "(I)Z", + reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_es)}, + {"native_set_supl_version", + "(I)Z", + reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_version)}, + {"native_set_supl_mode", + "(I)Z", + reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_mode)}, + {"native_set_lpp_profile", + "(I)Z", + reinterpret_cast<void *>(android_location_GnssConfiguration_set_lpp_profile)}, + {"native_set_gnss_pos_protocol_select", + "(I)Z", + reinterpret_cast<void *>( + android_location_GnssConfiguration_set_gnss_pos_protocol_select)}, + {"native_set_gps_lock", + "(I)Z", + reinterpret_cast<void *>(android_location_GnssConfiguration_set_gps_lock)}, + {"native_set_emergency_supl_pdn", + "(I)Z", + reinterpret_cast<void *>(android_location_GnssConfiguration_set_emergency_supl_pdn)}, + {"native_set_satellite_blacklist", + "([I[I)Z", + reinterpret_cast<void *>(android_location_GnssConfiguration_set_satellite_blacklist)}, + {"native_set_es_extension_sec", + "(I)Z", + reinterpret_cast<void *>(android_location_GnssConfiguration_set_es_extension_sec)}, +}; + int register_android_server_location_GnssLocationProvider(JNIEnv* env) { jniRegisterNativeMethods( env, @@ -2689,6 +2762,11 @@ int register_android_server_location_GnssLocationProvider(JNIEnv* env) { "com/android/server/location/GnssNetworkConnectivityHandler", sNetworkConnectivityMethods, NELEM(sNetworkConnectivityMethods)); + jniRegisterNativeMethods( + env, + "com/android/server/location/GnssConfiguration", + sConfigurationMethods, + NELEM(sConfigurationMethods)); return jniRegisterNativeMethods( env, "com/android/server/location/GnssLocationProvider", diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java index 05912a5e3776..de5dd1749830 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java @@ -66,6 +66,9 @@ class AbUpdateInstaller extends UpdateInstaller { map.put( DOWNLOAD_STATE_INITIALIZATION_ERROR, InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION); + map.put( + UpdateEngine.ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR, + InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION); // Error constants corresponding to errors related to bad update file. map.put( diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 781e1c4a41d9..7f6895a4cf83 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -4990,26 +4990,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token, int flags, int callingUid, int userHandle) { int quality; - final int realQuality; synchronized (getLockObject()) { quality = getPasswordQuality(null, userHandle, /* parent */ false); if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { quality = PASSWORD_QUALITY_UNSPECIFIED; } final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password); - realQuality = metrics.quality; - if (quality != PASSWORD_QUALITY_UNSPECIFIED) { - - if (realQuality < quality - && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { - Slog.w(LOG_TAG, "resetPassword: password quality 0x" - + Integer.toHexString(realQuality) - + " does not meet required quality 0x" - + Integer.toHexString(quality)); - return false; - } - quality = Math.max(realQuality, quality); + final int realQuality = metrics.quality; + if (realQuality < quality + && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { + Slog.w(LOG_TAG, "resetPassword: password quality 0x" + + Integer.toHexString(realQuality) + + " does not meet required quality 0x" + + Integer.toHexString(quality)); + return false; } + quality = Math.max(realQuality, quality); int length = getPasswordMinimumLength(null, userHandle, /* parent */ false); if (password.length() < length) { Slog.w(LOG_TAG, "resetPassword: password length " + password.length() @@ -5086,7 +5082,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { if (token == null) { if (!TextUtils.isEmpty(password)) { - mLockPatternUtils.saveLockPassword(password, null, realQuality, userHandle); + mLockPatternUtils.saveLockPassword(password, null, quality, userHandle); } else { mLockPatternUtils.clearLock(null, userHandle); } @@ -5095,7 +5091,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { result = mLockPatternUtils.setLockCredentialWithToken(password, TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE : LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - realQuality, tokenHandle, token, userHandle); + quality, tokenHandle, token, userHandle); } boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0; if (requireEntry) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index be09aea65073..4326c39c43a2 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -145,6 +145,7 @@ import com.android.server.webkit.WebViewUpdateService; import com.android.server.wm.ActivityTaskManagerService; import com.android.server.wm.WindowManagerGlobalLock; import com.android.server.wm.WindowManagerService; +import com.google.android.startop.iorap.IorapForwardingService; import dalvik.system.VMRuntime; @@ -1007,10 +1008,13 @@ public final class SystemServer { mSystemServiceManager.startService(PinnerService.class); traceEnd(); + traceBeginAndSlog("IorapForwardingService"); + mSystemServiceManager.startService(IorapForwardingService.class); + traceEnd(); + traceBeginAndSlog("SignedConfigService"); SignedConfigService.registerUpdateReceiver(mSystemContext); traceEnd(); - } catch (RuntimeException e) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting core service", e); diff --git a/services/net/Android.bp b/services/net/Android.bp index e0ae68f20483..ae697b7f093a 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -2,3 +2,19 @@ java_library_static { name: "services.net", srcs: ["java/**/*.java"], } + +// TODO: move to networking module with DhcpClient and remove lib +java_library { + name: "dhcp-packet-lib", + srcs: [ + "java/android/net/dhcp/*Packet.java", + ] +} + +// TODO: move to networking module with IpNeighborMonitor/ConnectivityPacketTracker and remove lib +java_library { + name: "frameworks-net-shared-utils", + srcs: [ + "java/android/net/util/FdEventsReader.java", + ] +}
\ No newline at end of file diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java index 6ba7d94117b1..ce8b7e78d0f8 100644 --- a/services/net/java/android/net/dhcp/DhcpPacket.java +++ b/services/net/java/android/net/dhcp/DhcpPacket.java @@ -1,8 +1,5 @@ package android.net.dhcp; -import static android.net.util.NetworkConstants.IPV4_MAX_MTU; -import static android.net.util.NetworkConstants.IPV4_MIN_MTU; - import android.annotation.Nullable; import android.net.DhcpResults; import android.net.LinkAddress; @@ -37,6 +34,9 @@ import java.util.List; public abstract class DhcpPacket { protected static final String TAG = "DhcpPacket"; + // TODO: use NetworkStackConstants.IPV4_MIN_MTU once this class is moved to the network stack. + private static final int IPV4_MIN_MTU = 68; + // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the // DHCP client timeout. diff --git a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java new file mode 100644 index 000000000000..f068c3ac16e2 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -0,0 +1,172 @@ +/* + * 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.dhcp; + +import static android.net.NetworkUtils.inet4AddressToIntHTH; + +import android.annotation.NonNull; +import android.net.LinkAddress; + +import com.google.android.collect.Sets; + +import java.net.Inet4Address; +import java.util.Collection; +import java.util.Set; + +/** + * Subclass of {@link DhcpServingParamsParcel} with additional utility methods for building. + * + * <p>This utility class does not check for validity of the parameters: invalid parameters are + * reported by the receiving module when unparceling the parcel. + * + * @see DhcpServingParams + * @hide + */ +public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { + public static final int MTU_UNSET = 0; + + /** + * Set the server address and served prefix for the DHCP server. + * + * <p>This parameter is required. + */ + public DhcpServingParamsParcelExt setServerAddr(@NonNull LinkAddress serverAddr) { + this.serverAddr = inet4AddressToIntHTH((Inet4Address) serverAddr.getAddress()); + this.serverAddrPrefixLength = serverAddr.getPrefixLength(); + return this; + } + + /** + * Set the default routers to be advertised to DHCP clients. + * + * <p>Each router must be inside the served prefix. This may be an empty set, but it must + * always be set explicitly. + */ + public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) { + this.defaultRouters = toIntArray(defaultRouters); + return this; + } + + /** + * Set the default routers to be advertised to DHCP clients. + * + * <p>Each router must be inside the served prefix. This may be an empty list of routers, + * but it must always be set explicitly. + */ + public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Inet4Address... defaultRouters) { + return setDefaultRouters(Sets.newArraySet(defaultRouters)); + } + + /** + * Convenience method to build the parameters with no default router. + * + * <p>Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address. + */ + public DhcpServingParamsParcelExt setNoDefaultRouter() { + return setDefaultRouters(); + } + + /** + * Set the DNS servers to be advertised to DHCP clients. + * + * <p>This may be an empty set, but it must always be set explicitly. + */ + public DhcpServingParamsParcelExt setDnsServers(@NonNull Set<Inet4Address> dnsServers) { + this.dnsServers = toIntArray(dnsServers); + return this; + } + + /** + * Set the DNS servers to be advertised to DHCP clients. + * + * <p>This may be an empty list of servers, but it must always be set explicitly. + */ + public DhcpServingParamsParcelExt setDnsServers(@NonNull Inet4Address... dnsServers) { + return setDnsServers(Sets.newArraySet(dnsServers)); + } + + /** + * Convenience method to build the parameters with no DNS server. + * + * <p>Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address. + */ + public DhcpServingParamsParcelExt setNoDnsServer() { + return setDnsServers(); + } + + /** + * Set excluded addresses that the DHCP server is not allowed to assign to clients. + * + * <p>This parameter is optional. DNS servers and default routers are always excluded + * and do not need to be set here. + */ + public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) { + this.excludedAddrs = toIntArray(excludedAddrs); + return this; + } + + /** + * Set excluded addresses that the DHCP server is not allowed to assign to clients. + * + * <p>This parameter is optional. DNS servers and default routers are always excluded + * and do not need to be set here. + */ + public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) { + return setExcludedAddrs(Sets.newArraySet(excludedAddrs)); + } + + /** + * Set the lease time for leases assigned by the DHCP server. + * + * <p>This parameter is required. + */ + public DhcpServingParamsParcelExt setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) { + this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs; + return this; + } + + /** + * Set the link MTU to be advertised to DHCP clients. + * + * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter + * is optional and defaults to {@link #MTU_UNSET}. + */ + public DhcpServingParamsParcelExt setLinkMtu(int linkMtu) { + this.linkMtu = linkMtu; + return this; + } + + /** + * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option. + * + * <p>If not set, the default value is false. + */ + public DhcpServingParamsParcelExt setMetered(boolean metered) { + this.metered = metered; + return this; + } + + private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) { + int[] res = new int[addrs.size()]; + int i = 0; + for (Inet4Address addr : addrs) { + res[i] = inet4AddressToIntHTH(addr); + i++; + } + return res; + } +} diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java index 493350d776f3..8b22f68286af 100644 --- a/services/net/java/android/net/ip/IpServer.java +++ b/services/net/java/android/net/ip/IpServer.java @@ -17,20 +17,26 @@ package android.net.ip; import static android.net.NetworkUtils.numericToInetAddress; -import static android.net.util.NetworkConstants.asByte; +import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.util.NetworkConstants.FF; import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; +import static android.net.util.NetworkConstants.asByte; +import android.content.Context; import android.net.ConnectivityManager; import android.net.INetd; +import android.net.INetworkStackStatusCallback; import android.net.INetworkStatsService; import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.NetworkStack; import android.net.RouteInfo; -import android.net.dhcp.DhcpServer; -import android.net.dhcp.DhcpServingParams; +import android.net.dhcp.DhcpServerCallbacks; +import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.DhcpServingParamsParcelExt; +import android.net.dhcp.IDhcpServer; import android.net.ip.RouterAdvertisementDaemon.RaParams; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; @@ -126,6 +132,10 @@ public class IpServer extends StateMachine { } public static class Dependencies { + private final Context mContext; + public Dependencies(Context context) { + mContext = context; + } public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) { return new RouterAdvertisementDaemon(ifParams); } @@ -138,9 +148,12 @@ public class IpServer extends StateMachine { return NetdService.getInstance(); } - public DhcpServer makeDhcpServer(Looper looper, String ifName, - DhcpServingParams params, SharedLog log) { - return new DhcpServer(looper, ifName, params, log); + /** + * Create a DhcpServer instance to be used by IpServer. + */ + public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, + DhcpServerCallbacks cb) { + mContext.getSystemService(NetworkStack.class).makeDhcpServer(ifName, params, cb); } } @@ -197,7 +210,10 @@ public class IpServer extends StateMachine { // Advertisements (otherwise, we do not add them to mLinkProperties at all). private LinkProperties mLastIPv6LinkProperties; private RouterAdvertisementDaemon mRaDaemon; - private DhcpServer mDhcpServer; + + // To be accessed only on the handler thread + private int mDhcpServerStartIndex = 0; + private IDhcpServer mDhcpServer; private RaParams mLastRaParams; public IpServer( @@ -252,35 +268,109 @@ public class IpServer extends StateMachine { private boolean startIPv4() { return configureIPv4(true); } + /** + * Convenience wrapper around INetworkStackStatusCallback to run callbacks on the IpServer + * handler. + * + * <p>Different instances of this class can be created for each call to IDhcpServer methods, + * with different implementations of the callback, to differentiate handling of success/error in + * each call. + */ + private abstract class OnHandlerStatusCallback extends INetworkStackStatusCallback.Stub { + @Override + public void onStatusAvailable(int statusCode) { + getHandler().post(() -> callback(statusCode)); + } + + public abstract void callback(int statusCode); + } + + private class DhcpServerCallbacksImpl extends DhcpServerCallbacks { + private final int mStartIndex; + + private DhcpServerCallbacksImpl(int startIndex) { + mStartIndex = startIndex; + } + + @Override + public void onDhcpServerCreated(int statusCode, IDhcpServer server) throws RemoteException { + getHandler().post(() -> { + // We are on the handler thread: mDhcpServerStartIndex can be read safely. + if (mStartIndex != mDhcpServerStartIndex) { + // This start request is obsolete. When the |server| binder token goes out of + // scope, the garbage collector will finalize it, which causes the network stack + // process garbage collector to collect the server itself. + return; + } + + if (statusCode != STATUS_SUCCESS) { + mLog.e("Error obtaining DHCP server: " + statusCode); + handleError(); + return; + } + + mDhcpServer = server; + try { + mDhcpServer.start(new OnHandlerStatusCallback() { + @Override + public void callback(int startStatusCode) { + if (startStatusCode != STATUS_SUCCESS) { + mLog.e("Error starting DHCP server: " + startStatusCode); + handleError(); + } + } + }); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + }); + } + + private void handleError() { + mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR; + transitionTo(mInitialState); + } + } + private boolean startDhcp(Inet4Address addr, int prefixLen) { if (mUsingLegacyDhcp) { return true; } - final DhcpServingParams params; - try { - params = new DhcpServingParams.Builder() - .setDefaultRouters(addr) - .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) - .setDnsServers(addr) - .setServerAddr(new LinkAddress(addr, prefixLen)) - .setMetered(true) - .build(); - // TODO: also advertise link MTU - } catch (DhcpServingParams.InvalidParameterException e) { - Log.e(TAG, "Invalid DHCP parameters", e); - return false; - } - - mDhcpServer = mDeps.makeDhcpServer(getHandler().getLooper(), mIfaceName, params, - mLog.forSubComponent("DHCP")); - mDhcpServer.start(); + final DhcpServingParamsParcel params; + params = new DhcpServingParamsParcelExt() + .setDefaultRouters(addr) + .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) + .setDnsServers(addr) + .setServerAddr(new LinkAddress(addr, prefixLen)) + .setMetered(true); + // TODO: also advertise link MTU + + mDhcpServerStartIndex++; + mDeps.makeDhcpServer( + mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex)); return true; } private void stopDhcp() { + // Make all previous start requests obsolete so servers are not started later + mDhcpServerStartIndex++; + if (mDhcpServer != null) { - mDhcpServer.stop(); - mDhcpServer = null; + try { + mDhcpServer.stop(new OnHandlerStatusCallback() { + @Override + public void callback(int statusCode) { + if (statusCode != STATUS_SUCCESS) { + mLog.e("Error stopping DHCP server: " + statusCode); + mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR; + // Not much more we can do here + } + } + }); + mDhcpServer = null; + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } } diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java index 3defe56939f5..c183b81362dc 100644 --- a/services/net/java/android/net/util/NetworkConstants.java +++ b/services/net/java/android/net/util/NetworkConstants.java @@ -16,9 +16,6 @@ package android.net.util; -import java.nio.ByteBuffer; - - /** * Networking protocol constants. * @@ -81,8 +78,6 @@ public final class NetworkConstants { * - https://tools.ietf.org/html/rfc791 */ public static final int IPV4_HEADER_MIN_LEN = 20; - public static final int IPV4_MIN_MTU = 68; - public static final int IPV4_MAX_MTU = 65_535; public static final int IPV4_IHL_MASK = 0xf; public static final int IPV4_FLAGS_OFFSET = 6; public static final int IPV4_FRAGMENT_MASK = 0x1fff; diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java index 5a73a4e492ee..8b7b59d20978 100644 --- a/services/net/java/android/net/util/SharedLog.java +++ b/services/net/java/android/net/util/SharedLog.java @@ -32,11 +32,12 @@ import java.util.StringJoiner; * * All access to class methods other than dump() must be on the same thread. * + * TODO: this is a copy of SharedLog in the NetworkStack. Remove after Tethering is migrated. * @hide */ public class SharedLog { - private final static int DEFAULT_MAX_RECORDS = 500; - private final static String COMPONENT_DELIMITER = "."; + private static final int DEFAULT_MAX_RECORDS = 500; + private static final String COMPONENT_DELIMITER = "."; private enum Category { NONE, @@ -69,6 +70,9 @@ public class SharedLog { mComponent = component; } + /** + * Create a SharedLog based on this log with an additional component prefix on each logged line. + */ public SharedLog forSubComponent(String component) { if (!isRootLogInstance()) { component = mComponent + COMPONENT_DELIMITER + component; @@ -76,6 +80,11 @@ public class SharedLog { return new SharedLog(mLocalLog, mTag, component); } + /** + * Dump the contents of this log. + * + * <p>This method may be called on any thread. + */ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mLocalLog.readOnlyLocalLog().dump(fd, writer, args); } @@ -84,10 +93,21 @@ public class SharedLog { // Methods that both log an entry and emit it to the system log. ////// + /** + * Log an error due to an exception. This does not include the exception stacktrace. + * + * <p>The log entry will be also added to the system log. + * @see #e(String, Throwable) + */ public void e(Exception e) { Log.e(mTag, record(Category.ERROR, e.toString())); } + /** + * Log an error message. + * + * <p>The log entry will be also added to the system log. + */ public void e(String msg) { Log.e(mTag, record(Category.ERROR, msg)); } @@ -96,7 +116,7 @@ public class SharedLog { * Log an error due to an exception, with the exception stacktrace if provided. * * <p>The error and exception message appear in the shared log, but the stacktrace is only - * logged in general log output (logcat). + * logged in general log output (logcat). The log entry will be also added to the system log. */ public void e(@NonNull String msg, @Nullable Throwable exception) { if (exception == null) { @@ -106,10 +126,20 @@ public class SharedLog { Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception); } + /** + * Log an informational message. + * + * <p>The log entry will be also added to the system log. + */ public void i(String msg) { Log.i(mTag, record(Category.NONE, msg)); } + /** + * Log a warning message. + * + * <p>The log entry will be also added to the system log. + */ public void w(String msg) { Log.w(mTag, record(Category.WARN, msg)); } @@ -118,14 +148,30 @@ public class SharedLog { // Methods that only log an entry (and do NOT emit to the system log). ////// + /** + * Log a general message to be only included in the in-memory log. + * + * <p>The log entry will *not* be added to the system log. + */ public void log(String msg) { record(Category.NONE, msg); } + /** + * Log a general, formatted message to be only included in the in-memory log. + * + * <p>The log entry will *not* be added to the system log. + * @see String#format(String, Object...) + */ public void logf(String fmt, Object... args) { log(String.format(fmt, args)); } + /** + * Log a message with MARK level. + * + * <p>The log entry will *not* be added to the system log. + */ public void mark(String msg) { record(Category.MARK, msg); } diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java index b8723c520cf8..769a9d4a2bd4 100644 --- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java +++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java @@ -16,6 +16,7 @@ package com.android.server.backup; +import static android.Manifest.permission.BACKUP; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread; @@ -192,6 +193,19 @@ public class BackupManagerServiceTest { /** Test that the service unregisters users when stopped. */ @Test + public void testStopServiceForUser_forRegisteredUser_tearsDownCorrectUser() throws Exception { + BackupManagerService backupManagerService = + createServiceAndRegisterUser(mUserOneId, mUserOneService); + backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService); + + backupManagerService.stopServiceForUser(mUserOneId); + + verify(mUserOneService).tearDownService(); + verify(mUserTwoService, never()).tearDownService(); + } + + /** Test that the service unregisters users when stopped. */ + @Test public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception { BackupManagerService backupManagerService = createService(); @@ -1528,6 +1542,7 @@ public class BackupManagerServiceTest { } private BackupManagerService createService() { + mShadowContext.grantPermissions(BACKUP); return new BackupManagerService( mContext, new Trampoline(mContext), startBackupThread(null)); } diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java index bb60c27a2543..8d5c301d93e7 100644 --- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java +++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java @@ -829,7 +829,7 @@ public class UserBackupManagerServiceTest { public void testRequestBackup_whenNotProvisioned() throws Exception { mShadowContext.grantPermissions(android.Manifest.permission.BACKUP); UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks(); - backupManagerService.setProvisioned(false); + backupManagerService.setSetupComplete(false); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); @@ -848,7 +848,7 @@ public class UserBackupManagerServiceTest { setUpCurrentTransport(mTransportManager, mTransport.unregistered()); UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks(); backupManagerService.setEnabled(true); - backupManagerService.setProvisioned(true); + backupManagerService.setSetupComplete(true); int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); @@ -868,7 +868,7 @@ public class UserBackupManagerServiceTest { setUpCurrentTransport(mTransportManager, mTransport); UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks(); backupManagerService.setEnabled(true); - backupManagerService.setProvisioned(true); + backupManagerService.setSetupComplete(true); // Haven't set PACKAGE_1 as eligible int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0); @@ -965,14 +965,13 @@ public class UserBackupManagerServiceTest { private UserBackupManagerService createBackupManagerServiceForRequestBackup() { UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks(); backupManagerService.setEnabled(true); - backupManagerService.setProvisioned(true); + backupManagerService.setSetupComplete(true); return backupManagerService; } /** - * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context, - * Trampoline, HandlerThread, File, File, TransportManager)} posts a transport registration task - * to the backup thread. + * Test verifying that creating a new instance posts a transport registration task to the backup + * thread. */ @Test public void testCreateAndInitializeService_postRegisterTransports() { @@ -992,9 +991,8 @@ public class UserBackupManagerServiceTest { } /** - * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context, - * Trampoline, HandlerThread, File, File, TransportManager)} does not directly register - * transports on the main thread. + * Test verifying that creating a new instance does not directly register transports on the main + * thread. */ @Test public void testCreateAndInitializeService_doesNotRegisterTransportsSynchronously() { @@ -1013,11 +1011,7 @@ public class UserBackupManagerServiceTest { verify(mTransportManager, never()).registerTransports(); } - /** - * Test checking non-null argument on {@link - * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File, - * File, TransportManager)}. - */ + /** Test checking non-null argument on instance creation. */ @Test public void testCreateAndInitializeService_withNullContext_throws() { expectThrows( @@ -1033,11 +1027,7 @@ public class UserBackupManagerServiceTest { mTransportManager)); } - /** - * Test checking non-null argument on {@link - * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File, - * File, TransportManager)}. - */ + /** Test checking non-null argument on instance creation. */ @Test public void testCreateAndInitializeService_withNullTrampoline_throws() { expectThrows( @@ -1053,11 +1043,7 @@ public class UserBackupManagerServiceTest { mTransportManager)); } - /** - * Test checking non-null argument on {@link - * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File, - * File, TransportManager)}. - */ + /** Test checking non-null argument on instance creation. */ @Test public void testCreateAndInitializeService_withNullBackupThread_throws() { expectThrows( @@ -1073,11 +1059,7 @@ public class UserBackupManagerServiceTest { mTransportManager)); } - /** - * Test checking non-null argument on {@link - * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File, - * File, TransportManager)}. - */ + /** Test checking non-null argument on instance creation. */ @Test public void testCreateAndInitializeService_withNullStateDir_throws() { expectThrows( diff --git a/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java b/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java index 423512ce4b70..aca48b647efa 100644 --- a/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java +++ b/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java @@ -12,6 +12,7 @@ import static org.robolectric.Shadows.shadowOf; import static org.testng.Assert.expectThrows; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.Application; import android.app.backup.BackupDataInput; import android.app.backup.FullBackupDataOutput; @@ -62,6 +63,7 @@ public class AppMetadataBackupWriterTest { private static final String TEST_PACKAGE_INSTALLER = "com.test.package.installer"; private static final Long TEST_PACKAGE_VERSION_CODE = 100L; + private @UserIdInt int mUserId; private PackageManager mPackageManager; private ShadowApplicationPackageManager mShadowPackageManager; private File mFilesDir; @@ -72,6 +74,7 @@ public class AppMetadataBackupWriterTest { public void setUp() throws Exception { Application application = RuntimeEnvironment.application; + mUserId = UserHandle.USER_SYSTEM; mPackageManager = application.getPackageManager(); mShadowPackageManager = (ShadowApplicationPackageManager) shadowOf(mPackageManager); @@ -352,7 +355,7 @@ public class AppMetadataBackupWriterTest { byte[] obbBytes = "obb".getBytes(); File obbFile = createObbFileAndWrite(obbDir, obbBytes); - mBackupWriter.backupObb(packageInfo); + mBackupWriter.backupObb(mUserId, packageInfo); byte[] writtenBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false); assertThat(writtenBytes).isEqualTo(obbBytes); @@ -366,7 +369,7 @@ public class AppMetadataBackupWriterTest { File obbDir = createObbDirForPackage(packageInfo.packageName); // No obb file created. - mBackupWriter.backupObb(packageInfo); + mBackupWriter.backupObb(mUserId, packageInfo); assertThat(mBackupDataOutputFile.length()).isEqualTo(0); } diff --git a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java new file mode 100644 index 000000000000..b754356ca0cb --- /dev/null +++ b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2019 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.backup.internal; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.os.Handler; +import android.os.HandlerThread; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; + +import com.android.server.backup.KeyValueBackupJob; +import com.android.server.backup.TransportManager; +import com.android.server.backup.UserBackupManagerService; +import com.android.server.backup.testing.BackupManagerServiceTestUtils; +import com.android.server.backup.testing.TestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.io.File; + +/** + * Tests verifying the interaction between {@link SetupObserver} and {@link + * UserBackupManagerService}. + */ +@RunWith(RobolectricTestRunner.class) +@Presubmit +public class SetupObserverTest { + private static final String TAG = "SetupObserverTest"; + private static final int USER_ID = 10; + + @Mock private TransportManager mTransportManager; + + private Context mContext; + private UserBackupManagerService mUserBackupManagerService; + private HandlerThread mHandlerThread; + + /** Setup state. */ + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mHandlerThread = BackupManagerServiceTestUtils.startSilentBackupThread(TAG); + mUserBackupManagerService = + BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks( + USER_ID, + mContext, + mHandlerThread, + new File(mContext.getDataDir(), "test1"), + new File(mContext.getDataDir(), "test2"), + mTransportManager); + } + + /** Test observer handles changes from not setup -> setup correctly. */ + @Test + public void testOnChange_whenNewlySetup_updatesState() throws Exception { + SetupObserver setupObserver = new SetupObserver(mUserBackupManagerService, new Handler()); + mUserBackupManagerService.setSetupComplete(false); + changeSetupCompleteSettingForUser(true, USER_ID); + + setupObserver.onChange(true); + + assertThat(mUserBackupManagerService.isSetupComplete()).isTrue(); + } + + /** Test observer handles changes from setup -> not setup correctly. */ + @Test + public void testOnChange_whenPreviouslySetup_doesNotUpdateState() throws Exception { + SetupObserver setupObserver = new SetupObserver(mUserBackupManagerService, new Handler()); + mUserBackupManagerService.setSetupComplete(true); + changeSetupCompleteSettingForUser(false, USER_ID); + + setupObserver.onChange(true); + + assertThat(mUserBackupManagerService.isSetupComplete()).isTrue(); + } + + /** Test observer handles changes from not setup -> not setup correctly. */ + @Test + public void testOnChange_whenNotPreviouslySetup_doesNotUpdateStateIfNoChange() + throws Exception { + SetupObserver setupObserver = new SetupObserver(mUserBackupManagerService, new Handler()); + mUserBackupManagerService.setSetupComplete(false); + changeSetupCompleteSettingForUser(false, USER_ID); + + setupObserver.onChange(true); + + assertThat(mUserBackupManagerService.isSetupComplete()).isFalse(); + } + + /** Test observer handles changes from not setup -> setup correctly. */ + @Test + public void testOnChange_whenNewlySetup_schedulesBackup() throws Exception { + SetupObserver setupObserver = new SetupObserver(mUserBackupManagerService, new Handler()); + mUserBackupManagerService.setSetupComplete(false); + changeSetupCompleteSettingForUser(true, USER_ID); + // Setup conditions for a full backup job to be scheduled. + mUserBackupManagerService.setEnabled(true); + mUserBackupManagerService.enqueueFullBackup("testPackage", /* lastBackedUp */ 0); + // Clear the handler of all pending tasks. This is to prevent the below assertion on the + // handler from encountering false positives due to other tasks being scheduled as part of + // setup work. + TestUtils.runToEndOfTasks(mHandlerThread.getLooper()); + + setupObserver.onChange(true); + + assertThat(KeyValueBackupJob.isScheduled()).isTrue(); + // Verifies that the full backup job is scheduled. The job is scheduled via a posted message + // on the backup handler so we verify that a message exists. + assertThat(mUserBackupManagerService.getBackupHandler().hasMessagesOrCallbacks()).isTrue(); + } + + private void changeSetupCompleteSettingForUser(boolean value, int userId) { + Settings.Secure.putIntForUser( + mContext.getContentResolver(), + Settings.Secure.USER_SETUP_COMPLETE, + value ? 1 : 0, + userId); + } +} diff --git a/services/startop/Android.bp b/services/startop/Android.bp new file mode 100644 index 000000000000..093b4ec66ddf --- /dev/null +++ b/services/startop/Android.bp @@ -0,0 +1,24 @@ +/* + * 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. + */ + +java_library_static { + name: "services.startop", + + static_libs: [ + // frameworks/base/startop/iorap + "services.startop.iorap", + ], +} 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 ea0e095cfc1f..6a10ff487d2d 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -71,6 +71,8 @@ import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; import com.android.server.AppOpsService; +import com.android.server.am.ProcessList.IsolatedUidRange; +import com.android.server.am.ProcessList.IsolatedUidRangeAllocator; import com.android.server.wm.ActivityTaskManagerService; import org.junit.After; @@ -294,6 +296,113 @@ public class ActivityManagerServiceTest { } } + private void validateAppZygoteIsolatedUidRange(IsolatedUidRange uidRange) { + assertNotNull(uidRange); + assertTrue(uidRange.mFirstUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID + && uidRange.mFirstUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID); + assertTrue(uidRange.mLastUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID + && uidRange.mLastUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID); + assertTrue(uidRange.mLastUid > uidRange.mFirstUid + && ((uidRange.mLastUid - uidRange.mFirstUid + 1) + == Process.NUM_UIDS_PER_APP_ZYGOTE)); + } + + private void verifyUidRangesNoOverlap(IsolatedUidRange uidRange1, IsolatedUidRange uidRange2) { + IsolatedUidRange lowRange = uidRange1.mFirstUid <= uidRange2.mFirstUid ? uidRange1 : uidRange2; + IsolatedUidRange highRange = lowRange == uidRange1 ? uidRange2 : uidRange1; + + assertTrue(highRange.mFirstUid > lowRange.mLastUid); + } + + @Test + public void testIsolatedUidRangeAllocator() { + final IsolatedUidRangeAllocator allocator = mAms.mProcessList.mAppIsolatedUidRangeAllocator; + + // Create initial range + ApplicationInfo appInfo = new ApplicationInfo(); + appInfo.processName = "com.android.test.app"; + appInfo.uid = 10000; + final IsolatedUidRange range = allocator.getOrCreateIsolatedUidRangeLocked(appInfo); + validateAppZygoteIsolatedUidRange(range); + verifyIsolatedUidAllocator(range); + + // Create a second range + ApplicationInfo appInfo2 = new ApplicationInfo(); + appInfo2.processName = "com.android.test.app2"; + appInfo2.uid = 10001; + IsolatedUidRange range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2); + validateAppZygoteIsolatedUidRange(range2); + verifyIsolatedUidAllocator(range2); + + // Verify ranges don't overlap + verifyUidRangesNoOverlap(range, range2); + + // Free range, reallocate and verify + allocator.freeUidRangeLocked(appInfo2); + range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2); + validateAppZygoteIsolatedUidRange(range2); + verifyUidRangesNoOverlap(range, range2); + verifyIsolatedUidAllocator(range2); + + // Free both, then try to allocate the maximum number of UID ranges + allocator.freeUidRangeLocked(appInfo); + allocator.freeUidRangeLocked(appInfo2); + + int maxNumUidRanges = (Process.LAST_APP_ZYGOTE_ISOLATED_UID + - Process.FIRST_APP_ZYGOTE_ISOLATED_UID + 1) / Process.NUM_UIDS_PER_APP_ZYGOTE; + for (int i = 0; i < maxNumUidRanges; i++) { + appInfo = new ApplicationInfo(); + appInfo.uid = 10000 + i; + appInfo.processName = "com.android.test.app" + Integer.toString(i); + IsolatedUidRange uidRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo); + validateAppZygoteIsolatedUidRange(uidRange); + verifyIsolatedUidAllocator(uidRange); + } + + // Try to allocate another one and make sure it fails + appInfo = new ApplicationInfo(); + appInfo.uid = 9000; + appInfo.processName = "com.android.test.app.failed"; + IsolatedUidRange failedRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo); + + assertNull(failedRange); + } + + public void verifyIsolatedUid(ProcessList.IsolatedUidRange range, int uid) { + assertTrue(uid >= range.mFirstUid && uid <= range.mLastUid); + } + + public void verifyIsolatedUidAllocator(ProcessList.IsolatedUidRange range) { + int uid = range.allocateIsolatedUidLocked(0); + verifyIsolatedUid(range, uid); + + int uid2 = range.allocateIsolatedUidLocked(0); + verifyIsolatedUid(range, uid2); + assertTrue(uid2 != uid); + + // Free both + range.freeIsolatedUidLocked(uid); + range.freeIsolatedUidLocked(uid2); + + // Allocate the entire range + for (int i = 0; i < (range.mLastUid - range.mFirstUid + 1); ++i) { + uid = range.allocateIsolatedUidLocked(0); + verifyIsolatedUid(range, uid); + } + + // Ensure the next one fails + uid = range.allocateIsolatedUidLocked(0); + assertEquals(uid, -1); + } + + @Test + public void testGlobalIsolatedUidAllocator() { + final IsolatedUidRange globalUidRange = mAms.mProcessList.mGlobalIsolatedUids; + assertEquals(globalUidRange.mFirstUid, Process.FIRST_ISOLATED_UID); + assertEquals(globalUidRange.mLastUid, Process.LAST_ISOLATED_UID); + verifyIsolatedUidAllocator(globalUidRange); + } + @Test public void testBlockStateForUid() { final UidRecord uidRec = new UidRecord(TEST_UID, null /* atmInternal */); diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index abf90402250c..4742a73b17a8 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -389,7 +389,7 @@ public class DisplayManagerServiceTest { if (attr == null) return; //sampling not supported on device, skip remainder of test. boolean enabled = displayManager.setDisplayedContentSamplingEnabledInternal(0, true, 0, 0); - assertTrue(!enabled); + assertTrue(enabled); displayManager.setDisplayedContentSamplingEnabledInternal(0, false, 0, 0); DisplayedContentSample sample = displayManager.getDisplayedContentSampleInternal(0, 0, 0); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java index 7484edd286f0..4255e37aac2d 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java @@ -18,8 +18,12 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.MessageQueue; + import com.android.internal.annotations.VisibleForTesting; import com.android.server.hdmi.HdmiCecController.NativeWrapper; + +import com.google.common.collect.Iterables; + import java.util.ArrayList; import java.util.List; @@ -45,7 +49,6 @@ final class FakeNativeWrapper implements NativeWrapper { }; private final List<HdmiCecMessage> mResultMessages = new ArrayList<>(); - private HdmiCecMessage mResultMessage; private int mMyPhysicalAddress = 0; @Override @@ -112,11 +115,12 @@ final class FakeNativeWrapper implements NativeWrapper { return new ArrayList<>(mResultMessages); } - public HdmiCecMessage getOnlyResultMessage() throws Exception { - if (mResultMessages.size() != 1) { - throw new Exception("There is not exactly one message"); - } - return mResultMessages.get(0); + public HdmiCecMessage getOnlyResultMessage() throws IllegalArgumentException { + return Iterables.getOnlyElement(mResultMessages); + } + + public void clearResultMessages() { + mResultMessages.clear(); } public void setPollAddressResponse(int logicalAddress, int response) { diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java index 9e3a0eaa68f6..bdede3354ef7 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -20,22 +20,20 @@ import static com.android.server.hdmi.Constants.ADDR_BROADCAST; import static com.android.server.hdmi.Constants.ADDR_TV; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF; -import static com.google.common.truth.Truth.assertThat; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import android.media.AudioManager; import android.os.Looper; import android.os.SystemProperties; import android.os.test.TestLooper; + import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; + import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -61,6 +59,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { private int mMusicVolume; private int mMusicMaxVolume; private boolean mMusicMute; + private int mAvrPhysicalAddress; @Before public void setUp() { @@ -115,7 +114,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { @Override public void setWiredDeviceConnectionState( - int type, int state, String address, String name) { + int type, int state, String address, String name) { // Do nothing. } }; @@ -123,6 +122,11 @@ public class HdmiCecLocalDeviceAudioSystemTest { @Override void wakeUp() {} + + @Override + boolean isControlEnabled() { + return true; + } }; mMyLooper = mTestLooper.getLooper(); @@ -140,11 +144,15 @@ public class HdmiCecLocalDeviceAudioSystemTest { // No TV device interacts with AVR so system audio control won't be turned on here mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); + mAvrPhysicalAddress = 0x2000; + mNativeWrapper.setPhysicalAddress(mAvrPhysicalAddress); SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true"); + SystemProperties.set(Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, "true"); } @Test - public void handleGiveAudioStatus_volume_10_mute_true() { + public void handleGiveAudioStatus_volume_10_mute_true() throws Exception { mMusicVolume = 10; mMusicMute = true; mMusicMaxVolume = 20; @@ -154,14 +162,13 @@ public class HdmiCecLocalDeviceAudioSystemTest { ADDR_AUDIO_SYSTEM, ADDR_TV, scaledVolume, true); HdmiCecMessage messageGive = HdmiCecMessageBuilder.buildGiveAudioStatus(ADDR_TV, ADDR_AUDIO_SYSTEM); - assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(messageGive)) - .isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(messageGive)).isTrue(); mTestLooper.dispatchAll(); - assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } @Test - public void handleGiveSystemAudioModeStatus_originalOff() { + public void handleGiveSystemAudioModeStatus_originalOff() throws Exception { HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false); HdmiCecMessage messageGive = @@ -169,10 +176,9 @@ public class HdmiCecLocalDeviceAudioSystemTest { assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive)) .isTrue(); mTestLooper.dispatchAll(); - assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); } - @Ignore("b/80297700") @Test public void handleRequestShortAudioDescriptor_featureDisabled() throws Exception { HdmiCecMessage expectedMessage = @@ -228,7 +234,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test - public void handleSetSystemAudioMode_setOn_orignalOff() { + public void handleSetSystemAudioMode_setOn_orignalOff() throws Exception { mMusicMute = true; HdmiCecMessage messageSet = HdmiCecMessageBuilder.buildSetSystemAudioMode(ADDR_TV, ADDR_AUDIO_SYSTEM, true); @@ -240,23 +246,22 @@ public class HdmiCecLocalDeviceAudioSystemTest { assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive)) .isTrue(); mTestLooper.dispatchAll(); - assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); // Check if correctly turned on + mNativeWrapper.clearResultMessages(); expectedMessage = HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, true); - assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet)) - .isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet)).isTrue(); mTestLooper.dispatchAll(); assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive)) .isTrue(); mTestLooper.dispatchAll(); - assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); assertThat(mMusicMute).isFalse(); } - @Ignore("b/80297700") @Test - public void handleSystemAudioModeRequest_turnOffByTv() { + public void handleSystemAudioModeRequest_turnOffByTv() throws Exception { assertThat(mMusicMute).isFalse(); // Check if feature correctly turned off HdmiCecMessage messageGive = @@ -270,19 +275,22 @@ public class HdmiCecLocalDeviceAudioSystemTest { assertThat(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(messageRequestOff)) .isTrue(); mTestLooper.dispatchAll(); - assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); + + mNativeWrapper.clearResultMessages(); expectedMessage = HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false); assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive)) .isTrue(); mTestLooper.dispatchAll(); - assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); assertThat(mMusicMute).isTrue(); } - @Ignore("b/80297700") @Test - public void onStandbyAudioSystem_currentSystemAudioControlOn() { + public void onStandbyAudioSystem_currentSystemAudioControlOn() throws Exception { + mHdmiCecLocalDeviceAudioSystem.setAutoDeviceOff(false); + mHdmiCecLocalDeviceAudioSystem.setAutoTvOff(false); // Set system audio control on first mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true); // Check if standby correctly turns off the feature @@ -291,12 +299,12 @@ public class HdmiCecLocalDeviceAudioSystemTest { HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildSetSystemAudioMode( ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false); - assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); assertThat(mMusicMute).isTrue(); } @Test - public void systemAudioControlOnPowerOn_alwaysOn() { + public void systemAudioControlOnPowerOn_alwaysOn() throws Exception { mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class); mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn( Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true); @@ -307,7 +315,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test - public void systemAudioControlOnPowerOn_neverOn() { + public void systemAudioControlOnPowerOn_neverOn() throws Exception { mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class); mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn( Constants.NEVER_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, false); @@ -318,7 +326,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test - public void systemAudioControlOnPowerOn_useLastState_off() { + public void systemAudioControlOnPowerOn_useLastState_off() throws Exception { mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class); mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn( Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, false); @@ -329,7 +337,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test - public void systemAudioControlOnPowerOn_useLastState_on() { + public void systemAudioControlOnPowerOn_useLastState_on() throws Exception { mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class); mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn( Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true); @@ -340,18 +348,17 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test - public void handleActiveSource_updateActiveSource() { + public void handleActiveSource_updateActiveSource() throws Exception { HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000); ActiveSource expectedActiveSource = new ActiveSource(ADDR_TV, 0x0000); - assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message)) - .isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message)).isTrue(); mTestLooper.dispatchAll(); assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().equals(expectedActiveSource)) .isTrue(); } @Test - public void terminateSystemAudioMode_systemAudioModeOff() { + public void terminateSystemAudioMode_systemAudioModeOff() throws Exception { mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false); assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse(); mMusicMute = false; @@ -361,12 +368,11 @@ public class HdmiCecLocalDeviceAudioSystemTest { mHdmiCecLocalDeviceAudioSystem.terminateSystemAudioMode(); assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse(); assertThat(mMusicMute).isFalse(); - assertThat(mNativeWrapper.getResultMessages()).doesNotContain(message); + assertThat(mNativeWrapper.getResultMessages()).isEmpty(); } - @Ignore("b/80297700") @Test - public void terminateSystemAudioMode_systemAudioModeOn() { + public void terminateSystemAudioMode_systemAudioModeOn() throws Exception { mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true); assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue(); mMusicMute = false; @@ -381,124 +387,146 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test - public void isPhysicalAddressMeOrBelow_isMe() { + public void pathToPort_isMe() throws Exception { int targetPhysicalAddress = 0x1000; mNativeWrapper.setPhysicalAddress(0x1000); - assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) - .isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem + .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) + .isEqualTo(0); } @Test - public void isPhysicalAddressMeOrBelow_isBelow() { + public void pathToPort_isBelow() throws Exception { int targetPhysicalAddress = 0x1100; mNativeWrapper.setPhysicalAddress(0x1000); - assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) - .isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem + .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) + .isEqualTo(1); } @Test - public void isPhysicalAddressMeOrBelow_neitherMeNorBelow() { + public void pathToPort_neitherMeNorBelow() throws Exception { int targetPhysicalAddress = 0x3000; mNativeWrapper.setPhysicalAddress(0x2000); - assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) - .isFalse(); + assertThat(mHdmiCecLocalDeviceAudioSystem + .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) + .isEqualTo(-1); targetPhysicalAddress = 0x2200; mNativeWrapper.setPhysicalAddress(0x3300); - assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) - .isFalse(); + assertThat(mHdmiCecLocalDeviceAudioSystem + .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) + .isEqualTo(-1); targetPhysicalAddress = 0x2213; mNativeWrapper.setPhysicalAddress(0x2212); - assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) - .isFalse(); + assertThat(mHdmiCecLocalDeviceAudioSystem + .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) + .isEqualTo(-1); targetPhysicalAddress = 0x2340; mNativeWrapper.setPhysicalAddress(0x2310); - assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress)) - .isFalse(); + assertThat(mHdmiCecLocalDeviceAudioSystem + .getLocalPortFromPhysicalAddress(targetPhysicalAddress)) + .isEqualTo(-1); } @Test - public void handleRequestArcInitiate_isNotDirectConnectedToTv() { - HdmiCecMessage message = HdmiCecMessageBuilder - .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM); - HdmiCecMessage expectedMessage = HdmiCecMessageBuilder - .buildFeatureAbortCommand( - ADDR_AUDIO_SYSTEM, ADDR_TV, - Constants.MESSAGE_REQUEST_ARC_INITIATION, - Constants.ABORT_NOT_IN_CORRECT_MODE); + public void handleRequestArcInitiate_isNotDirectConnectedToTv() throws Exception { + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM); + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + Constants.MESSAGE_REQUEST_ARC_INITIATION, + Constants.ABORT_NOT_IN_CORRECT_MODE); mNativeWrapper.setPhysicalAddress(0x1100); - assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)) - .isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue(); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); } @Test - public void handleRequestArcInitiate_startArcInitiationActionFromAvr() { - HdmiCecMessage message = HdmiCecMessageBuilder - .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM); + public void handleRequestArcInitiate_startArcInitiationActionFromAvr() throws Exception { + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM); mNativeWrapper.setPhysicalAddress(0x1000); - mHdmiCecLocalDeviceAudioSystem.removeAction( - ArcInitiationActionFromAvr.class); + mHdmiCecLocalDeviceAudioSystem.removeAction(ArcInitiationActionFromAvr.class); - assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)) - .isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue(); mTestLooper.dispatchAll(); - assertThat(mHdmiCecLocalDeviceAudioSystem - .getActions(ArcInitiationActionFromAvr.class)).isNotEmpty(); + assertThat(mHdmiCecLocalDeviceAudioSystem.getActions(ArcInitiationActionFromAvr.class)) + .isNotEmpty(); } @Test - public void handleRequestArcTerminate_arcIsOn_startTerminationActionFromAvr() { + public void handleRequestArcTerminate_arcIsOn_startTerminationActionFromAvr() throws Exception { mHdmiCecLocalDeviceAudioSystem.setArcStatus(true); assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue(); - HdmiCecMessage message = HdmiCecMessageBuilder - .buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM); - mHdmiCecLocalDeviceAudioSystem.removeAction( - ArcTerminationActionFromAvr.class); + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceAudioSystem.removeAction(ArcTerminationActionFromAvr.class); - assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message)) - .isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message)).isTrue(); mTestLooper.dispatchAll(); - assertThat(mHdmiCecLocalDeviceAudioSystem - .getActions(ArcTerminationActionFromAvr.class)).isNotEmpty(); + assertThat(mHdmiCecLocalDeviceAudioSystem.getActions(ArcTerminationActionFromAvr.class)) + .isNotEmpty(); } @Test - public void handleRequestArcTerminate_arcIsNotOn() { + public void handleRequestArcTerminate_arcIsNotOn() throws Exception { assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse(); - HdmiCecMessage message = HdmiCecMessageBuilder - .buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM); - HdmiCecMessage expectedMessage = HdmiCecMessageBuilder - .buildFeatureAbortCommand( - ADDR_AUDIO_SYSTEM, ADDR_TV, - Constants.MESSAGE_REQUEST_ARC_TERMINATION, - Constants.ABORT_NOT_IN_CORRECT_MODE); - - assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message)) - .isTrue(); + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM); + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + Constants.MESSAGE_REQUEST_ARC_TERMINATION, + Constants.ABORT_NOT_IN_CORRECT_MODE); + + assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message)).isTrue(); mTestLooper.dispatchAll(); assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); } @Test - public void handleRequestArcInit_arcIsNotSupported() { - HdmiCecMessage message = HdmiCecMessageBuilder - .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM); - HdmiCecMessage expectedMessage = HdmiCecMessageBuilder - .buildFeatureAbortCommand( - ADDR_AUDIO_SYSTEM, ADDR_TV, - Constants.MESSAGE_REQUEST_ARC_INITIATION, - Constants.ABORT_UNRECOGNIZED_OPCODE); + public void handleRequestArcInit_arcIsNotSupported() throws Exception { + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM); + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildFeatureAbortCommand( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + Constants.MESSAGE_REQUEST_ARC_INITIATION, + Constants.ABORT_UNRECOGNIZED_OPCODE); SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "false"); - assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)) - .isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue(); mTestLooper.dispatchAll(); - assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); + } + + @Test + public void onStandby_setAutoDeviceOff_true() throws Exception { + HdmiCecMessage expectedMessage = + HdmiCecMessageBuilder.buildStandby(ADDR_AUDIO_SYSTEM, ADDR_BROADCAST); + mHdmiCecLocalDeviceAudioSystem.setAutoDeviceOff(true); + mHdmiCecLocalDeviceAudioSystem.onStandby(false, STANDBY_SCREEN_OFF); + + mTestLooper.dispatchAll(); + assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage); + } + + @Test + public void handleSetStreamPath_underCurrentDevice() { + assertThat(mHdmiCecLocalDeviceAudioSystem.getLocalActivePath()).isEqualTo(0); + HdmiCecMessage message = + HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2100); + assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetStreamPath(message)).isTrue(); + assertThat(mHdmiCecLocalDeviceAudioSystem.getLocalActivePath()).isEqualTo(1); } } diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java index 813fa8237096..d9faaa418c88 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java @@ -16,8 +16,6 @@ package com.android.server.pm.dex; -import static com.android.server.pm.PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -31,16 +29,16 @@ import android.util.SparseArray; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import org.junit.Test; -import org.junit.runner.RunWith; - import dalvik.system.DelegateLastClassLoader; import dalvik.system.DexClassLoader; import dalvik.system.PathClassLoader; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.File; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -412,12 +410,6 @@ public class DexoptUtilsTest { @Test public void testEncodeClassLoader() { - assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader( - SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.PathClassLoader")); - assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader( - SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.DexClassLoader")); - assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader( - SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.DelegateLastClassLoader")); assertEquals("PCL[xyz]", DexoptUtils.encodeClassLoader("xyz", "dalvik.system.PathClassLoader")); assertEquals("PCL[xyz]", DexoptUtils.encodeClassLoader("xyz", @@ -435,15 +427,8 @@ public class DexoptUtilsTest { @Test public void testEncodeClassLoaderChain() { - assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain( - SKIP_SHARED_LIBRARY_CHECK, "PCL[a]")); - assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain("PCL[a]", - SKIP_SHARED_LIBRARY_CHECK)); assertEquals("PCL[a];DLC[b]", DexoptUtils.encodeClassLoaderChain("PCL[a]", "DLC[b]")); - assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain("PCL[a]", - SKIP_SHARED_LIBRARY_CHECK)); - try { DexoptUtils.encodeClassLoaderChain("a", null); fail(); // exception is expected diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java index 8496a961959d..b348aeef802e 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java @@ -699,10 +699,52 @@ public class AppTimeLimitControllerTests { assertTrue(hasUsageSessionObserver(UID, OBS_ID1)); } + /** Verify the timeout message is delivered at the right time after past usage was reported */ + @Test + public void testAppUsageObserver_PastUsage() throws Exception { + setTime(10_000L); + addAppUsageObserver(OBS_ID1, GROUP1, 6_000L); + setTime(20_000L); + startPastUsage(PKG_SOC1, 5_000); + setTime(21_000L); + assertTrue(mLimitReachedLatch.await(2_000L, TimeUnit.MILLISECONDS)); + stopUsage(PKG_SOC1); + // Verify that the observer was removed + assertFalse(hasAppUsageObserver(UID, OBS_ID1)); + } + + /** + * Verify the timeout message is delivered at the right time after past usage was reported + * that overlaps with already known usage + */ + @Test + public void testAppUsageObserver_PastUsageOverlap() throws Exception { + setTime(0L); + addAppUsageObserver(OBS_ID1, GROUP1, 20_000L); + setTime(10_000L); + startUsage(PKG_SOC1); + setTime(20_000L); + stopUsage(PKG_SOC1); + setTime(25_000L); + startPastUsage(PKG_SOC1, 9_000); + setTime(26_000L); + // the 4 seconds of overlapped usage should not be counted + assertFalse(mLimitReachedLatch.await(2_000L, TimeUnit.MILLISECONDS)); + setTime(30_000L); + assertTrue(mLimitReachedLatch.await(4_000L, TimeUnit.MILLISECONDS)); + stopUsage(PKG_SOC1); + // Verify that the observer was removed + assertFalse(hasAppUsageObserver(UID, OBS_ID1)); + } + private void startUsage(String packageName) { mController.noteUsageStart(packageName, USER_ID); } + private void startPastUsage(String packageName, int timeAgo) { + mController.noteUsageStart(packageName, USER_ID, timeAgo); + } + private void stopUsage(String packageName) { mController.noteUsageStop(packageName, USER_ID); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java index 8b65e763b088..20f72bfe9938 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java @@ -613,7 +613,7 @@ public class ManagedServicesTest extends UiServiceTestCase { } @Test - public void testGetAllowedPackages() throws Exception { + public void testGetAllowedPackages_byUser() throws Exception { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm, approvalLevel); @@ -681,6 +681,30 @@ public class ManagedServicesTest extends UiServiceTestCase { } @Test + public void testGetAllowedPackages() throws Exception { + ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, + mIpm, APPROVAL_BY_COMPONENT); + loadXml(service); + service.mApprovalLevel = APPROVAL_BY_PACKAGE; + loadXml(service); + + List<String> allowedPackages = new ArrayList<>(); + allowedPackages.add("this.is.a.package.name"); + allowedPackages.add("another.package"); + allowedPackages.add("secondary"); + allowedPackages.add("this.is.another.package"); + allowedPackages.add("package"); + allowedPackages.add("component"); + allowedPackages.add("bananas!"); + + Set<String> actual = service.getAllowedPackages(); + assertEquals(allowedPackages.size(), actual.size()); + for (String pkg : allowedPackages) { + assertTrue(actual.contains(pkg)); + } + } + + @Test public void testOnUserRemoved() throws Exception { for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) { ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java index 65e640f5f73c..1458266089c5 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java @@ -825,4 +825,24 @@ public class NotificationRecordTest extends UiServiceTestCase { assertNotEquals(-1, record.getLastAudiblyAlertedMs()); } + + @Test + public void testIsNewEnoughForAlerting_new() { + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, groupId /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + + assertTrue(record.isNewEnoughForAlerting(record.mUpdateTimeMs)); + } + + @Test + public void testIsNewEnoughForAlerting_old() { + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, groupId /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + + assertFalse(record.isNewEnoughForAlerting(record.mUpdateTimeMs + (1000 * 60 * 60))); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java index 49f134fdeac0..174c5fa6a51e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java @@ -299,6 +299,59 @@ public class SnoozeHelperTest extends UiServiceTestCase { assertEquals(1, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); } + @Test + public void testClearData() { + // snooze 2 from same package + NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); + NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); + mSnoozeHelper.snooze(r, 1000); + mSnoozeHelper.snooze(r2, 1000); + assertTrue(mSnoozeHelper.isSnoozed( + UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); + assertTrue(mSnoozeHelper.isSnoozed( + UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey())); + + // clear data + mSnoozeHelper.clearData(UserHandle.USER_SYSTEM, "pkg"); + + // nothing snoozed; alarms canceled + assertFalse(mSnoozeHelper.isSnoozed( + UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); + assertFalse(mSnoozeHelper.isSnoozed( + UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey())); + // twice for initial snooze, twice for canceling the snooze + verify(mAm, times(4)).cancel(any(PendingIntent.class)); + } + + @Test + public void testClearData_otherRecordsUntouched() { + // 2 packages, 2 users + NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); + NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.ALL); + NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM); + mSnoozeHelper.snooze(r, 1000); + mSnoozeHelper.snooze(r2, 1000); + mSnoozeHelper.snooze(r3, 1000); + assertTrue(mSnoozeHelper.isSnoozed( + UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); + assertTrue(mSnoozeHelper.isSnoozed( + UserHandle.USER_ALL, r2.sbn.getPackageName(), r2.getKey())); + assertTrue(mSnoozeHelper.isSnoozed( + UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey())); + + // clear data + mSnoozeHelper.clearData(UserHandle.USER_SYSTEM, "pkg"); + + assertFalse(mSnoozeHelper.isSnoozed( + UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey())); + assertTrue(mSnoozeHelper.isSnoozed( + UserHandle.USER_ALL, r2.sbn.getPackageName(), r2.getKey())); + assertTrue(mSnoozeHelper.isSnoozed( + UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey())); + // once for each initial snooze, once for canceling one snooze + verify(mAm, times(4)).cancel(any(PendingIntent.class)); + } + private NotificationRecord getNotificationRecord(String pkg, int id, String tag, UserHandle user, String groupKey, boolean groupSummary) { Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID) diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 569c6d4af37d..bd29d2a3a884 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -31,6 +31,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -38,6 +39,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doCallRealMethod; + import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.IApplicationThread; @@ -115,6 +119,10 @@ class ActivityTestsBase { @After public void tearDownBase() { mTestInjector.tearDown(); + if (mService != null) { + mService.setWindowManager(null); + mService = null; + } } ActivityTaskManagerService createActivityTaskManagerService() { @@ -144,6 +152,13 @@ class ActivityTestsBase { return display; } + /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */ + TestActivityDisplay addNewActivityDisplayAt(DisplayInfo info, int position) { + final TestActivityDisplay display = createNewActivityDisplay(info); + mRootActivityContainer.addChild(display, position); + return display; + } + /** * Builder for creating new activities. */ @@ -154,6 +169,7 @@ class ActivityTestsBase { private final ActivityTaskManagerService mService; private ComponentName mComponent; + private String mTargetActivity; private TaskRecord mTaskRecord; private int mUid; private boolean mCreateTask; @@ -170,6 +186,11 @@ class ActivityTestsBase { return this; } + ActivityBuilder setTargetActivity(String targetActivity) { + mTargetActivity = targetActivity; + return this; + } + static ComponentName getDefaultComponent() { return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, DEFAULT_COMPONENT_PACKAGE_NAME); @@ -224,6 +245,10 @@ class ActivityTestsBase { aInfo.applicationInfo = new ApplicationInfo(); aInfo.applicationInfo.packageName = mComponent.getPackageName(); aInfo.applicationInfo.uid = mUid; + aInfo.packageName = mComponent.getPackageName(); + if (mTargetActivity != null) { + aInfo.targetActivity = mTargetActivity; + } aInfo.flags |= mActivityFlags; aInfo.launchMode = mLaunchMode; @@ -234,6 +259,10 @@ class ActivityTestsBase { mService.mStackSupervisor, null /* options */, null /* sourceRecord */); spyOn(activity); activity.mAppWindowToken = mock(AppWindowToken.class); + doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility(); + doCallRealMethod().when(activity.mAppWindowToken) + .setOrientation(anyInt(), any(), any()); + doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt()); doNothing().when(activity).removeWindowContainer(); if (mTaskRecord != null) { @@ -346,6 +375,7 @@ class ActivityTestsBase { mStack.addTask(task, true, "creating test task"); task.setStack(mStack); task.setTask(); + mStack.getWindowContainerController().mContainer.addChild(task.mTask, 0); } task.touchActiveTime(); @@ -365,7 +395,10 @@ class ActivityTestsBase { setTask(); } - private void setTask() { + void setTask() { + Task mockTask = mock(Task.class); + mockTask.mTaskRecord = this; + doCallRealMethod().when(mockTask).onDescendantOrientationChanged(any(), any()); setTask(mock(Task.class)); } } @@ -619,7 +652,13 @@ class ActivityTestsBase { } } + private static WindowManagerService sMockWindowManagerService; + private static WindowManagerService prepareMockWindowManager() { + if (sMockWindowManagerService != null) { + return sMockWindowManagerService; + } + final WindowManagerService service = mock(WindowManagerService.class); service.mRoot = mock(RootWindowContainer.class); @@ -631,6 +670,7 @@ class ActivityTestsBase { return null; }).when(service).inSurfaceTransaction(any()); + sMockWindowManagerService = service; return service; } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java index dcfb8797eaba..d0b9225715c4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java @@ -87,8 +87,8 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture()); callbackCaptor.getValue().onAnimationFinished(mSpec); - verify(mTransaction).destroy(eq(leash)); - verify(mTransaction).destroy(eq(animationBoundsLayer)); + verify(mTransaction).reparent(eq(leash), eq(null)); + verify(mTransaction).reparent(eq(animationBoundsLayer), eq(null)); assertThat(mToken.mNeedsAnimationBoundsLayer).isFalse(); } @@ -100,8 +100,8 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { final SurfaceControl animationBoundsLayer = mToken.mAnimationBoundsLayer; mToken.mSurfaceAnimator.cancelAnimation(); - verify(mTransaction).destroy(eq(leash)); - verify(mTransaction).destroy(eq(animationBoundsLayer)); + verify(mTransaction).reparent(eq(leash), eq(null)); + verify(mTransaction).reparent(eq(animationBoundsLayer), eq(null)); assertThat(mToken.mNeedsAnimationBoundsLayer).isFalse(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java index ee1c8dfdd319..f99cd4b18647 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java @@ -212,7 +212,7 @@ public class DimmerTests extends WindowTestsBase { mDimmer.updateDims(mTransaction, new Rect()); verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any( SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean()); - verify(mHost.getPendingTransaction()).destroy(dimLayer); + verify(mHost.getPendingTransaction()).reparent(dimLayer, null); } @Test @@ -269,7 +269,7 @@ public class DimmerTests extends WindowTestsBase { mDimmer.updateDims(mTransaction, new Rect()); verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any( SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean()); - verify(mTransaction).destroy(dimLayer); + verify(mTransaction).reparent(dimLayer, null); } private SurfaceControl getDimLayer() { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index 6b31e6fdbd28..198e7ce63f52 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -63,6 +63,7 @@ import com.android.server.statusbar.StatusBarManagerInternal; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -86,7 +87,7 @@ public class DisplayRotationTests { private StatusBarManagerInternal mPreviousStatusBarManagerInternal; - private WindowManagerService mMockWm; + private static WindowManagerService sMockWm; private DisplayContent mMockDisplayContent; private DisplayPolicy mMockDisplayPolicy; private Context mMockContext; @@ -108,13 +109,16 @@ public class DisplayRotationTests { private DisplayRotation mTarget; + @BeforeClass + public static void setUpOnce() { + sMockWm = mock(WindowManagerService.class); + sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class); + } + @Before public void setUp() { FakeSettingsProvider.clearSettingsProvider(); - mMockWm = mock(WindowManagerService.class); - mMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class); - mPreviousStatusBarManagerInternal = LocalServices.getService( StatusBarManagerInternal.class); LocalServices.removeServiceForTest(StatusBarManagerInternal.class); @@ -452,7 +456,7 @@ public class DisplayRotationTests { mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); assertTrue(waitForUiHandler()); - verify(mMockWm).updateRotation(false, false); + verify(sMockWm).updateRotation(false, false); } @Test @@ -833,8 +837,9 @@ public class DisplayRotationTests { .thenReturn(mFakeSettingsProvider.getIContentProvider()); mMockDisplayWindowSettings = mock(DisplayWindowSettings.class); - mTarget = new DisplayRotation(mMockWm, mMockDisplayContent, mMockDisplayPolicy, + mTarget = new DisplayRotation(sMockWm, mMockDisplayContent, mMockDisplayPolicy, mMockDisplayWindowSettings, mMockContext, new Object()); + reset(sMockWm); captureObservers(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java index a9f150b10e73..e24eb75a2750 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java @@ -34,7 +34,12 @@ import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.isNull; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; @@ -47,10 +52,6 @@ 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 android.app.StatusBarManager; import android.app.admin.DevicePolicyManager; @@ -115,6 +116,7 @@ public class LockTaskControllerTest { private LockTaskController mLockTaskController; private Context mContext; + private String mPackageName; private String mLockToAppSetting; @Before @@ -122,6 +124,7 @@ public class LockTaskControllerTest { MockitoAnnotations.initMocks(this); mContext = getInstrumentation().getTargetContext(); + mPackageName = mContext.getPackageName(); mLockToAppSetting = Settings.Secure.getString(mContext.getContentResolver(), Settings.Secure.LOCK_TO_APP_EXIT_LOCKED); @@ -146,6 +149,7 @@ public class LockTaskControllerTest { @After public void tearDown() throws Exception { + mLockTaskController.setWindowManager(null); Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, mLockToAppSetting); } @@ -223,7 +227,7 @@ public class LockTaskControllerTest { // THEN lock task mode should be started verifyLockTaskStarted(STATUS_BAR_MASK_PINNED, DISABLE2_NONE); // THEN screen pinning toast should be shown - verify(mStatusBarService).showPinningEnterExitToast(true /* entering */); + verify(mStatusBarService).showPinningEnterExitToast(eq(true /* entering */)); } @Test @@ -390,9 +394,9 @@ public class LockTaskControllerTest { // THEN lock task mode should have been finished verifyLockTaskStopped(times(1)); // THEN the keyguard should be shown - verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL); + verify(mLockPatternUtils).requireCredentialEntry(eq(UserHandle.USER_ALL)); // THEN screen pinning toast should be shown - verify(mStatusBarService).showPinningEnterExitToast(false /* entering */); + verify(mStatusBarService).showPinningEnterExitToast(eq(false /* entering */)); } @Test @@ -509,9 +513,9 @@ public class LockTaskControllerTest { & ~DISABLE_HOME; int expectedFlags2 = DISABLE2_MASK; verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); // reset invocation counter reset(mStatusBarService); @@ -526,9 +530,9 @@ public class LockTaskControllerTest { expectedFlags2 = DISABLE2_MASK & ~DISABLE2_NOTIFICATION_SHADE; verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); } @Test @@ -548,9 +552,9 @@ public class LockTaskControllerTest { // THEN status bar shouldn't change verify(mStatusBarService, never()).disable(anyInt(), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); verify(mStatusBarService, never()).disable2(anyInt(), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); } @Test @@ -657,14 +661,14 @@ public class LockTaskControllerTest { verify(mWindowManager).disableKeyguard(any(IBinder.class), anyString(), eq(TEST_USER_ID)); // THEN the status bar should have been disabled verify(mStatusBarService).disable(eq(statusBarMask), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); verify(mStatusBarService).disable2(eq(statusBarMask2), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); // THEN recents should have been notified verify(mRecentTasks).onLockTaskModeStateChanged(anyInt(), eq(TEST_USER_ID)); // THEN the DO/PO should be informed about the operation - verify(mDevicePolicyManager).notifyLockTaskModeChanged(true, TEST_PACKAGE_NAME, - TEST_USER_ID); + verify(mDevicePolicyManager).notifyLockTaskModeChanged(eq(true), eq(TEST_PACKAGE_NAME), + eq(TEST_USER_ID)); } private void verifyLockTaskStopped(VerificationMode mode) throws Exception { @@ -672,11 +676,12 @@ public class LockTaskControllerTest { verify(mWindowManager, mode).reenableKeyguard(any(IBinder.class), eq(TEST_USER_ID)); // THEN the status bar should have been disabled verify(mStatusBarService, mode).disable(eq(StatusBarManager.DISABLE_NONE), - any(IBinder.class), eq(mContext.getPackageName())); + any(IBinder.class), eq(mPackageName)); verify(mStatusBarService, mode).disable2(eq(StatusBarManager.DISABLE2_NONE), - any(IBinder.class), eq(mContext.getPackageName())); + any(IBinder.class), eq(mPackageName)); // THEN the DO/PO should be informed about the operation - verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(false, null, TEST_USER_ID); + verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(eq(false), isNull(), + eq(TEST_USER_ID)); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java index ad2a708b88d9..413b6f4b3905 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -143,8 +143,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { @Test public void testTimeout_scaled() throws Exception { - mWm.setAnimationScale(2, 5.0f); try { + mWm.setAnimationScale(2, 5.0f); final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken, diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java index 36eccd1892a7..03aba39517eb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java @@ -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 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; @@ -58,7 +60,6 @@ import android.view.WindowInsets; import android.view.WindowManager; import android.widget.TextView; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import org.junit.After; @@ -80,8 +81,8 @@ import java.util.function.BooleanSupplier; @Presubmit public class ScreenDecorWindowTests { - private final Context mContext = InstrumentationRegistry.getTargetContext(); - private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); + private final Context mContext = getInstrumentation().getTargetContext(); + private final Instrumentation mInstrumentation = getInstrumentation(); private WindowManager mWm; private ArrayList<View> mWindows = new ArrayList<>(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java index d14f30db8e9f..ad80cd6ddfb7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java @@ -96,7 +96,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { callbackCaptor.getValue().onAnimationFinished(mSpec); assertNotAnimating(mAnimatable); assertTrue(mAnimatable.mFinishedCallbackCalled); - verify(mTransaction).destroy(eq(mAnimatable.mLeash)); + verify(mTransaction).reparent(eq(mAnimatable.mLeash), eq(null)); // TODO: Verify reparenting once we use mPendingTransaction to reparent it back } @@ -106,7 +106,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { final SurfaceControl firstLeash = mAnimatable.mLeash; mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */); - verify(mTransaction).destroy(eq(firstLeash)); + verify(mTransaction).reparent(eq(firstLeash), eq(null)); assertFalse(mAnimatable.mFinishedCallbackCalled); final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass( @@ -133,7 +133,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { assertNotAnimating(mAnimatable); verify(mSpec).onAnimationCancelled(any()); assertTrue(mAnimatable.mFinishedCallbackCalled); - verify(mTransaction).destroy(eq(mAnimatable.mLeash)); + verify(mTransaction).reparent(eq(mAnimatable.mLeash), eq(null)); } @Test @@ -155,7 +155,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { verifyZeroInteractions(mSpec); assertNotAnimating(mAnimatable); assertTrue(mAnimatable.mFinishedCallbackCalled); - verify(mTransaction).destroy(eq(mAnimatable.mLeash)); + verify(mTransaction).reparent(eq(mAnimatable.mLeash), eq(null)); } @Test @@ -171,11 +171,11 @@ public class SurfaceAnimatorTest extends WindowTestsBase { assertNotAnimating(mAnimatable); assertAnimating(mAnimatable2); assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash); - verify(mTransaction, never()).destroy(eq(leash)); + verify(mTransaction, never()).reparent(eq(leash), eq(null)); callbackCaptor.getValue().onAnimationFinished(mSpec); assertNotAnimating(mAnimatable2); assertTrue(mAnimatable2.mFinishedCallbackCalled); - verify(mTransaction).destroy(eq(leash)); + verify(mTransaction).reparent(eq(leash), eq(null)); } @Test @@ -198,7 +198,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase { mDeferFinishAnimatable.mEndDeferFinishCallback.run(); assertNotAnimating(mAnimatable2); assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled); - verify(mTransaction).destroy(eq(mDeferFinishAnimatable.mLeash)); + verify(mTransaction).reparent(eq(mDeferFinishAnimatable.mLeash), eq(null)); } private void assertAnimating(MyAnimatable animatable) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index 7da85af444d6..8a98cbe5cd52 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -21,6 +21,11 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + +import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.sameInstance; @@ -133,17 +138,6 @@ public class TaskRecordTests extends ActivityTestsBase { assertTrue(task.returnsToHomeStack()); } - /** Ensures that bounds are clipped to their parent. */ - @Test - public void testAppBounds_BoundsClipping() { - final Rect shiftedBounds = new Rect(mParentBounds); - shiftedBounds.offset(10, 10); - final Rect expectedBounds = new Rect(mParentBounds); - expectedBounds.intersect(shiftedBounds); - testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, shiftedBounds, - expectedBounds); - } - /** Ensures that empty bounds are not propagated to the configuration. */ @Test public void testAppBounds_EmptyBounds() { @@ -167,36 +161,145 @@ public class TaskRecordTests extends ActivityTestsBase { final Rect insetBounds = new Rect(mParentBounds); insetBounds.inset(5, 5, 5, 5); testStackBoundsConfiguration( - WINDOWING_MODE_FULLSCREEN, mParentBounds, insetBounds, insetBounds); + WINDOWING_MODE_FREEFORM, mParentBounds, insetBounds, insetBounds); } - /** Ensures that full screen free form bounds are clipped */ + /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */ @Test - public void testAppBounds_FullScreenFreeFormBounds() { + public void testBoundsOnModeChangeFreeformToFullscreen() { ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay(); + ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display) + .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + TaskRecord task = stack.getChildAt(0); + task.getRootActivity().mAppWindowToken.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED); DisplayInfo info = new DisplayInfo(); display.mDisplay.getDisplayInfo(info); final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight); - testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, fullScreenBounds, - mParentBounds); + final Rect freeformBounds = new Rect(fullScreenBounds); + freeformBounds.inset((int) (freeformBounds.width() * 0.2), + (int) (freeformBounds.height() * 0.2)); + task.setBounds(freeformBounds); + + assertEquals(freeformBounds, task.getBounds()); + + // FULLSCREEN inherits bounds + stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + assertEquals(fullScreenBounds, task.getBounds()); + assertEquals(freeformBounds, task.mLastNonFullscreenBounds); + + // FREEFORM restores bounds + stack.setWindowingMode(WINDOWING_MODE_FREEFORM); + assertEquals(freeformBounds, task.getBounds()); + } + + /** + * This is a temporary hack to trigger an onConfigurationChange at the task level after an + * orientation is requested. Normally this is done by the onDescendentOrientationChanged call + * up the WM hierarchy, but since the WM hierarchy is mocked out, it doesn't happen here. + * TODO: remove this when we either get a WM hierarchy or when hierarchies are merged. + */ + private void setActivityRequestedOrientation(ActivityRecord activity, int orientation) { + activity.setRequestedOrientation(orientation); + ConfigurationContainer taskRecord = activity.getParent(); + taskRecord.onConfigurationChanged(taskRecord.getParent().getConfiguration()); + } + + /** + * Tests that a task with forced orientation has orientation-consistent bounds within the + * parent. + */ + @Test + public void testFullscreenBoundsForcedOrientation() { + final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080); + final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920); + DisplayInfo info = new DisplayInfo(); + info.logicalWidth = fullScreenBounds.width(); + info.logicalHeight = fullScreenBounds.height(); + ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP); + assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null); + ActivityStack stack = new StackBuilder(mRootActivityContainer) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build(); + TaskRecord task = stack.getChildAt(0); + ActivityRecord root = task.getRootActivity(); + ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build(); + assertEquals(root, task.getRootActivity()); + + assertEquals(fullScreenBounds, task.getBounds()); + + // Setting app to fixed portrait fits within parent + setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT); + assertEquals(root, task.getRootActivity()); + assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation()); + assertTrue(task.getBounds().width() < task.getBounds().height()); + assertEquals(fullScreenBounds.height(), task.getBounds().height()); + + // Setting non-root app has no effect + setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE); + assertTrue(task.getBounds().width() < task.getBounds().height()); + + // Setting app to unspecified restores + setActivityRequestedOrientation(root, SCREEN_ORIENTATION_UNSPECIFIED); + assertEquals(fullScreenBounds, task.getBounds()); + + // Setting app to fixed landscape and changing display + setActivityRequestedOrientation(root, SCREEN_ORIENTATION_LANDSCAPE); + display.setBounds(fullScreenBoundsPort); + assertTrue(task.getBounds().width() > task.getBounds().height()); + assertEquals(fullScreenBoundsPort.width(), task.getBounds().width()); + + // in FREEFORM, no constraint + final Rect freeformBounds = new Rect(display.getBounds()); + freeformBounds.inset((int) (freeformBounds.width() * 0.2), + (int) (freeformBounds.height() * 0.2)); + stack.setWindowingMode(WINDOWING_MODE_FREEFORM); + task.setBounds(freeformBounds); + assertEquals(freeformBounds, task.getBounds()); + + // FULLSCREEN letterboxes bounds + stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + assertTrue(task.getBounds().width() > task.getBounds().height()); + assertEquals(fullScreenBoundsPort.width(), task.getBounds().width()); + + // FREEFORM restores bounds as before + stack.setWindowingMode(WINDOWING_MODE_FREEFORM); + assertEquals(freeformBounds, task.getBounds()); } /** Ensures that the alias intent won't have target component resolved. */ @Test public void testTaskIntentActivityAlias() { - final String aliasActivity = DEFAULT_COMPONENT_PACKAGE_NAME + ".aliasActivity"; - final String targetActivity = DEFAULT_COMPONENT_PACKAGE_NAME + ".targetActivity"; + final String aliasClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".aliasActivity"; + final String targetClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".targetActivity"; + final ComponentName aliasComponent = + new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, aliasClassName); + final ComponentName targetComponent = + new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, targetClassName); + final Intent intent = new Intent(); - intent.setComponent(new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, aliasActivity)); + intent.setComponent(aliasComponent); final ActivityInfo info = new ActivityInfo(); info.applicationInfo = new ApplicationInfo(); info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME; - info.targetActivity = targetActivity; + info.targetActivity = targetClassName; final TaskRecord task = TaskRecord.create(mService, 1 /* taskId */, info, intent, null /* taskDescription */); - assertEquals("The alias activity component should be saved in task intent.", aliasActivity, + assertEquals("The alias activity component should be saved in task intent.", aliasClassName, task.intent.getComponent().getClassName()); + + ActivityRecord aliasActivity = new ActivityBuilder(mService).setComponent( + aliasComponent).setTargetActivity(targetClassName).build(); + assertEquals("Should be the same intent filter.", true, + task.isSameIntentFilter(aliasActivity)); + + ActivityRecord targetActivity = new ActivityBuilder(mService).setComponent( + targetComponent).build(); + assertEquals("Should be the same intent filter.", true, + task.isSameIntentFilter(targetActivity)); + + ActivityRecord defaultActivity = new ActivityBuilder(mService).build(); + assertEquals("Should not be the same intent filter.", false, + task.isSameIntentFilter(defaultActivity)); } private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds, diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index 624ef9ba1653..ca815eca9a1f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -39,6 +39,7 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.Surface; +import android.view.SurfaceControl; import androidx.test.filters.SmallTest; @@ -65,7 +66,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { final TaskSnapshot snapshot = new TaskSnapshot(new ComponentName("", ""), buffer, ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */); - mSurface = new TaskSnapshotSurface(mWm, new Window(), new Surface(), snapshot, "Test", + mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test", Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds, ORIENTATION_PORTRAIT); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java deleted file mode 100644 index 04e433e98678..000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * 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.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; -import static android.view.Display.DEFAULT_DISPLAY; - -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; - -import android.app.ActivityManagerInternal; -import android.content.Context; -import android.hardware.display.DisplayManagerInternal; -import android.os.PowerManagerInternal; -import android.os.PowerSaveState; -import android.view.Display; -import android.view.InputChannel; -import android.view.SurfaceControl; -import android.view.SurfaceControl.Transaction; - -import com.android.server.LocalServices; -import com.android.server.input.InputManagerService; -import com.android.server.policy.WindowManagerPolicy; - -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; -import org.mockito.invocation.InvocationOnMock; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; - -/** - * A test rule that sets up a fresh WindowManagerService instance before each test and makes sure - * to properly tear it down after. - * - * <p> - * Usage: - * <pre> - * {@literal @}Rule - * public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule(); - * </pre> - */ -public class WindowManagerServiceRule implements TestRule { - - private WindowManagerService mService; - private TestWindowManagerPolicy mPolicy; - // Record all {@link SurfaceControl.Transaction} created while testing and releases native - // resources when test finishes. - private final List<WeakReference<Transaction>> mSurfaceTransactions = new ArrayList<>(); - // Record all {@link SurfaceControl} created while testing and releases native resources when - // test finishes. - private final List<WeakReference<SurfaceControl>> mSurfaceControls = new ArrayList<>(); - - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - runWithDexmakerShareClassLoader(this::setUp); - try { - base.evaluate(); - } finally { - tearDown(); - } - } - - private void setUp() { - final Context context = getInstrumentation().getTargetContext(); - - removeServices(); - - LocalServices.addService(DisplayManagerInternal.class, - mock(DisplayManagerInternal.class)); - - LocalServices.addService(PowerManagerInternal.class, - mock(PowerManagerInternal.class)); - final PowerManagerInternal pm = - LocalServices.getService(PowerManagerInternal.class); - doNothing().when(pm).registerLowPowerModeObserver(any()); - PowerSaveState state = new PowerSaveState.Builder().build(); - doReturn(state).when(pm).getLowPowerState(anyInt()); - - LocalServices.addService(ActivityManagerInternal.class, - mock(ActivityManagerInternal.class)); - LocalServices.addService(ActivityTaskManagerInternal.class, - mock(ActivityTaskManagerInternal.class)); - final ActivityTaskManagerInternal atm = - LocalServices.getService(ActivityTaskManagerInternal.class); - doAnswer((InvocationOnMock invocationOnMock) -> { - final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); - if (runnable != null) { - runnable.run(); - } - return null; - }).when(atm).notifyKeyguardFlagsChanged(any(), anyInt()); - - InputManagerService ims = mock(InputManagerService.class); - // InputChannel is final and can't be mocked. - InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM); - if (input != null && input.length > 1) { - doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt()); - } - ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class); - when(atms.getGlobalLock()).thenReturn(new WindowManagerGlobalLock()); - - mService = WindowManagerService.main(context, ims, false, false, - mPolicy = new TestWindowManagerPolicy( - WindowManagerServiceRule.this::getWindowManagerService), atms); - mService.mTransactionFactory = () -> { - final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); - mSurfaceTransactions.add(new WeakReference<>(transaction)); - return transaction; - }; - mService.mSurfaceBuilderFactory = session -> new SurfaceControl.Builder(session) { - @Override - public SurfaceControl build() { - final SurfaceControl control = super.build(); - mSurfaceControls.add(new WeakReference<>(control)); - return control; - } - }; - - mService.onInitReady(); - - final Display display = mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY); - // Display creation is driven by the ActivityManagerService via - // ActivityStackSupervisor. We emulate those steps here. - mService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class)); - } - - private void removeServices() { - LocalServices.removeServiceForTest(DisplayManagerInternal.class); - LocalServices.removeServiceForTest(PowerManagerInternal.class); - LocalServices.removeServiceForTest(ActivityManagerInternal.class); - LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); - LocalServices.removeServiceForTest(WindowManagerInternal.class); - LocalServices.removeServiceForTest(WindowManagerPolicy.class); - } - - private void tearDown() { - cancelAllPendingAnimations(); - waitUntilWindowManagerHandlersIdle(); - destroyAllSurfaceTransactions(); - destroyAllSurfaceControls(); - removeServices(); - mService = null; - mPolicy = null; - } - }; - } - - WindowManagerService getWindowManagerService() { - return mService; - } - - private void cancelAllPendingAnimations() { - for (final WeakReference<SurfaceControl> reference : mSurfaceControls) { - final SurfaceControl sc = reference.get(); - if (sc != null) { - mService.mSurfaceAnimationRunner.onAnimationCancelled(sc); - } - } - } - - void waitUntilWindowManagerHandlersIdle() { - final WindowManagerService wm = getWindowManagerService(); - if (wm == null) { - return; - } - wm.mH.removeCallbacksAndMessages(null); - wm.mAnimationHandler.removeCallbacksAndMessages(null); - SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null); - wm.mH.runWithScissors(() -> { }, 0); - wm.mAnimationHandler.runWithScissors(() -> { }, 0); - SurfaceAnimationThread.getHandler().runWithScissors(() -> { }, 0); - } - - private void destroyAllSurfaceTransactions() { - for (final WeakReference<Transaction> reference : mSurfaceTransactions) { - final Transaction transaction = reference.get(); - if (transaction != null) { - reference.clear(); - transaction.close(); - } - } - } - - private void destroyAllSurfaceControls() { - for (final WeakReference<SurfaceControl> reference : mSurfaceControls) { - final SurfaceControl control = reference.get(); - if (control != null) { - reference.clear(); - control.destroy(); - } - } - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 5c3368bd25ac..638cb03f4707 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -53,6 +53,7 @@ import android.view.WindowManager; import com.android.server.AttributeCache; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -95,17 +96,22 @@ class WindowTestsBase { public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); - @Rule - public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule(); - - static WindowState.PowerManagerWrapper sPowerManagerWrapper; // TODO(roosa): make non-static. + static WindowState.PowerManagerWrapper sPowerManagerWrapper; @BeforeClass public static void setUpOnceBase() { AttributeCache.init(getInstrumentation().getTargetContext()); + + WmServiceUtils.setUpWindowManagerService(); + sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); } + @AfterClass + public static void tearDonwOnceBase() { + WmServiceUtils.tearDownWindowManagerService(); + } + @Before public void setUpBase() { // If @Before throws an exception, the error isn't logged. This will make sure any failures @@ -115,7 +121,7 @@ class WindowTestsBase { final Context context = getInstrumentation().getTargetContext(); - mWm = mWmRule.getWindowManagerService(); + mWm = WmServiceUtils.getWindowManagerService(); beforeCreateDisplay(); context.getDisplay().getDisplayInfo(mDisplayInfo); @@ -192,8 +198,8 @@ class WindowTestsBase { mDisplayContent.mInputMethodTarget = null; } - // Wait until everything is really cleaned up. - waitUntilHandlersIdle(); + // Cleaned up everything in Handler. + WmServiceUtils.cleanupWindowManagerHandlers(); } catch (Exception e) { Log.e(TAG, "Failed to tear down test", e); throw e; @@ -214,7 +220,7 @@ class WindowTestsBase { * Waits until the main handler for WM has processed all messages. */ void waitUntilHandlersIdle() { - mWmRule.waitUntilWindowManagerHandlersIdle(); + WmServiceUtils.waitUntilWindowManagerHandlersIdle(); } private WindowToken createWindowToken( diff --git a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java b/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java new file mode 100644 index 000000000000..05ac8c1072c0 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2019 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.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; +import static android.view.Display.DEFAULT_DISPLAY; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + +import android.app.ActivityManagerInternal; +import android.app.AppOpsManager; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.hardware.display.DisplayManagerInternal; +import android.net.Uri; +import android.os.Handler; +import android.os.PowerManagerInternal; +import android.os.PowerSaveState; +import android.os.UserHandle; +import android.view.Display; +import android.view.InputChannel; + +import com.android.dx.mockito.inline.extended.StaticMockitoSession; +import com.android.server.LocalServices; +import com.android.server.LockGuard; +import com.android.server.Watchdog; +import com.android.server.input.InputManagerService; +import com.android.server.policy.WindowManagerPolicy; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.quality.Strictness; + +import java.util.concurrent.CountDownLatch; + +/** + * A Test utility class to create a mock {@link WindowManagerService} instance for tests. + */ +class WmServiceUtils { + private static StaticMockitoSession sMockitoSession; + private static WindowManagerService sService; + private static TestWindowManagerPolicy sPolicy; + + static void setUpWindowManagerService() { + sMockitoSession = mockitoSession() + .spyStatic(LockGuard.class) + .spyStatic(Watchdog.class) + .strictness(Strictness.LENIENT) + .startMocking(); + + runWithDexmakerShareClassLoader(WmServiceUtils::setUpTestWindowService); + } + + static void tearDownWindowManagerService() { + waitUntilWindowManagerHandlersIdle(); + removeLocalServices(); + sService = null; + sPolicy = null; + + sMockitoSession.finishMocking(); + } + + private static void setUpTestWindowService() { + doReturn(null).when(() -> LockGuard.installLock(any(), anyInt())); + doReturn(mock(Watchdog.class)).when(Watchdog::getInstance); + + final Context context = getInstrumentation().getTargetContext(); + spyOn(context); + + doReturn(null).when(context) + .registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class)); + doReturn(null).when(context) + .registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class), + any(IntentFilter.class), nullable(String.class), nullable(Handler.class)); + + final ContentResolver contentResolver = context.getContentResolver(); + spyOn(contentResolver); + doNothing().when(contentResolver) + .registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class), + anyInt()); + + final AppOpsManager appOpsManager = mock(AppOpsManager.class); + doReturn(appOpsManager).when(context) + .getSystemService(eq(Context.APP_OPS_SERVICE)); + + removeLocalServices(); + + final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class); + LocalServices.addService(DisplayManagerInternal.class, dmi); + + final PowerManagerInternal pmi = mock(PowerManagerInternal.class); + LocalServices.addService(PowerManagerInternal.class, pmi); + final PowerSaveState state = new PowerSaveState.Builder().build(); + doReturn(state).when(pmi).getLowPowerState(anyInt()); + + final ActivityManagerInternal ami = mock(ActivityManagerInternal.class); + LocalServices.addService(ActivityManagerInternal.class, ami); + + final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class); + LocalServices.addService(ActivityTaskManagerInternal.class, atmi); + doAnswer((InvocationOnMock invocationOnMock) -> { + final Runnable runnable = invocationOnMock.getArgument(0); + if (runnable != null) { + runnable.run(); + } + return null; + }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt()); + + final InputManagerService ims = mock(InputManagerService.class); + // InputChannel is final and can't be mocked. + final InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM); + if (input != null && input.length > 1) { + doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt()); + } + + final ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class); + final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock(); + doReturn(wmLock).when(atms).getGlobalLock(); + + sPolicy = new TestWindowManagerPolicy(WmServiceUtils::getWindowManagerService); + sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms); + + sService.onInitReady(); + + final Display display = sService.mDisplayManager.getDisplay(DEFAULT_DISPLAY); + // Display creation is driven by the ActivityManagerService via + // ActivityStackSupervisor. We emulate those steps here. + sService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class)); + } + + private static void removeLocalServices() { + LocalServices.removeServiceForTest(DisplayManagerInternal.class); + LocalServices.removeServiceForTest(PowerManagerInternal.class); + LocalServices.removeServiceForTest(ActivityManagerInternal.class); + LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); + LocalServices.removeServiceForTest(WindowManagerInternal.class); + LocalServices.removeServiceForTest(WindowManagerPolicy.class); + } + + static WindowManagerService getWindowManagerService() { + return sService; + } + + static void cleanupWindowManagerHandlers() { + final WindowManagerService wm = getWindowManagerService(); + if (wm == null) { + return; + } + wm.mH.removeCallbacksAndMessages(null); + wm.mAnimationHandler.removeCallbacksAndMessages(null); + SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null); + } + + static void waitUntilWindowManagerHandlersIdle() { + final WindowManagerService wm = getWindowManagerService(); + if (wm == null) { + return; + } + // Removing delayed FORCE_GC message decreases time for waiting idle. + wm.mH.removeMessages(WindowManagerService.H.FORCE_GC); + waitHandlerIdle(wm.mH); + waitHandlerIdle(wm.mAnimationHandler); + waitHandlerIdle(SurfaceAnimationThread.getHandler()); + } + + private static void waitHandlerIdle(Handler handler) { + if (!handler.hasMessagesOrCallbacks()) { + return; + } + final CountDownLatch latch = new CountDownLatch(1); + // Wait for delayed messages are processed. + handler.getLooper().getQueue().addIdleHandler(() -> { + if (handler.hasMessagesOrCallbacks()) { + return true; // keep idle handler. + } + latch.countDown(); + return false; // remove idle handler. + }); + try { + latch.await(); + } catch (InterruptedException e) { + } + } +} diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java index 8e1ede116abf..2ed11fe92e15 100644 --- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java +++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java @@ -23,7 +23,6 @@ import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; @@ -62,6 +61,8 @@ public class AppTimeLimitController { private static final long ONE_MINUTE = 60_000L; + private static final Integer ONE = new Integer(1); + /** Collection of data for each user that has reported usage */ @GuardedBy("mLock") private final SparseArray<UserData> mUsers = new SparseArray<>(); @@ -79,11 +80,11 @@ public class AppTimeLimitController { private @UserIdInt int userId; - /** Set of the currently active entities */ - private final ArraySet<String> currentlyActive = new ArraySet<>(); + /** Count of the currently active entities */ + public final ArrayMap<String, Integer> currentlyActive = new ArrayMap<>(); /** Map from entity name for quick lookup */ - private final ArrayMap<String, ArrayList<UsageGroup>> observedMap = new ArrayMap<>(); + public final ArrayMap<String, ArrayList<UsageGroup>> observedMap = new ArrayMap<>(); private UserData(@UserIdInt int userId) { this.userId = userId; @@ -94,7 +95,7 @@ public class AppTimeLimitController { // TODO: Consider using a bloom filter here if number of actives becomes large final int size = entities.length; for (int i = 0; i < size; i++) { - if (currentlyActive.contains(entities[i])) { + if (currentlyActive.containsKey(entities[i])) { return true; } } @@ -137,7 +138,7 @@ public class AppTimeLimitController { pw.print(" Currently Active:"); final int nActive = currentlyActive.size(); for (int i = 0; i < nActive; i++) { - pw.print(currentlyActive.valueAt(i)); + pw.print(currentlyActive.keyAt(i)); pw.print(", "); } pw.println(); @@ -233,6 +234,7 @@ public class AppTimeLimitController { protected long mUsageTimeMs; protected int mActives; protected long mLastKnownUsageTimeMs; + protected long mLastUsageEndTimeMs; protected WeakReference<UserData> mUserRef; protected WeakReference<ObserverAppData> mObserverAppRef; protected PendingIntent mLimitReachedCallback; @@ -271,9 +273,15 @@ public class AppTimeLimitController { @GuardedBy("mLock") void noteUsageStart(long startTimeMs, long currentTimeMs) { if (mActives++ == 0) { + // If last known usage ended after the start of this usage, there is overlap + // between the last usage session and this one. Avoid double counting by only + // counting from the end of the last session. This has a rare side effect that some + // usage will not be accounted for if the previous session started and stopped + // within this current usage. + startTimeMs = mLastUsageEndTimeMs > startTimeMs ? mLastUsageEndTimeMs : startTimeMs; mLastKnownUsageTimeMs = startTimeMs; final long timeRemaining = - mTimeLimitMs - mUsageTimeMs + currentTimeMs - startTimeMs; + mTimeLimitMs - mUsageTimeMs - currentTimeMs + startTimeMs; if (timeRemaining > 0) { if (DEBUG) { Slog.d(TAG, "Posting timeout for " + mObserverId + " for " @@ -287,7 +295,7 @@ public class AppTimeLimitController { mActives = mObserved.length; final UserData user = mUserRef.get(); if (user == null) return; - final Object[] array = user.currentlyActive.toArray(); + final Object[] array = user.currentlyActive.keySet().toArray(); Slog.e(TAG, "Too many noted usage starts! Observed entities: " + Arrays.toString( mObserved) + " Active Entities: " + Arrays.toString(array)); @@ -300,6 +308,8 @@ public class AppTimeLimitController { if (--mActives == 0) { final boolean limitNotCrossed = mUsageTimeMs < mTimeLimitMs; mUsageTimeMs += stopTimeMs - mLastKnownUsageTimeMs; + + mLastUsageEndTimeMs = stopTimeMs; if (limitNotCrossed && mUsageTimeMs >= mTimeLimitMs) { // Crossed the limit if (DEBUG) Slog.d(TAG, "MTB informing group obs=" + mObserverId); @@ -312,7 +322,7 @@ public class AppTimeLimitController { mActives = 0; final UserData user = mUserRef.get(); if (user == null) return; - final Object[] array = user.currentlyActive.toArray(); + final Object[] array = user.currentlyActive.keySet().toArray(); Slog.e(TAG, "Too many noted usage stops! Observed entities: " + Arrays.toString( mObserved) + " Active Entities: " + Arrays.toString(array)); @@ -409,7 +419,6 @@ public class AppTimeLimitController { } class SessionUsageGroup extends UsageGroup { - private long mLastUsageEndTimeMs; private long mNewSessionThresholdMs; private PendingIntent mSessionEndCallback; @@ -451,7 +460,6 @@ public class AppTimeLimitController { public void noteUsageStop(long stopTimeMs) { super.noteUsageStop(stopTimeMs); if (mActives == 0) { - mLastUsageEndTimeMs = stopTimeMs; if (mUsageTimeMs >= mTimeLimitMs) { // Usage has ended. Schedule the session end callback to be triggered once // the new session threshold has been reached @@ -467,7 +475,10 @@ public class AppTimeLimitController { UserData user = mUserRef.get(); if (user == null) return; if (mListener != null) { - mListener.onSessionEnd(mObserverId, user.userId, mUsageTimeMs, mSessionEndCallback); + mListener.onSessionEnd(mObserverId, + user.userId, + mUsageTimeMs, + mSessionEndCallback); } } @@ -599,7 +610,7 @@ public class AppTimeLimitController { // TODO: Consider using a bloom filter here if number of actives becomes large final int size = group.mObserved.length; for (int i = 0; i < size; i++) { - if (user.currentlyActive.contains(group.mObserved[i])) { + if (user.currentlyActive.containsKey(group.mObserved[i])) { // Entity is currently active. Start group's usage. group.noteUsageStart(currentTimeMs); } @@ -717,21 +728,28 @@ public class AppTimeLimitController { /** * Called when an entity becomes active. * - * @param name The entity that became active - * @param userId The user + * @param name The entity that became active + * @param userId The user + * @param timeAgoMs Time since usage was started */ - public void noteUsageStart(String name, int userId) throws IllegalArgumentException { + public void noteUsageStart(String name, int userId, long timeAgoMs) + throws IllegalArgumentException { synchronized (mLock) { UserData user = getOrCreateUserDataLocked(userId); if (DEBUG) Slog.d(TAG, "Usage entity " + name + " became active"); - if (user.currentlyActive.contains(name)) { - throw new IllegalArgumentException( - "Unable to start usage for " + name + ", already in use"); + + final int index = user.currentlyActive.indexOfKey(name); + if (index >= 0) { + final Integer count = user.currentlyActive.valueAt(index); + if (count != null) { + // There are multiple instances of this entity. Just increment the count. + user.currentlyActive.setValueAt(index, count + 1); + return; + } } final long currentTime = getUptimeMillis(); - // Add to the list of active entities - user.currentlyActive.add(name); + user.currentlyActive.put(name, ONE); ArrayList<UsageGroup> groups = user.observedMap.get(name); if (groups == null) return; @@ -739,12 +757,22 @@ public class AppTimeLimitController { final int size = groups.size(); for (int i = 0; i < size; i++) { UsageGroup group = groups.get(i); - group.noteUsageStart(currentTime); + group.noteUsageStart(currentTime - timeAgoMs, currentTime); } } } /** + * Called when an entity becomes active. + * + * @param name The entity that became active + * @param userId The user + */ + public void noteUsageStart(String name, int userId) throws IllegalArgumentException { + noteUsageStart(name, userId, 0); + } + + /** * Called when an entity becomes inactive. * * @param name The entity that became inactive @@ -754,10 +782,21 @@ public class AppTimeLimitController { synchronized (mLock) { UserData user = getOrCreateUserDataLocked(userId); if (DEBUG) Slog.d(TAG, "Usage entity " + name + " became inactive"); - if (!user.currentlyActive.remove(name)) { + + final int index = user.currentlyActive.indexOfKey(name); + if (index < 0) { throw new IllegalArgumentException( "Unable to stop usage for " + name + ", not in use"); } + + final Integer count = user.currentlyActive.valueAt(index); + if (!count.equals(ONE)) { + // There are multiple instances of this entity. Just decrement the count. + user.currentlyActive.setValueAt(index, count - 1); + return; + } + + user.currentlyActive.removeAt(index); final long currentTime = getUptimeMillis(); // Check if any of the groups need to watch for this entity @@ -769,6 +808,7 @@ public class AppTimeLimitController { UsageGroup group = groups.get(i); group.noteUsageStop(currentTime); } + } } @@ -780,7 +820,8 @@ public class AppTimeLimitController { @GuardedBy("mLock") private void postInformSessionEndListenerLocked(SessionUsageGroup group, long timeout) { - mHandler.sendMessageDelayed(mHandler.obtainMessage(MyHandler.MSG_INFORM_SESSION_END, group), + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MyHandler.MSG_INFORM_SESSION_END, group), timeout); } @@ -800,7 +841,27 @@ public class AppTimeLimitController { mHandler.removeMessages(MyHandler.MSG_CHECK_TIMEOUT, group); } - void dump(PrintWriter pw) { + void dump(String[] args, PrintWriter pw) { + if (args != null) { + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if ("actives".equals(arg)) { + synchronized (mLock) { + final int nUsers = mUsers.size(); + for (int user = 0; user < nUsers; user++) { + final ArrayMap<String, Integer> actives = + mUsers.valueAt(user).currentlyActive; + final int nActive = actives.size(); + for (int active = 0; active < nActive; active++) { + pw.println(actives.keyAt(active)); + } + } + } + return; + } + } + } + synchronized (mLock) { pw.println("\n App Time Limits"); final int nUsers = mUsers.size(); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 57dc08fcd253..f146370b01d7 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -53,6 +53,7 @@ import android.os.Binder; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; +import android.os.IBinder; import android.os.IDeviceIdleController; import android.os.Looper; import android.os.Message; @@ -105,6 +106,8 @@ public class UsageStatsService extends SystemService implements private static final boolean ENABLE_KERNEL_UPDATES = true; private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set"); + private static final char TOKEN_DELIMITER = '/'; + // Handler message types. static final int MSG_REPORT_EVENT = 0; static final int MSG_FLUSH_TO_DISK = 1; @@ -135,6 +138,10 @@ public class UsageStatsService extends SystemService implements /** Manages app time limit observers */ AppTimeLimitController mAppTimeLimit; + final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray(); + final SparseArray<String> mVisibleActivities = new SparseArray(); + + private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener = new UsageStatsManagerInternal.AppIdleStateChangeListener() { @Override @@ -270,7 +277,7 @@ public class UsageStatsService extends SystemService implements mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget(); } } else if (Intent.ACTION_USER_STARTED.equals(action)) { - if (userId >=0) { + if (userId >= 0) { mAppStandby.postCheckIdleStates(userId); } } @@ -434,17 +441,46 @@ public class UsageStatsService extends SystemService implements mAppStandby.reportEvent(event, elapsedRealtime, userId); switch (event.mEventType) { case Event.ACTIVITY_RESUMED: - try { - mAppTimeLimit.noteUsageStart(event.getPackageName(), userId); - } catch (IllegalArgumentException iae) { - Slog.e(TAG, "Failed to note usage start", iae); + synchronized (mVisibleActivities) { + mVisibleActivities.put(event.mInstanceId, event.getClassName()); + try { + mAppTimeLimit.noteUsageStart(event.getPackageName(), userId); + } catch (IllegalArgumentException iae) { + Slog.e(TAG, "Failed to note usage start", iae); + } } break; - case Event.ACTIVITY_PAUSED: - try { - mAppTimeLimit.noteUsageStop(event.getPackageName(), userId); - } catch (IllegalArgumentException iae) { - Slog.e(TAG, "Failed to note usage stop", iae); + case Event.ACTIVITY_STOPPED: + case Event.ACTIVITY_DESTROYED: + ArraySet<String> tokens; + synchronized (mUsageReporters) { + tokens = mUsageReporters.removeReturnOld(event.mInstanceId); + } + if (tokens != null) { + synchronized (tokens) { + final int size = tokens.size(); + // Stop usage on behalf of a UsageReporter that stopped + for (int i = 0; i < size; i++) { + final String token = tokens.valueAt(i); + try { + mAppTimeLimit.noteUsageStop( + buildFullToken(event.getPackageName(), token), userId); + } catch (IllegalArgumentException iae) { + Slog.w(TAG, "Failed to stop usage for during reporter death: " + + iae); + } + } + } + } + + synchronized (mVisibleActivities) { + if (mVisibleActivities.removeReturnOld(event.mInstanceId) != null) { + try { + mAppTimeLimit.noteUsageStop(event.getPackageName(), userId); + } catch (IllegalArgumentException iae) { + Slog.w(TAG, "Failed to note usage stop", iae); + } + } } break; } @@ -599,6 +635,14 @@ public class UsageStatsService extends SystemService implements return beginTime <= currentTime && beginTime < endTime; } + private String buildFullToken(String packageName, String token) { + final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1); + sb.append(packageName); + sb.append(TOKEN_DELIMITER); + sb.append(token); + return sb.toString(); + } + private void flushToDiskLocked() { final int userCount = mUserState.size(); for (int i = 0; i < userCount; i++) { @@ -627,8 +671,7 @@ public class UsageStatsService extends SystemService implements String arg = args[i]; if ("--checkin".equals(arg)) { checkin = true; - } else - if ("-c".equals(arg)) { + } else if ("-c".equals(arg)) { compact = true; } else if ("flush".equals(arg)) { flushToDiskLocked(); @@ -637,6 +680,15 @@ public class UsageStatsService extends SystemService implements } else if ("is-app-standby-enabled".equals(arg)) { pw.println(mAppStandby.mAppIdleEnabled); return; + } else if ("apptimelimit".equals(arg)) { + if (i + 1 >= args.length) { + mAppTimeLimit.dump(null, pw); + } else { + final String[] remainingArgs = + Arrays.copyOfRange(args, i + 1, args.length); + mAppTimeLimit.dump(remainingArgs, pw); + } + return; } else if (arg != null && !arg.startsWith("-")) { // Anything else that doesn't start with '-' is a pkg to filter pkg = arg; @@ -666,7 +718,7 @@ public class UsageStatsService extends SystemService implements mAppStandby.dumpState(args, pw); } - mAppTimeLimit.dump(pw); + mAppTimeLimit.dump(null, pw); } } @@ -1231,16 +1283,82 @@ public class UsageStatsService extends SystemService implements final int userId = UserHandle.getUserId(callingUid); final long token = Binder.clearCallingIdentity(); try { - UsageStatsService.this.unregisterUsageSessionObserver(callingUid, sessionObserverId, userId); + UsageStatsService.this.unregisterUsageSessionObserver(callingUid, sessionObserverId, + userId); } finally { Binder.restoreCallingIdentity(token); } } + + @Override + public void reportUsageStart(IBinder activity, String token, String callingPackage) { + reportPastUsageStart(activity, token, 0, callingPackage); + } + + @Override + public void reportPastUsageStart(IBinder activity, String token, long timeAgoMs, + String callingPackage) { + + final int callingUid = Binder.getCallingUid(); + final int userId = UserHandle.getUserId(callingUid); + final long binderToken = Binder.clearCallingIdentity(); + try { + ArraySet<String> tokens; + synchronized (mUsageReporters) { + tokens = mUsageReporters.get(activity.hashCode()); + if (tokens == null) { + tokens = new ArraySet(); + mUsageReporters.put(activity.hashCode(), tokens); + } + } + + synchronized (tokens) { + if (!tokens.add(token)) { + throw new IllegalArgumentException(token + " for " + callingPackage + + " is already reported as started for this activity"); + } + } + + mAppTimeLimit.noteUsageStart(buildFullToken(callingPackage, token), + userId, timeAgoMs); + } finally { + Binder.restoreCallingIdentity(binderToken); + } + } + + @Override + public void reportUsageStop(IBinder activity, String token, String callingPackage) { + final int callingUid = Binder.getCallingUid(); + final int userId = UserHandle.getUserId(callingUid); + final long binderToken = Binder.clearCallingIdentity(); + try { + ArraySet<String> tokens; + synchronized (mUsageReporters) { + tokens = mUsageReporters.get(activity.hashCode()); + if (tokens == null) { + throw new IllegalArgumentException( + "Unknown reporter trying to stop token " + token + " for " + + callingPackage); + } + } + + synchronized (tokens) { + if (!tokens.remove(token)) { + throw new IllegalArgumentException(token + " for " + callingPackage + + " is already reported as stopped for this activity"); + } + } + mAppTimeLimit.noteUsageStop(buildFullToken(callingPackage, token), userId); + } finally { + Binder.restoreCallingIdentity(binderToken); + } + } } void registerAppUsageObserver(int callingUid, int observerId, String[] packages, long timeLimitMs, PendingIntent callbackIntent, int userId) { - mAppTimeLimit.addAppUsageObserver(callingUid, observerId, packages, timeLimitMs, callbackIntent, + mAppTimeLimit.addAppUsageObserver(callingUid, observerId, packages, timeLimitMs, + callbackIntent, userId); } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index 38efc743fe34..3d7cbb51a3ad 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -657,9 +657,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return; } - if (event.status != SoundTrigger.RECOGNITION_STATUS_GET_STATE_RESPONSE) { - model.setStopped(); - } + model.setStopped(); + try { callback.onGenericSoundTriggerDetected((GenericRecognitionEvent) event); } catch (DeadObjectException e) { @@ -802,9 +801,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return; } - if (event.status != SoundTrigger.RECOGNITION_STATUS_GET_STATE_RESPONSE) { - modelData.setStopped(); - } + modelData.setStopped(); try { modelData.getCallback().onKeyphraseDetected((KeyphraseRecognitionEvent) event); diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp index b3b09001e7ee..59a80fbae792 100644 --- a/startop/iorap/Android.bp +++ b/startop/iorap/Android.bp @@ -13,7 +13,7 @@ // limitations under the License. java_library_static { - name: "libiorap-java", + name: "services.startop.iorap", aidl: { include_dirs: [ @@ -21,6 +21,8 @@ java_library_static { ], }, + libs: ["services.core"], + srcs: [ ":iorap-aidl", "**/*.java", diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java new file mode 100644 index 000000000000..c2e4581285fd --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java @@ -0,0 +1,368 @@ +/* + * 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.google.android.startop.iorap; + +import android.annotation.LongDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.os.Parcel; +import android.os.Parcelable; + +// TODO: fix this. either move this class into system server or add a dependency on +// these wm classes to libiorap-java and libiorap-java-tests (somehow). +import com.android.server.wm.ActivityMetricsLaunchObserver; +import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto; +import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.InvocationTargetException; +import java.util.Objects; + +/** + * Provide a hint to iorapd that an app launch sequence has transitioned state.<br /><br /> + * + * Knowledge of when an activity starts/stops can be used by iorapd to increase system + * performance (e.g. by launching perfetto tracing to record an io profile, or by + * playing back an ioprofile via readahead) over the long run.<br /><br /> + * + * /@see com.google.android.startop.iorap.IIorap#onAppLaunchEvent <br /><br /> + * @see com.android.server.wm.ActivityMetricsLaunchObserver + * ActivityMetricsLaunchObserver for the possible event states. + * @hide + */ +public abstract class AppLaunchEvent implements Parcelable { + @LongDef + @Retention(RetentionPolicy.SOURCE) + public @interface SequenceId {} + + public final @SequenceId + long sequenceId; + + protected AppLaunchEvent(@SequenceId long sequenceId) { + this.sequenceId = sequenceId; + } + + @Override + public boolean equals(Object other) { + if (other instanceof AppLaunchEvent) { + return equals((AppLaunchEvent) other); + } + return false; + } + + protected boolean equals(AppLaunchEvent other) { + return sequenceId == other.sequenceId; + } + + + @Override + public String toString() { + return getClass().getSimpleName() + + "{" + "sequenceId=" + Long.toString(sequenceId) + + toStringBody() + "}"; + } + + protected String toStringBody() { return ""; }; + + // List of possible variants: + + public static final class IntentStarted extends AppLaunchEvent { + @NonNull + public final Intent intent; + + public IntentStarted(@SequenceId long sequenceId, Intent intent) { + super(sequenceId); + this.intent = intent; + + Objects.requireNonNull(intent, "intent"); + } + + @Override + public boolean equals(Object other) { + if (other instanceof IntentStarted) { + return intent.equals(((IntentStarted)other).intent) && + super.equals(other); + } + return false; + } + + @Override + protected String toStringBody() { + return ", intent=" + intent.toString(); + } + + + @Override + protected void writeToParcelImpl(Parcel p, int flags) { + super.writeToParcelImpl(p, flags); + intent.writeToParcel(p, flags); + } + + IntentStarted(Parcel p) { + super(p); + intent = Intent.CREATOR.createFromParcel(p); + } + } + + public static final class IntentFailed extends AppLaunchEvent { + public IntentFailed(@SequenceId long sequenceId) { + super(sequenceId); + } + + @Override + public boolean equals(Object other) { + if (other instanceof IntentFailed) { + return super.equals(other); + } + return false; + } + + IntentFailed(Parcel p) { + super(p); + } + } + + public static abstract class BaseWithActivityRecordData extends AppLaunchEvent { + public final @NonNull + @ActivityRecordProto byte[] activityRecordSnapshot; + + protected BaseWithActivityRecordData(@SequenceId long sequenceId, + @NonNull @ActivityRecordProto byte[] snapshot) { + super(sequenceId); + activityRecordSnapshot = snapshot; + + Objects.requireNonNull(snapshot, "snapshot"); + } + + @Override + public boolean equals(Object other) { + if (other instanceof BaseWithActivityRecordData) { + return activityRecordSnapshot.equals( + ((BaseWithActivityRecordData)other).activityRecordSnapshot) && + super.equals(other); + } + return false; + } + + @Override + protected String toStringBody() { + return ", " + activityRecordSnapshot.toString(); + } + + @Override + protected void writeToParcelImpl(Parcel p, int flags) { + super.writeToParcelImpl(p, flags); + ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags); + } + + BaseWithActivityRecordData(Parcel p) { + super(p); + activityRecordSnapshot = ActivityRecordProtoParcelable.create(p); + } + } + + public static final class ActivityLaunched extends BaseWithActivityRecordData { + public final @ActivityMetricsLaunchObserver.Temperature + int temperature; + + public ActivityLaunched(@SequenceId long sequenceId, + @NonNull @ActivityRecordProto byte[] snapshot, + @ActivityMetricsLaunchObserver.Temperature int temperature) { + super(sequenceId, snapshot); + this.temperature = temperature; + } + + @Override + public boolean equals(Object other) { + if (other instanceof ActivityLaunched) { + return temperature == ((ActivityLaunched)other).temperature && + super.equals(other); + } + return false; + } + + @Override + protected String toStringBody() { + return ", temperature=" + Integer.toString(temperature); + } + + @Override + protected void writeToParcelImpl(Parcel p, int flags) { + super.writeToParcelImpl(p, flags); + p.writeInt(temperature); + } + + ActivityLaunched(Parcel p) { + super(p); + temperature = p.readInt(); + } + } + + public static final class ActivityLaunchFinished extends BaseWithActivityRecordData { + public ActivityLaunchFinished(@SequenceId long sequenceId, + @NonNull @ActivityRecordProto byte[] snapshot) { + super(sequenceId, snapshot); + } + + @Override + public boolean equals(Object other) { + if (other instanceof ActivityLaunched) { + return super.equals(other); + } + return false; + } + } + + public static class ActivityLaunchCancelled extends AppLaunchEvent { + public final @Nullable + @ActivityRecordProto byte[] activityRecordSnapshot; + + public ActivityLaunchCancelled(@SequenceId long sequenceId, + @Nullable @ActivityRecordProto byte[] snapshot) { + super(sequenceId); + activityRecordSnapshot = snapshot; + } + + @Override + public boolean equals(Object other) { + if (other instanceof ActivityLaunchCancelled) { + return Objects.equals(activityRecordSnapshot, + ((ActivityLaunchCancelled)other).activityRecordSnapshot) && + super.equals(other); + } + return false; + } + + @Override + protected String toStringBody() { + return ", " + activityRecordSnapshot.toString(); + } + + @Override + protected void writeToParcelImpl(Parcel p, int flags) { + super.writeToParcelImpl(p, flags); + if (activityRecordSnapshot != null) { + p.writeBoolean(true); + ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags); + } else { + p.writeBoolean(false); + } + } + + ActivityLaunchCancelled(Parcel p) { + super(p); + if (p.readBoolean()) { + activityRecordSnapshot = ActivityRecordProtoParcelable.create(p); + } else { + activityRecordSnapshot = null; + } + } + } + + @Override + public @ContentsFlags int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel p, @WriteFlags int flags) { + p.writeInt(getTypeIndex()); + + writeToParcelImpl(p, flags); + } + + + public static Creator<AppLaunchEvent> CREATOR = + new Creator<AppLaunchEvent>() { + @Override + public AppLaunchEvent createFromParcel(Parcel source) { + int typeIndex = source.readInt(); + + Class<?> kls = getClassFromTypeIndex(typeIndex); + if (kls == null) { + throw new IllegalArgumentException("Invalid type index: " + typeIndex); + } + + try { + return (AppLaunchEvent) kls.getConstructor(Parcel.class).newInstance(source); + } catch (InstantiationException e) { + throw new AssertionError(e); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } catch (InvocationTargetException e) { + throw new AssertionError(e); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + @Override + public AppLaunchEvent[] newArray(int size) { + return new AppLaunchEvent[0]; + } + }; + + protected void writeToParcelImpl(Parcel p, int flags) { + p.writeLong(sequenceId); + } + + protected AppLaunchEvent(Parcel p) { + sequenceId = p.readLong(); + } + + private int getTypeIndex() { + for (int i = 0; i < sTypes.length; ++i) { + if (sTypes[i].equals(this.getClass())) { + return i; + } + } + throw new AssertionError("sTypes did not include this type: " + this.getClass()); + } + + private static @Nullable Class<?> getClassFromTypeIndex(int typeIndex) { + if (typeIndex >= 0 && typeIndex < sTypes.length) { + return sTypes[typeIndex]; + } + return null; + } + + // Index position matters: It is used to encode the specific type in parceling. + // Keep up-to-date with C++ side. + private static Class<?>[] sTypes = new Class[] { + IntentStarted.class, + IntentFailed.class, + ActivityLaunched.class, + ActivityLaunchFinished.class, + ActivityLaunchCancelled.class, + }; + + // TODO: move to @ActivityRecordProto byte[] once we have unit tests. + public static class ActivityRecordProtoParcelable { + public static void write(Parcel p, @ActivityRecordProto byte[] activityRecordSnapshot, + int flags) { + p.writeByteArray(activityRecordSnapshot); + } + + public static @ActivityRecordProto byte[] create(Parcel p) { + byte[] data = p.createByteArray(); + + return data; + } + } +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java new file mode 100644 index 000000000000..7fcad360b8fe --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java @@ -0,0 +1,216 @@ +/* + * 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.google.android.startop.iorap; +// TODO: rename to com.android.server.startop.iorap + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.os.IBinder; +import android.os.Parcel; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; +import com.android.server.SystemService; +import com.android.server.wm.ActivityMetricsLaunchObserver; +import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto; +import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature; +import com.android.server.wm.ActivityMetricsLaunchObserverRegistry; +import com.android.server.wm.ActivityTaskManagerInternal; + +/** + * System-server-local proxy into the {@code IIorap} native service. + */ +public class IorapForwardingService extends SystemService { + + public static final boolean DEBUG = true; // TODO: read from a getprop? + public static final String TAG = "IorapForwardingService"; + + private IIorap mIorapRemote; + + /** + * 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 IorapForwardingService(Context context) { + super(context); + } + + //<editor-fold desc="Providers"> + /* + * Providers for external dependencies: + * - These are marked as protected to allow tests to inject different values via mocks. + */ + + @VisibleForTesting + protected ActivityMetricsLaunchObserverRegistry provideLaunchObserverRegistry() { + ActivityTaskManagerInternal amtInternal = + LocalServices.getService(ActivityTaskManagerInternal.class); + ActivityMetricsLaunchObserverRegistry launchObserverRegistry = + amtInternal.getLaunchObserverRegistry(); + return launchObserverRegistry; + } + + @VisibleForTesting + protected IIorap provideIorapRemote() { + try { + return IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd")); + } catch (ServiceManager.ServiceNotFoundException e) { + // TODO: how do we handle service being missing? + throw new AssertionError(e); + } + } + + //</editor-fold> + + @Override + public void onStart() { + if (DEBUG) { + Log.v(TAG, "onStart"); + } + + // Connect to the native binder service. + mIorapRemote = provideIorapRemote(); + invokeRemote( () -> mIorapRemote.setTaskListener(new RemoteTaskListener()) ); + + // Listen to App Launch Sequence events from ActivityTaskManager, + // and forward them to the native binder service. + ActivityMetricsLaunchObserverRegistry launchObserverRegistry = + provideLaunchObserverRegistry(); + launchObserverRegistry.registerLaunchObserver(new AppLaunchObserver()); + } + + private class AppLaunchObserver implements ActivityMetricsLaunchObserver { + // We add a synthetic sequence ID here to make it easier to differentiate new + // launch sequences on the native side. + private @AppLaunchEvent.SequenceId long mSequenceId = -1; + + @Override + public void onIntentStarted(@NonNull Intent intent) { + // #onIntentStarted [is the only transition that] initiates a new launch sequence. + ++mSequenceId; + + if (DEBUG) { + Log.v(TAG, String.format("AppLaunchObserver#onIntentStarted(%d, %s)", + mSequenceId, intent)); + } + + invokeRemote(() -> + mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + new AppLaunchEvent.IntentStarted(mSequenceId, intent)) + ); + } + + @Override + public void onIntentFailed() { + if (DEBUG) { + Log.v(TAG, String.format("AppLaunchObserver#onIntentFailed(%d)", mSequenceId)); + } + + invokeRemote(() -> + mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + new AppLaunchEvent.IntentFailed(mSequenceId)) + ); + } + + @Override + public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity, + @Temperature int temperature) { + if (DEBUG) { + Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunched(%d, %s, %d)", + mSequenceId, activity, temperature)); + } + + invokeRemote(() -> + mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + new AppLaunchEvent.ActivityLaunched(mSequenceId, activity, temperature)) + ); + } + + @Override + public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) { + if (DEBUG) { + Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchCancelled(%d, %s)", + mSequenceId, activity)); + } + + invokeRemote(() -> + mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId, + activity))); + } + + @Override + public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity) { + if (DEBUG) { + Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchFinished(%d, %s)", + mSequenceId, activity)); + } + + invokeRemote(() -> + mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(), + new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId, activity)) + ); + } + } + + private class RemoteTaskListener extends ITaskListener.Stub { + @Override + public void onProgress(RequestId requestId, TaskResult result) throws RemoteException { + if (DEBUG) { + Log.v(TAG, + String.format("RemoteTaskListener#onProgress(%s, %s)", requestId, result)); + } + + // TODO: implement rest. + } + + @Override + public void onComplete(RequestId requestId, TaskResult result) throws RemoteException { + if (DEBUG) { + Log.v(TAG, + String.format("RemoteTaskListener#onComplete(%s, %s)", requestId, result)); + } + + // TODO: implement rest. + } + } + + private interface RemoteRunnable { + void run() throws RemoteException; + } + + private static void invokeRemote(RemoteRunnable r) { + try { + r.run(); + } catch (RemoteException e) { + // TODO: what do we do with exceptions? + throw new AssertionError("not implemented", e); + } + } +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java index 2c79319a1459..adb3a910f7fe 100644 --- a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java +++ b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java @@ -71,7 +71,7 @@ public class RequestId implements Parcelable { @Override public String toString() { - return String.format("{requestId: %ld}", requestId); + return String.format("{requestId: %d}", requestId); } @Override diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp index 76057846e896..5ac4a46b81f1 100644 --- a/startop/iorap/tests/Android.bp +++ b/startop/iorap/tests/Android.bp @@ -18,8 +18,15 @@ java_library { srcs: ["src/**/*.kt"], static_libs: [ - // non-test dependencies - "libiorap-java", + // Non-test dependencies + + // library under test + "services.startop.iorap", + // need the system_server code to be on the classpath, + "services.core", + + // Test Dependencies + // test android dependencies "platform-test-annotations", "android-support-test", diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp index 91cec554d7cd..2fc3a0dd874e 100644 --- a/startop/view_compiler/Android.bp +++ b/startop/view_compiler/Android.bp @@ -22,18 +22,37 @@ cc_defaults { shared_libs: [ "libbase", "libdexfile", + "libz", "slicer", ], static_libs: [ "libtinyxml2", + "liblog", + "libutils", + "libziparchive", ], + cppflags: ["-std=c++17"], + target: { + android: { + shared_libs: [ + "libandroidfw", + ], + }, + host: { + static_libs: [ + "libandroidfw", + ], + }, + }, } cc_library_host_static { name: "libviewcompiler", defaults: ["viewcompiler_defaults"], srcs: [ + "apk_layout_compiler.cc", "dex_builder.cc", + "dex_layout_compiler.cc", "java_lang_builder.cc", "tinyxml_layout_parser.cc", "util.cc", diff --git a/startop/view_compiler/apk_layout_compiler.cc b/startop/view_compiler/apk_layout_compiler.cc new file mode 100644 index 000000000000..e95041ba34a4 --- /dev/null +++ b/startop/view_compiler/apk_layout_compiler.cc @@ -0,0 +1,159 @@ +/* + * 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. + */ + +#include "apk_layout_compiler.h" +#include "dex_layout_compiler.h" +#include "java_lang_builder.h" +#include "layout_validation.h" +#include "util.h" + +#include "androidfw/ApkAssets.h" +#include "androidfw/AssetManager2.h" +#include "androidfw/ResourceTypes.h" + +#include <iostream> +#include <locale> + +#include "android-base/stringprintf.h" + +namespace startop { + +using android::ResXMLParser; +using android::base::StringPrintf; + +class ResXmlVisitorAdapter { + public: + ResXmlVisitorAdapter(ResXMLParser* parser) : parser_{parser} {} + + template <typename Visitor> + void Accept(Visitor* visitor) { + size_t depth{0}; + do { + switch (parser_->next()) { + case ResXMLParser::START_DOCUMENT: + depth++; + visitor->VisitStartDocument(); + break; + case ResXMLParser::END_DOCUMENT: + depth--; + visitor->VisitEndDocument(); + break; + case ResXMLParser::START_TAG: { + depth++; + size_t name_length = 0; + const char16_t* name = parser_->getElementName(&name_length); + visitor->VisitStartTag(std::u16string{name, name_length}); + break; + } + case ResXMLParser::END_TAG: + depth--; + visitor->VisitEndTag(); + break; + default:; + } + } while (depth > 0 || parser_->getEventType() == ResXMLParser::FIRST_CHUNK_CODE); + } + + private: + ResXMLParser* parser_; +}; + +bool CanCompileLayout(ResXMLParser* parser) { + ResXmlVisitorAdapter adapter{parser}; + LayoutValidationVisitor visitor; + adapter.Accept(&visitor); + + return visitor.can_compile(); +} + +void CompileApkLayouts(const std::string& filename, CompilationTarget target, + std::ostream& target_out) { + auto assets = android::ApkAssets::Load(filename); + android::AssetManager2 resources; + resources.SetApkAssets({assets.get()}); + + std::string package_name; + + // TODO: handle multiple packages better + bool first = true; + for (const auto& package : assets->GetLoadedArsc()->GetPackages()) { + CHECK(first); + package_name = package->GetPackageName(); + first = false; + } + + dex::DexBuilder dex_file; + dex::ClassBuilder compiled_view{ + dex_file.MakeClass(StringPrintf("%s.CompiledView", package_name.c_str()))}; + std::vector<dex::MethodBuilder> methods; + + assets->ForEachFile("res/", [&](const android::StringPiece& s, android::FileType) { + if (s == "layout") { + auto path = StringPrintf("res/%s/", s.to_string().c_str()); + assets->ForEachFile(path, [&](const android::StringPiece& layout_file, android::FileType) { + auto layout_path = StringPrintf("%s%s", path.c_str(), layout_file.to_string().c_str()); + android::ApkAssetsCookie cookie = android::kInvalidCookie; + auto asset = resources.OpenNonAsset(layout_path, android::Asset::ACCESS_RANDOM, &cookie); + CHECK(asset); + CHECK(android::kInvalidCookie != cookie); + const auto dynamic_ref_table = resources.GetDynamicRefTableForCookie(cookie); + CHECK(nullptr != dynamic_ref_table); + android::ResXMLTree xml_tree{dynamic_ref_table}; + xml_tree.setTo(asset->getBuffer(/*wordAligned=*/true), + asset->getLength(), + /*copy_data=*/true); + android::ResXMLParser parser{xml_tree}; + parser.restart(); + if (CanCompileLayout(&parser)) { + parser.restart(); + const std::string layout_name = startop::util::FindLayoutNameFromFilename(layout_path); + ResXmlVisitorAdapter adapter{&parser}; + switch (target) { + case CompilationTarget::kDex: { + methods.push_back(compiled_view.CreateMethod( + layout_name, + dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.View"), + dex::TypeDescriptor::FromClassname("android.content.Context"), + dex::TypeDescriptor::Int()})); + DexViewBuilder builder(&methods.back()); + builder.Start(); + LayoutCompilerVisitor visitor{&builder}; + adapter.Accept(&visitor); + builder.Finish(); + methods.back().Encode(); + break; + } + case CompilationTarget::kJavaLanguage: { + JavaLangViewBuilder builder{package_name, layout_name, target_out}; + builder.Start(); + LayoutCompilerVisitor visitor{&builder}; + adapter.Accept(&visitor); + builder.Finish(); + break; + } + } + } + }); + } + }); + + if (target == CompilationTarget::kDex) { + slicer::MemView image{dex_file.CreateImage()}; + target_out.write(image.ptr<const char>(), image.size()); + } +} + +} // namespace startop diff --git a/startop/view_compiler/apk_layout_compiler.h b/startop/view_compiler/apk_layout_compiler.h new file mode 100644 index 000000000000..c85ddd65ac1b --- /dev/null +++ b/startop/view_compiler/apk_layout_compiler.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef APK_LAYOUT_COMPILER_H_ +#define APK_LAYOUT_COMPILER_H_ + +#include <string> + +namespace startop { + +enum class CompilationTarget { kJavaLanguage, kDex }; + +void CompileApkLayouts(const std::string& filename, CompilationTarget target, + std::ostream& target_out); + +} // namespace startop + +#endif // APK_LAYOUT_COMPILER_H_
\ No newline at end of file diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp index 4449ea0f707e..d4f38ed148c9 100644 --- a/startop/view_compiler/dex_builder_test/Android.bp +++ b/startop/view_compiler/dex_builder_test/Android.bp @@ -14,16 +14,30 @@ // limitations under the License. // +genrule { + name: "generate_compiled_layout", + tools: [":viewcompiler"], + cmd: "$(location :viewcompiler) $(in) --dex --out $(out) --package android.startop.test", + srcs: ["res/layout/layout1.xml"], + out: [ + "layout1.dex", + ], +} + android_test { name: "dex-builder-test", - srcs: ["src/android/startop/test/DexBuilderTest.java"], + srcs: [ + "src/android/startop/test/DexBuilderTest.java", + "src/android/startop/test/LayoutCompilerTest.java", + ], sdk_version: "current", - data: [":generate_dex_testcases"], + data: [":generate_dex_testcases", ":generate_compiled_layout"], static_libs: [ "android-support-test", "guava", ], manifest: "AndroidManifest.xml", + resource_dirs: ["res"], test_config: "AndroidTest.xml", test_suites: ["general-tests"], } diff --git a/startop/view_compiler/dex_builder_test/AndroidTest.xml b/startop/view_compiler/dex_builder_test/AndroidTest.xml index 6f90cf3b81a7..68d8fdc444d8 100644 --- a/startop/view_compiler/dex_builder_test/AndroidTest.xml +++ b/startop/view_compiler/dex_builder_test/AndroidTest.xml @@ -25,6 +25,7 @@ <option name="cleanup" value="true" /> <option name="push" value="trivial.dex->/data/local/tmp/dex-builder-test/trivial.dex" /> <option name="push" value="simple.dex->/data/local/tmp/dex-builder-test/simple.dex" /> + <option name="push" value="layout1.dex->/data/local/tmp/dex-builder-test/layout1.dex" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > diff --git a/startop/view_compiler/dex_builder_test/res/layout/layout1.xml b/startop/view_compiler/dex_builder_test/res/layout/layout1.xml new file mode 100644 index 000000000000..0f9375c6ebce --- /dev/null +++ b/startop/view_compiler/dex_builder_test/res/layout/layout1.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:orientation="vertical" + android:gravity="center"> + + <Button + android:layout_width="match_parent" + android:layout_height="match_parent"/> + <Button + android:layout_width="match_parent" + android:layout_height="match_parent"/> + + </LinearLayout> diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java new file mode 100644 index 000000000000..ce3ce8328559 --- /dev/null +++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java @@ -0,0 +1,46 @@ +/* + * 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.startop.test; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.view.View; +import com.google.common.io.ByteStreams; +import dalvik.system.InMemoryDexClassLoader; +import dalvik.system.PathClassLoader; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import org.junit.Assert; +import org.junit.Test; + +// Adding tests here requires changes in several other places. See README.md in +// the view_compiler directory for more information. +public class LayoutCompilerTest { + static ClassLoader loadDexFile(String filename) throws Exception { + return new PathClassLoader("/data/local/tmp/dex-builder-test/" + filename, + ClassLoader.getSystemClassLoader()); + } + + @Test + public void loadAndInflaterLayout1() throws Exception { + ClassLoader dex_file = loadDexFile("layout1.dex"); + Class compiled_view = dex_file.loadClass("android.startop.test.CompiledView"); + Method layout1 = compiled_view.getMethod("layout1", Context.class, int.class); + Context context = InstrumentationRegistry.getTargetContext(); + layout1.invoke(null, context, R.layout.layout1); + } +} diff --git a/startop/view_compiler/dex_layout_compiler.cc b/startop/view_compiler/dex_layout_compiler.cc new file mode 100644 index 000000000000..c68793d10399 --- /dev/null +++ b/startop/view_compiler/dex_layout_compiler.cc @@ -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. + */ + +#include "dex_layout_compiler.h" +#include "layout_validation.h" + +#include "android-base/stringprintf.h" + +namespace startop { + +using android::base::StringPrintf; + +void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) { + if (0 == name.compare(u"merge")) { + message_ = "Merge tags are not supported"; + can_compile_ = false; + } + if (0 == name.compare(u"include")) { + message_ = "Include tags are not supported"; + can_compile_ = false; + } + if (0 == name.compare(u"view")) { + message_ = "View tags are not supported"; + can_compile_ = false; + } + if (0 == name.compare(u"fragment")) { + message_ = "Fragment tags are not supported"; + can_compile_ = false; + } +} + +DexViewBuilder::DexViewBuilder(dex::MethodBuilder* method) + : method_{method}, + context_{dex::Value::Parameter(0)}, + resid_{dex::Value::Parameter(1)}, + inflater_{method->MakeRegister()}, + xml_{method->MakeRegister()}, + attrs_{method->MakeRegister()}, + classname_tmp_{method->MakeRegister()}, + xml_next_{method->dex_file()->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.content.res.XmlResourceParser"), "next", + dex::Prototype{dex::TypeDescriptor::Int()})}, + try_create_view_{method->dex_file()->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"), "tryCreateView", + dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.View"), + dex::TypeDescriptor::FromClassname("android.view.View"), + dex::TypeDescriptor::FromClassname("java.lang.String"), + dex::TypeDescriptor::FromClassname("android.content.Context"), + dex::TypeDescriptor::FromClassname("android.util.AttributeSet")})}, + generate_layout_params_{method->dex_file()->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.view.ViewGroup"), "generateLayoutParams", + dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams"), + dex::TypeDescriptor::FromClassname("android.util.AttributeSet")})}, + add_view_{method->dex_file()->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.view.ViewGroup"), "addView", + dex::Prototype{ + dex::TypeDescriptor::Void(), + dex::TypeDescriptor::FromClassname("android.view.View"), + dex::TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams")})}, + // The register stack starts with one register, which will be null for the root view. + register_stack_{{method->MakeRegister()}} {} + +void DexViewBuilder::Start() { + dex::DexBuilder* const dex = method_->dex_file(); + + // LayoutInflater inflater = LayoutInflater.from(context); + auto layout_inflater_from = dex->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"), + "from", + dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"), + dex::TypeDescriptor::FromClassname("android.content.Context")}); + method_->AddInstruction( + dex::Instruction::InvokeStaticObject(layout_inflater_from.id, /*dest=*/inflater_, context_)); + + // Resources res = context.getResources(); + auto context_type = dex::TypeDescriptor::FromClassname("android.content.Context"); + auto resources_type = dex::TypeDescriptor::FromClassname("android.content.res.Resources"); + auto get_resources = + dex->GetOrDeclareMethod(context_type, "getResources", dex::Prototype{resources_type}); + method_->AddInstruction(dex::Instruction::InvokeVirtualObject(get_resources.id, xml_, context_)); + + // XmlResourceParser xml = res.getLayout(resid); + auto xml_resource_parser_type = + dex::TypeDescriptor::FromClassname("android.content.res.XmlResourceParser"); + auto get_layout = + dex->GetOrDeclareMethod(resources_type, + "getLayout", + dex::Prototype{xml_resource_parser_type, dex::TypeDescriptor::Int()}); + method_->AddInstruction(dex::Instruction::InvokeVirtualObject(get_layout.id, xml_, xml_, resid_)); + + // AttributeSet attrs = Xml.asAttributeSet(xml); + auto as_attribute_set = dex->GetOrDeclareMethod( + dex::TypeDescriptor::FromClassname("android.util.Xml"), + "asAttributeSet", + dex::Prototype{dex::TypeDescriptor::FromClassname("android.util.AttributeSet"), + dex::TypeDescriptor::FromClassname("org.xmlpull.v1.XmlPullParser")}); + method_->AddInstruction(dex::Instruction::InvokeStaticObject(as_attribute_set.id, attrs_, xml_)); + + // xml.next(); // start document + method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_)); +} + +void DexViewBuilder::Finish() {} + +namespace { +std::string ResolveName(const std::string& name) { + if (name == "View") return "android.view.View"; + if (name == "ViewGroup") return "android.view.ViewGroup"; + if (name.find(".") == std::string::npos) { + return StringPrintf("android.widget.%s", name.c_str()); + } + return name; +} +} // namespace + +void DexViewBuilder::StartView(const std::string& name, bool is_viewgroup) { + bool const is_root_view = view_stack_.empty(); + + // xml.next(); // start tag + method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_)); + + dex::Value view = AcquireRegister(); + // try to create the view using the factories + method_->BuildConstString(classname_tmp_, + name); // TODO: the need to fully qualify the classname + if (is_root_view) { + dex::Value null = AcquireRegister(); + method_->BuildConst4(null, 0); + method_->AddInstruction(dex::Instruction::InvokeVirtualObject( + try_create_view_.id, view, inflater_, null, classname_tmp_, context_, attrs_)); + ReleaseRegister(); + } else { + method_->AddInstruction(dex::Instruction::InvokeVirtualObject( + try_create_view_.id, view, inflater_, GetCurrentView(), classname_tmp_, context_, attrs_)); + } + auto label = method_->MakeLabel(); + // branch if not null + method_->AddInstruction( + dex::Instruction::OpWithArgs(dex::Instruction::Op::kBranchNEqz, /*dest=*/{}, view, label)); + + // If null, create the class directly. + method_->BuildNew(view, + dex::TypeDescriptor::FromClassname(ResolveName(name)), + dex::Prototype{dex::TypeDescriptor::Void(), + dex::TypeDescriptor::FromClassname("android.content.Context"), + dex::TypeDescriptor::FromClassname("android.util.AttributeSet")}, + context_, + attrs_); + + method_->AddInstruction( + dex::Instruction::OpWithArgs(dex::Instruction::Op::kBindLabel, /*dest=*/{}, label)); + + if (is_viewgroup) { + // Cast to a ViewGroup so we can add children later. + const ir::Type* view_group_def = method_->dex_file()->GetOrAddType( + dex::TypeDescriptor::FromClassname("android.view.ViewGroup").descriptor()); + method_->AddInstruction(dex::Instruction::Cast(view, dex::Value::Type(view_group_def->orig_index))); + } + + if (!is_root_view) { + // layout_params = parent.generateLayoutParams(attrs); + dex::Value layout_params{AcquireRegister()}; + method_->AddInstruction(dex::Instruction::InvokeVirtualObject( + generate_layout_params_.id, layout_params, GetCurrentView(), attrs_)); + view_stack_.push_back({view, layout_params}); + } else { + view_stack_.push_back({view, {}}); + } +} + +void DexViewBuilder::FinishView() { + if (view_stack_.size() == 1) { + method_->BuildReturn(GetCurrentView(), /*is_object=*/true); + } else { + // parent.add(view, layout_params) + method_->AddInstruction(dex::Instruction::InvokeVirtual( + add_view_.id, /*dest=*/{}, GetParentView(), GetCurrentView(), GetCurrentLayoutParams())); + // xml.next(); // end tag + method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_)); + } + PopViewStack(); +} + +dex::Value DexViewBuilder::AcquireRegister() { + top_register_++; + if (register_stack_.size() == top_register_) { + register_stack_.push_back(method_->MakeRegister()); + } + return register_stack_[top_register_]; +} + +void DexViewBuilder::ReleaseRegister() { top_register_--; } + +dex::Value DexViewBuilder::GetCurrentView() const { return view_stack_.back().view; } +dex::Value DexViewBuilder::GetCurrentLayoutParams() const { + return view_stack_.back().layout_params.value(); +} +dex::Value DexViewBuilder::GetParentView() const { + return view_stack_[view_stack_.size() - 2].view; +} + +void DexViewBuilder::PopViewStack() { + const auto& top = view_stack_.back(); + // release the layout params if we have them + if (top.layout_params.has_value()) { + ReleaseRegister(); + } + // Unconditionally release the view register. + ReleaseRegister(); + view_stack_.pop_back(); +} + +} // namespace startop
\ No newline at end of file diff --git a/startop/view_compiler/dex_layout_compiler.h b/startop/view_compiler/dex_layout_compiler.h new file mode 100644 index 000000000000..170a1a610297 --- /dev/null +++ b/startop/view_compiler/dex_layout_compiler.h @@ -0,0 +1,118 @@ +/* + * 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. + */ + +#ifndef DEX_LAYOUT_COMPILER_H_ +#define DEX_LAYOUT_COMPILER_H_ + +#include "dex_builder.h" + +#include <codecvt> +#include <locale> +#include <string> +#include <vector> + +namespace startop { + +// This visitor does the actual view compilation, using a supplied builder. +template <typename Builder> +class LayoutCompilerVisitor { + public: + explicit LayoutCompilerVisitor(Builder* builder) : builder_{builder} {} + + void VisitStartDocument() { builder_->Start(); } + void VisitEndDocument() { builder_->Finish(); } + void VisitStartTag(const std::u16string& name) { + parent_stack_.push_back(ViewEntry{ + std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(name), {}}); + } + void VisitEndTag() { + auto entry = parent_stack_.back(); + parent_stack_.pop_back(); + + if (parent_stack_.empty()) { + GenerateCode(entry); + } else { + parent_stack_.back().children.push_back(entry); + } + } + + private: + struct ViewEntry { + std::string name; + std::vector<ViewEntry> children; + }; + + void GenerateCode(const ViewEntry& view) { + builder_->StartView(view.name, !view.children.empty()); + for (const auto& child : view.children) { + GenerateCode(child); + } + builder_->FinishView(); + } + + Builder* builder_; + + std::vector<ViewEntry> parent_stack_; +}; + +class DexViewBuilder { + public: + DexViewBuilder(dex::MethodBuilder* method); + + void Start(); + void Finish(); + void StartView(const std::string& name, bool is_viewgroup); + void FinishView(); + + private: + // Accessors for the stack of views that are under construction. + dex::Value AcquireRegister(); + void ReleaseRegister(); + dex::Value GetCurrentView() const; + dex::Value GetCurrentLayoutParams() const; + dex::Value GetParentView() const; + void PopViewStack(); + + dex::MethodBuilder* method_; + + // Registers used for code generation + dex::Value const context_; + dex::Value const resid_; + const dex::Value inflater_; + const dex::Value xml_; + const dex::Value attrs_; + const dex::Value classname_tmp_; + + const dex::MethodDeclData xml_next_; + const dex::MethodDeclData try_create_view_; + const dex::MethodDeclData generate_layout_params_; + const dex::MethodDeclData add_view_; + + // used for keeping track of which registers are in use + size_t top_register_{0}; + std::vector<dex::Value> register_stack_; + + // Keep track of the views currently in progress. + struct ViewEntry { + dex::Value view; + std::optional<dex::Value> layout_params; + }; + std::vector<ViewEntry> view_stack_; +}; + +} // namespace startop + +#endif // DEX_LAYOUT_COMPILER_H_ diff --git a/startop/view_compiler/java_lang_builder.cc b/startop/view_compiler/java_lang_builder.cc index 0b8754fc7096..920caeecf58e 100644 --- a/startop/view_compiler/java_lang_builder.cc +++ b/startop/view_compiler/java_lang_builder.cc @@ -67,7 +67,7 @@ void JavaLangViewBuilder::Finish() const { "}\n"; // end CompiledView } -void JavaLangViewBuilder::StartView(const string& class_name) { +void JavaLangViewBuilder::StartView(const string& class_name, bool /*is_viewgroup*/) { const string view_var = MakeVar("view"); const string layout_var = MakeVar("layout"); std::string parent = "null"; diff --git a/startop/view_compiler/java_lang_builder.h b/startop/view_compiler/java_lang_builder.h index c8d20b23cd13..69356d3a6594 100644 --- a/startop/view_compiler/java_lang_builder.h +++ b/startop/view_compiler/java_lang_builder.h @@ -35,7 +35,7 @@ class JavaLangViewBuilder { void Finish() const; // Begin creating a view (i.e. process the opening tag) - void StartView(const std::string& class_name); + void StartView(const std::string& class_name, bool is_viewgroup); // Finish a view, after all of its child nodes have been processed. void FinishView(); diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc index 609bcf377b46..871a421cee2d 100644 --- a/startop/view_compiler/main.cc +++ b/startop/view_compiler/main.cc @@ -16,8 +16,12 @@ #include "gflags/gflags.h" +#include "android-base/stringprintf.h" +#include "apk_layout_compiler.h" #include "dex_builder.h" +#include "dex_layout_compiler.h" #include "java_lang_builder.h" +#include "layout_validation.h" #include "tinyxml_layout_parser.h" #include "util.h" @@ -32,43 +36,60 @@ namespace { using namespace tinyxml2; +using android::base::StringPrintf; +using startop::dex::ClassBuilder; +using startop::dex::DexBuilder; +using startop::dex::MethodBuilder; +using startop::dex::Prototype; +using startop::dex::TypeDescriptor; using namespace startop::util; using std::string; constexpr char kStdoutFilename[]{"stdout"}; +DEFINE_bool(apk, false, "Compile layouts in an APK"); DEFINE_bool(dex, false, "Generate a DEX file instead of Java"); DEFINE_string(out, kStdoutFilename, "Where to write the generated class"); DEFINE_string(package, "", "The package name for the generated class (required)"); -class ViewCompilerXmlVisitor : public XMLVisitor { +template <typename Visitor> +class XmlVisitorAdapter : public XMLVisitor { public: - explicit ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {} + explicit XmlVisitorAdapter(Visitor* visitor) : visitor_{visitor} {} bool VisitEnter(const XMLDocument& /*doc*/) override { - builder_->Start(); + visitor_->VisitStartDocument(); return true; } bool VisitExit(const XMLDocument& /*doc*/) override { - builder_->Finish(); + visitor_->VisitEndDocument(); return true; } bool VisitEnter(const XMLElement& element, const XMLAttribute* /*firstAttribute*/) override { - builder_->StartView(element.Name()); + visitor_->VisitStartTag( + std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes( + element.Name())); return true; } bool VisitExit(const XMLElement& /*element*/) override { - builder_->FinishView(); + visitor_->VisitEndTag(); return true; } private: - JavaLangViewBuilder* builder_; + Visitor* visitor_; }; +template <typename Builder> +void CompileLayout(XMLDocument* xml, Builder* builder) { + startop::LayoutCompilerVisitor visitor{builder}; + XmlVisitorAdapter<decltype(visitor)> adapter{&visitor}; + xml->Accept(&adapter); +} + } // end namespace int main(int argc, char** argv) { @@ -88,16 +109,23 @@ int main(int argc, char** argv) { return 1; } - if (FLAGS_dex) { - startop::dex::WriteTestDexFile("test.dex"); - return 0; + const char* const filename = argv[kFileNameParam]; + const bool is_stdout = FLAGS_out == kStdoutFilename; + + std::ofstream outfile; + if (!is_stdout) { + outfile.open(FLAGS_out); } - const char* const filename = argv[kFileNameParam]; - const string layout_name = FindLayoutNameFromFilename(filename); + if (FLAGS_apk) { + startop::CompileApkLayouts( + filename, + FLAGS_dex ? startop::CompilationTarget::kDex : startop::CompilationTarget::kJavaLanguage, + is_stdout ? std::cout : outfile); + return 0; + } - // We want to generate Java language code to inflate exactly this layout. This means - // generating code to walk the resource XML too. + const string layout_name = startop::util::FindLayoutNameFromFilename(filename); XMLDocument xml; xml.LoadFile(filename); @@ -108,15 +136,27 @@ int main(int argc, char** argv) { return 1; } - std::ofstream outfile; - if (FLAGS_out != kStdoutFilename) { - outfile.open(FLAGS_out); + if (FLAGS_dex) { + DexBuilder dex_file; + string class_name = StringPrintf("%s.CompiledView", FLAGS_package.c_str()); + ClassBuilder compiled_view{dex_file.MakeClass(class_name)}; + MethodBuilder method{compiled_view.CreateMethod( + layout_name, + Prototype{TypeDescriptor::FromClassname("android.view.View"), + TypeDescriptor::FromClassname("android.content.Context"), + TypeDescriptor::Int()})}; + startop::DexViewBuilder builder{&method}; + CompileLayout(&xml, &builder); + method.Encode(); + + slicer::MemView image{dex_file.CreateImage()}; + + (is_stdout ? std::cout : outfile).write(image.ptr<const char>(), image.size()); + } else { + // Generate Java language output. + JavaLangViewBuilder builder{FLAGS_package, layout_name, is_stdout ? std::cout : outfile}; + + CompileLayout(&xml, &builder); } - JavaLangViewBuilder builder{ - FLAGS_package, layout_name, FLAGS_out == kStdoutFilename ? std::cout : outfile}; - - ViewCompilerXmlVisitor visitor{&builder}; - xml.Accept(&visitor); - return 0; } diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java index b906d0bf3136..329911776993 100644 --- a/telecomm/java/android/telecom/CallRedirectionService.java +++ b/telecomm/java/android/telecom/CallRedirectionService.java @@ -16,6 +16,7 @@ package android.telecom; +import android.annotation.NonNull; import android.annotation.SdkConstant; import android.app.Service; import android.content.Intent; @@ -27,8 +28,8 @@ import android.os.Message; import android.os.RemoteException; import com.android.internal.os.SomeArgs; -import com.android.internal.telecom.ICallRedirectionService; import com.android.internal.telecom.ICallRedirectionAdapter; +import com.android.internal.telecom.ICallRedirectionService; /** * This service can be implemented to interact between Telecom and its implementor @@ -62,22 +63,35 @@ public abstract class CallRedirectionService extends Service { /** * Telecom calls this method to inform the implemented {@link CallRedirectionService} of - * a new outgoing call which is being placed. + * a new outgoing call which is being placed. Telecom does not request to redirect emergency + * calls and does not request to redirect calls with gateway information. + * + * <p>Telecom will cancel the call if Telecom does not receive a response in 5 seconds from + * the implemented {@link CallRedirectionService} set by users. * - * The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()}, - * {@link #redirectCall(Uri, PhoneAccountHandle)}, and {@link #cancelCall()} only from here. + * <p>The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()}, + * {@link #redirectCall(Uri, PhoneAccountHandle, boolean)}, and {@link #cancelCall()} only + * from here. * - * @param handle the phone number dialed by the user - * @param targetPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed. + * @param handle the phone number dialed by the user, represented in E.164 format if possible + * @param initialPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed. + * @param allowInteractiveResponse a boolean to tell if the implemented + * {@link CallRedirectionService} should allow interactive + * responses with users. Will be {@code false} if, for example + * the device is in car mode and the user would not be able to + * interact with their device. */ - public abstract void onPlaceCall(Uri handle, PhoneAccountHandle targetPhoneAccount); + public abstract void onPlaceCall(@NonNull Uri handle, + @NonNull PhoneAccountHandle initialPhoneAccount, + boolean allowInteractiveResponse); /** * The implemented {@link CallRedirectionService} calls this method to response a request - * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that no changes - * are required to the outgoing call, and that the call should be placed as-is. + * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that + * no changes are required to the outgoing call, and that the call should be placed as-is. * - * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}. + * <p>This can only be called from implemented + * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. * */ public final void placeCallUnmodified() { @@ -89,29 +103,39 @@ public abstract class CallRedirectionService extends Service { /** * The implemented {@link CallRedirectionService} calls this method to response a request - * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that changes - * are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing call. + * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that + * changes are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing + * call. Telecom will cancel the call if the implemented {@link CallRedirectionService} + * replies Telecom a handle for an emergency number. * - * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}. + * <p>This can only be called from implemented + * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. * * @param handle the new phone number to dial * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call. * If {@code null}, no change will be made to the * {@link PhoneAccountHandle} used to place the call. + * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog + * if the confirmFirst is true, and if the redirection request of this + * response was sent with a true flag of allowInteractiveResponse via + * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} */ - public final void redirectCall(Uri handle, PhoneAccountHandle targetPhoneAccount) { + public final void redirectCall(@NonNull Uri handle, + @NonNull PhoneAccountHandle targetPhoneAccount, + boolean confirmFirst) { try { - mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount); + mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst); } catch (RemoteException e) { } } /** * The implemented {@link CallRedirectionService} calls this method to response a request - * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that an outgoing - * call should be canceled entirely. + * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that + * an outgoing call should be canceled entirely. * - * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}. + * <p>This can only be called from implemented + * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. * */ public final void cancelCall() { @@ -137,7 +161,8 @@ public abstract class CallRedirectionService extends Service { SomeArgs args = (SomeArgs) msg.obj; try { mCallRedirectionAdapter = (ICallRedirectionAdapter) args.arg1; - onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3); + onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3, + (boolean) args.arg4); } finally { args.recycle(); } @@ -152,15 +177,20 @@ public abstract class CallRedirectionService extends Service { * Telecom calls this method to inform the CallRedirectionService of a new outgoing call * which is about to be placed. * @param handle the phone number dialed by the user - * @param targetPhoneAccount the URI of the number the user dialed + * @param initialPhoneAccount the URI of the number the user dialed + * @param allowInteractiveResponse a boolean to tell if the implemented + * {@link CallRedirectionService} should allow interactive + * responses with users. */ @Override - public void placeCall(ICallRedirectionAdapter adapter, Uri handle, - PhoneAccountHandle targetPhoneAccount) { + public void placeCall(@NonNull ICallRedirectionAdapter adapter, @NonNull Uri handle, + @NonNull PhoneAccountHandle initialPhoneAccount, + boolean allowInteractiveResponse) { SomeArgs args = SomeArgs.obtain(); args.arg1 = adapter; args.arg2 = handle; - args.arg3 = targetPhoneAccount; + args.arg3 = initialPhoneAccount; + args.arg4 = allowInteractiveResponse; mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget(); } } diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl index 46bf983f52a2..0a42a3f4f02e 100644 --- a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl @@ -31,5 +31,6 @@ oneway interface ICallRedirectionAdapter { void placeCallUnmodified(); - void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount); + void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount, + boolean confirmFirst); } diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl index d8d360beb64d..c1bc44007b0b 100644 --- a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl +++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl @@ -30,5 +30,5 @@ import com.android.internal.telecom.ICallRedirectionAdapter; */ oneway interface ICallRedirectionService { void placeCall(in ICallRedirectionAdapter adapter, in Uri handle, - in PhoneAccountHandle targetPhoneAccount); + in PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse); } diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index 893dbe31ce0b..61c6b48976c5 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -30,7 +30,7 @@ import java.util.Objects; public final class CellSignalStrengthLte extends CellSignalStrength implements Parcelable { private static final String LOG_TAG = "CellSignalStrengthLte"; - private static final boolean DBG = true; + private static final boolean DBG = false; /** * Indicates the unknown or undetectable RSSI value in ASU. diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index c53b37d8ae6a..26ec6ded8224 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.content.Context; import android.os.PersistableBundle; @@ -34,6 +35,7 @@ import java.util.Set; * Returned as the reason for a data connection failure as defined by modem and some local errors. * @hide */ +@SystemApi public final class DataFailCause { /** There is no failure */ public static final int NONE = 0; @@ -101,8 +103,8 @@ public final class DataFailCause { public static final int PDN_CONN_DOES_NOT_EXIST = 0x36; /** Multiple connections to a same PDN is not allowed. */ public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37; - /** Packet Data Protocol (PDP) */ - public static final int MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41; + /** Max number of Packet Data Protocol (PDP) context reached. */ + public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 0x41; /** Unsupported APN in current public land mobile network (PLMN). */ public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42; /** Invalid transaction id. */ @@ -165,22 +167,36 @@ public final class DataFailCause { // Local errors generated by Vendor RIL // specified in ril.h + /** Data fail due to registration failure. */ public static final int REGISTRATION_FAIL = -1; + /** Data fail due to GPRS registration failure. */ public static final int GPRS_REGISTRATION_FAIL = -2; + /** Data call drop due to network/modem disconnect. */ public static final int SIGNAL_LOST = -3; /* no retry */ + /** + * Preferred technology has changed, must retry with parameters appropriate for new technology. + */ public static final int PREF_RADIO_TECH_CHANGED = -4; + /** data call was disconnected because radio was resetting, powered off. */ public static final int RADIO_POWER_OFF = -5; /* no retry */ + /** Data call was disconnected by modem because tethered. */ public static final int TETHERED_CALL_ACTIVE = -6; /* no retry */ + /** Data call fail due to unspecific errors. */ public static final int ERROR_UNSPECIFIED = 0xFFFF; // Errors generated by the Framework // specified here + /** Unknown data failure cause. */ public static final int UNKNOWN = 0x10000; + /** Data fail due to radio not unavailable. */ public static final int RADIO_NOT_AVAILABLE = 0x10001; /* no retry */ + /** @hide */ public static final int UNACCEPTABLE_NETWORK_PARAMETER = 0x10002; /* no retry */ + /** @hide */ public static final int CONNECTION_TO_DATACONNECTIONAC_BROKEN = 0x10003; + /** Data connection was lost. */ public static final int LOST_CONNECTION = 0x10004; - /** Data was reset by framework. */ + /** @hide */ public static final int RESET_BY_FRAMEWORK = 0x10005; /** @hide */ @@ -216,7 +232,7 @@ public final class DataFailCause { ESM_INFO_NOT_RECEIVED, PDN_CONN_DOES_NOT_EXIST, MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED, - MAX_ACTIVE_PDP_CONTEXT_REACHED, + ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED, UNSUPPORTED_APN_IN_CURRENT_PLMN, INVALID_TRANSACTION_ID, MESSAGE_INCORRECT_SEMANTIC, @@ -308,8 +324,8 @@ public final class DataFailCause { sFailCauseMap.put(PDN_CONN_DOES_NOT_EXIST, "PDN_CONN_DOES_NOT_EXIST"); sFailCauseMap.put(MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED, "MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED"); - sFailCauseMap.put(MAX_ACTIVE_PDP_CONTEXT_REACHED, - "MAX_ACTIVE_PDP_CONTEXT_REACHED"); + sFailCauseMap.put(ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED, + "ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED"); sFailCauseMap.put(UNSUPPORTED_APN_IN_CURRENT_PLMN, "UNSUPPORTED_APN_IN_CURRENT_PLMN"); sFailCauseMap.put(INVALID_TRANSACTION_ID, "INVALID_TRANSACTION_ID"); @@ -369,6 +385,9 @@ public final class DataFailCause { sFailCauseMap.put(RESET_BY_FRAMEWORK, "RESET_BY_FRAMEWORK"); } + private DataFailCause() { + } + /** * Map of subId -> set of data call setup permanent failure for the carrier. */ @@ -382,6 +401,8 @@ public final class DataFailCause { * @param cause data disconnect cause * @param subId subscription index * @return true if the fail cause code needs platform to trigger a modem restart. + * + * @hide */ public static boolean isRadioRestartFailure(@NonNull Context context, @FailCause int cause, int subId) { @@ -410,6 +431,7 @@ public final class DataFailCause { return false; } + /** @hide */ public static boolean isPermanentFailure(@NonNull Context context, @FailCause int failCause, int subId) { synchronized (sPermanentFailureCache) { @@ -469,6 +491,7 @@ public final class DataFailCause { } } + /** @hide */ public static boolean isEventLoggable(@FailCause int dataFailCause) { return (dataFailCause == OPERATOR_BARRED) || (dataFailCause == INSUFFICIENT_RESOURCES) || (dataFailCause == UNKNOWN_PDP_ADDRESS_TYPE) @@ -488,11 +511,13 @@ public final class DataFailCause { || (dataFailCause == UNACCEPTABLE_NETWORK_PARAMETER); } + /** @hide */ public static String toString(@FailCause int dataFailCause) { int cause = getFailCause(dataFailCause); return (cause == UNKNOWN) ? "UNKNOWN(" + dataFailCause + ")" : sFailCauseMap.get(cause); } + /** @hide */ public static int getFailCause(@FailCause int failCause) { if (sFailCauseMap.containsKey(failCause)) { return failCause; diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 9317aa73ffc2..e27b38596324 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -184,14 +184,17 @@ public class PhoneStateListener { public static final int LISTEN_PRECISE_CALL_STATE = 0x00000800; /** - * Listen for precise changes and fails on the data connection (cellular). + * Listen for {@link PreciseDataConnectionState} on the data connection (cellular). + * * {@more} * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE * READ_PRECISE_PHONE_STATE} * * @see #onPreciseDataConnectionStateChanged + * * @hide */ + @SystemApi public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 0x00001000; /** @@ -564,10 +567,11 @@ public class PhoneStateListener { /** * Callback invoked when data connection state changes with precise information. + * @param dataConnectionState {@link PreciseDataConnectionState} * * @hide */ - @UnsupportedAppUsage + @SystemApi public void onPreciseDataConnectionStateChanged( PreciseDataConnectionState dataConnectionState) { // default implementation empty diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java index 83738997a067..57a18266259a 100644 --- a/telephony/java/android/telephony/PreciseDataConnectionState.java +++ b/telephony/java/android/telephony/PreciseDataConnectionState.java @@ -16,10 +16,12 @@ package android.telephony; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.net.LinkProperties; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.data.ApnSetting; import java.util.Objects; @@ -31,7 +33,7 @@ import java.util.Objects; * <ul> * <li>Data connection state. * <li>Network type of the connection. - * <li>APN type. + * <li>APN types. * <li>APN. * <li>The properties of the network link. * <li>Data connection fail cause. @@ -39,14 +41,15 @@ import java.util.Objects; * * @hide */ -public class PreciseDataConnectionState implements Parcelable { +@SystemApi +public final class PreciseDataConnectionState implements Parcelable { - private int mState = TelephonyManager.DATA_UNKNOWN; - private int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - private String mAPNType = ""; + private @TelephonyManager.DataState int mState = TelephonyManager.DATA_UNKNOWN; + private @TelephonyManager.NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + private @DataFailCause.FailCause int mFailCause = DataFailCause.NONE; + private @ApnSetting.ApnType int mAPNTypes = ApnSetting.TYPE_NONE; private String mAPN = ""; private LinkProperties mLinkProperties = null; - private String mFailCause = ""; /** * Constructor @@ -54,11 +57,14 @@ public class PreciseDataConnectionState implements Parcelable { * @hide */ @UnsupportedAppUsage - public PreciseDataConnectionState(int state, int networkType, String apnType, String apn, - LinkProperties linkProperties, String failCause) { + public PreciseDataConnectionState(@TelephonyManager.DataState int state, + @TelephonyManager.NetworkType int networkType, + @ApnSetting.ApnType int apnTypes, String apn, + LinkProperties linkProperties, + @DataFailCause.FailCause int failCause) { mState = state; mNetworkType = networkType; - mAPNType = apnType; + mAPNTypes = apnTypes; mAPN = apn; mLinkProperties = linkProperties; mFailCause = failCause; @@ -74,73 +80,52 @@ public class PreciseDataConnectionState implements Parcelable { /** * Construct a PreciseDataConnectionState object from the given parcel. + * + * @hide */ private PreciseDataConnectionState(Parcel in) { mState = in.readInt(); mNetworkType = in.readInt(); - mAPNType = in.readString(); + mAPNTypes = in.readInt(); mAPN = in.readString(); mLinkProperties = (LinkProperties)in.readParcelable(null); - mFailCause = in.readString(); + mFailCause = in.readInt(); } /** - * Get data connection state - * - * @see TelephonyManager#DATA_UNKNOWN - * @see TelephonyManager#DATA_DISCONNECTED - * @see TelephonyManager#DATA_CONNECTING - * @see TelephonyManager#DATA_CONNECTED - * @see TelephonyManager#DATA_SUSPENDED + * Returns the state of data connection that supported the apn types returned by + * {@link #getDataConnectionApnTypeBitMask()} */ - @UnsupportedAppUsage - public int getDataConnectionState() { + public @TelephonyManager.DataState int getDataConnectionState() { return mState; } /** - * Get data connection network type - * - * @see TelephonyManager#NETWORK_TYPE_UNKNOWN - * @see TelephonyManager#NETWORK_TYPE_GPRS - * @see TelephonyManager#NETWORK_TYPE_EDGE - * @see TelephonyManager#NETWORK_TYPE_UMTS - * @see TelephonyManager#NETWORK_TYPE_CDMA - * @see TelephonyManager#NETWORK_TYPE_EVDO_0 - * @see TelephonyManager#NETWORK_TYPE_EVDO_A - * @see TelephonyManager#NETWORK_TYPE_1xRTT - * @see TelephonyManager#NETWORK_TYPE_HSDPA - * @see TelephonyManager#NETWORK_TYPE_HSUPA - * @see TelephonyManager#NETWORK_TYPE_HSPA - * @see TelephonyManager#NETWORK_TYPE_IDEN - * @see TelephonyManager#NETWORK_TYPE_EVDO_B - * @see TelephonyManager#NETWORK_TYPE_LTE - * @see TelephonyManager#NETWORK_TYPE_EHRPD - * @see TelephonyManager#NETWORK_TYPE_HSPAP + * Returns the network type associated with this data connection. + * @hide */ - @UnsupportedAppUsage - public int getDataConnectionNetworkType() { + public @TelephonyManager.NetworkType int getDataConnectionNetworkType() { return mNetworkType; } /** - * Get data connection APN type + * Returns the data connection APN types supported by this connection and triggers + * {@link PreciseDataConnectionState} change. */ - @UnsupportedAppUsage - public String getDataConnectionAPNType() { - return mAPNType; + public @ApnSetting.ApnType int getDataConnectionApnTypeBitMask() { + return mAPNTypes; } /** - * Get data connection APN. + * Returns APN {@link ApnSetting} of this data connection. */ - @UnsupportedAppUsage - public String getDataConnectionAPN() { + public String getDataConnectionApn() { return mAPN; } /** - * Get the properties of the network link. + * Get the properties of the network link {@link LinkProperties}. + * @hide */ @UnsupportedAppUsage public LinkProperties getDataConnectionLinkProperties() { @@ -148,10 +133,9 @@ public class PreciseDataConnectionState implements Parcelable { } /** - * Get data connection fail cause, in case there was a failure. + * Returns data connection fail cause, in case there was a failure. */ - @UnsupportedAppUsage - public String getDataConnectionFailCause() { + public @DataFailCause.FailCause int getDataConnectionFailCause() { return mFailCause; } @@ -164,10 +148,10 @@ public class PreciseDataConnectionState implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(mState); out.writeInt(mNetworkType); - out.writeString(mAPNType); + out.writeInt(mAPNTypes); out.writeString(mAPN); out.writeParcelable(mLinkProperties, flags); - out.writeString(mFailCause); + out.writeInt(mFailCause); } public static final Parcelable.Creator<PreciseDataConnectionState> CREATOR @@ -184,56 +168,23 @@ public class PreciseDataConnectionState implements Parcelable { @Override public int hashCode() { - return Objects.hash(mState, mNetworkType, mAPNType, mAPN, mLinkProperties, mFailCause); + return Objects.hash(mState, mNetworkType, mAPNTypes, mAPN, mLinkProperties, + mFailCause); } @Override public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { + + if (!(obj instanceof PreciseDataConnectionState)) { return false; } + PreciseDataConnectionState other = (PreciseDataConnectionState) obj; - if (mAPN == null) { - if (other.mAPN != null) { - return false; - } - } else if (!mAPN.equals(other.mAPN)) { - return false; - } - if (mAPNType == null) { - if (other.mAPNType != null) { - return false; - } - } else if (!mAPNType.equals(other.mAPNType)) { - return false; - } - if (mFailCause == null) { - if (other.mFailCause != null) { - return false; - } - } else if (!mFailCause.equals(other.mFailCause)) { - return false; - } - if (mLinkProperties == null) { - if (other.mLinkProperties != null) { - return false; - } - } else if (!mLinkProperties.equals(other.mLinkProperties)) { - return false; - } - if (mNetworkType != other.mNetworkType) { - return false; - } - if (mState != other.mState) { - return false; - } - return true; + return Objects.equals(mAPN, other.mAPN) && mAPNTypes == other.mAPNTypes + && mFailCause == other.mFailCause + && Objects.equals(mLinkProperties, other.mLinkProperties) + && mNetworkType == other.mNetworkType + && mState == other.mState; } @Override @@ -242,10 +193,10 @@ public class PreciseDataConnectionState implements Parcelable { sb.append("Data Connection state: " + mState); sb.append(", Network type: " + mNetworkType); - sb.append(", APN type: " + mAPNType); + sb.append(", APN types: " + ApnSetting.getApnTypesStringFromBitmask(mAPNTypes)); sb.append(", APN: " + mAPN); sb.append(", Link properties: " + mLinkProperties); - sb.append(", Fail cause: " + mFailCause); + sb.append(", Fail cause: " + DataFailCause.toString(mFailCause)); return sb.toString(); } diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index ef185c5eeaf1..2271069dddb7 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -369,7 +369,7 @@ public class SignalStrength implements Parcelable { public int getLevel() { int level = getPrimary().getLevel(); if (level < SIGNAL_STRENGTH_NONE_OR_UNKNOWN || level > SIGNAL_STRENGTH_GREAT) { - log("Invalid Level " + level + ", this=" + this); + loge("Invalid Level " + level + ", this=" + this); return SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } return getPrimary().getLevel(); @@ -657,9 +657,16 @@ public class SignalStrength implements Parcelable { } /** - * log + * log warning */ private static void log(String s) { Rlog.w(LOG_TAG, s); } + + /** + * log error + */ + private static void loge(String s) { + Rlog.e(LOG_TAG, s); + } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 8dfdb2f4a334..648400509bac 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -4585,9 +4585,18 @@ public class TelephonyManager { } } - /** Data connection state: Unknown. Used before we know the state. - * @hide - */ + /** @hide */ + @IntDef(prefix = {"DATA_"}, value = { + DATA_UNKNOWN, + DATA_DISCONNECTED, + DATA_CONNECTING, + DATA_CONNECTED, + DATA_SUSPENDED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DataState{} + + /** Data connection state: Unknown. Used before we know the state. */ public static final int DATA_UNKNOWN = -1; /** Data connection state: Disconnected. IP traffic not available. */ public static final int DATA_DISCONNECTED = 0; @@ -5849,9 +5858,14 @@ public class TelephonyManager { /** * Returns the IMS Service Table (IST) that was loaded from the ISIM. + * + * See 3GPP TS 31.103 (Section 4.2.7) for the definition and more information on this table. + * * @return IMS Service Table or null if not present or not loaded * @hide */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst() { try { IPhoneSubInfo info = getSubscriberInfo(); diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index fe062d5d974a..a94b163ffd75 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -29,6 +29,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -198,21 +199,53 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT); } + /** + * Indicated the framework does not know whether an emergency call should be placed using + * emergency or normal call routing. This means the underlying radio or IMS implementation is + * free to determine for itself how to route the call. + */ + public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0; + /** + * Indicates the radio or IMS implementation must handle the call through emergency routing. + */ + public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1; + /** + * Indicates the radio or IMS implementation must handle the call through normal call routing. + */ + public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2; + + /** + * The routing to tell how to handle the call for the corresponding emergency number. + * + * @hide + */ + @IntDef(flag = false, prefix = { "EMERGENCY_CALL_ROUTING_" }, value = { + EMERGENCY_CALL_ROUTING_UNKNOWN, + EMERGENCY_CALL_ROUTING_EMERGENCY, + EMERGENCY_CALL_ROUTING_NORMAL + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EmergencyCallRouting {} + + private final String mNumber; private final String mCountryIso; private final String mMnc; private final int mEmergencyServiceCategoryBitmask; private final int mEmergencyNumberSourceBitmask; + private final int mEmergencyCallRouting; /** @hide */ - public EmergencyNumber(@NonNull String number, @NonNull String countryIso, - @NonNull String mnc, int emergencyServiceCategories, - int emergencyNumberSources) { + public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc, + @EmergencyServiceCategories int emergencyServiceCategories, + @EmergencyNumberSources int emergencyNumberSources, + @EmergencyCallRouting int emergencyCallRouting) { this.mNumber = number; this.mCountryIso = countryIso; this.mMnc = mnc; this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories; this.mEmergencyNumberSourceBitmask = emergencyNumberSources; + this.mEmergencyCallRouting = emergencyCallRouting; } /** @hide */ @@ -222,8 +255,33 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu mMnc = source.readString(); mEmergencyServiceCategoryBitmask = source.readInt(); mEmergencyNumberSourceBitmask = source.readInt(); + mEmergencyCallRouting = source.readInt(); + } + + @Override + /** @hide */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mNumber); + dest.writeString(mCountryIso); + dest.writeString(mMnc); + dest.writeInt(mEmergencyServiceCategoryBitmask); + dest.writeInt(mEmergencyNumberSourceBitmask); + dest.writeInt(mEmergencyCallRouting); } + public static final Parcelable.Creator<EmergencyNumber> CREATOR = + new Parcelable.Creator<EmergencyNumber>() { + @Override + public EmergencyNumber createFromParcel(Parcel in) { + return new EmergencyNumber(in); + } + + @Override + public EmergencyNumber[] newArray(int size) { + return new EmergencyNumber[size]; + } + }; + /** * Get the dialing number of the emergency number. * @@ -352,14 +410,17 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu return (mEmergencyNumberSourceBitmask & sources) == sources; } - @Override - /** @hide */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mNumber); - dest.writeString(mCountryIso); - dest.writeString(mMnc); - dest.writeInt(mEmergencyServiceCategoryBitmask); - dest.writeInt(mEmergencyNumberSourceBitmask); + /** + * Returns the emergency call routing information. + * + * <p>Some regions require some emergency numbers which are not routed using typical emergency + * call processing, but are instead placed as regular phone calls. The emergency call routing + * field provides information about how an emergency call will be routed when it is placed. + * + * @return the emergency call routing requirement + */ + public @EmergencyCallRouting int getEmergencyCallRouting() { + return mEmergencyCallRouting; } @Override @@ -373,7 +434,8 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso + "|Mnc-" + mMnc + "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask) - + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask); + + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask) + + "|Routing-" + Integer.toBinaryString(mEmergencyCallRouting); } @Override @@ -381,7 +443,19 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu if (!EmergencyNumber.class.isInstance(o)) { return false; } - return (o == this || toString().equals(o.toString())); + EmergencyNumber other = (EmergencyNumber) o; + return mNumber.equals(other.mNumber) + && mCountryIso.equals(other.mCountryIso) + && mMnc.equals(other.mMnc) + && mEmergencyServiceCategoryBitmask == other.mEmergencyServiceCategoryBitmask + && mEmergencyNumberSourceBitmask == other.mEmergencyNumberSourceBitmask + && mEmergencyCallRouting == other.mEmergencyCallRouting; + } + + @Override + public int hashCode() { + return Objects.hash(mNumber, mCountryIso, mMnc, mEmergencyServiceCategoryBitmask, + mEmergencyNumberSourceBitmask, mEmergencyCallRouting); } /** @@ -462,12 +536,12 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu continue; } for (int j = i + 1; j < emergencyNumberList.size(); j++) { - if (isSameEmergencyNumber( + if (areSameEmergencyNumbers( emergencyNumberList.get(i), emergencyNumberList.get(j))) { Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: " + emergencyNumberList.get(i) + " vs " + emergencyNumberList.get(j)); // Set the merged emergency number in the current position - emergencyNumberList.set(i, mergeNumbers( + emergencyNumberList.set(i, mergeSameEmergencyNumbers( emergencyNumberList.get(i), emergencyNumberList.get(j))); // Mark the emergency number has been merged mergedEmergencyNumber.add(emergencyNumberList.get(j)); @@ -486,8 +560,8 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu * Check if two emergency numbers are the same. * * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and - * 'categories' fields. Multiple Emergency Number Sources should be merged into one bitfield - * for the same EmergencyNumber. + * 'categories', and 'routing' fields. Multiple Emergency Number Sources should be + * merged into one bitfield for the same EmergencyNumber. * * @param first first EmergencyNumber to compare * @param second second EmergencyNumber to compare @@ -495,8 +569,8 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu * * @hide */ - public static boolean isSameEmergencyNumber(@NonNull EmergencyNumber first, - @NonNull EmergencyNumber second) { + public static boolean areSameEmergencyNumbers(@NonNull EmergencyNumber first, + @NonNull EmergencyNumber second) { if (!first.getNumber().equals(second.getNumber())) { return false; } @@ -510,11 +584,15 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu != second.getEmergencyServiceCategoryBitmask()) { return false; } + if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) { + return false; + } return true; } /** - * Get a merged EmergencyNumber for two numbers if they are the same. + * Get a merged EmergencyNumber from two same emergency numbers. Two emergency numbers are + * the same if {@link #areSameEmergencyNumbers} returns {@code true}. * * @param first first EmergencyNumber to compare * @param second second EmergencyNumber to compare @@ -522,27 +600,15 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu * * @hide */ - public static EmergencyNumber mergeNumbers(@NonNull EmergencyNumber first, - @NonNull EmergencyNumber second) { - if (isSameEmergencyNumber(first, second)) { + public static EmergencyNumber mergeSameEmergencyNumbers(@NonNull EmergencyNumber first, + @NonNull EmergencyNumber second) { + if (areSameEmergencyNumbers(first, second)) { return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(), first.getEmergencyServiceCategoryBitmask(), first.getEmergencyNumberSourceBitmask() - | second.getEmergencyNumberSourceBitmask()); + | second.getEmergencyNumberSourceBitmask(), + first.getEmergencyCallRouting()); } return null; } - - public static final Parcelable.Creator<EmergencyNumber> CREATOR = - new Parcelable.Creator<EmergencyNumber>() { - @Override - public EmergencyNumber createFromParcel(Parcel in) { - return new EmergencyNumber(in); - } - - @Override - public EmergencyNumber[] newArray(int size) { - return new EmergencyNumber[size]; - } - }; } diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index cb6fcd7b62c2..9c8d078a579b 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -24,9 +24,11 @@ import android.os.Parcel; import android.os.Parcelable; import android.telecom.VideoProfile; import android.telephony.emergency.EmergencyNumber; +import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting; import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.PhoneConstants; import java.lang.annotation.Retention; @@ -321,6 +323,20 @@ public final class ImsCallProfile implements Parcelable { EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED; /** + * The emergency call routing, only valid if {@link #getServiceType} returns + * {@link #SERVICE_TYPE_EMERGENCY} + * + * If valid, the value is any of the following constants: + * <ol> + * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li> + * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li> + * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li> + * </ol> + */ + private @EmergencyCallRouting int mEmergencyCallRouting = + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN; + + /** * Extras associated with this {@link ImsCallProfile}. * <p> * Valid data types include: @@ -503,10 +519,12 @@ public final class ImsCallProfile implements Parcelable { @Override public String toString() { - return "{ serviceType=" + mServiceType + - ", callType=" + mCallType + - ", restrictCause=" + mRestrictCause + - ", mediaProfile=" + mMediaProfile.toString() + " }"; + return "{ serviceType=" + mServiceType + + ", callType=" + mCallType + + ", restrictCause=" + mRestrictCause + + ", mediaProfile=" + mMediaProfile.toString() + + ", emergencyServiceCategories=" + mEmergencyCallRouting + + ", emergencyCallRouting=" + mEmergencyCallRouting + " }"; } @Override @@ -522,6 +540,7 @@ public final class ImsCallProfile implements Parcelable { out.writeBundle(filteredExtras); out.writeParcelable(mMediaProfile, 0); out.writeInt(mEmergencyServiceCategories); + out.writeInt(mEmergencyCallRouting); } private void readFromParcel(Parcel in) { @@ -530,6 +549,7 @@ public final class ImsCallProfile implements Parcelable { mCallExtras = in.readBundle(); mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader()); mEmergencyServiceCategories = in.readInt(); + mEmergencyCallRouting = in.readInt(); } public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() { @@ -740,6 +760,21 @@ public final class ImsCallProfile implements Parcelable { } /** + * Set the emergency service categories and emergency call routing. The set value is valid + * only if {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY} + * + * Reference: 3gpp 23.167, Section 6 - Functional description; + * 3gpp 22.101, Section 10 - Emergency Calls. + * + * @hide + */ + public void setEmergencyCallInfo(EmergencyNumber num) { + setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmask()); + setEmergencyCallRouting(num.getEmergencyCallRouting()); + } + + + /** * Set the emergency service categories. The set value is valid only if * {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY} * @@ -758,12 +793,29 @@ public final class ImsCallProfile implements Parcelable { * Reference: 3gpp 23.167, Section 6 - Functional description; * 3gpp 22.101, Section 10 - Emergency Calls. */ + @VisibleForTesting public void setEmergencyServiceCategories( @EmergencyServiceCategories int emergencyServiceCategories) { mEmergencyServiceCategories = emergencyServiceCategories; } /** + * Set the emergency call routing, only valid if {@link #getServiceType} returns + * {@link #SERVICE_TYPE_EMERGENCY} + * + * If valid, the value is any of the following constants: + * <ol> + * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li> + * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li> + * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li> + * </ol> + */ + @VisibleForTesting + public void setEmergencyCallRouting(@EmergencyCallRouting int emergencyCallRouting) { + mEmergencyCallRouting = emergencyCallRouting; + } + + /** * Get the emergency service categories, only valid if {@link #getServiceType} returns * {@link #SERVICE_TYPE_EMERGENCY} * @@ -787,4 +839,19 @@ public final class ImsCallProfile implements Parcelable { public @EmergencyServiceCategories int getEmergencyServiceCategories() { return mEmergencyServiceCategories; } + + /** + * Get the emergency call routing, only valid if {@link #getServiceType} returns + * {@link #SERVICE_TYPE_EMERGENCY} + * + * If valid, the value is any of the following constants: + * <ol> + * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li> + * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li> + * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li> + * </ol> + */ + public @EmergencyCallRouting int getEmergencyCallRouting() { + return mEmergencyCallRouting; + } } diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 122626f0c77a..e2350fe78500 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -714,7 +714,7 @@ public class ImsMmTelManager { * @see #setVoWiFiRoamingSetting(boolean) */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - @WiFiCallingMode int getVoWiFiRoamingModeSetting() { + public @WiFiCallingMode int getVoWiFiRoamingModeSetting() { try { return getITelephony().getVoWiFiRoamingModeSetting(mSubId); } catch (RemoteException e) { diff --git a/telephony/java/android/telephony/ims/RcsParticipant.java b/telephony/java/android/telephony/ims/RcsParticipant.java index 70500aaa2e8b..f678ec7e435b 100644 --- a/telephony/java/android/telephony/ims/RcsParticipant.java +++ b/telephony/java/android/telephony/ims/RcsParticipant.java @@ -15,22 +15,111 @@ */ package android.telephony.ims; +import static android.telephony.ims.RcsMessageStore.TAG; + +import android.annotation.NonNull; +import android.annotation.WorkerThread; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.telephony.Rlog; +import android.telephony.ims.aidl.IRcs; +import android.text.TextUtils; + +import com.android.internal.util.Preconditions; /** * RcsParticipant is an RCS capable contact that can participate in {@link RcsThread}s. * @hide - TODO(sahinc) make this public */ public class RcsParticipant implements Parcelable { + // The row ID of this participant in the database + private int mId; + // The phone number of this participant + private String mCanonicalAddress; + // The RCS alias of this participant. This is different than the name of the contact in the + // Contacts app - i.e. RCS protocol allows users to define aliases for themselves that doesn't + // require other users to add them as contacts and give them a name. + private String mAlias; + /** - * Returns the row id of this participant. + * Constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController} + * to create instances of participants. This is not meant to be part of the SDK. + * + * @hide + */ + public RcsParticipant(int id, @NonNull String canonicalAddress) { + mId = id; + mCanonicalAddress = canonicalAddress; + } + + /** + * @return Returns the canonical address (i.e. normalized phone number) for this participant + */ + public String getCanonicalAddress() { + return mCanonicalAddress; + } + + /** + * Sets the canonical address for this participant and updates it in storage. + * @param canonicalAddress the canonical address to update to. + */ + @WorkerThread + public void setCanonicalAddress(@NonNull String canonicalAddress) { + Preconditions.checkNotNull(canonicalAddress); + if (canonicalAddress.equals(mCanonicalAddress)) { + return; + } + + mCanonicalAddress = canonicalAddress; + + try { + IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs")); + if (iRcs != null) { + iRcs.updateRcsParticipantCanonicalAddress(mId, mCanonicalAddress); + } + } catch (RemoteException re) { + Rlog.e(TAG, "RcsParticipant: Exception happened during setCanonicalAddress", re); + } + } + + /** + * @return Returns the alias for this participant. Alias is usually the real name of the person + * themselves. + */ + public String getAlias() { + return mAlias; + } + + /** + * Sets the alias for this participant and persists it in storage. Alias is usually the real + * name of the person themselves. + */ + @WorkerThread + public void setAlias(String alias) { + if (TextUtils.equals(mAlias, alias)) { + return; + } + mAlias = alias; + + try { + IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs")); + if (iRcs != null) { + iRcs.updateRcsParticipantAlias(mId, mAlias); + } + } catch (RemoteException re) { + Rlog.e(TAG, "RcsParticipant: Exception happened during setCanonicalAddress", re); + } + } + + /** + * Returns the row id of this participant. This is not meant to be part of the SDK * - * TODO(sahinc) implement * @hide */ public int getId() { - return 12345; + return mId; } public static final Creator<RcsParticipant> CREATOR = new Creator<RcsParticipant>() { @@ -46,6 +135,9 @@ public class RcsParticipant implements Parcelable { }; protected RcsParticipant(Parcel in) { + mId = in.readInt(); + mCanonicalAddress = in.readString(); + mAlias = in.readString(); } @Override @@ -55,6 +147,8 @@ public class RcsParticipant implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - + dest.writeInt(mId); + dest.writeString(mCanonicalAddress); + dest.writeString(mAlias); } } diff --git a/telephony/java/android/telephony/ims/aidl/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcs.aidl index 9badac5be230..0c958ba719f3 100644 --- a/telephony/java/android/telephony/ims/aidl/IRcs.aidl +++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl @@ -37,8 +37,13 @@ interface IRcs { Rcs1To1Thread createRcs1To1Thread(in RcsParticipant participant); - RcsParticipant createRcsParticipant(String canonicalAddress); - // RcsThread APIs int getMessageCount(int rcsThreadId); + + // RcsParticipant APIs + RcsParticipant createRcsParticipant(String canonicalAddress); + + void updateRcsParticipantCanonicalAddress(int id, String canonicalAddress); + + void updateRcsParticipantAlias(int id, String alias); }
\ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 02a6f311c1da..5632c630999b 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -68,7 +68,7 @@ interface ITelephonyRegistry { int backgroundCallState); void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause); void notifyPreciseDataConnectionFailed(String apnType, String apn, - String failCause); + int failCause); void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo); void notifySrvccStateChanged(in int subId, in int lteState); void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId, diff --git a/tests/ActivityViewTest/Android.mk b/tests/ActivityViewTest/Android.mk index 9c8076417bc8..9c7ca7eb5d00 100644 --- a/tests/ActivityViewTest/Android.mk +++ b/tests/ActivityViewTest/Android.mk @@ -1,7 +1,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ActivityViewTest LOCAL_PRIVATE_PLATFORM_APIS := true diff --git a/tests/ActivityViewTest/AndroidManifest.xml b/tests/ActivityViewTest/AndroidManifest.xml index de54cc9986e5..0be1ea0fdfd2 100644 --- a/tests/ActivityViewTest/AndroidManifest.xml +++ b/tests/ActivityViewTest/AndroidManifest.xml @@ -35,17 +35,20 @@ <activity android:name=".ActivityViewActivity" android:label="AV" - android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"> + android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density" + android:windowSoftInputMode="stateHidden|adjustResize"> </activity> <activity android:name=".ActivityViewResizeActivity" android:label="AV Resize" - android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"> + android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density" + android:windowSoftInputMode="stateHidden|adjustResize"> </activity> <activity android:name=".ActivityViewScrollActivity" android:label="AV Scroll" - android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"> + android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density" + android:windowSoftInputMode="stateHidden"> </activity> <activity android:name=".ActivityViewTestActivity" diff --git a/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml index f7ec56264c3a..338d68adfafb 100644 --- a/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml +++ b/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml @@ -15,6 +15,7 @@ --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/test_activity_root" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" @@ -60,11 +61,10 @@ android:background="#00000000" android:gravity="center" /> - <View - android:id="@+id/touch_intercept_view" + <EditText + android:id="@+id/test_activity_edittext" android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="#00000000" - /> - + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:layout_margin="16dp" /> </RelativeLayout>
\ No newline at end of file diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java index 0d62786f40b0..ba2c764bd7d7 100644 --- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java +++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java @@ -29,26 +29,24 @@ import android.view.View; import android.view.ViewTreeObserver; import android.widget.TextView; -public class ActivityViewTestActivity extends Activity implements View.OnTouchListener { +public class ActivityViewTestActivity extends Activity { + private View mRoot; private TextView mTextView; private TextView mWidthTextView; private TextView mHeightTextView; private TextView mTouchStateTextView; - private View mTouchInterceptView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view_test_activity); - + mRoot = findViewById(R.id.test_activity_root); mTextView = findViewById(R.id.test_activity_title); mWidthTextView = findViewById(R.id.test_activity_width_text); mHeightTextView = findViewById(R.id.test_activity_height_text); mTouchStateTextView = findViewById(R.id.test_activity_touch_state); - mTouchInterceptView = findViewById(R.id.touch_intercept_view); - mTouchInterceptView.setOnTouchListener(this); - ViewTreeObserver viewTreeObserver = mTouchInterceptView.getViewTreeObserver(); + ViewTreeObserver viewTreeObserver = mRoot.getViewTreeObserver(); if (viewTreeObserver.isAlive()) { viewTreeObserver.addOnGlobalLayoutListener(this::updateDimensionTexts); } @@ -90,8 +88,8 @@ public class ActivityViewTestActivity extends Activity implements View.OnTouchLi } private void updateDimensionTexts() { - mWidthTextView.setText("" + mTouchInterceptView.getWidth()); - mHeightTextView.setText("" + mTouchInterceptView.getHeight()); + mWidthTextView.setText("" + mRoot.getWidth()); + mHeightTextView.setText("" + mRoot.getHeight()); } private void updateTouchState(MotionEvent event) { @@ -108,8 +106,8 @@ public class ActivityViewTestActivity extends Activity implements View.OnTouchLi } @Override - public boolean onTouch(View v, MotionEvent event) { + public boolean dispatchTouchEvent(MotionEvent event) { updateTouchState(event); - return true; + return super.dispatchTouchEvent(event); } } diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java new file mode 100644 index 000000000000..c402dbffc84b --- /dev/null +++ b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java @@ -0,0 +1,46 @@ +/* + * 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.tests.ims; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Bundle; +import android.support.test.runner.AndroidJUnit4; +import android.telephony.ims.RcsParticipant; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class RcsParticipantTest { + private static final int ID = 123; + private static final String ALIAS = "alias"; + private static final String CANONICAL_ADDRESS = "+1234567890"; + + @Test + public void testCanUnparcel() { + RcsParticipant rcsParticipant = new RcsParticipant(ID, CANONICAL_ADDRESS); + rcsParticipant.setAlias(ALIAS); + + Bundle bundle = new Bundle(); + bundle.putParcelable("Some key", rcsParticipant); + rcsParticipant = bundle.getParcelable("Some key"); + + assertThat(rcsParticipant.getId()).isEqualTo(ID); + assertThat(rcsParticipant.getAlias()).isEqualTo(ALIAS); + assertThat(rcsParticipant.getCanonicalAddress()).isEqualTo(CANONICAL_ADDRESS); + } +} diff --git a/tests/RollbackTest/TEST_MAPPING b/tests/RollbackTest/TEST_MAPPING new file mode 100644 index 000000000000..c1d95ac85c23 --- /dev/null +++ b/tests/RollbackTest/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "RollbackTest" + } + ] +} diff --git a/tests/UsageReportingTest/Android.mk b/tests/UsageReportingTest/Android.mk new file mode 100644 index 000000000000..afb6e16b1fdf --- /dev/null +++ b/tests/UsageReportingTest/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_USE_AAPT2 := true +LOCAL_STATIC_ANDROID_LIBRARIES := androidx.legacy_legacy-support-v4 + +LOCAL_CERTIFICATE := platform + +LOCAL_PACKAGE_NAME := UsageReportingTest +LOCAL_PRIVATE_PLATFORM_APIS := true + +include $(BUILD_PACKAGE) diff --git a/tests/UsageReportingTest/AndroidManifest.xml b/tests/UsageReportingTest/AndroidManifest.xml new file mode 100644 index 000000000000..be0b09e972a5 --- /dev/null +++ b/tests/UsageReportingTest/AndroidManifest.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Note: Add android:sharedUserId="android.uid.system" to the root element to simulate the system UID + caller case. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.tests.usagereporter" + > + + <application android:label="@string/reporter_app"> + <activity android:name="UsageReporterActivity" + android:label="UsageReporter"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> +</manifest> diff --git a/tests/UsageReportingTest/res/layout/row_item.xml b/tests/UsageReportingTest/res/layout/row_item.xml new file mode 100644 index 000000000000..1eb2dab29124 --- /dev/null +++ b/tests/UsageReportingTest/res/layout/row_item.xml @@ -0,0 +1,36 @@ +<?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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:background="@color/inactive_color"> + + <TextView android:id="@+id/token" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textStyle="bold"/> + + <Button android:id="@+id/start" style="@style/ActionButton" + android:text="@string/start" /> + + <Button android:id="@+id/stop" style="@style/ActionButton" + android:text="@string/stop" /> +</LinearLayout> diff --git a/tests/UsageReportingTest/res/menu/main.xml b/tests/UsageReportingTest/res/menu/main.xml new file mode 100644 index 000000000000..9847c2dce8f2 --- /dev/null +++ b/tests/UsageReportingTest/res/menu/main.xml @@ -0,0 +1,28 @@ +<?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. +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/add_token" + android:title="@string/add_token"/> + <item android:id="@+id/add_many_tokens" + android:title="@string/add_many_tokens"/> + <item android:id="@+id/stop_all" + android:title="@string/stop_all_tokens"/> + <group android:checkableBehavior="all"> + <item android:id="@+id/restore_on_start" + android:title="@string/restore_tokens_on_start"/> + </group> +</menu>
\ No newline at end of file diff --git a/tests/UsageReportingTest/res/values/colors.xml b/tests/UsageReportingTest/res/values/colors.xml new file mode 100644 index 000000000000..03bcf8a60182 --- /dev/null +++ b/tests/UsageReportingTest/res/values/colors.xml @@ -0,0 +1,19 @@ +<?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> + <color name="active_color">#FFF</color> + <color name="inactive_color">#AAA</color> +</resources>
\ No newline at end of file diff --git a/tests/UsageReportingTest/res/values/strings.xml b/tests/UsageReportingTest/res/values/strings.xml new file mode 100644 index 000000000000..015290e732a0 --- /dev/null +++ b/tests/UsageReportingTest/res/values/strings.xml @@ -0,0 +1,47 @@ +<?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> + <!-- Do not translate --> + <string name="reporter_app">Usage Reporter App</string> + <!-- Do not translate --> + <string name="start">Start</string> + <!-- Do not translate --> + <string name="stop">Stop</string> + <!-- Do not translate --> + <string name="default_token">SuperSecretToken</string> + + <!-- Do not translate --> + <string name="add_token">Add Token</string> + <!-- Do not translate --> + <string name="add_many_tokens">Add Many Tokens</string> + <!-- Do not translate --> + <string name="stop_all_tokens">Stop All</string> + <!-- Do not translate --> + <string name="restore_tokens_on_start">Readd Tokens on Start</string> + + + <!-- Do not translate --> + <string name="token_query">Enter token(s) (delimit tokens with commas)</string> + <!-- Do not translate --> + <string name="many_tokens_query">Generate how many tokens?</string> + <!-- Do not translate --> + <string name="stop_all_tokens_query">Stop all tokens?</string> + <!-- Do not translate --> + <string name="ok">OK</string> + <!-- Do not translate --> + <string name="cancel">Cancel</string> +</resources>
\ No newline at end of file diff --git a/tests/UsageReportingTest/res/values/styles.xml b/tests/UsageReportingTest/res/values/styles.xml new file mode 100644 index 000000000000..e5b86c5e836b --- /dev/null +++ b/tests/UsageReportingTest/res/values/styles.xml @@ -0,0 +1,31 @@ +<?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> + <style name="ActionButton"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:textAppearance">@style/TextAppearance.ActionButton</item> + </style> + + <style name="TextAppearance" parent="android:TextAppearance"> + </style> + + <style name="TextAppearance.ActionButton"> + <item name="android:textStyle">italic</item> + </style> + +</resources> diff --git a/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java b/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java new file mode 100644 index 000000000000..946be8fe93d3 --- /dev/null +++ b/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java @@ -0,0 +1,320 @@ +/* + * 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.tests.usagereporter; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ListActivity; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.text.InputType; +import android.text.TextUtils; +import android.util.ArraySet; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; + +public class UsageReporterActivity extends ListActivity { + + private Activity mActivity; + private final ArrayList<String> mTokens = new ArrayList(); + private final ArraySet<String> mActives = new ArraySet(); + private UsageStatsManager mUsageStatsManager; + private Adapter mAdapter; + private boolean mRestoreOnStart = false; + private static Context sContext; + + /** Called with the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + sContext = getApplicationContext(); + + mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); + + mAdapter = new Adapter(); + setListAdapter(mAdapter); + } + + @Override + protected void onStart() { + super.onStart(); + mActivity = this; + + + if (mRestoreOnStart) { + ArrayList<String> removed = null; + for (String token : mActives) { + try { + mUsageStatsManager.reportUsageStart(mActivity, token); + } catch (Exception e) { + // Somthing went wrong, recover and move on + if (removed == null) { + removed = new ArrayList(); + } + removed.add(token); + } + } + if (removed != null) { + for (String token : removed) { + mActives.remove(token); + } + } + } else { + mActives.clear(); + } + } + + /** + * Called when the activity is about to start interacting with the user. + */ + @Override + protected void onResume() { + super.onResume(); + mAdapter.notifyDataSetChanged(); + } + + + /** + * Called when your activity's options menu needs to be created. + */ + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main, menu); + return super.onCreateOptionsMenu(menu); + } + + + /** + * Called when a menu item is selected. + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.add_token: + callAddToken(); + return true; + case R.id.add_many_tokens: + callAddManyTokens(); + return true; + case R.id.stop_all: + callStopAll(); + return true; + case R.id.restore_on_start: + mRestoreOnStart = !mRestoreOnStart; + item.setChecked(mRestoreOnStart); + return true; + } + + return super.onOptionsItemSelected(item); + } + + private void callAddToken() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.token_query)); + final EditText input = new EditText(this); + input.setInputType(InputType.TYPE_CLASS_TEXT); + input.setHint(getString(R.string.default_token)); + builder.setView(input); + + builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String tokenNames = input.getText().toString().trim(); + if (TextUtils.isEmpty(tokenNames)) { + tokenNames = getString(R.string.default_token); + } + String[] tokens = tokenNames.split(","); + for (String token : tokens) { + if (mTokens.contains(token)) continue; + mTokens.add(token); + } + mAdapter.notifyDataSetChanged(); + + } + }); + builder.setNegativeButton(getString(R.string.cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.show(); + } + + private void callAddManyTokens() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.many_tokens_query)); + final EditText input = new EditText(this); + input.setInputType(InputType.TYPE_CLASS_NUMBER); + builder.setView(input); + + builder.setPositiveButton(getString(R.string.ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String val = input.getText().toString().trim(); + if (TextUtils.isEmpty(val)) return; + int n = Integer.parseInt(val); + for (int i = 0; i < n; i++) { + final String token = getString(R.string.default_token) + i; + if (mTokens.contains(token)) continue; + mTokens.add(token); + } + mAdapter.notifyDataSetChanged(); + + } + }); + builder.setNegativeButton(getString(R.string.cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.show(); + } + + private void callStopAll() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.stop_all_tokens_query)); + + builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + for (String token : mActives) { + mUsageStatsManager.reportUsageStop(mActivity, token); + } + mActives.clear(); + mAdapter.notifyDataSetChanged(); + } + }); + builder.setNegativeButton(getString(R.string.cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + builder.show(); + } + + /** + * A call-back for when the user presses the back button. + */ + OnClickListener mStartListener = new OnClickListener() { + public void onClick(View v) { + final View parent = (View) v.getParent(); + final String token = ((TextView) parent.findViewById(R.id.token)).getText().toString(); + try { + mUsageStatsManager.reportUsageStart(mActivity, token); + } catch (Exception e) { + Toast.makeText(sContext, e.toString(), Toast.LENGTH_LONG).show(); + } + parent.setBackgroundColor(getColor(R.color.active_color)); + mActives.add(token); + } + }; + + /** + * A call-back for when the user presses the clear button. + */ + OnClickListener mStopListener = new OnClickListener() { + public void onClick(View v) { + final View parent = (View) v.getParent(); + + final String token = ((TextView) parent.findViewById(R.id.token)).getText().toString(); + try { + mUsageStatsManager.reportUsageStop(mActivity, token); + } catch (Exception e) { + Toast.makeText(sContext, e.toString(), Toast.LENGTH_LONG).show(); + } + parent.setBackgroundColor(getColor(R.color.inactive_color)); + mActives.remove(token); + } + }; + + + private class Adapter extends BaseAdapter { + @Override + public int getCount() { + return mTokens.size(); + } + + @Override + public Object getItem(int position) { + return mTokens.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final ViewHolder holder; + if (convertView == null) { + convertView = LayoutInflater.from(UsageReporterActivity.this) + .inflate(R.layout.row_item, parent, false); + holder = new ViewHolder(); + holder.tokenName = (TextView) convertView.findViewById(R.id.token); + + holder.startButton = ((Button) convertView.findViewById(R.id.start)); + holder.startButton.setOnClickListener(mStartListener); + holder.stopButton = ((Button) convertView.findViewById(R.id.stop)); + holder.stopButton.setOnClickListener(mStopListener); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + final String token = mTokens.get(position); + holder.tokenName.setText(mTokens.get(position)); + if (mActives.contains(token)) { + convertView.setBackgroundColor(getColor(R.color.active_color)); + } else { + convertView.setBackgroundColor(getColor(R.color.inactive_color)); + } + return convertView; + } + } + + private static class ViewHolder { + public TextView tokenName; + public Button startButton; + public Button stopButton; + } +} diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java index 3d8ce21a2c00..3c628f6e0013 100644 --- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java +++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java @@ -155,7 +155,7 @@ public class UsageStatsActivity extends ListActivity { intent.setPackage(getPackageName()); intent.putExtra(EXTRA_KEY_TIMEOUT, true); mUsageStatsManager.registerAppUsageObserver(1, packages, - 30, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this, + 60, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this, 1, intent, 0)); } } diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java index d5987a5373b4..85646987940f 100644 --- a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java +++ b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java @@ -28,6 +28,7 @@ import android.view.DisplayCutout; import android.view.IWindowSession; import android.view.InsetsState; import android.view.Surface; +import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; @@ -106,7 +107,7 @@ public class MainActivity extends Activity { window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, -1, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, new DisplayCutout.ParcelableWrapper(), new MergedConfiguration(), - new Surface(), new InsetsState()); + new SurfaceControl(), new InsetsState()); } catch (RemoteException e) { e.printStackTrace(); } diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java index 9695e9a033b8..f82b380f5d43 100644 --- a/tests/net/java/android/net/LinkPropertiesTest.java +++ b/tests/net/java/android/net/LinkPropertiesTest.java @@ -53,6 +53,8 @@ public class LinkPropertiesTest { private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1"); private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1"); private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888"); + private static InetAddress PCSCFV6 = NetworkUtils.numericToInetAddress( + "2001:0db8:85a3:0000:0000:8a2e:0370:1"); private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1"); private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1"); private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613"); @@ -86,6 +88,9 @@ public class LinkPropertiesTest { assertTrue(source.isIdenticalValidatedPrivateDnses(target)); assertTrue(target.isIdenticalValidatedPrivateDnses(source)); + assertTrue(source.isIdenticalPcscfs(target)); + assertTrue(target.isIdenticalPcscfs(source)); + assertTrue(source.isIdenticalRoutes(target)); assertTrue(target.isIdenticalRoutes(source)); @@ -128,6 +133,8 @@ public class LinkPropertiesTest { // set 2 dnses source.addDnsServer(DNS1); source.addDnsServer(DNS2); + // set 1 pcscf + source.addPcscfServer(PCSCFV6); // set 2 gateways source.addRoute(new RouteInfo(GATEWAY1)); source.addRoute(new RouteInfo(GATEWAY2)); @@ -141,6 +148,7 @@ public class LinkPropertiesTest { target.addLinkAddress(LINKADDRV6); target.addDnsServer(DNS1); target.addDnsServer(DNS2); + target.addPcscfServer(PCSCFV6); target.addRoute(new RouteInfo(GATEWAY1)); target.addRoute(new RouteInfo(GATEWAY2)); target.setMtu(MTU); @@ -154,6 +162,7 @@ public class LinkPropertiesTest { target.addLinkAddress(LINKADDRV6); target.addDnsServer(DNS1); target.addDnsServer(DNS2); + target.addPcscfServer(PCSCFV6); target.addRoute(new RouteInfo(GATEWAY1)); target.addRoute(new RouteInfo(GATEWAY2)); target.setMtu(MTU); @@ -167,6 +176,7 @@ public class LinkPropertiesTest { target.addLinkAddress(LINKADDRV6); target.addDnsServer(DNS1); target.addDnsServer(DNS2); + target.addPcscfServer(PCSCFV6); target.addRoute(new RouteInfo(GATEWAY1)); target.addRoute(new RouteInfo(GATEWAY2)); target.setMtu(MTU); @@ -179,6 +189,21 @@ public class LinkPropertiesTest { // change dnses target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2")); target.addDnsServer(DNS2); + target.addPcscfServer(PCSCFV6); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); + target.setMtu(MTU); + assertFalse(source.equals(target)); + + target.clear(); + target.setInterfaceName(NAME); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2")); + target.addDnsServer(DNS2); + // change pcscf + target.addPcscfServer(NetworkUtils.numericToInetAddress( + "2001::1")); target.addRoute(new RouteInfo(GATEWAY1)); target.addRoute(new RouteInfo(GATEWAY2)); target.setMtu(MTU); diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java new file mode 100644 index 000000000000..4a6f20a043bb --- /dev/null +++ b/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java @@ -0,0 +1,113 @@ +/* + * 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.dhcp; + +import static android.net.InetAddresses.parseNumericAddress; + +import static com.google.android.collect.Sets.newHashSet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.LinkAddress; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DhcpServingParamsParcelExtTest { + private static final Inet4Address TEST_ADDRESS = inet4Addr("192.168.0.123"); + private static final int TEST_ADDRESS_PARCELED = 0xc0a8007b; + private static final int TEST_PREFIX_LENGTH = 17; + private static final int TEST_LEASE_TIME_SECS = 120; + private static final int TEST_MTU = 1000; + private static final Set<Inet4Address> TEST_ADDRESS_SET = + newHashSet(inet4Addr("192.168.1.123"), inet4Addr("192.168.1.124")); + private static final Set<Integer> TEST_ADDRESS_SET_PARCELED = + newHashSet(0xc0a8017b, 0xc0a8017c); + + private DhcpServingParamsParcelExt mParcel; + + @Before + public void setUp() { + mParcel = new DhcpServingParamsParcelExt(); + } + + @Test + public void testSetServerAddr() { + mParcel.setServerAddr(new LinkAddress(TEST_ADDRESS, TEST_PREFIX_LENGTH)); + + assertEquals(TEST_ADDRESS_PARCELED, mParcel.serverAddr); + assertEquals(TEST_PREFIX_LENGTH, mParcel.serverAddrPrefixLength); + } + + @Test + public void testSetDefaultRouters() { + mParcel.setDefaultRouters(TEST_ADDRESS_SET); + assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.defaultRouters)); + } + + @Test + public void testSetDnsServers() { + mParcel.setDnsServers(TEST_ADDRESS_SET); + assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.dnsServers)); + } + + @Test + public void testSetExcludedAddrs() { + mParcel.setExcludedAddrs(TEST_ADDRESS_SET); + assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.excludedAddrs)); + } + + @Test + public void testSetDhcpLeaseTimeSecs() { + mParcel.setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS); + assertEquals(TEST_LEASE_TIME_SECS, mParcel.dhcpLeaseTimeSecs); + } + + @Test + public void testSetLinkMtu() { + mParcel.setLinkMtu(TEST_MTU); + assertEquals(TEST_MTU, mParcel.linkMtu); + } + + @Test + public void testSetMetered() { + mParcel.setMetered(true); + assertTrue(mParcel.metered); + mParcel.setMetered(false); + assertFalse(mParcel.metered); + } + + private static Inet4Address inet4Addr(String addr) { + return (Inet4Address) parseNumericAddress(addr); + } + + private static Set<Integer> asSet(int[] ints) { + return IntStream.of(ints).boxed().collect(Collectors.toSet()); + } +} diff --git a/tests/net/java/android/net/ip/IpServerTest.java b/tests/net/java/android/net/ip/IpServerTest.java index 2c675c68a076..c3162af1868d 100644 --- a/tests/net/java/android/net/ip/IpServerTest.java +++ b/tests/net/java/android/net/ip/IpServerTest.java @@ -16,31 +16,37 @@ package android.net.ip; +import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; +import static android.net.ConnectivityManager.TETHERING_USB; +import static android.net.ConnectivityManager.TETHERING_WIFI; +import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; +import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; +import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; +import static android.net.NetworkUtils.intToInet4AddressHTH; +import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; +import static android.net.ip.IpServer.STATE_AVAILABLE; +import static android.net.ip.IpServer.STATE_TETHERED; +import static android.net.ip.IpServer.STATE_UNAVAILABLE; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; -import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; -import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; -import static android.net.ConnectivityManager.TETHERING_USB; -import static android.net.ConnectivityManager.TETHERING_WIFI; -import static android.net.ip.IpServer.STATE_AVAILABLE; -import static android.net.ip.IpServer.STATE_TETHERED; -import static android.net.ip.IpServer.STATE_UNAVAILABLE; - import android.net.INetworkStatsService; import android.net.InterfaceConfiguration; import android.net.IpPrefix; @@ -48,8 +54,9 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; import android.net.RouteInfo; -import android.net.dhcp.DhcpServer; -import android.net.dhcp.DhcpServingParams; +import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.IDhcpServer; +import android.net.dhcp.IDhcpServerCallbacks; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.SharedLog; @@ -60,8 +67,6 @@ import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.TextUtils; -import java.net.Inet4Address; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -71,6 +76,8 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.net.Inet4Address; + @RunWith(AndroidJUnit4.class) @SmallTest public class IpServerTest { @@ -82,16 +89,18 @@ public class IpServerTest { private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams( IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */); + private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000; + @Mock private INetworkManagementService mNMService; @Mock private INetworkStatsService mStatsService; @Mock private IpServer.Callback mCallback; @Mock private InterfaceConfiguration mInterfaceConfiguration; @Mock private SharedLog mSharedLog; - @Mock private DhcpServer mDhcpServer; + @Mock private IDhcpServer mDhcpServer; @Mock private RouterAdvertisementDaemon mRaDaemon; @Mock private IpServer.Dependencies mDependencies; - @Captor private ArgumentCaptor<DhcpServingParams> mDhcpParamsCaptor; + @Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor; private final TestLooper mLooper = new TestLooper(); private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor = @@ -112,8 +121,18 @@ public class IpServerTest { mLooper.dispatchAll(); reset(mNMService, mStatsService, mCallback); when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); - when(mDependencies.makeDhcpServer( - any(), any(), mDhcpParamsCaptor.capture(), any())).thenReturn(mDhcpServer); + + doAnswer(inv -> { + final IDhcpServerCallbacks cb = inv.getArgument(2); + new Thread(() -> { + try { + cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer); + } catch (RemoteException e) { + fail(e.getMessage()); + } + }).run(); + return null; + }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any()); when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon); when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS); @@ -399,21 +418,20 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */); dispatchTetherConnectionChanged(UPSTREAM_IFACE); - verify(mDependencies, never()).makeDhcpServer(any(), any(), any(), any()); + verify(mDependencies, never()).makeDhcpServer(any(), any(), any()); } - private void assertDhcpStarted(IpPrefix expectedPrefix) { - verify(mDependencies, times(1)).makeDhcpServer( - eq(mLooper.getLooper()), eq(IFACE_NAME), any(), eq(mSharedLog)); - verify(mDhcpServer, times(1)).start(); - final DhcpServingParams params = mDhcpParamsCaptor.getValue(); + private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception { + verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any()); + verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).start(any()); + final DhcpServingParamsParcel params = mDhcpParamsCaptor.getValue(); // Last address byte is random - assertTrue(expectedPrefix.contains(params.serverAddr.getAddress())); - assertEquals(expectedPrefix.getPrefixLength(), params.serverAddr.getPrefixLength()); - assertEquals(1, params.defaultRouters.size()); - assertEquals(params.serverAddr.getAddress(), params.defaultRouters.iterator().next()); - assertEquals(1, params.dnsServers.size()); - assertEquals(params.serverAddr.getAddress(), params.dnsServers.iterator().next()); + assertTrue(expectedPrefix.contains(intToInet4AddressHTH(params.serverAddr))); + assertEquals(expectedPrefix.getPrefixLength(), params.serverAddrPrefixLength); + assertEquals(1, params.defaultRouters.length); + assertEquals(params.serverAddr, params.defaultRouters[0]); + assertEquals(1, params.dnsServers.length); + assertEquals(params.serverAddr, params.dnsServers[0]); assertEquals(DHCP_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs); } @@ -458,7 +476,7 @@ public class IpServerTest { addr4 = addr; break; } - assertTrue("missing IPv4 address", addr4 != null); + assertNotNull("missing IPv4 address", addr4); // Assert the presence of the associated directly connected route. final RouteInfo directlyConnected = new RouteInfo(addr4, null, lp.getInterfaceName()); diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index e6b43d286a3d..1ea83c2bbb6b 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -27,6 +27,7 @@ import static android.net.ConnectivityManager.TETHERING_USB; import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -37,6 +38,7 @@ import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Matchers.anyInt; @@ -47,6 +49,8 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -74,8 +78,9 @@ import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.RouteInfo; -import android.net.dhcp.DhcpServer; -import android.net.dhcp.DhcpServingParams; +import android.net.dhcp.DhcpServerCallbacks; +import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.IDhcpServer; import android.net.ip.IpServer; import android.net.ip.RouterAdvertisementDaemon; import android.net.util.InterfaceParams; @@ -86,7 +91,6 @@ import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; import android.os.INetworkManagementService; -import android.os.Looper; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserHandle; @@ -129,6 +133,8 @@ public class TetheringTest { private static final String TEST_USB_IFNAME = "test_rndis0"; private static final String TEST_WLAN_IFNAME = "test_wlan0"; + private static final int DHCPSERVER_START_TIMEOUT_MS = 1000; + @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; @Mock private INetworkManagementService mNMService; @@ -143,9 +149,11 @@ public class TetheringTest { @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor; @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator; @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon; - @Mock private DhcpServer mDhcpServer; + @Mock private IDhcpServer mDhcpServer; @Mock private INetd mNetd; + private final MockIpServerDependencies mIpServerDependencies = + spy(new MockIpServerDependencies()); private final MockTetheringDependencies mTetheringDependencies = new MockTetheringDependencies(); @@ -185,6 +193,47 @@ public class TetheringTest { } } + public class MockIpServerDependencies extends IpServer.Dependencies { + MockIpServerDependencies() { + super(null); + } + + @Override + public RouterAdvertisementDaemon getRouterAdvertisementDaemon( + InterfaceParams ifParams) { + return mRouterAdvertisementDaemon; + } + + @Override + public InterfaceParams getInterfaceParams(String ifName) { + assertTrue("Non-mocked interface " + ifName, + ifName.equals(TEST_USB_IFNAME) + || ifName.equals(TEST_WLAN_IFNAME) + || ifName.equals(TEST_MOBILE_IFNAME)); + final String[] ifaces = new String[] { + TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME }; + return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET, + MacAddress.ALL_ZEROS_ADDRESS); + } + + @Override + public INetd getNetdService() { + return mNetd; + } + + @Override + public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, + DhcpServerCallbacks cb) { + new Thread(() -> { + try { + cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer); + } catch (RemoteException e) { + fail(e.getMessage()); + } + }).run(); + } + } + public class MockTetheringDependencies extends TetheringDependencies { StateMachine upstreamNetworkMonitorMasterSM; ArrayList<IpServer> ipv6CoordinatorNotifyList; @@ -216,35 +265,8 @@ public class TetheringTest { } @Override - public IpServer.Dependencies getIpServerDependencies() { - return new IpServer.Dependencies() { - @Override - public RouterAdvertisementDaemon getRouterAdvertisementDaemon( - InterfaceParams ifParams) { - return mRouterAdvertisementDaemon; - } - - @Override - public InterfaceParams getInterfaceParams(String ifName) { - final String[] ifaces = new String[] { - TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME }; - final int index = ArrayUtils.indexOf(ifaces, ifName); - assertTrue("Non-mocked interface: " + ifName, index >= 0); - return new InterfaceParams(ifName, index + IFINDEX_OFFSET, - MacAddress.ALL_ZEROS_ADDRESS); - } - - @Override - public INetd getNetdService() { - return mNetd; - } - - @Override - public DhcpServer makeDhcpServer(Looper looper, String ifName, - DhcpServingParams params, SharedLog log) { - return mDhcpServer; - } - }; + public IpServer.Dependencies getIpServerDependencies(Context context) { + return mIpServerDependencies; } @Override @@ -546,7 +568,7 @@ public class TetheringTest { sendIPv6TetherUpdates(upstreamState); verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull()); - verify(mDhcpServer, times(1)).start(); + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); } @Test @@ -557,7 +579,7 @@ public class TetheringTest { runUsbTethering(upstreamState); sendIPv6TetherUpdates(upstreamState); - verify(mDhcpServer, never()).start(); + verify(mIpServerDependencies, never()).makeDhcpServer(any(), any(), any()); } @Test @@ -581,7 +603,7 @@ public class TetheringTest { verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mRouterAdvertisementDaemon, times(1)).start(); - verify(mDhcpServer, times(1)).start(); + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); sendIPv6TetherUpdates(upstreamState); verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull()); @@ -595,7 +617,7 @@ public class TetheringTest { verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mDhcpServer, times(1)).start(); + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME); @@ -612,7 +634,7 @@ public class TetheringTest { runUsbTethering(upstreamState); verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); - verify(mDhcpServer, times(1)).start(); + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); // Then 464xlat comes up @@ -636,7 +658,7 @@ public class TetheringTest { verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME); // DHCP not restarted on downstream (still times(1)) - verify(mDhcpServer, times(1)).start(); + verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any()); } @Test diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 6476abd8268e..acf1f1e9902e 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -26,7 +26,7 @@ $ git blame api/current.txt -t -e > /tmp/currentblame.txt $ apilint.py /tmp/currentblame.txt previous.txt --no-color """ -import re, sys, collections, traceback, argparse +import re, sys, collections, traceback, argparse, itertools BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8) @@ -50,45 +50,37 @@ def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False): return "\033[%sm" % (";".join(codes)) -def ident(raw): - """Strips superficial signature changes, giving us a strong key that - can be used to identify members across API levels.""" - raw = raw.replace(" deprecated ", " ") - raw = raw.replace(" synchronized ", " ") - raw = raw.replace(" final ", " ") - raw = re.sub("<.+?>", "", raw) - if " throws " in raw: - raw = raw[:raw.index(" throws ")] - return raw - - class Field(): - def __init__(self, clazz, line, raw, blame): + def __init__(self, clazz, line, raw, blame, sig_format = 1): self.clazz = clazz self.line = line self.raw = raw.strip(" {;") self.blame = blame - # drop generics for now; may need multiple passes - raw = re.sub("<[^<]+?>", "", raw) - raw = re.sub("<[^<]+?>", "", raw) + if sig_format == 2: + V2LineParser(raw).parse_into_field(self) + elif sig_format == 1: + # drop generics for now; may need multiple passes + raw = re.sub("<[^<]+?>", "", raw) + raw = re.sub("<[^<]+?>", "", raw) - raw = raw.split() - self.split = list(raw) + raw = raw.split() + self.split = list(raw) - for r in ["field", "volatile", "transient", "public", "protected", "static", "final", "deprecated"]: - while r in raw: raw.remove(r) + for r in ["field", "volatile", "transient", "public", "protected", "static", "final", "deprecated"]: + while r in raw: raw.remove(r) - # ignore annotations for now - raw = [ r for r in raw if not r.startswith("@") ] + # ignore annotations for now + raw = [ r for r in raw if not r.startswith("@") ] - self.typ = raw[0] - self.name = raw[1].strip(";") - if len(raw) >= 4 and raw[2] == "=": - self.value = raw[3].strip(';"') - else: - self.value = None - self.ident = ident(self.raw) + self.typ = raw[0] + self.name = raw[1].strip(";") + if len(raw) >= 4 and raw[2] == "=": + self.value = raw[3].strip(';"') + else: + self.value = None + + self.ident = "-".join((self.typ, self.name, self.value or "")) def __hash__(self): return hash(self.raw) @@ -96,48 +88,55 @@ class Field(): def __repr__(self): return self.raw - class Method(): - def __init__(self, clazz, line, raw, blame): + def __init__(self, clazz, line, raw, blame, sig_format = 1): self.clazz = clazz self.line = line self.raw = raw.strip(" {;") self.blame = blame - # drop generics for now; may need multiple passes - raw = re.sub("<[^<]+?>", "", raw) - raw = re.sub("<[^<]+?>", "", raw) - - # handle each clause differently - raw_prefix, raw_args, _, raw_throws = re.match(r"(.*?)\((.*?)\)( throws )?(.*?);$", raw).groups() - - # parse prefixes - raw = re.split("[\s]+", raw_prefix) - for r in ["", ";"]: - while r in raw: raw.remove(r) - self.split = list(raw) - - for r in ["method", "public", "protected", "static", "final", "deprecated", "abstract", "default", "operator"]: - while r in raw: raw.remove(r) - - self.typ = raw[0] - self.name = raw[1] - - # parse args - self.args = [] - for arg in re.split(",\s*", raw_args): - arg = re.split("\s", arg) - # ignore annotations for now - arg = [ a for a in arg if not a.startswith("@") ] - if len(arg[0]) > 0: - self.args.append(arg[0]) + if sig_format == 2: + V2LineParser(raw).parse_into_method(self) + elif sig_format == 1: + # drop generics for now; may need multiple passes + raw = re.sub("<[^<]+?>", "", raw) + raw = re.sub("<[^<]+?>", "", raw) + + # handle each clause differently + raw_prefix, raw_args, _, raw_throws = re.match(r"(.*?)\((.*?)\)( throws )?(.*?);$", raw).groups() + + # parse prefixes + raw = re.split("[\s]+", raw_prefix) + for r in ["", ";"]: + while r in raw: raw.remove(r) + self.split = list(raw) + + for r in ["method", "public", "protected", "static", "final", "deprecated", "abstract", "default", "operator", "synchronized"]: + while r in raw: raw.remove(r) + + self.typ = raw[0] + self.name = raw[1] + + # parse args + self.args = [] + for arg in re.split(",\s*", raw_args): + arg = re.split("\s", arg) + # ignore annotations for now + arg = [ a for a in arg if not a.startswith("@") ] + if len(arg[0]) > 0: + self.args.append(arg[0]) + + # parse throws + self.throws = [] + for throw in re.split(",\s*", raw_throws): + self.throws.append(throw) + else: + raise ValueError("Unknown signature format: " + sig_format) - # parse throws - self.throws = [] - for throw in re.split(",\s*", raw_throws): - self.throws.append(throw) + self.ident = "-".join((self.typ, self.name, "-".join(self.args))) - self.ident = ident(self.raw) + def sig_matches(self, typ, name, args): + return typ == self.typ and name == self.name and args == self.args def __hash__(self): return hash(self.raw) @@ -147,7 +146,7 @@ class Method(): class Class(): - def __init__(self, pkg, line, raw, blame): + def __init__(self, pkg, line, raw, blame, sig_format = 1): self.pkg = pkg self.line = line self.raw = raw.strip(" {;") @@ -156,31 +155,44 @@ class Class(): self.fields = [] self.methods = [] - # drop generics for now; may need multiple passes - raw = re.sub("<[^<]+?>", "", raw) - raw = re.sub("<[^<]+?>", "", raw) + if sig_format == 2: + V2LineParser(raw).parse_into_class(self) + elif sig_format == 1: + # drop generics for now; may need multiple passes + raw = re.sub("<[^<]+?>", "", raw) + raw = re.sub("<[^<]+?>", "", raw) + + raw = raw.split() + self.split = list(raw) + if "class" in raw: + self.fullname = raw[raw.index("class")+1] + elif "interface" in raw: + self.fullname = raw[raw.index("interface")+1] + elif "@interface" in raw: + self.fullname = raw[raw.index("@interface")+1] + else: + raise ValueError("Funky class type %s" % (self.raw)) - raw = raw.split() - self.split = list(raw) - if "class" in raw: - self.fullname = raw[raw.index("class")+1] - elif "interface" in raw: - self.fullname = raw[raw.index("interface")+1] - elif "@interface" in raw: - self.fullname = raw[raw.index("@interface")+1] - else: - raise ValueError("Funky class type %s" % (self.raw)) + if "extends" in raw: + self.extends = raw[raw.index("extends")+1] + else: + self.extends = None - if "extends" in raw: - self.extends = raw[raw.index("extends")+1] - self.extends_path = self.extends.split(".") + if "implements" in raw: + self.implements = raw[raw.index("implements")+1] + else: + self.implements = None else: - self.extends = None - self.extends_path = [] + raise ValueError("Unknown signature format: " + sig_format) self.fullname = self.pkg.name + "." + self.fullname self.fullname_path = self.fullname.split(".") + if self.extends is not None: + self.extends_path = self.extends.split(".") + else: + self.extends_path = [] + self.name = self.fullname[self.fullname.rindex(".")+1:] def merge_from(self, other): @@ -208,6 +220,318 @@ class Package(): def __repr__(self): return self.raw +class V2Tokenizer(object): + __slots__ = ["raw"] + + DELIMITER = re.compile(r'\s+|[()@<>;,={}/"!?]|\[\]|\.\.\.') + STRING_SPECIAL = re.compile(r'["\\]') + + def __init__(self, raw): + self.raw = raw + + def tokenize(self): + tokens = [] + current = 0 + raw = self.raw + length = len(raw) + + while current < length: + while current < length: + start = current + match = V2Tokenizer.DELIMITER.search(raw, start) + if match is not None: + match_start = match.start() + if match_start == current: + end = match.end() + else: + end = match_start + else: + end = length + + token = raw[start:end] + current = end + + if token == "" or token[0] == " ": + continue + else: + break + + if token == "@": + if raw[start:start+11] == "@interface ": + current = start + 11 + tokens.append("@interface") + continue + elif token == '/': + if raw[start:start+2] == "//": + current = length + continue + elif token == '"': + current, string_token = self.tokenize_string(raw, length, current) + tokens.append(token + string_token) + continue + + tokens.append(token) + + return tokens + + def tokenize_string(self, raw, length, current): + start = current + end = length + while start < end: + match = V2Tokenizer.STRING_SPECIAL.search(raw, start) + if match: + if match.group() == '"': + end = match.end() + break + elif match.group() == '\\': + # ignore whatever is after the slash + start += 2 + else: + raise ValueError("Unexpected match: `%s`" % (match.group())) + else: + raise ValueError("Unexpected EOF tokenizing string: `%s`" % (raw[current - 1:],)) + + token = raw[current:end] + return end, token + +class V2LineParser(object): + __slots__ = ["tokenized", "current", "len"] + + MODIFIERS = set("public protected internal private abstract default static final transient volatile synchronized".split()) + JAVA_LANG_TYPES = set("AbstractMethodError AbstractStringBuilder Appendable ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException AssertionError AutoCloseable Boolean BootstrapMethodError Byte Character CharSequence Class ClassCastException ClassCircularityError ClassFormatError ClassLoader ClassNotFoundException Cloneable CloneNotSupportedException Comparable Compiler Deprecated Double Enum EnumConstantNotPresentException Error Exception ExceptionInInitializerError Float FunctionalInterface IllegalAccessError IllegalAccessException IllegalArgumentException IllegalMonitorStateException IllegalStateException IllegalThreadStateException IncompatibleClassChangeError IndexOutOfBoundsException InheritableThreadLocal InstantiationError InstantiationException Integer InternalError InterruptedException Iterable LinkageError Long Math NegativeArraySizeException NoClassDefFoundError NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException NullPointerException Number NumberFormatException Object OutOfMemoryError Override Package package-info.java Process ProcessBuilder ProcessEnvironment ProcessImpl Readable ReflectiveOperationException Runnable Runtime RuntimeException RuntimePermission SafeVarargs SecurityException SecurityManager Short StackOverflowError StackTraceElement StrictMath String StringBuffer StringBuilder StringIndexOutOfBoundsException SuppressWarnings System Thread ThreadDeath ThreadGroup ThreadLocal Throwable TypeNotPresentException UNIXProcess UnknownError UnsatisfiedLinkError UnsupportedClassVersionError UnsupportedOperationException VerifyError VirtualMachineError Void".split()) + + def __init__(self, raw): + self.tokenized = V2Tokenizer(raw).tokenize() + self.current = 0 + self.len = len(self.tokenized) + + def parse_into_method(self, method): + method.split = [] + kind = self.parse_one_of("ctor", "method") + method.split.append(kind) + annotations = self.parse_annotations() + method.split.extend(self.parse_modifiers()) + self.parse_matching_paren("<", ">") + if "@Deprecated" in annotations: + method.split.append("deprecated") + if kind == "ctor": + method.typ = "ctor" + else: + method.typ = self.parse_type() + method.split.append(method.typ) + method.name = self.parse_name() + method.split.append(method.name) + self.parse_token("(") + method.args = self.parse_args() + self.parse_token(")") + method.throws = self.parse_throws() + if "@interface" in method.clazz.split: + self.parse_annotation_default() + self.parse_token(";") + self.parse_eof() + + def parse_into_class(self, clazz): + clazz.split = [] + annotations = self.parse_annotations() + if "@Deprecated" in annotations: + clazz.split.append("deprecated") + clazz.split.extend(self.parse_modifiers()) + kind = self.parse_one_of("class", "interface", "@interface", "enum") + if kind == "enum": + # enums are implicitly final + clazz.split.append("final") + clazz.split.append(kind) + clazz.fullname = self.parse_name() + self.parse_matching_paren("<", ">") + extends = self.parse_extends() + clazz.extends = extends[0] if extends else None + implements = self.parse_implements() + clazz.implements = implements[0] if implements else None + # The checks assume that interfaces are always found in implements, which isn't true for + # subinterfaces. + if not implements and "interface" in clazz.split: + clazz.implements = clazz.extends + self.parse_token("{") + self.parse_eof() + + def parse_into_field(self, field): + kind = self.parse_token("field") + field.split = [kind] + annotations = self.parse_annotations() + if "@Deprecated" in annotations: + field.split.append("deprecated") + field.split.extend(self.parse_modifiers()) + field.typ = self.parse_type() + field.split.append(field.typ) + field.name = self.parse_name() + field.split.append(field.name) + if self.parse_if("="): + field.value = self.parse_value_stripped() + else: + field.value = None + + self.parse_token(";") + self.parse_eof() + + def lookahead(self): + return self.tokenized[self.current] + + def parse_one_of(self, *options): + found = self.lookahead() + if found not in options: + raise ValueError("Parsing failed, expected one of `%s` but found `%s` in %s" % (options, found, repr(self.tokenized))) + return self.parse_token() + + def parse_token(self, tok = None): + found = self.lookahead() + if tok is not None and found != tok: + raise ValueError("Parsing failed, expected `%s` but found `%s` in %s" % (tok, found, repr(self.tokenized))) + self.current += 1 + return found + + def eof(self): + return self.current == self.len + + def parse_eof(self): + if not self.eof(): + raise ValueError("Parsing failed, expected EOF, but %s has not been parsed in %s" % (self.tokenized[self.current:], self.tokenized)) + + def parse_if(self, tok): + if not self.eof() and self.lookahead() == tok: + self.parse_token() + return True + return False + + def parse_annotations(self): + ret = [] + while self.lookahead() == "@": + ret.append(self.parse_annotation()) + return ret + + def parse_annotation(self): + ret = self.parse_token("@") + self.parse_token() + self.parse_matching_paren("(", ")") + return ret + + def parse_matching_paren(self, open, close): + start = self.current + if not self.parse_if(open): + return + length = len(self.tokenized) + count = 1 + while count > 0: + if self.current == length: + raise ValueError("Unexpected EOF looking for closing paren: `%s`" % (self.tokenized[start:],)) + t = self.parse_token() + if t == open: + count += 1 + elif t == close: + count -= 1 + return self.tokenized[start:self.current] + + def parse_modifiers(self): + ret = [] + while self.lookahead() in V2LineParser.MODIFIERS: + ret.append(self.parse_token()) + return ret + + def parse_kotlin_nullability(self): + t = self.lookahead() + if t == "?" or t == "!": + return self.parse_token() + return None + + def parse_type(self): + type = self.parse_token() + if type in V2LineParser.JAVA_LANG_TYPES: + type = "java.lang." + type + self.parse_matching_paren("<", ">") + while True: + t = self.lookahead() + if t == "[]": + type += self.parse_token() + elif self.parse_kotlin_nullability() is not None: + pass # discard nullability for now + else: + break + return type + + def parse_arg_type(self): + type = self.parse_type() + if self.parse_if("..."): + type += "..." + self.parse_kotlin_nullability() # discard nullability for now + return type + + def parse_name(self): + return self.parse_token() + + def parse_args(self): + args = [] + if self.lookahead() == ")": + return args + + while True: + args.append(self.parse_arg()) + if self.lookahead() == ")": + return args + self.parse_token(",") + + def parse_arg(self): + self.parse_annotations() + type = self.parse_arg_type() + l = self.lookahead() + if l != "," and l != ")": + self.parse_token() # kotlin argument name + if self.parse_if('='): # kotlin default value + (self.parse_matching_paren('(', ')') or + self.parse_matching_paren('{', '}') or + self.parse_token() and self.parse_matching_paren('(', ')')) + return type + + def parse_throws(self): + ret = [] + if self.parse_if("throws"): + ret.append(self.parse_type()) + while self.parse_if(","): + ret.append(self.parse_type()) + return ret + + def parse_extends(self): + if self.parse_if("extends"): + return self.parse_space_delimited_type_list() + return [] + + def parse_implements(self): + if self.parse_if("implements"): + return self.parse_space_delimited_type_list() + return [] + + def parse_space_delimited_type_list(self, terminals = ["implements", "{"]): + types = [] + while True: + types.append(self.parse_type()) + if self.lookahead() in terminals: + return types + + def parse_annotation_default(self): + if self.parse_if("default"): + self.parse_value() + + def parse_value(self): + if self.lookahead() == "{": + return " ".join(self.parse_matching_paren("{", "}")) + elif self.lookahead() == "(": + return " ".join(self.parse_matching_paren("(", ")")) + else: + return self.parse_token() + + def parse_value_stripped(self): + value = self.parse_value() + if value[0] == '"': + return value[1:-1] + return value + def _parse_stream(f, clazz_cb=None, base_f=None, out_classes_with_base=None, in_classes_with_base=[]): @@ -252,6 +576,7 @@ def _parse_stream_to_generator(f): pkg = None clazz = None blame = None + sig_format = 1 re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$") for raw in f: @@ -264,16 +589,18 @@ def _parse_stream_to_generator(f): else: blame = None - if raw.startswith("package"): + if line == 1 and raw == "// Signature format: 2.0": + sig_format = 2 + elif raw.startswith("package"): pkg = Package(line, raw, blame) elif raw.startswith(" ") and raw.endswith("{"): - clazz = Class(pkg, line, raw, blame) + clazz = Class(pkg, line, raw, blame, sig_format=sig_format) elif raw.startswith(" ctor"): - clazz.ctors.append(Method(clazz, line, raw, blame)) + clazz.ctors.append(Method(clazz, line, raw, blame, sig_format=sig_format)) elif raw.startswith(" method"): - clazz.methods.append(Method(clazz, line, raw, blame)) + clazz.methods.append(Method(clazz, line, raw, blame, sig_format=sig_format)) elif raw.startswith(" field"): - clazz.fields.append(Field(clazz, line, raw, blame)) + clazz.fields.append(Field(clazz, line, raw, blame, sig_format=sig_format)) elif raw.startswith(" }") and clazz: yield clazz @@ -367,7 +694,7 @@ def _fail(clazz, detail, error, rule, msg): """Records an API failure to be processed later.""" global failures - sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg) + sig = "%s-%s-%s" % (clazz.fullname, detail.ident if detail else None, msg) sig = sig.replace(" deprecated ", " ") failures[sig] = Failure(sig, clazz, detail, error, rule, msg) @@ -408,7 +735,7 @@ def verify_constants(clazz): def verify_enums(clazz): """Enums are bad, mmkay?""" - if "extends java.lang.Enum" in clazz.raw: + if clazz.extends == "java.lang.Enum" or "enum" in clazz.split: error(clazz, None, "F5", "Enums are not allowed") @@ -467,7 +794,7 @@ def verify_listeners(clazz): interface OnFooListener { void onFoo() }""" if clazz.name.endswith("Listener"): - if " abstract class " in clazz.raw: + if "abstract" in clazz.split and "class" in clazz.split: error(clazz, None, "L1", "Listeners should be an interface, or otherwise renamed Callback") for m in clazz.methods: @@ -546,16 +873,16 @@ def verify_equals(clazz): eq = False hc = False for m in clazz.methods: - if " static " in m.raw: continue - if "boolean equals(java.lang.Object)" in m.raw: eq = True - if "int hashCode()" in m.raw: hc = True + if "static" in m.split: continue + if m.sig_matches("boolean", "equals", ["java.lang.Object"]): eq = True + if m.sig_matches("int", "hashCode", []): hc = True if eq != hc: error(clazz, None, "M8", "Must override both equals and hashCode; missing one") def verify_parcelable(clazz): """Verify that Parcelable objects aren't hiding required bits.""" - if "implements android.os.Parcelable" in clazz.raw: + if clazz.implements == "android.os.Parcelable": creator = [ i for i in clazz.fields if i.name == "CREATOR" ] write = [ i for i in clazz.methods if i.name == "writeToParcel" ] describe = [ i for i in clazz.methods if i.name == "describeContents" ] @@ -563,8 +890,7 @@ def verify_parcelable(clazz): if len(creator) == 0 or len(write) == 0 or len(describe) == 0: error(clazz, None, "FW3", "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one") - if ((" final class " not in clazz.raw) and - (" final deprecated class " not in clazz.raw)): + if "final" not in clazz.split: error(clazz, None, "FW8", "Parcelable classes must be final") for c in clazz.ctors: @@ -684,7 +1010,7 @@ def verify_helper_classes(clazz): """Verify that helper classes are named consistently with what they extend. All developer extendable methods should be named onFoo().""" test_methods = False - if "extends android.app.Service" in clazz.raw: + if clazz.extends == "android.app.Service": test_methods = True if not clazz.name.endswith("Service"): error(clazz, None, "CL4", "Inconsistent class name; should be FooService") @@ -696,7 +1022,7 @@ def verify_helper_classes(clazz): if f.value != clazz.fullname: error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname)) - if "extends android.content.ContentProvider" in clazz.raw: + if clazz.extends == "android.content.ContentProvider": test_methods = True if not clazz.name.endswith("Provider"): error(clazz, None, "CL4", "Inconsistent class name; should be FooProvider") @@ -708,12 +1034,12 @@ def verify_helper_classes(clazz): if f.value != clazz.fullname: error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname)) - if "extends android.content.BroadcastReceiver" in clazz.raw: + if clazz.extends == "android.content.BroadcastReceiver": test_methods = True if not clazz.name.endswith("Receiver"): error(clazz, None, "CL4", "Inconsistent class name; should be FooReceiver") - if "extends android.app.Activity" in clazz.raw: + if clazz.extends == "android.app.Activity": test_methods = True if not clazz.name.endswith("Activity"): error(clazz, None, "CL4", "Inconsistent class name; should be FooActivity") @@ -731,7 +1057,7 @@ def verify_helper_classes(clazz): def verify_builder(clazz): """Verify builder classes. Methods should return the builder to enable chaining.""" - if " extends " in clazz.raw: return + if clazz.extends: return if not clazz.name.endswith("Builder"): return if clazz.name != "Builder": @@ -759,7 +1085,7 @@ def verify_builder(clazz): def verify_aidl(clazz): """Catch people exposing raw AIDL.""" - if "extends android.os.Binder" in clazz.raw or "implements android.os.IInterface" in clazz.raw: + if clazz.extends == "android.os.Binder" or clazz.implements == "android.os.IInterface": error(clazz, None, None, "Raw AIDL interfaces must not be exposed") @@ -768,48 +1094,66 @@ def verify_internal(clazz): if clazz.pkg.name.startswith("com.android"): error(clazz, None, None, "Internal classes must not be exposed") +def layering_build_ranking(ranking_list): + r = {} + for rank, ps in enumerate(ranking_list): + if not isinstance(ps, list): + ps = [ps] + for p in ps: + rs = r + for n in p.split('.'): + if n not in rs: + rs[n] = {} + rs = rs[n] + rs['-rank'] = rank + return r + +LAYERING_PACKAGE_RANKING = layering_build_ranking([ + ["android.service","android.accessibilityservice","android.inputmethodservice","android.printservice","android.appwidget","android.webkit","android.preference","android.gesture","android.print"], + "android.app", + "android.widget", + "android.view", + "android.animation", + "android.provider", + ["android.content","android.graphics.drawable"], + "android.database", + "android.text", + "android.graphics", + "android.os", + "android.util" +]) def verify_layering(clazz): """Catch package layering violations. For example, something in android.os depending on android.app.""" - ranking = [ - ["android.service","android.accessibilityservice","android.inputmethodservice","android.printservice","android.appwidget","android.webkit","android.preference","android.gesture","android.print"], - "android.app", - "android.widget", - "android.view", - "android.animation", - "android.provider", - ["android.content","android.graphics.drawable"], - "android.database", - "android.text", - "android.graphics", - "android.os", - "android.util" - ] def rank(p): - for i in range(len(ranking)): - if isinstance(ranking[i], list): - for j in ranking[i]: - if p.startswith(j): return i + r = None + l = LAYERING_PACKAGE_RANKING + for n in p.split('.'): + if n in l: + l = l[n] + if '-rank' in l: + r = l['-rank'] else: - if p.startswith(ranking[i]): return i + break + return r cr = rank(clazz.pkg.name) if cr is None: return for f in clazz.fields: ir = rank(f.typ) - if ir and ir < cr: + if ir is not None and ir < cr: warn(clazz, f, "FW6", "Field type violates package layering") - for m in clazz.methods: + for m in itertools.chain(clazz.methods, clazz.ctors): ir = rank(m.typ) - if ir and ir < cr: + if ir is not None and ir < cr: warn(clazz, m, "FW6", "Method return type violates package layering") for arg in m.args: ir = rank(arg) - if ir and ir < cr: + if ir is not None and ir < cr: warn(clazz, m, "FW6", "Method argument type violates package layering") @@ -900,21 +1244,18 @@ def verify_exception(clazz): if len(m.args) == 0 and t in ["java.lang.IllegalArgumentException", "java.lang.NullPointerException"]: warn(clazz, m, "S1", "Methods taking no arguments should throw IllegalStateException") +GOOGLE_IGNORECASE = re.compile("google", re.IGNORECASE) def verify_google(clazz): """Verifies that APIs never reference Google.""" - if re.search("google", clazz.raw, re.IGNORECASE): + if GOOGLE_IGNORECASE.search(clazz.raw) is not None: error(clazz, None, None, "Must never reference Google") - test = [] - test.extend(clazz.ctors) - test.extend(clazz.fields) - test.extend(clazz.methods) - - for t in test: - if re.search("google", t.raw, re.IGNORECASE): - error(clazz, t, None, "Must never reference Google") + for test in clazz.ctors, clazz.fields, clazz.methods: + for t in test: + if GOOGLE_IGNORECASE.search(t.raw) is not None: + error(clazz, t, None, "Must never reference Google") def verify_bitset(clazz): @@ -1168,7 +1509,7 @@ def verify_abstract_inner(clazz): """Verifies that abstract inner classes are static.""" if re.match(".+?\.[A-Z][^\.]+\.[A-Z]", clazz.fullname): - if " abstract " in clazz.raw and " static " not in clazz.raw: + if "abstract" in clazz.split and "static" not in clazz.split: warn(clazz, None, None, "Abstract inner classes should be static to improve testability") @@ -1263,8 +1604,8 @@ def verify_units(clazz): def verify_closable(clazz): """Verifies that classes are AutoClosable.""" - if "implements java.lang.AutoCloseable" in clazz.raw: return - if "implements java.io.Closeable" in clazz.raw: return + if clazz.implements == "java.lang.AutoCloseable": return + if clazz.implements == "java.io.Closeable": return for m in clazz.methods: if len(m.args) > 0: continue @@ -1350,6 +1691,9 @@ def verify_method_name_not_kotlin_operator(clazz): def verify_collections_over_arrays(clazz): """Warn that [] should be Collections.""" + if "@interface" in clazz.split: + return + safe = ["java.lang.String[]","byte[]","short[]","int[]","long[]","float[]","double[]","boolean[]","char[]"] for m in clazz.methods: if m.typ.endswith("[]") and m.typ not in safe: @@ -1683,11 +2027,11 @@ def show_deprecations_at_birth(cur, prev): del cur[prev_clazz.fullname] for clazz in cur.values(): - if " deprecated " in clazz.raw and not clazz.fullname in prev: + if "deprecated" in clazz.split and not clazz.fullname in prev: error(clazz, None, None, "Found API deprecation at birth") for i in clazz.ctors + clazz.methods + clazz.fields: - if " deprecated " in i.raw: + if "deprecated" in i.split: error(clazz, i, None, "Found API deprecation at birth") print "%s Deprecated at birth %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py index ece69a99f579..081e98defa17 100644 --- a/tools/apilint/apilint_test.py +++ b/tools/apilint/apilint_test.py @@ -143,5 +143,148 @@ class BaseFileTests(unittest.TestCase): out_classes_with_base=classes_with_base) self.assertEquals(map(lambda x: x.fullname, classes_with_base), ["android.app.WallpaperColors"]) +class V2TokenizerTests(unittest.TestCase): + def _test(self, raw, expected): + self.assertEquals(apilint.V2Tokenizer(raw).tokenize(), expected) + + def test_simple(self): + self._test(" method public some.Type someName(some.Argument arg, int arg);", + ['method', 'public', 'some.Type', 'someName', '(', 'some.Argument', + 'arg', ',', 'int', 'arg', ')', ';']) + self._test("class Some.Class extends SomeOther {", + ['class', 'Some.Class', 'extends', 'SomeOther', '{']) + + def test_varargs(self): + self._test("name(String...)", + ['name', '(', 'String', '...', ')']) + + def test_kotlin(self): + self._test("String? name(String!...)", + ['String', '?', 'name', '(', 'String', '!', '...', ')']) + + def test_annotation(self): + self._test("method @Nullable public void name();", + ['method', '@', 'Nullable', 'public', 'void', 'name', '(', ')', ';']) + + def test_annotation_args(self): + self._test("@Some(val=1, other=2) class Class {", + ['@', 'Some', '(', 'val', '=', '1', ',', 'other', '=', '2', ')', + 'class', 'Class', '{']) + def test_comment(self): + self._test("some //comment", ['some']) + + def test_strings(self): + self._test(r'"" "foo" "\"" "\\"', ['""', '"foo"', r'"\""', r'"\\"']) + + def test_at_interface(self): + self._test("public @interface Annotation {", + ['public', '@interface', 'Annotation', '{']) + + def test_array_type(self): + self._test("int[][]", ['int', '[]', '[]']) + + def test_generics(self): + self._test("<>foobar<A extends Object>", + ['<', '>', 'foobar', '<', 'A', 'extends', 'Object', '>']) + +class V2ParserTests(unittest.TestCase): + def _cls(self, raw): + pkg = apilint.Package(999, "package pkg {", None) + return apilint.Class(pkg, 1, raw, '', sig_format=2) + + def _method(self, raw, cls=None): + if not cls: + cls = self._cls("class Class {") + return apilint.Method(cls, 1, raw, '', sig_format=2) + + def _field(self, raw): + cls = self._cls("class Class {") + return apilint.Field(cls, 1, raw, '', sig_format=2) + + def test_class(self): + cls = self._cls("@Deprecated @IntRange(from=1, to=2) public static abstract class Some.Name extends Super<Class> implements Interface<Class> {") + self.assertTrue('deprecated' in cls.split) + self.assertTrue('static' in cls.split) + self.assertTrue('abstract' in cls.split) + self.assertTrue('class' in cls.split) + self.assertEquals('Super', cls.extends) + self.assertEquals('Interface', cls.implements) + self.assertEquals('pkg.Some.Name', cls.fullname) + + def test_interface(self): + cls = self._cls("@Deprecated @IntRange(from=1, to=2) public interface Some.Name extends Interface<Class> {") + self.assertTrue('deprecated' in cls.split) + self.assertTrue('interface' in cls.split) + self.assertEquals('Interface', cls.extends) + self.assertEquals('Interface', cls.implements) + self.assertEquals('pkg.Some.Name', cls.fullname) + + def test_at_interface(self): + cls = self._cls("@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface SuppressLint {") + self.assertTrue('@interface' in cls.split) + self.assertEquals('pkg.SuppressLint', cls.fullname) + + def test_parse_method(self): + m = self._method("method @Deprecated public static <T> Class<T>[][] name(" + + "Class<T[]>[][], Class<T[][][]>[][]...) throws Exception, T;") + self.assertTrue('static' in m.split) + self.assertTrue('public' in m.split) + self.assertTrue('method' in m.split) + self.assertTrue('deprecated' in m.split) + self.assertEquals('java.lang.Class[][]', m.typ) + self.assertEquals('name', m.name) + self.assertEquals(['java.lang.Class[][]', 'java.lang.Class[][]...'], m.args) + self.assertEquals(['java.lang.Exception', 'T'], m.throws) + + def test_ctor(self): + m = self._method("ctor @Deprecated <T> ClassName();") + self.assertTrue('ctor' in m.split) + self.assertTrue('deprecated' in m.split) + self.assertEquals('ctor', m.typ) + self.assertEquals('ClassName', m.name) + + def test_parse_annotation_method(self): + cls = self._cls("@interface Annotation {") + self._method('method abstract String category() default "";', cls=cls) + self._method('method abstract boolean deepExport() default false;', cls=cls) + self._method('method abstract ViewDebug.FlagToString[] flagMapping() default {};', cls=cls) + + def test_parse_string_field(self): + f = self._field('field @Deprecated public final String SOME_NAME = "value";') + self.assertTrue('field' in f.split) + self.assertTrue('deprecated' in f.split) + self.assertTrue('final' in f.split) + self.assertEquals('java.lang.String', f.typ) + self.assertEquals('SOME_NAME', f.name) + self.assertEquals('value', f.value) + + def test_parse_field(self): + f = self._field('field public Object SOME_NAME;') + self.assertTrue('field' in f.split) + self.assertEquals('java.lang.Object', f.typ) + self.assertEquals('SOME_NAME', f.name) + self.assertEquals(None, f.value) + + def test_parse_int_field(self): + f = self._field('field public int NAME = 123;') + self.assertTrue('field' in f.split) + self.assertEquals('int', f.typ) + self.assertEquals('NAME', f.name) + self.assertEquals('123', f.value) + + def test_parse_quotient_field(self): + f = self._field('field public int NAME = (0.0/0.0);') + self.assertTrue('field' in f.split) + self.assertEquals('int', f.typ) + self.assertEquals('NAME', f.name) + self.assertEquals('( 0.0 / 0.0 )', f.value) + + def test_kotlin_types(self): + self._field('field public List<Integer[]?[]!>?[]![]? NAME;') + self._method("method <T?> Class<T!>?[]![][]? name(Type!, Type argname," + + "Class<T?>[][]?[]!...!) throws Exception, T;") + self._method("method <T> T name(T a = 1, T b = A(1), Lambda f = { false }, N? n = null, " + + """double c = (1/0), float d = 1.0f, String s = "heyo", char c = 'a');""") + if __name__ == "__main__": - unittest.main()
\ No newline at end of file + unittest.main() diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 11b408fb8b9e..9968bda6458f 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -775,6 +775,7 @@ static void write_java_method( const AtomDecl &attributionDecl) { for (set<vector<java_type_t>>::const_iterator signature = signatures.begin(); signature != signatures.end(); signature++) { + fprintf(out, " /** @hide */\n"); fprintf(out, " public static native int %s(int code", method_name.c_str()); int argIndex = 1; for (vector<java_type_t>::const_iterator arg = signature->begin(); @@ -820,6 +821,7 @@ static void write_java_work_source_method(FILE* out, const set<vector<java_type_ } // Method header (signature) + fprintf(out, " /** @hide */\n"); fprintf(out, " public static void write(int code"); int argIndex = 1; for (vector<java_type_t>::const_iterator arg = signature->begin(); @@ -900,6 +902,7 @@ write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionD if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second); } + fprintf(out, " * @hide\n"); fprintf(out, " */\n"); fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code); } @@ -916,6 +919,7 @@ write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionD field->name.c_str()); for (map<int, string>::const_iterator value = field->enumValues.begin(); value != field->enumValues.end(); value++) { + fprintf(out, " /** @hide */\n"); fprintf(out, " public static final int %s__%s__%s = %d;\n", make_constant_name(atom->message).c_str(), make_constant_name(field->name).c_str(), diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 1700006f939d..07f7cb39a78c 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -16,7 +16,6 @@ package android.net.wifi; - import android.content.pm.ParceledListSlice; import android.net.wifi.hotspot2.OsuProvider; @@ -61,11 +60,11 @@ interface IWifiManager ParceledListSlice getConfiguredNetworks(String packageName); - ParceledListSlice getPrivilegedConfiguredNetworks(); + ParceledListSlice getPrivilegedConfiguredNetworks(String packageName); - List<WifiConfiguration> getAllMatchingWifiConfigs(in List<ScanResult> scanResult); + Map getAllMatchingFqdnsForScanResults(in List<ScanResult> scanResult); - List<OsuProvider> getMatchingOsuProviders(in List<ScanResult> scanResult); + Map getMatchingOsuProviders(in List<ScanResult> scanResult); Map getMatchingPasspointConfigsForOsuProviders(in List<OsuProvider> osuProviders); @@ -77,6 +76,8 @@ interface IWifiManager List<PasspointConfiguration> getPasspointConfigurations(); + List<WifiConfiguration> getWifiConfigsForPasspointProfiles(in List<String> fqdnList); + void queryPasspointIcon(long bssid, String fileName); int matchProviderWithCurrentNetwork(String fqdn); diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 7cdd16a6a4ed..af5ad512a424 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -114,6 +114,11 @@ public class WifiInfo implements Parcelable { private boolean mTrusted; /** + * OSU (Online Sign Up) AP for Passpoint R2. + */ + private boolean mOsuAp; + + /** * Running total count of lost (not ACKed) transmitted unicast data packets. * @hide */ @@ -190,6 +195,7 @@ public class WifiInfo implements Parcelable { setFrequency(-1); setMeteredHint(false); setEphemeral(false); + setOsuAp(false); txBad = 0; txSuccess = 0; rxSuccess = 0; @@ -219,6 +225,7 @@ public class WifiInfo implements Parcelable { mMeteredHint = source.mMeteredHint; mEphemeral = source.mEphemeral; mTrusted = source.mTrusted; + mOsuAp = source.mOsuAp; txBad = source.txBad; txRetries = source.txRetries; txSuccess = source.txSuccess; @@ -411,6 +418,15 @@ public class WifiInfo implements Parcelable { return mTrusted; } + /** {@hide} */ + public void setOsuAp(boolean osuAp) { + mOsuAp = osuAp; + } + + /** {@hide} */ + public boolean isOsuAp() { + return mOsuAp; + } /** @hide */ @UnsupportedAppUsage @@ -565,6 +581,7 @@ public class WifiInfo implements Parcelable { dest.writeLong(rxSuccess); dest.writeDouble(rxSuccessRate); mSupplicantState.writeToParcel(dest, flags); + dest.writeInt(mOsuAp ? 1 : 0); } /** Implement the Parcelable interface {@hide} */ @@ -600,6 +617,7 @@ public class WifiInfo implements Parcelable { info.rxSuccess = in.readLong(); info.rxSuccessRate = in.readDouble(); info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in); + info.mOsuAp = in.readInt() != 0; return info; } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index e67e8ea7d9ab..b265c40e628d 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -16,6 +16,10 @@ package android.net.wifi; +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; +import static android.Manifest.permission.ACCESS_WIFI_STATE; +import static android.Manifest.permission.READ_WIFI_CREDENTIAL; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -44,6 +48,7 @@ import android.os.Messenger; import android.os.RemoteException; import android.os.WorkSource; import android.util.Log; +import android.util.Pair; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; @@ -1135,6 +1140,10 @@ public class WifiManager { /** * Return a list of all the networks configured for the current foreground * user. + * + * Requires the same permissions as {@link #getScanResults}. + * If such access is not allowed, this API will always return an empty list. + * * Not all fields of WifiConfiguration are returned. Only the following * fields are filled in: * <ul> @@ -1161,6 +1170,7 @@ public class WifiManager { * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return an empty list. */ @Deprecated + @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_WIFI_STATE}) public List<WifiConfiguration> getConfiguredNetworks() { try { ParceledListSlice<WifiConfiguration> parceledList = @@ -1176,11 +1186,11 @@ public class WifiManager { /** @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL) + @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL}) public List<WifiConfiguration> getPrivilegedConfiguredNetworks() { try { ParceledListSlice<WifiConfiguration> parceledList = - mService.getPrivilegedConfiguredNetworks(); + mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName()); if (parceledList == null) { return Collections.emptyList(); } @@ -1191,25 +1201,39 @@ public class WifiManager { } /** - * Returns all matching WifiConfigurations for a given list of ScanResult. + * Returns a list of all matching WifiConfigurations for a given list of ScanResult. * * An empty list will be returned when no configurations are installed or if no configurations * match the ScanResult. - + * * @param scanResults a list of scanResult that represents the BSSID - * @return A list of {@link WifiConfiguration} that can have duplicate entries. + * @return List that consists of {@link WifiConfiguration} and corresponding scanResults. * @throws UnsupportedOperationException if Passpoint is not enabled on the device. * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public List<WifiConfiguration> getAllMatchingWifiConfigs( + public List<Pair<WifiConfiguration, List<ScanResult>>> getAllMatchingWifiConfigs( @NonNull List<ScanResult> scanResults) { + List<Pair<WifiConfiguration, List<ScanResult>>> configs = new ArrayList<>(); try { - return mService.getAllMatchingWifiConfigs(scanResults); + Map<String, List<ScanResult>> results = mService.getAllMatchingFqdnsForScanResults( + scanResults); + if (results.isEmpty()) { + return configs; + } + List<WifiConfiguration> wifiConfigurations = + mService.getWifiConfigsForPasspointProfiles(new ArrayList<>(results.keySet())); + for (WifiConfiguration configuration : wifiConfigurations) { + List<ScanResult> scanResultList = results.get(configuration.FQDN); + if (scanResultList != null) { + configs.add(Pair.create(configuration, scanResultList)); + } + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } + + return configs; } /** @@ -1219,12 +1243,13 @@ public class WifiManager { * An empty list will be returned if no match is found. * * @param scanResults a list of ScanResult - * @return A list of {@link OsuProvider} that does not contain duplicate entries. + * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult} * @throws UnsupportedOperationException if Passpoint is not enabled on the device. * @hide */ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public List<OsuProvider> getMatchingOsuProviders(List<ScanResult> scanResults) { + public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders( + List<ScanResult> scanResults) { try { return mService.getMatchingOsuProviders(scanResults); } catch (RemoteException e) { diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index e94b9e6c8671..4e29dd1132f6 100644 --- a/wifi/java/com/android/server/wifi/AbstractWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -21,6 +21,7 @@ package com.android.server.wifi; import android.content.pm.ParceledListSlice; import android.net.DhcpInfo; import android.net.Network; +import android.net.wifi.IDppCallback; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.ISoftApCallback; import android.net.wifi.ITrafficStateCallback; @@ -35,6 +36,7 @@ import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; import android.os.IBinder; import android.os.Messenger; +import android.os.RemoteException; import android.os.ResultReceiver; import android.os.WorkSource; @@ -42,7 +44,7 @@ import java.util.List; import java.util.Map; /** - * Abstract class implementing IWifiManager with stub methods throwing runtime exceptions. + * Empty concrete class implementing IWifiManager with stub methods throwing runtime exceptions. * * This class is meant to be extended by real implementations of IWifiManager in order to facilitate * cross-repo changes to WiFi internal APIs, including the introduction of new APIs, the removal of @@ -53,10 +55,13 @@ import java.util.Map; * then given a short grace period to update themselves before the @Deprecated stub is removed for * good. If the API scheduled for removal has a replacement or an overload (signature change), * these should be introduced before the stub is removed to allow children to migrate. + * + * When a new API is added to IWifiManager.aidl, a stub should be added in BaseWifiService as + * well otherwise compilation will fail. */ -public abstract class AbstractWifiService extends IWifiManager.Stub { +public class BaseWifiService extends IWifiManager.Stub { - private static final String TAG = AbstractWifiService.class.getSimpleName(); + private static final String TAG = BaseWifiService.class.getSimpleName(); @Override public int getSupportedFeatures() { @@ -79,51 +84,19 @@ public abstract class AbstractWifiService extends IWifiManager.Stub { } @Override - public ParceledListSlice getPrivilegedConfiguredNetworks() { - throw new UnsupportedOperationException(); - } - - /** - * Returns a WifiConfiguration matching this ScanResult - * @param scanResult a single ScanResult Object - * @return - * @deprecated use {@link #getAllMatchingWifiConfigs(List)} instead. - */ - @Deprecated - public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) { - throw new UnsupportedOperationException(); - } - - /** - * Returns all matching WifiConfigurations for this ScanResult. - * @param scanResult a single ScanResult Object - * @return - * @deprecated use {@link #getAllMatchingWifiConfigs(List)} instead. - */ - @Deprecated - public List<WifiConfiguration> getAllMatchingWifiConfigs(ScanResult scanResult) { + public ParceledListSlice getPrivilegedConfiguredNetworks(String packageName) { throw new UnsupportedOperationException(); } @Override - public List<WifiConfiguration> getAllMatchingWifiConfigs(List<ScanResult> scanResults) { - throw new UnsupportedOperationException(); - } - - /** - * Returns a list of Hotspot 2.0 OSU (Online Sign-Up) providers associated with the given AP. - * - * @param scanResult a single ScanResult Object - * @return - * @deprecated use {@link #getMatchingOsuProviders(List)} instead. - */ - @Deprecated - public List<OsuProvider> getMatchingOsuProviders(ScanResult scanResult) { + public Map<String, List<ScanResult>> getAllMatchingFqdnsForScanResults( + List<ScanResult> scanResults) { throw new UnsupportedOperationException(); } @Override - public List<OsuProvider> getMatchingOsuProviders(List<ScanResult> scanResults) { + public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders( + List<ScanResult> scanResults) { throw new UnsupportedOperationException(); } @@ -155,6 +128,11 @@ public abstract class AbstractWifiService extends IWifiManager.Stub { } @Override + public List<WifiConfiguration> getWifiConfigsForPasspointProfiles(List<String> fqdnList) { + throw new UnsupportedOperationException(); + } + + @Override public void queryPasspointIcon(long bssid, String fileName) { throw new UnsupportedOperationException(); } @@ -464,4 +442,26 @@ public abstract class AbstractWifiService extends IWifiManager.Stub { public String[] getFactoryMacAddresses() { throw new UnsupportedOperationException(); } + + @Override + public void setDeviceMobilityState(int state) { + throw new UnsupportedOperationException(); + } + + @Override + public void startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri, + int selectedNetworkId, int netRole, IDppCallback callback) { + throw new UnsupportedOperationException(); + } + + @Override + public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri, + IDppCallback callback) { + throw new UnsupportedOperationException(); + } + + @Override + public void stopDppSession() throws RemoteException { + throw new UnsupportedOperationException(); + } } diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java index fb0af5fbcce3..677bf371c781 100644 --- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java +++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java @@ -47,6 +47,7 @@ public class WifiInfoTest { writeWifiInfo.txBad = TEST_TX_BAD; writeWifiInfo.rxSuccess = TEST_RX_SUCCESS; writeWifiInfo.setTrusted(true); + writeWifiInfo.setOsuAp(true); Parcel parcel = Parcel.obtain(); writeWifiInfo.writeToParcel(parcel, 0); @@ -60,5 +61,6 @@ public class WifiInfoTest { assertEquals(TEST_TX_BAD, readWifiInfo.txBad); assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess); assertTrue(readWifiInfo.isTrusted()); + assertTrue(readWifiInfo.isOsuAp()); } } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index c43948bb0c04..4fbef5a8493d 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -77,7 +77,9 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Unit tests for {@link android.net.wifi.WifiManager}. @@ -1274,14 +1276,20 @@ i * Verify that a call to cancel WPS immediately returns a failure. } /** - * Check the call to getAllMatchingWifiConfigs calls getAllMatchingWifiConfigs of WifiService - * with the provided a list of ScanResult. + * Check the call to getAllMatchingWifiConfigs calls getAllMatchingFqdnsForScanResults and + * getWifiConfigsForPasspointProfiles of WifiService in order. */ @Test public void testGetAllMatchingWifiConfigs() throws Exception { + Map<String, List<ScanResult>> fqdns = new HashMap<>(); + fqdns.put("www.test.com", new ArrayList<>()); + when(mWifiService.getAllMatchingFqdnsForScanResults(any(List.class))).thenReturn(fqdns); + InOrder inOrder = inOrder(mWifiService); + mWifiManager.getAllMatchingWifiConfigs(new ArrayList<>()); - verify(mWifiService).getAllMatchingWifiConfigs(any(List.class)); + inOrder.verify(mWifiService).getAllMatchingFqdnsForScanResults(any(List.class)); + inOrder.verify(mWifiService).getWifiConfigsForPasspointProfiles(any(List.class)); } /** |