Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 647bb179 authored by Chaohui Wang's avatar Chaohui Wang Committed by Automerger Merge Worker
Browse files

Merge changes from topic "jank-toggle" into tm-dev am: dfed7f9e

parents 0d5c8261 dfed7f9e
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL;
import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
@@ -46,6 +47,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_TOGGLE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER;
@@ -198,6 +200,7 @@ public class InteractionJankMonitor {
    public static final int CUJ_SETTINGS_SLIDER = 53;
    public static final int CUJ_TAKE_SCREENSHOT = 54;
    public static final int CUJ_VOLUME_CONTROL = 55;
    public static final int CUJ_SETTINGS_TOGGLE = 57;

    private static final int NO_STATSD_LOGGING = -1;

@@ -262,6 +265,8 @@ public class InteractionJankMonitor {
            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_SLIDER,
            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__TAKE_SCREENSHOT,
            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__VOLUME_CONTROL,
            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION,
            UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_TOGGLE,
    };

    private static volatile InteractionJankMonitor sInstance;
@@ -338,6 +343,7 @@ public class InteractionJankMonitor {
            CUJ_SETTINGS_SLIDER,
            CUJ_TAKE_SCREENSHOT,
            CUJ_VOLUME_CONTROL,
            CUJ_SETTINGS_TOGGLE,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface CujType {
@@ -768,6 +774,8 @@ public class InteractionJankMonitor {
                return "TAKE_SCREENSHOT";
            case CUJ_VOLUME_CONTROL:
                return "VOLUME_CONTROL";
            case CUJ_SETTINGS_TOGGLE:
                return "SETTINGS_TOGGLE";
        }
        return "UNKNOWN";
    }
+13 −20
Original line number Diff line number Diff line
@@ -19,8 +19,6 @@ package com.android.settingslib;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Switch;

import androidx.annotation.Keep;
@@ -28,6 +26,7 @@ import androidx.annotation.Nullable;
import androidx.preference.PreferenceViewHolder;

import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.core.instrumentation.SettingsJankMonitor;

/**
 * A custom preference that provides inline switch toggle. It has a mandatory field for title, and
@@ -65,31 +64,25 @@ public class PrimarySwitchPreference extends RestrictedPreference {
    @Override
    public void onBindViewHolder(PreferenceViewHolder holder) {
        super.onBindViewHolder(holder);
        final View switchWidget = holder.findViewById(R.id.switchWidget);
        if (switchWidget != null) {
            switchWidget.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
        mSwitch = (Switch) holder.findViewById(R.id.switchWidget);
        if (mSwitch != null) {
            mSwitch.setOnClickListener(v -> {
                if (mSwitch != null && !mSwitch.isEnabled()) {
                    return;
                }
                    setChecked(!mChecked);
                    if (!callChangeListener(mChecked)) {
                        setChecked(!mChecked);
                    } else {
                        persistBoolean(mChecked);
                    }
                final boolean newChecked = !mChecked;
                if (callChangeListener(newChecked)) {
                    SettingsJankMonitor.detectToggleJank(getKey(), mSwitch);
                    setChecked(newChecked);
                    persistBoolean(newChecked);
                }
            });

            // Consumes move events to ignore drag actions.
            switchWidget.setOnTouchListener((v, event) -> {
            mSwitch.setOnTouchListener((v, event) -> {
                return event.getActionMasked() == MotionEvent.ACTION_MOVE;
            });
        }

        mSwitch = (Switch) holder.findViewById(R.id.switchWidget);
        if (mSwitch != null) {
            mSwitch.setContentDescription(getTitle());
            mSwitch.setChecked(mChecked);
            mSwitch.setEnabled(mEnableSwitch);
+74 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.settingslib.core.instrumentation

import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.preference.PreferenceGroupAdapter
import androidx.preference.SwitchPreference
import androidx.recyclerview.widget.RecyclerView
import com.android.internal.jank.InteractionJankMonitor
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

/**
 * Helper class for Settings library to trace jank.
 */
object SettingsJankMonitor {
    private val jankMonitor = InteractionJankMonitor.getInstance()
    private val scheduledExecutorService = Executors.newSingleThreadScheduledExecutor()

    // Switch toggle animation duration is 250ms, and there is also a ripple effect animation when
    // clicks, which duration is variable. Use 300ms here to cover.
    @VisibleForTesting
    const val MONITORED_ANIMATION_DURATION_MS = 300L

    /**
     * Detects the jank when click on a SwitchPreference.
     *
     * @param recyclerView the recyclerView contains the preference
     * @param preference the clicked preference
     */
    @JvmStatic
    fun detectSwitchPreferenceClickJank(recyclerView: RecyclerView, preference: SwitchPreference) {
        val adapter = recyclerView.adapter as? PreferenceGroupAdapter ?: return
        val adapterPosition = adapter.getPreferenceAdapterPosition(preference)
        val viewHolder = recyclerView.findViewHolderForAdapterPosition(adapterPosition) ?: return
        detectToggleJank(preference.key, viewHolder.itemView)
    }

    /**
     * Detects the animation jank on the given view.
     *
     * @param tag the tag for jank monitor
     * @param view the instrumented view
     */
    @JvmStatic
    fun detectToggleJank(tag: String?, view: View) {
        val builder = InteractionJankMonitor.Configuration.Builder.withView(
            InteractionJankMonitor.CUJ_SETTINGS_TOGGLE,
            view
        )
        if (tag != null) {
            builder.setTag(tag)
        }
        if (jankMonitor.begin(builder)) {
            scheduledExecutorService.schedule({
                jankMonitor.end(InteractionJankMonitor.CUJ_SETTINGS_TOGGLE)
            }, MONITORED_ANIMATION_DURATION_MS, TimeUnit.MILLISECONDS)
        }
    }
}
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ java_library {

    libs: [
        "Robolectric_all-target",
        "mockito-robolectric-prebuilt",
        "truth-prebuilt",
    ],
}
+3 −0
Original line number Diff line number Diff line
@@ -30,14 +30,17 @@ import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.PreferenceViewHolder;

import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowInteractionJankMonitor.class})
public class PrimarySwitchPreferenceTest {

    private Context mContext;
Loading