From bb68271e4eced5b67905e50357e817d2178802b4 Mon Sep 17 00:00:00 2001 From: Tyler Freeman Date: Fri, 19 May 2023 11:36:07 -0700 Subject: [PATCH 001/563] fix(non linear font scaling): fix test timeout flakiness Fix: 283186902 Test: atest FrameworksCoreTests:android.content.res.FontScaleConverterActivityTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2d5f2f97b65729c6af1d08b5541bad375719e5b6) Merged-In: I67dc51b587602f72949549ac17253628ad1a2e1a Change-Id: I67dc51b587602f72949549ac17253628ad1a2e1a --- .../content/res/FontScaleConverterActivityTest.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java index df4fb44cd1ba..0941a2b6d263 100644 --- a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java +++ b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java @@ -137,7 +137,7 @@ public class FontScaleConverterActivityTest { ); }); - PollingCheck.waitFor(/* timeout= */ 5000, () -> { + PollingCheck.waitFor(/* timeout= */ 7000, () -> { AtomicBoolean isActivityAtCorrectScale = new AtomicBoolean(false); rule.getScenario().onActivity(activity -> isActivityAtCorrectScale.set( @@ -146,12 +146,7 @@ public class FontScaleConverterActivityTest { .fontScale == fontScale ) ); - return isActivityAtCorrectScale.get() && InstrumentationRegistry - .getInstrumentation() - .getContext() - .getResources() - .getConfiguration() - .fontScale == fontScale; + return isActivityAtCorrectScale.get(); }); } -- GitLab From 73e2b35a63d8c5da528b7a2dad2091f40b0f49c1 Mon Sep 17 00:00:00 2001 From: Tim Yu Date: Thu, 26 Oct 2023 17:25:47 +0000 Subject: [PATCH 002/563] Check permissions of URI inside of Autofill Slices Bug: 292104015 Test: Local poc app Change-Id: I25e96be5323ad408f1ba9aef5f9a80e4f00c77a2 --- .../com/android/server/autofill/Helper.java | 56 +++++++++++++++++-- .../RemoteInlineSuggestionViewConnector.java | 5 ++ 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java index ad8f5e1481e1..f32aac49ce7f 100644 --- a/services/autofill/java/com/android/server/autofill/Helper.java +++ b/services/autofill/java/com/android/server/autofill/Helper.java @@ -25,8 +25,11 @@ import android.app.ActivityManager; import android.app.assist.AssistStructure; import android.app.assist.AssistStructure.ViewNode; import android.app.assist.AssistStructure.WindowNode; +import android.app.slice.Slice; +import android.app.slice.SliceItem; import android.content.ComponentName; import android.content.Context; +import android.graphics.drawable.Icon; import android.hardware.display.DisplayManager; import android.metrics.LogMaker; import android.os.UserManager; @@ -55,7 +58,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.atomic.AtomicBoolean; - public final class Helper { private static final String TAG = "AutofillHelper"; @@ -92,11 +94,12 @@ public final class Helper { @UserIdInt int userId, @NonNull RemoteViews rView) { final AtomicBoolean permissionsOk = new AtomicBoolean(true); - rView.visitUris(uri -> { - int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri); - boolean allowed = uriOwnerId == userId; - permissionsOk.set(allowed & permissionsOk.get()); - }); + rView.visitUris( + uri -> { + int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri, userId); + boolean allowed = uriOwnerId == userId; + permissionsOk.set(allowed & permissionsOk.get()); + }); return permissionsOk.get(); } @@ -125,6 +128,47 @@ public final class Helper { return (ok ? rView : null); } + /** + * Checks the URI permissions of the icon in the slice, to see if the current userId is able to + * access it. + * + *

Returns null if slice contains user inaccessible icons + * + *

TODO: instead of returning a null Slice when the current userId cannot access an icon, + * return a reconstructed Slice without the icons. This is currently non-trivial since there are + * no public methods to generically add SliceItems to Slices + */ + public static @Nullable Slice sanitizeSlice(Slice slice) { + if (slice == null) { + return null; + } + + int userId = ActivityManager.getCurrentUser(); + + // Recontruct the Slice, filtering out bad icons + for (SliceItem sliceItem : slice.getItems()) { + if (!sliceItem.getFormat().equals(SliceItem.FORMAT_IMAGE)) { + // Not an image slice + continue; + } + + Icon icon = sliceItem.getIcon(); + if (icon.getType() != Icon.TYPE_URI + && icon.getType() != Icon.TYPE_URI_ADAPTIVE_BITMAP) { + // No URIs to sanitize + continue; + } + + int iconUriId = android.content.ContentProvider.getUserIdFromUri(icon.getUri(), userId); + + if (iconUriId != userId) { + Slog.w(TAG, "sanitizeSlice() user: " + userId + " cannot access icons in Slice"); + return null; + } + } + + return slice; + } @Nullable static AutofillId[] toArray(@Nullable ArraySet set) { diff --git a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java index 70443f9153d1..3d22182ec03f 100644 --- a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java +++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java @@ -27,6 +27,7 @@ import android.service.autofill.InlinePresentation; import android.util.Slog; import com.android.server.LocalServices; +import com.android.server.autofill.Helper; import com.android.server.autofill.RemoteInlineSuggestionRenderService; import com.android.server.inputmethod.InputMethodManagerInternal; @@ -83,6 +84,10 @@ final class RemoteInlineSuggestionViewConnector { */ public boolean renderSuggestion(int width, int height, @NonNull IInlineSuggestionUiCallback callback) { + if (Helper.sanitizeSlice(mInlinePresentation.getSlice()) == null) { + if (sDebug) Slog.d(TAG, "Skipped rendering inline suggestion."); + return false; + } if (mRemoteRenderService != null) { if (sDebug) Slog.d(TAG, "Request to recreate the UI"); mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height, -- GitLab From 57b2300f28285211c5b1b1e6e72c2ff043604ca0 Mon Sep 17 00:00:00 2001 From: Yunfan Chen Date: Wed, 22 May 2024 16:16:51 +0900 Subject: [PATCH 003/563] Avoid mentioning complex deprecated API in API docs In getBounds() API doc, the code snippet to get the window size excluding system decorations refers it as the legacy value of getSize() API. As the getSize() behavior becomes more complex, to explicitly describe the behavior instead of referring to it can make things clear. Bug: 151861875 Test: N/A Change-Id: If59ef701b833727885ea3baa16b0f6804c05cba8 --- core/java/android/view/Display.java | 7 ++++++- core/java/android/view/WindowMetrics.java | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 6464239eb2fc..be572f8249d5 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -1677,7 +1677,12 @@ public final class Display { * {@code getWindowManager()} or {@code getSystemService(Context.WINDOW_SERVICE)}), the * returned metrics provide the size of the current app window. As a result, in * multi-window mode, the returned size can be smaller than the size of the device - * screen. + * screen. System decoration handling may vary depending on API level: + *

*
  • If metrics are requested from a non-activity context (for example, the application * context, where the WindowManager is accessed by * {@code getApplicationContext().getSystemService(Context.WINDOW_SERVICE)}), the diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java index 8bcc9de118e2..12af692a4556 100644 --- a/core/java/android/view/WindowMetrics.java +++ b/core/java/android/view/WindowMetrics.java @@ -107,8 +107,8 @@ public final class WindowMetrics { * and display cutout areas depending on the calling context and target SDK level. Please refer * to {@link Display#getSize(Point)} for details. *

    - * The value reported by {@link Display#getSize(Point)} excluding system decoration areas can be - * obtained by using: + * The following code snippet shows how to get the bounds excluding navigation bars and display + * cutout: *

          * final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
          * // Gets all excluding insets
    -- 
    GitLab
    
    
    From 6823f28db3c1ce73bd8e395c16a51db2963178dd Mon Sep 17 00:00:00 2001
    From: Felipe Leme 
    Date: Tue, 17 Sep 2024 13:03:31 -0700
    Subject: [PATCH 004/563] Added --namespace parameter to dumpsys device_config
    
    Bug: 364399200
    Test: adb shell dumpsys device_config --namespace adservices
    Flag: android.provider.flags.dump_improvements
    
    Change-Id: Ifab219bccededb07de558dced9d6203efe568108
    ---
     .../settings/DeviceConfigService.java         | 44 ++++++++++++++++---
     1 file changed, 39 insertions(+), 5 deletions(-)
    
    diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
    index afbe84c54d9d..dc4408d93b19 100644
    --- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
    +++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
    @@ -16,6 +16,7 @@
     
     package com.android.providers.settings;
     
    +import static android.provider.DeviceConfig.DUMP_ARG_NAMESPACE;
     import static android.provider.Settings.Config.SYNC_DISABLED_MODE_NONE;
     import static android.provider.Settings.Config.SYNC_DISABLED_MODE_PERSISTENT;
     import static android.provider.Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT;
    @@ -42,6 +43,7 @@ import android.provider.DeviceConfigShellCommandHandler;
     import android.provider.Settings;
     import android.provider.Settings.Config.SyncDisabledMode;
     import android.provider.UpdatableDeviceConfigServiceReadiness;
    +import android.util.Log;
     import android.util.Slog;
     
     import com.android.internal.util.FastPrintWriter;
    @@ -55,11 +57,13 @@ import java.io.PrintWriter;
     import java.lang.reflect.Field;
     import java.lang.reflect.Modifier;
     import java.util.ArrayList;
    +import java.util.Arrays;
     import java.util.Collections;
     import java.util.HashMap;
     import java.util.HashSet;
     import java.util.List;
     import java.util.Map;
    +import java.util.regex.Pattern;
     
     /**
      * Receives shell commands from the command line related to device config flags, and dispatches them
    @@ -80,6 +84,7 @@ public final class DeviceConfigService extends Binder {
         final SettingsProvider mProvider;
     
         private static final String TAG = "DeviceConfigService";
    +    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     
         public DeviceConfigService(SettingsProvider provider) {
             mProvider = provider;
    @@ -97,14 +102,35 @@ public final class DeviceConfigService extends Binder {
             }
         }
     
    +    // TODO(b/364399200): add unit test
         @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    +        String filter = null;
             if (android.provider.flags.Flags.dumpImprovements()) {
    -            pw.print("SyncDisabledForTests: ");
    -            MyShellCommand.getSyncDisabledForTests(pw, pw);
    +            if (args.length > 0) {
    +                switch (args[0]) {
    +                    case DUMP_ARG_NAMESPACE:
    +                        if (args.length < 2) {
    +                            throw new IllegalArgumentException("argument " + DUMP_ARG_NAMESPACE
    +                                    + " requires an extra argument");
    +                        }
    +                        filter = args[1];
    +                        if (DEBUG) {
    +                            Slog.d(TAG, "dump(): setting filter as " + filter);
    +                        }
    +                        break;
    +                    default:
    +                        Slog.w(TAG, "dump(): ignoring invalid arguments: " + Arrays.toString(args));
    +                        break;
    +                }
    +            }
    +            if (filter == null) {
    +                pw.print("SyncDisabledForTests: ");
    +                MyShellCommand.getSyncDisabledForTests(pw, pw);
     
    -            pw.print("UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService(): ");
    -            pw.println(UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService());
    +                pw.print("UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService(): ");
    +                pw.println(UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService());
    +            }
     
                 pw.println("DeviceConfig provider: ");
                 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd)) {
    @@ -117,8 +143,16 @@ public final class DeviceConfigService extends Binder {
     
             IContentProvider iprovider = mProvider.getIContentProvider();
             pw.println("DeviceConfig flags:");
    +        Pattern lineFilter = filter == null ? null : Pattern.compile("^.*" + filter + ".*\\/.*$");
             for (String line : MyShellCommand.listAll(iprovider)) {
    -            pw.println(line);
    +            if (lineFilter == null || lineFilter.matcher(line).matches()) {
    +                pw.println(line);
    +            }
    +        }
    +
    +        if (filter != null) {
    +            // TODO(b/364399200): use filter to skip instead?
    +            return;
             }
     
             ArrayList missingFiles = new ArrayList();
    -- 
    GitLab
    
    
    From 770b1811ec72252d6eb7511b31e13a7478b36668 Mon Sep 17 00:00:00 2001
    From: Emil Bengtsson 
    Date: Mon, 16 Sep 2024 17:24:18 +0000
    Subject: [PATCH 005/563] Migrate WristOrientationService
    
    Test: atest ClockworkFrameworksRoboTests
    Bug: 352725980
    Flag: android.server.migrate_wrist_orientation
    (cherry picked from https://partner-android-review.googlesource.com/q/commit:869dba778f1e7b1c7eb1776269f5cd35b65cf373)
    Merged-In: I3b50563948f1ed4aad38b2aa6206920fa19f5d45
    Change-Id: I3b50563948f1ed4aad38b2aa6206920fa19f5d45
    ---
     services/java/com/android/server/SystemServer.java | 5 +++--
     services/java/com/android/server/flags.aconfig     | 8 ++++++++
     2 files changed, 11 insertions(+), 2 deletions(-)
    
    diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
    index ab459df1cdf6..637a69190048 100644
    --- a/services/java/com/android/server/SystemServer.java
    +++ b/services/java/com/android/server/SystemServer.java
    @@ -2737,8 +2737,9 @@ public final class SystemServer implements Dumpable {
                 mSystemServiceManager.startService(WEAR_MODE_SERVICE_CLASS);
                 t.traceEnd();
     
    -            boolean enableWristOrientationService = SystemProperties.getBoolean(
    -                    "config.enable_wristorientation", false);
    +            boolean enableWristOrientationService =
    +                    !android.server.Flags.migrateWristOrientation()
    +                    && SystemProperties.getBoolean("config.enable_wristorientation", false);
                 if (enableWristOrientationService) {
                     t.traceBegin("StartWristOrientationService");
                     mSystemServiceManager.startService(WRIST_ORIENTATION_SERVICE_CLASS);
    diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig
    index ec74ef191b81..5fda5f940995 100644
    --- a/services/java/com/android/server/flags.aconfig
    +++ b/services/java/com/android/server/flags.aconfig
    @@ -30,6 +30,14 @@ flag {
          bug: "340928692"
     }
     
    +flag {
    +     name: "migrate_wrist_orientation"
    +     namespace: "wear_frameworks"
    +     description: "Migrate wrist orientation service functionality to wear settings service"
    +     bug: "352725980"
    +     is_fixed_read_only: true
    +}
    +
     flag {
         name: "allow_network_time_update_service"
         namespace: "wear_systems"
    -- 
    GitLab
    
    
    From 2828cdc7ca40e8c142338b36c146968076eca33e Mon Sep 17 00:00:00 2001
    From: "T.J. Mercier" 
    Date: Fri, 25 Oct 2024 00:36:31 +0000
    Subject: [PATCH 006/563] Fix system_server SIGABRT due to non-UTF-8 process
     name in /proc/PID/stat
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    It is possible for process names to include non-printable characters.
    When that is the case, the second column (comm) of /proc/PID/stat output
    includes '�' characters which are fed directly into NewStringUTF.
    NewStringUTF detects the non-UTF-8 characters and aborts. Fix this by
    replacing all non-printable characters with question marks '?' before
    calling NewStringUTF.
    
    Bug: 351917521
    Bug: 361017804
    Test: adb wait-for-device shell 'echo -ne "\x9C\x88foo" > /proc/$$/comm; sleep 9999'
    Change-Id: I040c8640e441c4545747edb5870a746892d1b09c
    ---
     core/jni/android_util_Process.cpp | 3 +++
     1 file changed, 3 insertions(+)
    
    diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
    index 4cc904153aac..4369cb0d82b4 100644
    --- a/core/jni/android_util_Process.cpp
    +++ b/core/jni/android_util_Process.cpp
    @@ -33,6 +33,7 @@
     
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -1004,6 +1005,8 @@ jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz,
                     }
                 }
                 if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
    +                std::replace_if(buffer+start, buffer+end,
    +                                [](unsigned char c){ return !std::isprint(c); }, '?');
                     jstring str = env->NewStringUTF(buffer+start);
                     env->SetObjectArrayElement(outStrings, di, str);
                 }
    -- 
    GitLab
    
    
    From b819caadb50fd70f8c54f9b6b1d8ecca0615ff4a Mon Sep 17 00:00:00 2001
    From: Hans Boehm 
    Date: Wed, 30 Oct 2024 00:12:24 +0000
    Subject: [PATCH 007/563] Remove most fillInStackTrace() calls from core
    
    Throwable's constructor already calls it, and it is
    quite expensive. Removed calls were redundant.
    
    Bug: 373764538
    Flag: EXEMPT bugfix
    
    Change-Id: Iad26d10f3c6d89e772a1430ecf842c8cfb24effd
    ---
     core/java/android/app/ActivityManager.java    |  1 -
     .../app/ApplicationPackageManager.java        |  1 -
     core/java/android/app/LoadedApk.java          |  5 --
     core/java/android/app/LoaderManager.java      | 89 +++++++++----------
     core/java/android/app/ResourcesManager.java   |  3 -
     .../android/content/BroadcastReceiver.java    |  2 -
     .../android/content/res/AssetManager.java     | 27 +++---
     core/java/android/os/Parcel.java              |  1 -
     core/java/android/util/ArrayMap.java          |  1 -
     core/java/android/util/ArraySet.java          |  1 -
     core/java/android/view/ViewRootImpl.java      |  1 -
     .../app/procstats/AssociationState.java       |  5 --
     .../internal/app/procstats/ProcessState.java  |  4 -
     .../app/activity/ActivityTestsBase.java       |  9 +-
     .../app/activity/LaunchpadActivity.java       |  1 -
     15 files changed, 60 insertions(+), 91 deletions(-)
    
    diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
    index 36fc65a76d53..30d96ae253a5 100644
    --- a/core/java/android/app/ActivityManager.java
    +++ b/core/java/android/app/ActivityManager.java
    @@ -5286,7 +5286,6 @@ public class ActivityManager {
             if (!exported) {
                 /*
                 RuntimeException here = new RuntimeException("here");
    -            here.fillInStackTrace();
                 Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
                         here);
                 */
    diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
    index fb5a12b49921..e247916915d6 100644
    --- a/core/java/android/app/ApplicationPackageManager.java
    +++ b/core/java/android/app/ApplicationPackageManager.java
    @@ -1835,7 +1835,6 @@ public class ApplicationPackageManager extends PackageManager {
     
                     if (false) {
                         RuntimeException e = new RuntimeException("here");
    -                    e.fillInStackTrace();
                         Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resId)
                                         + " from package " + packageName
                                         + ": app scale=" + r.getCompatibilityInfo().applicationScale
    diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
    index 1e45d6fd1674..255ad557b9a5 100644
    --- a/core/java/android/app/LoadedApk.java
    +++ b/core/java/android/app/LoadedApk.java
    @@ -1648,7 +1648,6 @@ public final class LoadedApk {
                             }
                             RuntimeException ex = new IllegalArgumentException(
                                     "Originally unregistered here:");
    -                        ex.fillInStackTrace();
                             rd.setUnregisterLocation(ex);
                             holder.put(r, rd);
                         }
    @@ -1848,7 +1847,6 @@ public final class LoadedApk {
                 mInstrumentation = instrumentation;
                 mRegistered = registered;
                 mLocation = new IntentReceiverLeaked(null);
    -            mLocation.fillInStackTrace();
             }
     
             void validate(Context context, Handler activityThread) {
    @@ -1988,7 +1986,6 @@ public final class LoadedApk {
                             }
                             RuntimeException ex = new IllegalArgumentException(
                                     "Originally unbound here:");
    -                        ex.fillInStackTrace();
                             sd.setUnbindLocation(ex);
                             holder.put(c, sd);
                         }
    @@ -2064,7 +2061,6 @@ public final class LoadedApk {
                 mActivityThread = activityThread;
                 mActivityExecutor = null;
                 mLocation = new ServiceConnectionLeaked(null);
    -            mLocation.fillInStackTrace();
                 mFlags = flags;
             }
     
    @@ -2076,7 +2072,6 @@ public final class LoadedApk {
                 mActivityThread = null;
                 mActivityExecutor = activityExecutor;
                 mLocation = new ServiceConnectionLeaked(null);
    -            mLocation.fillInStackTrace();
                 mFlags = flags;
             }
     
    diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
    index e2de716d7e74..a70d4937b46c 100644
    --- a/core/java/android/app/LoaderManager.java
    +++ b/core/java/android/app/LoaderManager.java
    @@ -83,7 +83,7 @@ public abstract class LoaderManager {
              * transactions while in this call, since it can happen after an
              * activity's state is saved.  See {@link FragmentManager#beginTransaction()
              * FragmentManager.openTransaction()} for further discussion on this.
    -         * 
    +         *
              * 

    This function is guaranteed to be called prior to the release of * the last data that was supplied for this Loader. At this point * you should remove all use of the old data (since it will be released @@ -127,7 +127,7 @@ public abstract class LoaderManager { */ public void onLoaderReset(Loader loader); } - + /** * Ensures a loader is initialized and active. If the loader doesn't * already exist, one is created and (if the activity/fragment is currently @@ -228,7 +228,7 @@ class LoaderManagerImpl extends LoaderManager { boolean mStarted; boolean mRetaining; boolean mRetainingStarted; - + boolean mCreatingLoader; private FragmentHostCallback mHost; @@ -249,13 +249,13 @@ class LoaderManagerImpl extends LoaderManager { boolean mListenerRegistered; LoaderInfo mPendingLoader; - + public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks callbacks) { mId = id; mArgs = args; mCallbacks = callbacks; } - + void start() { if (mRetaining && mRetainingStarted) { // Our owner is started, but we were being retained from a @@ -271,7 +271,7 @@ class LoaderManagerImpl extends LoaderManager { } mStarted = true; - + if (DEBUG) Log.v(TAG, " Starting: " + this); if (mLoader == null && mCallbacks != null) { mLoader = mCallbacks.onCreateLoader(mId, mArgs); @@ -291,7 +291,7 @@ class LoaderManagerImpl extends LoaderManager { mLoader.startLoading(); } } - + void retain() { if (DEBUG) Log.v(TAG, " Retaining: " + this); mRetaining = true; @@ -299,7 +299,7 @@ class LoaderManagerImpl extends LoaderManager { mStarted = false; mCallbacks = null; } - + void finishRetain() { if (mRetaining) { if (DEBUG) Log.v(TAG, " Finished Retaining: " + this); @@ -324,7 +324,7 @@ class LoaderManagerImpl extends LoaderManager { callOnLoadFinished(mLoader, mData); } } - + void reportStart() { if (mStarted) { if (mReportNextStart) { @@ -430,7 +430,7 @@ class LoaderManagerImpl extends LoaderManager { @Override public void onLoadComplete(Loader loader, Object data) { if (DEBUG) Log.v(TAG, "onLoadComplete: " + this); - + if (mDestroyed) { if (DEBUG) Log.v(TAG, " Ignoring load complete -- destroyed"); return; @@ -442,7 +442,7 @@ class LoaderManagerImpl extends LoaderManager { if (DEBUG) Log.v(TAG, " Ignoring load complete -- not active"); return; } - + LoaderInfo pending = mPendingLoader; if (pending != null) { // There is a new request pending and we were just @@ -455,7 +455,7 @@ class LoaderManagerImpl extends LoaderManager { installLoader(pending); return; } - + // Notify of the new data so the app can switch out the old data before // we try to destroy it. if (mData != data || !mHaveData) { @@ -503,7 +503,7 @@ class LoaderManagerImpl extends LoaderManager { mDeliveredData = true; } } - + @Override public String toString() { StringBuilder sb = new StringBuilder(64); @@ -543,13 +543,13 @@ class LoaderManagerImpl extends LoaderManager { } } } - + LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) { mWho = who; mHost = host; mStarted = started; } - + void updateHostController(FragmentHostCallback host) { mHost = host; } @@ -557,7 +557,7 @@ class LoaderManagerImpl extends LoaderManager { public FragmentHostCallback getFragmentHostCallback() { return mHost; } - + private LoaderInfo createLoader(int id, Bundle args, LoaderManager.LoaderCallbacks callback) { LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks)callback); @@ -565,7 +565,7 @@ class LoaderManagerImpl extends LoaderManager { info.mLoader = (Loader)loader; return info; } - + private LoaderInfo createAndInstallLoader(int id, Bundle args, LoaderManager.LoaderCallbacks callback) { try { @@ -577,7 +577,7 @@ class LoaderManagerImpl extends LoaderManager { mCreatingLoader = false; } } - + void installLoader(LoaderInfo info) { mLoaders.put(info.mId, info); if (mStarted) { @@ -587,23 +587,23 @@ class LoaderManagerImpl extends LoaderManager { info.start(); } } - + /** * Call to initialize a particular ID with a Loader. If this ID already * has a Loader associated with it, it is left unchanged and any previous * callbacks replaced with the newly provided ones. If there is not currently * a Loader for the ID, a new one is created and started. - * + * *

    This function should generally be used when a component is initializing, * to ensure that a Loader it relies on is created. This allows it to re-use * an existing Loader's data if there already is one, so that for example * when an {@link Activity} is re-created after a configuration change it * does not need to re-create its loaders. - * + * *

    Note that in the case where an existing Loader is re-used, the * args given here will be ignored because you will * continue using the previous Loader. - * + * * @param id A unique (to this LoaderManager instance) identifier under * which to manage the new Loader. * @param args Optional arguments that will be propagated to @@ -617,9 +617,9 @@ class LoaderManagerImpl extends LoaderManager { if (mCreatingLoader) { throw new IllegalStateException("Called while creating a loader"); } - + LoaderInfo info = mLoaders.get(id); - + if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args); if (info == null) { @@ -630,30 +630,30 @@ class LoaderManagerImpl extends LoaderManager { if (DEBUG) Log.v(TAG, " Re-using existing loader " + info); info.mCallbacks = (LoaderManager.LoaderCallbacks)callback; } - + if (info.mHaveData && mStarted) { // If the loader has already generated its data, report it now. info.callOnLoadFinished(info.mLoader, info.mData); } - + return (Loader)info.mLoader; } - + /** * Call to re-create the Loader associated with a particular ID. If there * is currently a Loader associated with this ID, it will be * canceled/stopped/destroyed as appropriate. A new Loader with the given * arguments will be created and its data delivered to you once available. - * + * *

    This function does some throttling of Loaders. If too many Loaders * have been created for the given ID but not yet generated their data, * new calls to this function will create and return a new Loader but not * actually start it until some previous loaders have completed. - * + * *

    After calling this function, any previous Loaders associated with * this ID will be considered invalid, and you will receive no further * data updates from them. - * + * * @param id A unique (to this LoaderManager instance) identifier under * which to manage the new Loader. * @param args Optional arguments that will be propagated to @@ -667,7 +667,7 @@ class LoaderManagerImpl extends LoaderManager { if (mCreatingLoader) { throw new IllegalStateException("Called while creating a loader"); } - + LoaderInfo info = mLoaders.get(id); if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args); if (info != null) { @@ -706,7 +706,7 @@ class LoaderManagerImpl extends LoaderManager { info.mPendingLoader = null; } if (DEBUG) Log.v(TAG, " Enqueuing as new pending loader"); - info.mPendingLoader = createLoader(id, args, + info.mPendingLoader = createLoader(id, args, (LoaderManager.LoaderCallbacks)callback); return (Loader)info.mPendingLoader.mLoader; } @@ -719,11 +719,11 @@ class LoaderManagerImpl extends LoaderManager { mInactiveLoaders.put(id, info); } } - + info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks)callback); return (Loader)info.mLoader; } - + /** * Rip down, tear apart, shred to pieces a current Loader ID. After returning * from this function, any Loader objects associated with this ID are @@ -735,7 +735,7 @@ class LoaderManagerImpl extends LoaderManager { if (mCreatingLoader) { throw new IllegalStateException("Called while creating a loader"); } - + if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id); int idx = mLoaders.indexOfKey(id); if (idx >= 0) { @@ -763,7 +763,7 @@ class LoaderManagerImpl extends LoaderManager { if (mCreatingLoader) { throw new IllegalStateException("Called while creating a loader"); } - + LoaderInfo loaderInfo = mLoaders.get(id); if (loaderInfo != null) { if (loaderInfo.mPendingLoader != null) { @@ -773,16 +773,15 @@ class LoaderManagerImpl extends LoaderManager { } return null; } - + void doStart() { if (DEBUG) Log.v(TAG, "Starting in " + this); if (mStarted) { RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); Log.w(TAG, "Called doStart when already started: " + this, e); return; } - + mStarted = true; // Call out to sub classes so they can start their loaders @@ -791,12 +790,11 @@ class LoaderManagerImpl extends LoaderManager { mLoaders.valueAt(i).start(); } } - + void doStop() { if (DEBUG) Log.v(TAG, "Stopping in " + this); if (!mStarted) { RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); Log.w(TAG, "Called doStop when not started: " + this, e); return; } @@ -806,12 +804,11 @@ class LoaderManagerImpl extends LoaderManager { } mStarted = false; } - + void doRetain() { if (DEBUG) Log.v(TAG, "Retaining in " + this); if (!mStarted) { RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); Log.w(TAG, "Called doRetain when not started: " + this, e); return; } @@ -822,7 +819,7 @@ class LoaderManagerImpl extends LoaderManager { mLoaders.valueAt(i).retain(); } } - + void finishRetain() { if (mRetaining) { if (DEBUG) Log.v(TAG, "Finished Retaining in " + this); @@ -833,7 +830,7 @@ class LoaderManagerImpl extends LoaderManager { } } } - + void doReportNextStart() { for (int i = mLoaders.size()-1; i >= 0; i--) { mLoaders.valueAt(i).mReportNextStart = true; @@ -854,7 +851,7 @@ class LoaderManagerImpl extends LoaderManager { } mLoaders.clear(); } - + if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this); for (int i = mInactiveLoaders.size()-1; i >= 0; i--) { mInactiveLoaders.valueAt(i).destroy(); diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index a458b4e45796..599a46b131d5 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -1137,7 +1137,6 @@ public class ResourcesManager { synchronized (mLock) { if (DEBUG) { Throwable here = new Throwable(); - here.fillInStackTrace(); Slog.w(TAG, "!! Create resources for key=" + key, here); } @@ -1158,7 +1157,6 @@ public class ResourcesManager { synchronized (mLock) { if (DEBUG) { Throwable here = new Throwable(); - here.fillInStackTrace(); Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here); } @@ -1302,7 +1300,6 @@ public class ResourcesManager { if (DEBUG) { Throwable here = new Throwable(); - here.fillInStackTrace(); Slog.d(TAG, "updating resources override for activity=" + activityToken + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig) diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index 964a8be0f153..a81629445263 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -356,7 +356,6 @@ public abstract class BroadcastReceiver { } RuntimeException e = new RuntimeException( "BroadcastReceiver trying to return result during a non-ordered broadcast"); - e.fillInStackTrace(); Log.e("BroadcastReceiver", e.getMessage(), e); } } @@ -768,7 +767,6 @@ public abstract class BroadcastReceiver { } RuntimeException e = new RuntimeException( "BroadcastReceiver trying to return result during a non-ordered broadcast"); - e.fillInStackTrace(); Log.e("BroadcastReceiver", e.getMessage(), e); } } diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 6fd4d0141977..4551bd52c960 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -973,9 +973,9 @@ public final class AssetManager implements AutoCloseable { * Open an asset using ACCESS_STREAMING mode. This provides access to * files that have been bundled with an application as assets -- that is, * files placed in to the "assets" directory. - * + * * @param fileName The name of the asset to open. This name can be hierarchical. - * + * * @see #open(String, int) * @see #list */ @@ -988,10 +988,10 @@ public final class AssetManager implements AutoCloseable { * read its contents. This provides access to files that have been bundled * with an application as assets -- that is, files placed in to the * "assets" directory. - * + * * @param fileName The name of the asset to open. This name can be hierarchical. * @param accessMode Desired access mode for retrieving the data. - * + * * @see #ACCESS_UNKNOWN * @see #ACCESS_STREAMING * @see #ACCESS_RANDOM @@ -1037,14 +1037,14 @@ public final class AssetManager implements AutoCloseable { /** * Return a String array of all the assets at the given path. - * + * * @param path A relative path within the assets, i.e., "docs/home.html". - * + * * @return String[] Array of strings, one for each asset. These file * names are relative to 'path'. You can open the file by * concatenating 'path' and a name in the returned string (via * File) and passing that to open(). - * + * * @see #open */ public @Nullable String[] list(@NonNull String path) throws IOException { @@ -1167,20 +1167,20 @@ public final class AssetManager implements AutoCloseable { return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]); } } - + /** * Retrieve a parser for a compiled XML file. - * + * * @param fileName The name of the file to retrieve. */ public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName) throws IOException { return openXmlResourceParser(0, fileName); } - + /** * Retrieve a parser for a compiled XML file. - * + * * @param cookie Identifier of the package to be opened. * @param fileName The name of the file to retrieve. */ @@ -1200,7 +1200,7 @@ public final class AssetManager implements AutoCloseable { /** * Retrieve a non-asset as a compiled XML file. Not for use by applications. - * + * * @param fileName The name of the file to retrieve. * @hide */ @@ -1211,7 +1211,7 @@ public final class AssetManager implements AutoCloseable { /** * Retrieve a non-asset as a compiled XML file. Not for use by * applications. - * + * * @param cookie Identifier of the package to be opened. * @param fileName Name of the asset to retrieve. * @hide @@ -1675,7 +1675,6 @@ public final class AssetManager implements AutoCloseable { mRefStacks = new HashMap<>(); } RuntimeException ex = new RuntimeException(); - ex.fillInStackTrace(); mRefStacks.put(id, ex); } mNumRefs++; diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index f7285523c01a..bf7116d6a05b 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -1371,7 +1371,6 @@ public final class Parcel { writeInt(N); if (DEBUG_ARRAY_MAP) { RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); Log.d(TAG, "Writing " + N + " ArrayMap entries", here); } int startPos; diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java index 174e0c8e6549..7ee0ff15c5ad 100644 --- a/core/java/android/util/ArrayMap.java +++ b/core/java/android/util/ArrayMap.java @@ -649,7 +649,6 @@ public final class ArrayMap implements Map { } if (index > 0 && mHashes[index-1] > hash) { RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); Log.w(TAG, "New hash " + hash + " is before end of array hash " + mHashes[index-1] + " at index " + index + (DEBUG ? " key " + key : ""), e); diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java index bfbca07ed256..1344bb9a73eb 100644 --- a/core/java/android/util/ArraySet.java +++ b/core/java/android/util/ArraySet.java @@ -526,7 +526,6 @@ public final class ArraySet implements Collection, Set { // Cannot optimize since it would break the sorted order - fallback to add() if (DEBUG) { RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); Log.w(TAG, "New hash " + hash + " is before end of array hash " + mHashes[index - 1] + " at index " + index, e); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index d57a88075f8a..9f665bb23516 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1249,7 +1249,6 @@ public final class ViewRootImpl implements ViewParent, mExtraDisplayListenerLogging = !TextUtils.isEmpty(name) && name.equals(mBasePackageName); mThread = Thread.currentThread(); mLocation = new WindowLeaked(null); - mLocation.fillInStackTrace(); mWidth = -1; mHeight = -1; mDirty = new Rect(); diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java index a21a84261ae0..543adac14d36 100644 --- a/core/java/com/android/internal/app/procstats/AssociationState.java +++ b/core/java/com/android/internal/app/procstats/AssociationState.java @@ -257,7 +257,6 @@ public final class AssociationState { if (VALIDATE_TIMES) { if (mActiveDuration > mAssociationState.mTotalActiveDuration) { RuntimeException ex = new RuntimeException(); - ex.fillInStackTrace(); Slog.w(TAG, "Source act duration " + mActiveDurations + " exceeds total " + mAssociationState.mTotalActiveDuration + " in procstate " + mActiveProcState + " in source " @@ -650,7 +649,6 @@ public final class AssociationState { + mySrc.mKey.mProcess + " to assoc " + mName); if ((mySrc.mDuration + otherSrc.mDuration) > mTotalDuration) { RuntimeException ex = new RuntimeException(); - ex.fillInStackTrace(); Slog.w(TAG, "Source tot duration " + mySrc.mDuration + "+" + otherSrc.mDuration + (newSrc ? " (new)" : " (old)") + " exceeds total " @@ -665,7 +663,6 @@ public final class AssociationState { + mySrc.mKey.mProcess + " to assoc " + mName); if ((mySrc.mActiveDuration + otherSrc.mActiveDuration) > mTotalDuration) { RuntimeException ex = new RuntimeException(); - ex.fillInStackTrace(); Slog.w(TAG, "Source act duration " + mySrc.mActiveDuration + "+" + otherSrc.mActiveDuration + (newSrc ? " (new)" : " (old)") + " exceeds total " @@ -746,14 +743,12 @@ public final class AssociationState { if (VALIDATE_TIMES) { if (src.mDuration > mTotalDuration) { RuntimeException ex = new RuntimeException(); - ex.fillInStackTrace(); Slog.w(TAG, "Reading tot duration " + src.mDuration + " exceeds total " + mTotalDuration + " in source " + src.mKey.mProcess + " to assoc " + mName, ex); } if (src.mActiveDurations == null && src.mActiveDuration > mTotalDuration) { RuntimeException ex = new RuntimeException(); - ex.fillInStackTrace(); Slog.w(TAG, "Reading act duration " + src.mActiveDuration + " exceeds total " + mTotalDuration + " in source " + src.mKey.mProcess + " to assoc " + mName, ex); diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java index 0dbdb36977f4..7523a2d24af8 100644 --- a/core/java/com/android/internal/app/procstats/ProcessState.java +++ b/core/java/com/android/internal/app/procstats/ProcessState.java @@ -538,7 +538,6 @@ public final class ProcessState { public void incActiveServices(String serviceName) { if (DEBUG && "".equals(mName)) { RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName + " to " + (mNumActiveServices+1), here); } @@ -551,7 +550,6 @@ public final class ProcessState { public void decActiveServices(String serviceName) { if (DEBUG && "".equals(mName)) { RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName + " to " + (mNumActiveServices-1), here); } @@ -569,7 +567,6 @@ public final class ProcessState { public void incStartedServices(int memFactor, long now, String serviceName) { if (false) { RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName + " to " + (mNumStartedServices+1), here); } @@ -585,7 +582,6 @@ public final class ProcessState { public void decStartedServices(int memFactor, long now, String serviceName) { if (false) { RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName + " to " + (mNumStartedServices-1), here); } diff --git a/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java b/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java index 232abe281e0f..7f069ad3cab8 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java +++ b/core/tests/coretests/src/android/app/activity/ActivityTestsBase.java @@ -22,7 +22,7 @@ import android.content.Intent; import android.test.AndroidTestCase; import android.test.PerformanceTestCase; -public class ActivityTestsBase extends AndroidTestCase +public class ActivityTestsBase extends AndroidTestCase implements PerformanceTestCase, LaunchpadActivity.CallingTest { public static final String PERMISSION_GRANTED = "com.android.frameworks.coretests.permission.TEST_GRANTED"; @@ -111,7 +111,6 @@ public class ActivityTestsBase extends AndroidTestCase public void finishWithResult(int resultCode, Intent data) { RuntimeException where = new RuntimeException("Original error was here"); - where.fillInStackTrace(); finishWithResult(resultCode, data, where); } @@ -194,15 +193,15 @@ public class ActivityTestsBase extends AndroidTestCase public int getResultCode() { return mResultCode; } - + public Intent getResultData() { return mData; } - + public RuntimeException getResultStack() { return mResultStack; } - + public void onTimeout() { String msg = mExpecting == null ? "Timeout" : ("Timeout while expecting " + mExpecting); diff --git a/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java b/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java index fda249f3c6ae..9b358e0a7954 100644 --- a/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java +++ b/core/tests/coretests/src/android/app/activity/LaunchpadActivity.java @@ -461,7 +461,6 @@ public class LaunchpadActivity extends Activity { mResultCode = resultCode; mData = data; mResultStack = new RuntimeException("Original error was here"); - mResultStack.fillInStackTrace(); } private void registerMyReceiver(IntentFilter filter) { -- GitLab From 85cfd4a19811d6db8c180384e650500a58df288c Mon Sep 17 00:00:00 2001 From: Angela Wang Date: Fri, 1 Nov 2024 03:15:40 +0000 Subject: [PATCH 008/563] Update hearing device dialog UI 1. Move title out of spinner 2. Spinner dropdown style 3. Add title of related tools Flag: EXEMPT bugfix Bug: 376779544 Test: manually check the UI, results attached in bug Test: atest HearingDevicesDialogDelegateTest Change-Id: Iffa77fc5283635dc73b18508eb07e6b257511057 --- .../HearingDevicesDialogDelegateTest.java | 57 ++++++--- ...=> hearing_devices_spinner_background.xml} | 7 +- ...ring_devices_spinner_popup_background.xml} | 0 ...g_devices_spinner_selected_background.xml} | 18 ++- packages/SystemUI/res/drawable/ic_check.xml | 25 ++++ ...earing_devices_preset_spinner_selected.xml | 48 ------- .../hearing_devices_spinner_dropdown_view.xml | 45 +++++++ .../layout/hearing_devices_spinner_view.xml | 32 +++++ .../layout/hearing_devices_tile_dialog.xml | 117 ++++++++++-------- .../SystemUI/res/layout/hearing_tool_item.xml | 2 +- packages/SystemUI/res/values/dimens.xml | 7 +- packages/SystemUI/res/values/strings.xml | 4 + .../HearingDevicesDialogDelegate.java | 54 ++++---- .../HearingDevicesSpinnerAdapter.java | 85 +++++++++++++ 14 files changed, 343 insertions(+), 158 deletions(-) rename packages/SystemUI/res/drawable/{hearing_devices_preset_spinner_background.xml => hearing_devices_spinner_background.xml} (94%) rename packages/SystemUI/res/drawable/{hearing_devices_preset_spinner_popup_background.xml => hearing_devices_spinner_popup_background.xml} (100%) rename packages/SystemUI/res/{layout/hearing_devices_preset_dropdown_item.xml => drawable/hearing_devices_spinner_selected_background.xml} (54%) create mode 100644 packages/SystemUI/res/drawable/ic_check.xml delete mode 100644 packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml create mode 100644 packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml create mode 100644 packages/SystemUI/res/layout/hearing_devices_spinner_view.xml create mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java index fcb433b5db4e..b866e81c9017 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java @@ -47,7 +47,6 @@ import android.provider.Settings; import android.testing.TestableLooper; import android.view.View; import android.view.ViewGroup; -import android.widget.LinearLayout; import android.widget.Space; import android.widget.Spinner; @@ -215,6 +214,18 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { TEST_LAUNCH_SOURCE_ID); } + @Test + @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS) + public void showDialog_noLiveCaption_noRelatedToolsInConfig_relatedToolLayoutGone() { + mContext.getOrCreateTestableResources().addOverride( + R.array.config_quickSettingsHearingDevicesRelatedToolName, new String[]{}); + + setUpPairNewDeviceDialog(); + mDialog.show(); + + assertToolsUi(0); + } + @Test @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS) public void showDialog_hasLiveCaption_noRelatedToolsInConfig_showOneRelatedTool() { @@ -227,8 +238,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpPairNewDeviceDialog(); mDialog.show(); - LinearLayout relatedToolsView = (LinearLayout) getRelatedToolsView(mDialog); - assertThat(countChildWithoutSpace(relatedToolsView)).isEqualTo(1); + assertToolsUi(1); } @Test @@ -251,8 +261,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpPairNewDeviceDialog(); mDialog.show(); - LinearLayout relatedToolsView = (LinearLayout) getRelatedToolsView(mDialog); - assertThat(countChildWithoutSpace(relatedToolsView)).isEqualTo(2); + assertToolsUi(2); } @Test @@ -263,8 +272,8 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpDeviceListDialog(); mDialog.show(); - Spinner spinner = (Spinner) getPresetSpinner(mDialog); - assertThat(spinner.getVisibility()).isEqualTo(View.GONE); + ViewGroup presetLayout = getPresetLayout(mDialog); + assertThat(presetLayout.getVisibility()).isEqualTo(View.GONE); } @Test @@ -276,8 +285,9 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpDeviceListDialog(); mDialog.show(); - Spinner spinner = (Spinner) getPresetSpinner(mDialog); - assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE); + ViewGroup presetLayout = getPresetLayout(mDialog); + assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE); + Spinner spinner = getPresetSpinner(mDialog); assertThat(spinner.getSelectedItemPosition()).isEqualTo(0); } @@ -292,8 +302,9 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { mDialogDelegate.onActiveDeviceChanged(mCachedDevice, BluetoothProfile.LE_AUDIO); mTestableLooper.processAllMessages(); - Spinner spinner = (Spinner) getPresetSpinner(mDialog); - assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE); + ViewGroup presetLayout = getPresetLayout(mDialog); + assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE); + Spinner spinner = getPresetSpinner(mDialog); assertThat(spinner.getSelectedItemPosition()).isEqualTo(0); } @@ -359,14 +370,23 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { return dialog.requireViewById(R.id.pair_new_device_button); } - private View getRelatedToolsView(SystemUIDialog dialog) { - return dialog.requireViewById(R.id.related_tools_container); + private ViewGroup getToolsContainer(SystemUIDialog dialog) { + return dialog.requireViewById(R.id.tools_container); + } + + private ViewGroup getToolsLayout(SystemUIDialog dialog) { + return dialog.requireViewById(R.id.tools_layout); } - private View getPresetSpinner(SystemUIDialog dialog) { + private Spinner getPresetSpinner(SystemUIDialog dialog) { return dialog.requireViewById(R.id.preset_spinner); } + private ViewGroup getPresetLayout(SystemUIDialog dialog) { + return dialog.requireViewById(R.id.preset_layout); + } + + private int countChildWithoutSpace(ViewGroup viewGroup) { int spaceCount = 0; for (int i = 0; i < viewGroup.getChildCount(); i++) { @@ -377,6 +397,15 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { return viewGroup.getChildCount() - spaceCount; } + private void assertToolsUi(int childCount) { + ViewGroup toolsContainer = getToolsContainer(mDialog); + assertThat(countChildWithoutSpace(toolsContainer)).isEqualTo(childCount); + + int targetVisibility = childCount == 0 ? View.GONE : View.VISIBLE; + ViewGroup toolsLayout = getToolsLayout(mDialog); + assertThat(toolsLayout.getVisibility()).isEqualTo(targetVisibility); + } + @After public void reset() { if (mDialogDelegate != null) { diff --git a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_background.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml similarity index 94% rename from packages/SystemUI/res/drawable/hearing_devices_preset_spinner_background.xml rename to packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml index c83b6d38a0e1..dfefb9d166af 100644 --- a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_background.xml +++ b/packages/SystemUI/res/drawable/hearing_devices_spinner_background.xml @@ -14,7 +14,8 @@ limitations under the License. --> - @@ -30,8 +31,8 @@ android:end="20dp" android:gravity="end|center_vertical"> diff --git a/packages/SystemUI/res/drawable/hearing_devices_preset_spinner_popup_background.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml similarity index 100% rename from packages/SystemUI/res/drawable/hearing_devices_preset_spinner_popup_background.xml rename to packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml diff --git a/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_selected_background.xml similarity index 54% rename from packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml rename to packages/SystemUI/res/drawable/hearing_devices_spinner_selected_background.xml index 17c0222ef69e..c708d2280161 100644 --- a/packages/SystemUI/res/layout/hearing_devices_preset_dropdown_item.xml +++ b/packages/SystemUI/res/drawable/hearing_devices_spinner_selected_background.xml @@ -1,3 +1,4 @@ + - - \ No newline at end of file + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_check.xml b/packages/SystemUI/res/drawable/ic_check.xml new file mode 100644 index 000000000000..80707d876146 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_check.xml @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml b/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml deleted file mode 100644 index d512e7c3a433..000000000000 --- a/packages/SystemUI/res/layout/hearing_devices_preset_spinner_selected.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml b/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml new file mode 100644 index 000000000000..70f2cd5fcc28 --- /dev/null +++ b/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml @@ -0,0 +1,45 @@ + + + + + + + diff --git a/packages/SystemUI/res/layout/hearing_devices_spinner_view.xml b/packages/SystemUI/res/layout/hearing_devices_spinner_view.xml new file mode 100644 index 000000000000..75742440e889 --- /dev/null +++ b/packages/SystemUI/res/layout/hearing_devices_spinner_view.xml @@ -0,0 +1,32 @@ + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml index 80692f9481b7..bf04a6f64d6a 100644 --- a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml +++ b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml @@ -28,50 +28,16 @@ android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@id/preset_spinner" /> - - - - + app:layout_constraintEnd_toEndOf="parent" />