Merge changes from topic "accessibility1" into tm-qpr-dev
* changes: Support accessibility for battery chart (4) Support accessibility for battery chart (3) Support accessibility for battery chart (2) Support accessibility for battery chart (1)
This commit is contained in:
@@ -30,6 +30,7 @@ import android.text.format.DateFormat;
|
|||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.accessibility.AccessibilityManager;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
@@ -107,12 +108,9 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
private boolean mIs24HourFormat;
|
private boolean mIs24HourFormat;
|
||||||
private boolean mIsFooterPrefAdded = false;
|
private boolean mIsFooterPrefAdded = false;
|
||||||
private View mBatteryChartViewGroup;
|
private View mBatteryChartViewGroup;
|
||||||
|
private View mCategoryTitleView;
|
||||||
private PreferenceScreen mPreferenceScreen;
|
private PreferenceScreen mPreferenceScreen;
|
||||||
private FooterPreference mFooterPreference;
|
private FooterPreference mFooterPreference;
|
||||||
// Daily view model only saves abbreviated day of week texts (e.g. MON). This field saves the
|
|
||||||
// full day of week texts (e.g. Monday), which is used in category title and battery detail
|
|
||||||
// page.
|
|
||||||
private List<String> mDailyTimestampFullTexts;
|
|
||||||
private BatteryChartViewModel mDailyViewModel;
|
private BatteryChartViewModel mDailyViewModel;
|
||||||
private List<BatteryChartViewModel> mHourlyViewModels;
|
private List<BatteryChartViewModel> mHourlyViewModels;
|
||||||
|
|
||||||
@@ -127,6 +125,13 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
private final AnimatorListenerAdapter mHourlyChartFadeOutAdapter =
|
private final AnimatorListenerAdapter mHourlyChartFadeOutAdapter =
|
||||||
createHourlyChartAnimatorListenerAdapter(/*isToShow=*/ false);
|
createHourlyChartAnimatorListenerAdapter(/*isToShow=*/ false);
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
final DailyChartLabelTextGenerator mDailyChartLabelTextGenerator =
|
||||||
|
new DailyChartLabelTextGenerator();
|
||||||
|
@VisibleForTesting
|
||||||
|
final HourlyChartLabelTextGenerator mHourlyChartLabelTextGenerator =
|
||||||
|
new HourlyChartLabelTextGenerator();
|
||||||
|
|
||||||
// Preference cache to avoid create new instance each time.
|
// Preference cache to avoid create new instance each time.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final Map<String, Preference> mPreferenceCache = new HashMap<>();
|
final Map<String, Preference> mPreferenceCache = new HashMap<>();
|
||||||
@@ -284,29 +289,24 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
getTotalHours(batteryLevelData));
|
getTotalHours(batteryLevelData));
|
||||||
|
|
||||||
if (batteryLevelData == null) {
|
if (batteryLevelData == null) {
|
||||||
mDailyTimestampFullTexts = null;
|
|
||||||
mDailyViewModel = null;
|
mDailyViewModel = null;
|
||||||
mHourlyViewModels = null;
|
mHourlyViewModels = null;
|
||||||
refreshUi();
|
refreshUi();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mDailyTimestampFullTexts = generateTimestampDayOfWeekTexts(
|
|
||||||
mContext, batteryLevelData.getDailyBatteryLevels().getTimestamps(),
|
|
||||||
/* isAbbreviation= */ false);
|
|
||||||
mDailyViewModel = new BatteryChartViewModel(
|
mDailyViewModel = new BatteryChartViewModel(
|
||||||
batteryLevelData.getDailyBatteryLevels().getLevels(),
|
batteryLevelData.getDailyBatteryLevels().getLevels(),
|
||||||
generateTimestampDayOfWeekTexts(
|
batteryLevelData.getDailyBatteryLevels().getTimestamps(),
|
||||||
mContext, batteryLevelData.getDailyBatteryLevels().getTimestamps(),
|
BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
|
||||||
/* isAbbreviation= */ true),
|
mDailyChartLabelTextGenerator);
|
||||||
BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS);
|
|
||||||
mHourlyViewModels = new ArrayList<>();
|
mHourlyViewModels = new ArrayList<>();
|
||||||
for (BatteryLevelData.PeriodBatteryLevelData hourlyBatteryLevelsPerDay :
|
for (BatteryLevelData.PeriodBatteryLevelData hourlyBatteryLevelsPerDay :
|
||||||
batteryLevelData.getHourlyBatteryLevelsPerDay()) {
|
batteryLevelData.getHourlyBatteryLevelsPerDay()) {
|
||||||
mHourlyViewModels.add(new BatteryChartViewModel(
|
mHourlyViewModels.add(new BatteryChartViewModel(
|
||||||
hourlyBatteryLevelsPerDay.getLevels(),
|
hourlyBatteryLevelsPerDay.getLevels(),
|
||||||
generateTimestampHourTexts(
|
hourlyBatteryLevelsPerDay.getTimestamps(),
|
||||||
mContext, hourlyBatteryLevelsPerDay.getTimestamps()),
|
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
|
||||||
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
|
mHourlyChartLabelTextGenerator));
|
||||||
}
|
}
|
||||||
refreshUi();
|
refreshUi();
|
||||||
}
|
}
|
||||||
@@ -334,6 +334,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
mDailyChartIndex = trapezoidIndex;
|
mDailyChartIndex = trapezoidIndex;
|
||||||
mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
|
mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
|
||||||
refreshUi();
|
refreshUi();
|
||||||
|
requestAccessibilityFocusForCategoryTitle(mDailyChartView);
|
||||||
mMetricsFeatureProvider.action(
|
mMetricsFeatureProvider.action(
|
||||||
mPrefContext,
|
mPrefContext,
|
||||||
trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
|
trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
|
||||||
@@ -349,6 +350,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
Log.d(TAG, "onHourlyChartSelect:" + trapezoidIndex);
|
Log.d(TAG, "onHourlyChartSelect:" + trapezoidIndex);
|
||||||
mHourlyChartIndex = trapezoidIndex;
|
mHourlyChartIndex = trapezoidIndex;
|
||||||
refreshUi();
|
refreshUi();
|
||||||
|
requestAccessibilityFocusForCategoryTitle(mHourlyChartView);
|
||||||
mMetricsFeatureProvider.action(
|
mMetricsFeatureProvider.action(
|
||||||
mPrefContext,
|
mPrefContext,
|
||||||
trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
|
trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
|
||||||
@@ -532,6 +534,18 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void requestAccessibilityFocusForCategoryTitle(View view) {
|
||||||
|
if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mCategoryTitleView == null) {
|
||||||
|
mCategoryTitleView = view.getRootView().findViewById(com.android.internal.R.id.title);
|
||||||
|
}
|
||||||
|
if (mCategoryTitleView != null) {
|
||||||
|
mCategoryTitleView.requestAccessibilityFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String getSlotInformation(boolean isApp, String slotInformation) {
|
private String getSlotInformation(boolean isApp, String slotInformation) {
|
||||||
// TODO: Updates the right slot information from daily and hourly chart selection.
|
// TODO: Updates the right slot information from daily and hourly chart selection.
|
||||||
// Null means we show all information without a specific time slot.
|
// Null means we show all information without a specific time slot.
|
||||||
@@ -548,8 +562,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
String getSlotInformation() {
|
String getSlotInformation() {
|
||||||
if (mDailyTimestampFullTexts == null || mDailyViewModel == null
|
if (mDailyViewModel == null || mHourlyViewModels == null) {
|
||||||
|| mHourlyViewModels == null) {
|
|
||||||
// No data
|
// No data
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -557,17 +570,13 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String selectedDayText = mDailyTimestampFullTexts.get(mDailyChartIndex);
|
final String selectedDayText = mDailyViewModel.getFullText(mDailyChartIndex);
|
||||||
if (mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
|
if (mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
|
||||||
return selectedDayText;
|
return selectedDayText;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String fromHourText = mHourlyViewModels.get(mDailyChartIndex).texts().get(
|
final String selectedHourText = mHourlyViewModels.get(mDailyChartIndex).getFullText(
|
||||||
mHourlyChartIndex);
|
mHourlyChartIndex);
|
||||||
final String toHourText = mHourlyViewModels.get(mDailyChartIndex).texts().get(
|
|
||||||
mHourlyChartIndex + 1);
|
|
||||||
final String selectedHourText =
|
|
||||||
String.format("%s%s%s", fromHourText, mIs24HourFormat ? "-" : " - ", toHourText);
|
|
||||||
if (isBatteryLevelDataInOneDay()) {
|
if (isBatteryLevelDataInOneDay()) {
|
||||||
return selectedHourText;
|
return selectedHourText;
|
||||||
}
|
}
|
||||||
@@ -712,25 +721,6 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
/ DateUtils.HOUR_IN_MILLIS);
|
/ DateUtils.HOUR_IN_MILLIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> generateTimestampDayOfWeekTexts(@NonNull final Context context,
|
|
||||||
@NonNull final List<Long> timestamps, final boolean isAbbreviation) {
|
|
||||||
final ArrayList<String> texts = new ArrayList<>();
|
|
||||||
for (Long timestamp : timestamps) {
|
|
||||||
texts.add(ConvertUtils.utcToLocalTimeDayOfWeek(context, timestamp, isAbbreviation));
|
|
||||||
}
|
|
||||||
return texts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> generateTimestampHourTexts(
|
|
||||||
@NonNull final Context context, @NonNull final List<Long> timestamps) {
|
|
||||||
final boolean is24HourFormat = DateFormat.is24HourFormat(context);
|
|
||||||
final ArrayList<String> texts = new ArrayList<>();
|
|
||||||
for (Long timestamp : timestamps) {
|
|
||||||
texts.add(ConvertUtils.utcToLocalTimeHour(context, timestamp, is24HourFormat));
|
|
||||||
}
|
|
||||||
return texts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Used for {@link AppBatteryPreferenceController}. */
|
/** Used for {@link AppBatteryPreferenceController}. */
|
||||||
public static List<BatteryDiffEntry> getAppBatteryUsageData(Context context) {
|
public static List<BatteryDiffEntry> getAppBatteryUsageData(Context context) {
|
||||||
final long start = System.currentTimeMillis();
|
final long start = System.currentTimeMillis();
|
||||||
@@ -776,4 +766,36 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class DailyChartLabelTextGenerator implements
|
||||||
|
BatteryChartViewModel.LabelTextGenerator {
|
||||||
|
@Override
|
||||||
|
public String generateText(List<Long> timestamps, int index) {
|
||||||
|
return ConvertUtils.utcToLocalTimeDayOfWeek(mContext,
|
||||||
|
timestamps.get(index), /* isAbbreviation= */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateFullText(List<Long> timestamps, int index) {
|
||||||
|
return ConvertUtils.utcToLocalTimeDayOfWeek(mContext,
|
||||||
|
timestamps.get(index), /* isAbbreviation= */ false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class HourlyChartLabelTextGenerator implements
|
||||||
|
BatteryChartViewModel.LabelTextGenerator {
|
||||||
|
@Override
|
||||||
|
public String generateText(List<Long> timestamps, int index) {
|
||||||
|
return ConvertUtils.utcToLocalTimeHour(mContext, timestamps.get(index),
|
||||||
|
mIs24HourFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateFullText(List<Long> timestamps, int index) {
|
||||||
|
return index == timestamps.size() - 1
|
||||||
|
? generateText(timestamps, index)
|
||||||
|
: String.format("%s%s%s", generateText(timestamps, index),
|
||||||
|
mIs24HourFormat ? "-" : " - ", generateText(timestamps, index + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,6 @@ import static com.android.settings.Utils.formatPercentage;
|
|||||||
import static java.lang.Math.round;
|
import static java.lang.Math.round;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
@@ -29,34 +28,34 @@ import android.graphics.CornerPathEffect;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Handler;
|
import android.os.Bundle;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.HapticFeedbackConstants;
|
import android.view.HapticFeedbackConstants;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewParent;
|
||||||
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
import android.view.accessibility.AccessibilityNodeProvider;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.widget.AppCompatImageView;
|
import androidx.appcompat.widget.AppCompatImageView;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
|
||||||
import com.android.settingslib.Utils;
|
import com.android.settingslib.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/** A widget component to draw chart graph. */
|
/** A widget component to draw chart graph. */
|
||||||
public class BatteryChartView extends AppCompatImageView implements View.OnClickListener,
|
public class BatteryChartView extends AppCompatImageView implements View.OnClickListener {
|
||||||
AccessibilityManager.AccessibilityStateChangeListener {
|
|
||||||
private static final String TAG = "BatteryChartView";
|
private static final String TAG = "BatteryChartView";
|
||||||
private static final List<String> ACCESSIBILITY_SERVICE_NAMES =
|
|
||||||
Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService");
|
|
||||||
|
|
||||||
private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5");
|
private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5");
|
||||||
private static final long UPDATE_STATE_DELAYED_TIME = 500L;
|
private static final long UPDATE_STATE_DELAYED_TIME = 500L;
|
||||||
@@ -67,48 +66,32 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
void onSelect(int trapezoidIndex);
|
void onSelect(int trapezoidIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BatteryChartViewModel mViewModel;
|
private final String[] mPercentages = getPercentages();
|
||||||
|
private final Rect mIndent = new Rect();
|
||||||
|
private final Rect[] mPercentageBounds = new Rect[]{new Rect(), new Rect(), new Rect()};
|
||||||
|
private final List<Rect> mAxisLabelsBounds = new ArrayList<>();
|
||||||
|
|
||||||
|
private BatteryChartViewModel mViewModel;
|
||||||
|
private int mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
|
||||||
private int mDividerWidth;
|
private int mDividerWidth;
|
||||||
private int mDividerHeight;
|
private int mDividerHeight;
|
||||||
private float mTrapezoidVOffset;
|
private float mTrapezoidVOffset;
|
||||||
private float mTrapezoidHOffset;
|
private float mTrapezoidHOffset;
|
||||||
private boolean mIsSlotsClickabled;
|
|
||||||
private String[] mPercentages = getPercentages();
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
int mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
|
|
||||||
|
|
||||||
// Colors for drawing the trapezoid shape and dividers.
|
|
||||||
private int mTrapezoidColor;
|
private int mTrapezoidColor;
|
||||||
private int mTrapezoidSolidColor;
|
private int mTrapezoidSolidColor;
|
||||||
private int mTrapezoidHoverColor;
|
private int mTrapezoidHoverColor;
|
||||||
// For drawing the percentage information.
|
|
||||||
private int mTextPadding;
|
private int mTextPadding;
|
||||||
private final Rect mIndent = new Rect();
|
|
||||||
private final Rect[] mPercentageBounds =
|
|
||||||
new Rect[]{new Rect(), new Rect(), new Rect()};
|
|
||||||
// For drawing the axis label information.
|
|
||||||
private final List<Rect> mAxisLabelsBounds = new ArrayList<>();
|
|
||||||
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
Handler mHandler = new Handler();
|
|
||||||
@VisibleForTesting
|
|
||||||
final Runnable mUpdateClickableStateRun = () -> updateClickableState();
|
|
||||||
|
|
||||||
private Paint mTextPaint;
|
|
||||||
private Paint mDividerPaint;
|
private Paint mDividerPaint;
|
||||||
private Paint mTrapezoidPaint;
|
private Paint mTrapezoidPaint;
|
||||||
|
private Paint mTextPaint;
|
||||||
|
private AccessibilityNodeProvider mAccessibilityNodeProvider;
|
||||||
|
private BatteryChartView.OnSelectListener mOnSelectListener;
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
Paint mTrapezoidCurvePaint = null;
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
TrapezoidSlot[] mTrapezoidSlots;
|
TrapezoidSlot[] mTrapezoidSlots;
|
||||||
// Records the location to calculate selected index.
|
// Records the location to calculate selected index.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
float mTouchUpEventX = Float.MIN_VALUE;
|
float mTouchUpEventX = Float.MIN_VALUE;
|
||||||
private BatteryChartView.OnSelectListener mOnSelectListener;
|
|
||||||
|
|
||||||
public BatteryChartView(Context context) {
|
public BatteryChartView(Context context) {
|
||||||
super(context, null);
|
super(context, null);
|
||||||
@@ -175,7 +158,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
if (mViewModel != null) {
|
if (mViewModel != null) {
|
||||||
int maxTop = 0;
|
int maxTop = 0;
|
||||||
for (int index = 0; index < mViewModel.size(); index++) {
|
for (int index = 0; index < mViewModel.size(); index++) {
|
||||||
final String text = mViewModel.texts().get(index);
|
final String text = mViewModel.getText(index);
|
||||||
mTextPaint.getTextBounds(text, 0, text.length(), mAxisLabelsBounds.get(index));
|
mTextPaint.getTextBounds(text, 0, text.length(), mAxisLabelsBounds.get(index));
|
||||||
maxTop = Math.max(maxTop, -mAxisLabelsBounds.get(index).top);
|
maxTop = Math.max(maxTop, -mAxisLabelsBounds.get(index).top);
|
||||||
}
|
}
|
||||||
@@ -225,10 +208,23 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
if (mHoveredIndex != trapezoidIndex) {
|
if (mHoveredIndex != trapezoidIndex) {
|
||||||
mHoveredIndex = trapezoidIndex;
|
mHoveredIndex = trapezoidIndex;
|
||||||
invalidate();
|
invalidate();
|
||||||
|
sendAccessibilityEventForHover(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
|
||||||
}
|
}
|
||||||
break;
|
// Ignore the super.onHoverEvent() because the hovered trapezoid has already been
|
||||||
|
// sent here.
|
||||||
|
return true;
|
||||||
|
case MotionEvent.ACTION_HOVER_EXIT:
|
||||||
|
if (mHoveredIndex != BatteryChartViewModel.SELECTED_INDEX_INVALID) {
|
||||||
|
sendAccessibilityEventForHover(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
|
||||||
|
mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID; // reset
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
// Ignore the super.onHoverEvent() because the hovered trapezoid has already been
|
||||||
|
// sent here.
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return super.onTouchEvent(event);
|
||||||
}
|
}
|
||||||
return super.onHoverEvent(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -246,79 +242,51 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
Log.w(TAG, "invalid motion event for onClick() callback");
|
Log.w(TAG, "invalid motion event for onClick() callback");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final int trapezoidIndex = getTrapezoidIndex(mTouchUpEventX);
|
onTrapezoidClicked(view, getTrapezoidIndex(mTouchUpEventX));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccessibilityNodeProvider getAccessibilityNodeProvider() {
|
||||||
|
if (mViewModel == null) {
|
||||||
|
return super.getAccessibilityNodeProvider();
|
||||||
|
}
|
||||||
|
if (mAccessibilityNodeProvider == null) {
|
||||||
|
mAccessibilityNodeProvider = new BatteryChartAccessibilityNodeProvider();
|
||||||
|
}
|
||||||
|
return mAccessibilityNodeProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onTrapezoidClicked(View view, int index) {
|
||||||
// Ignores the click event if the level is zero.
|
// Ignores the click event if the level is zero.
|
||||||
if (trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_INVALID
|
if (!isValidToDraw(mViewModel, index)) {
|
||||||
|| !isValidToDraw(mViewModel, trapezoidIndex)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mOnSelectListener != null) {
|
if (mOnSelectListener != null) {
|
||||||
// Selects all if users click the same trapezoid item two times.
|
// Selects all if users click the same trapezoid item two times.
|
||||||
mOnSelectListener.onSelect(
|
mOnSelectListener.onSelect(
|
||||||
trapezoidIndex == mViewModel.selectedIndex()
|
index == mViewModel.selectedIndex()
|
||||||
? BatteryChartViewModel.SELECTED_INDEX_ALL : trapezoidIndex);
|
? BatteryChartViewModel.SELECTED_INDEX_ALL : index);
|
||||||
}
|
}
|
||||||
view.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
|
view.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private boolean sendAccessibilityEvent(int virtualDescendantId, int eventType) {
|
||||||
public void onAttachedToWindow() {
|
ViewParent parent = getParent();
|
||||||
super.onAttachedToWindow();
|
if (parent == null || !AccessibilityManager.getInstance(mContext).isEnabled()) {
|
||||||
updateClickableState();
|
return false;
|
||||||
mContext.getSystemService(AccessibilityManager.class)
|
|
||||||
.addAccessibilityStateChangeListener(/*listener=*/ this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDetachedFromWindow() {
|
|
||||||
super.onDetachedFromWindow();
|
|
||||||
mContext.getSystemService(AccessibilityManager.class)
|
|
||||||
.removeAccessibilityStateChangeListener(/*listener=*/ this);
|
|
||||||
mHandler.removeCallbacks(mUpdateClickableStateRun);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAccessibilityStateChanged(boolean enabled) {
|
|
||||||
Log.d(TAG, "onAccessibilityStateChanged:" + enabled);
|
|
||||||
mHandler.removeCallbacks(mUpdateClickableStateRun);
|
|
||||||
// We should delay it a while since accessibility manager will spend
|
|
||||||
// some times to bind with new enabled accessibility services.
|
|
||||||
mHandler.postDelayed(
|
|
||||||
mUpdateClickableStateRun, UPDATE_STATE_DELAYED_TIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateClickableState() {
|
|
||||||
final Context context = mContext;
|
|
||||||
mIsSlotsClickabled =
|
|
||||||
FeatureFactory.getFactory(context)
|
|
||||||
.getPowerUsageFeatureProvider(context)
|
|
||||||
.isChartGraphSlotsEnabled(context)
|
|
||||||
&& !isAccessibilityEnabled(context);
|
|
||||||
Log.d(TAG, "isChartGraphSlotsEnabled:" + mIsSlotsClickabled);
|
|
||||||
setClickable(isClickable());
|
|
||||||
// Initializes the trapezoid curve paint for non-clickable case.
|
|
||||||
if (!mIsSlotsClickabled && mTrapezoidCurvePaint == null) {
|
|
||||||
mTrapezoidCurvePaint = new Paint();
|
|
||||||
mTrapezoidCurvePaint.setAntiAlias(true);
|
|
||||||
mTrapezoidCurvePaint.setColor(mTrapezoidSolidColor);
|
|
||||||
mTrapezoidCurvePaint.setStyle(Paint.Style.STROKE);
|
|
||||||
mTrapezoidCurvePaint.setStrokeWidth(mDividerWidth * 2);
|
|
||||||
} else if (mIsSlotsClickabled) {
|
|
||||||
mTrapezoidCurvePaint = null;
|
|
||||||
// Sets view model again to force update the click state.
|
|
||||||
setViewModel(mViewModel);
|
|
||||||
}
|
}
|
||||||
invalidate();
|
AccessibilityEvent accessibilityEvent = new AccessibilityEvent(eventType);
|
||||||
|
accessibilityEvent.setSource(this, virtualDescendantId);
|
||||||
|
accessibilityEvent.setEnabled(true);
|
||||||
|
accessibilityEvent.setClassName(getAccessibilityClassName());
|
||||||
|
accessibilityEvent.setPackageName(getContext().getPackageName());
|
||||||
|
return parent.requestSendAccessibilityEvent(this, accessibilityEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void sendAccessibilityEventForHover(int eventType) {
|
||||||
public void setClickable(boolean clickable) {
|
if (isTrapezoidIndexValid(mViewModel, mHoveredIndex)) {
|
||||||
super.setClickable(mIsSlotsClickabled && clickable);
|
sendAccessibilityEvent(mHoveredIndex, eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
void setClickableForce(boolean clickable) {
|
|
||||||
super.setClickable(clickable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTrapezoidSlots(int count) {
|
private void initializeTrapezoidSlots(int count) {
|
||||||
@@ -522,7 +490,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
Canvas canvas, final int index, final Rect displayArea, final float baselineY) {
|
Canvas canvas, final int index, final Rect displayArea, final float baselineY) {
|
||||||
mTextPaint.setTextAlign(Paint.Align.CENTER);
|
mTextPaint.setTextAlign(Paint.Align.CENTER);
|
||||||
canvas.drawText(
|
canvas.drawText(
|
||||||
mViewModel.texts().get(index),
|
mViewModel.getText(index),
|
||||||
displayArea.centerX(),
|
displayArea.centerX(),
|
||||||
baselineY,
|
baselineY,
|
||||||
mTextPaint);
|
mTextPaint);
|
||||||
@@ -545,25 +513,20 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
for (int index = 0; index < mTrapezoidSlots.length; index++) {
|
for (int index = 0; index < mTrapezoidSlots.length; index++) {
|
||||||
// Not draws the trapezoid for corner or not initialization cases.
|
// Not draws the trapezoid for corner or not initialization cases.
|
||||||
if (!isValidToDraw(mViewModel, index)) {
|
if (!isValidToDraw(mViewModel, index)) {
|
||||||
if (mTrapezoidCurvePaint != null && trapezoidCurvePath != null) {
|
|
||||||
canvas.drawPath(trapezoidCurvePath, mTrapezoidCurvePaint);
|
|
||||||
trapezoidCurvePath = null;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Configures the trapezoid paint color.
|
// Configures the trapezoid paint color.
|
||||||
final int trapezoidColor = mIsSlotsClickabled && (mViewModel.selectedIndex() == index
|
final int trapezoidColor = (mViewModel.selectedIndex() == index
|
||||||
|| mViewModel.selectedIndex() == BatteryChartViewModel.SELECTED_INDEX_ALL)
|
|| mViewModel.selectedIndex() == BatteryChartViewModel.SELECTED_INDEX_ALL)
|
||||||
? mTrapezoidSolidColor : mTrapezoidColor;
|
? mTrapezoidSolidColor : mTrapezoidColor;
|
||||||
final boolean isHoverState =
|
final boolean isHoverState = mHoveredIndex == index && isValidToDraw(mViewModel,
|
||||||
mIsSlotsClickabled && mHoveredIndex == index
|
mHoveredIndex);
|
||||||
&& isValidToDraw(mViewModel, mHoveredIndex);
|
|
||||||
mTrapezoidPaint.setColor(isHoverState ? mTrapezoidHoverColor : trapezoidColor);
|
mTrapezoidPaint.setColor(isHoverState ? mTrapezoidHoverColor : trapezoidColor);
|
||||||
|
|
||||||
final float leftTop = round(
|
final float leftTop = round(
|
||||||
trapezoidBottom - requireNonNull(mViewModel.levels().get(index)) * unitHeight);
|
trapezoidBottom - requireNonNull(mViewModel.getLevel(index)) * unitHeight);
|
||||||
final float rightTop = round(trapezoidBottom
|
final float rightTop = round(trapezoidBottom
|
||||||
- requireNonNull(mViewModel.levels().get(index + 1)) * unitHeight);
|
- requireNonNull(mViewModel.getLevel(index + 1)) * unitHeight);
|
||||||
trapezoidPath.reset();
|
trapezoidPath.reset();
|
||||||
trapezoidPath.moveTo(mTrapezoidSlots[index].mLeft, trapezoidBottom);
|
trapezoidPath.moveTo(mTrapezoidSlots[index].mLeft, trapezoidBottom);
|
||||||
trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
|
trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
|
||||||
@@ -574,22 +537,6 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
|
trapezoidPath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
|
||||||
// Draws the trapezoid shape into canvas.
|
// Draws the trapezoid shape into canvas.
|
||||||
canvas.drawPath(trapezoidPath, mTrapezoidPaint);
|
canvas.drawPath(trapezoidPath, mTrapezoidPaint);
|
||||||
|
|
||||||
// Generates path for non-clickable trapezoid curve.
|
|
||||||
if (mTrapezoidCurvePaint != null) {
|
|
||||||
if (trapezoidCurvePath == null) {
|
|
||||||
trapezoidCurvePath = new Path();
|
|
||||||
trapezoidCurvePath.moveTo(mTrapezoidSlots[index].mLeft, leftTop);
|
|
||||||
} else {
|
|
||||||
trapezoidCurvePath.lineTo(mTrapezoidSlots[index].mLeft, leftTop);
|
|
||||||
}
|
|
||||||
trapezoidCurvePath.lineTo(mTrapezoidSlots[index].mRight, rightTop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Draws the trapezoid curve for non-clickable case.
|
|
||||||
if (mTrapezoidCurvePaint != null && trapezoidCurvePath != null) {
|
|
||||||
canvas.drawPath(trapezoidCurvePath, mTrapezoidCurvePaint);
|
|
||||||
trapezoidCurvePath = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,14 +564,19 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
|
|
||||||
private static boolean isTrapezoidValid(
|
private static boolean isTrapezoidValid(
|
||||||
@NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
|
@NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
|
||||||
return viewModel.levels().get(trapezoidIndex) != null
|
return viewModel.getLevel(trapezoidIndex) != null
|
||||||
&& viewModel.levels().get(trapezoidIndex + 1) != null;
|
&& viewModel.getLevel(trapezoidIndex + 1) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isTrapezoidIndexValid(
|
||||||
|
@NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
|
||||||
|
return viewModel != null
|
||||||
|
&& trapezoidIndex >= 0
|
||||||
|
&& trapezoidIndex < viewModel.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValidToDraw(BatteryChartViewModel viewModel, int trapezoidIndex) {
|
private static boolean isValidToDraw(BatteryChartViewModel viewModel, int trapezoidIndex) {
|
||||||
return viewModel != null
|
return isTrapezoidIndexValid(viewModel, trapezoidIndex)
|
||||||
&& trapezoidIndex >= 0
|
|
||||||
&& trapezoidIndex < viewModel.size() - 1
|
|
||||||
&& isTrapezoidValid(viewModel, trapezoidIndex);
|
&& isTrapezoidValid(viewModel, trapezoidIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,27 +597,61 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
formatPercentage(/*percentage=*/ 0, /*round=*/ true)};
|
formatPercentage(/*percentage=*/ 0, /*round=*/ true)};
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
private class BatteryChartAccessibilityNodeProvider extends AccessibilityNodeProvider {
|
||||||
static boolean isAccessibilityEnabled(Context context) {
|
@Override
|
||||||
final AccessibilityManager accessibilityManager =
|
public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
|
||||||
context.getSystemService(AccessibilityManager.class);
|
if (virtualViewId == AccessibilityNodeProvider.HOST_VIEW_ID) {
|
||||||
if (!accessibilityManager.isEnabled()) {
|
final AccessibilityNodeInfo hostInfo =
|
||||||
return false;
|
new AccessibilityNodeInfo(BatteryChartView.this);
|
||||||
}
|
for (int index = 0; index < mViewModel.size() - 1; index++) {
|
||||||
final List<AccessibilityServiceInfo> serviceInfoList =
|
hostInfo.addChild(BatteryChartView.this, index);
|
||||||
accessibilityManager.getEnabledAccessibilityServiceList(
|
|
||||||
AccessibilityServiceInfo.FEEDBACK_SPOKEN
|
|
||||||
| AccessibilityServiceInfo.FEEDBACK_GENERIC);
|
|
||||||
for (AccessibilityServiceInfo info : serviceInfoList) {
|
|
||||||
for (String serviceName : ACCESSIBILITY_SERVICE_NAMES) {
|
|
||||||
final String serviceId = info.getId();
|
|
||||||
if (serviceId != null && serviceId.contains(serviceName)) {
|
|
||||||
Log.d(TAG, "acccessibilityEnabled:" + serviceId);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return hostInfo;
|
||||||
|
}
|
||||||
|
final int index = virtualViewId;
|
||||||
|
if (!isTrapezoidIndexValid(mViewModel, index)) {
|
||||||
|
Log.w(TAG, "Invalid virtual view id:" + index);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final AccessibilityNodeInfo childInfo =
|
||||||
|
new AccessibilityNodeInfo(BatteryChartView.this, index);
|
||||||
|
onInitializeAccessibilityNodeInfo(childInfo);
|
||||||
|
childInfo.setClickable(isValidToDraw(mViewModel, index));
|
||||||
|
childInfo.setText(mViewModel.getFullText(index));
|
||||||
|
childInfo.setContentDescription(mViewModel.getFullText(index));
|
||||||
|
|
||||||
|
final Rect bounds = new Rect();
|
||||||
|
getBoundsOnScreen(bounds, true);
|
||||||
|
final int hostLeft = bounds.left;
|
||||||
|
bounds.left = round(hostLeft + mTrapezoidSlots[index].mLeft);
|
||||||
|
bounds.right = round(hostLeft + mTrapezoidSlots[index].mRight);
|
||||||
|
childInfo.setBoundsInScreen(bounds);
|
||||||
|
return childInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performAction(int virtualViewId, int action,
|
||||||
|
@Nullable Bundle arguments) {
|
||||||
|
if (virtualViewId == AccessibilityNodeProvider.HOST_VIEW_ID) {
|
||||||
|
return performAccessibilityAction(action, arguments);
|
||||||
|
}
|
||||||
|
switch (action) {
|
||||||
|
case AccessibilityNodeInfo.ACTION_CLICK:
|
||||||
|
onTrapezoidClicked(BatteryChartView.this, virtualViewId);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
|
||||||
|
return sendAccessibilityEvent(virtualViewId,
|
||||||
|
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
|
||||||
|
|
||||||
|
case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
|
||||||
|
return sendAccessibilityEvent(virtualViewId,
|
||||||
|
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return performAccessibilityAction(action, arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A container class for each trapezoid left and right location.
|
// A container class for each trapezoid left and right location.
|
||||||
|
@@ -19,6 +19,7 @@ package com.android.settings.fuelgauge.batteryusage;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.util.Preconditions;
|
import androidx.core.util.Preconditions;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -38,34 +39,59 @@ class BatteryChartViewModel {
|
|||||||
CENTER_OF_TRAPEZOIDS,
|
CENTER_OF_TRAPEZOIDS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LabelTextGenerator {
|
||||||
|
/** Generate the label text. The text may be abbreviated to save space. */
|
||||||
|
String generateText(List<Long> timestamps, int index);
|
||||||
|
|
||||||
|
/** Generate the full text for accessibility. */
|
||||||
|
String generateFullText(List<Long> timestamps, int index);
|
||||||
|
}
|
||||||
|
|
||||||
private final List<Integer> mLevels;
|
private final List<Integer> mLevels;
|
||||||
private final List<String> mTexts;
|
private final List<Long> mTimestamps;
|
||||||
private final AxisLabelPosition mAxisLabelPosition;
|
private final AxisLabelPosition mAxisLabelPosition;
|
||||||
|
private final LabelTextGenerator mLabelTextGenerator;
|
||||||
|
private final String[] mTexts;
|
||||||
|
private final String[] mFullTexts;
|
||||||
|
|
||||||
private int mSelectedIndex = SELECTED_INDEX_ALL;
|
private int mSelectedIndex = SELECTED_INDEX_ALL;
|
||||||
|
|
||||||
BatteryChartViewModel(
|
BatteryChartViewModel(@NonNull List<Integer> levels, @NonNull List<Long> timestamps,
|
||||||
@NonNull List<Integer> levels, @NonNull List<String> texts,
|
@NonNull AxisLabelPosition axisLabelPosition,
|
||||||
@NonNull AxisLabelPosition axisLabelPosition) {
|
@NonNull LabelTextGenerator labelTextGenerator) {
|
||||||
Preconditions.checkArgument(
|
Preconditions.checkArgument(
|
||||||
levels.size() == texts.size() && levels.size() >= MIN_LEVELS_DATA_SIZE,
|
levels.size() == timestamps.size() && levels.size() >= MIN_LEVELS_DATA_SIZE,
|
||||||
String.format(Locale.ENGLISH,
|
String.format(Locale.ENGLISH,
|
||||||
"Invalid BatteryChartViewModel levels.size: %d, texts.size: %d.",
|
"Invalid BatteryChartViewModel levels.size: %d, timestamps.size: %d.",
|
||||||
levels.size(), texts.size()));
|
levels.size(), timestamps.size()));
|
||||||
mLevels = levels;
|
mLevels = levels;
|
||||||
mTexts = texts;
|
mTimestamps = timestamps;
|
||||||
mAxisLabelPosition = axisLabelPosition;
|
mAxisLabelPosition = axisLabelPosition;
|
||||||
|
mLabelTextGenerator = labelTextGenerator;
|
||||||
|
mTexts = new String[size()];
|
||||||
|
mFullTexts = new String[size()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
return mLevels.size();
|
return mLevels.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Integer> levels() {
|
public Integer getLevel(int index) {
|
||||||
return mLevels;
|
return mLevels.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> texts() {
|
public String getText(int index) {
|
||||||
return mTexts;
|
if (mTexts[index] == null) {
|
||||||
|
mTexts[index] = mLabelTextGenerator.generateText(mTimestamps, index);
|
||||||
|
}
|
||||||
|
return mTexts[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullText(int index) {
|
||||||
|
if (mFullTexts[index] == null) {
|
||||||
|
mFullTexts[index] = mLabelTextGenerator.generateFullText(mTimestamps, index);
|
||||||
|
}
|
||||||
|
return mFullTexts[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
public AxisLabelPosition axisLabelPosition() {
|
public AxisLabelPosition axisLabelPosition() {
|
||||||
@@ -82,7 +108,7 @@ class BatteryChartViewModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(mLevels, mTexts, mSelectedIndex, mAxisLabelPosition);
|
return Objects.hash(mLevels, mTimestamps, mSelectedIndex, mAxisLabelPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,16 +120,26 @@ class BatteryChartViewModel {
|
|||||||
}
|
}
|
||||||
final BatteryChartViewModel batteryChartViewModel = (BatteryChartViewModel) other;
|
final BatteryChartViewModel batteryChartViewModel = (BatteryChartViewModel) other;
|
||||||
return Objects.equals(mLevels, batteryChartViewModel.mLevels)
|
return Objects.equals(mLevels, batteryChartViewModel.mLevels)
|
||||||
&& Objects.equals(mTexts, batteryChartViewModel.mTexts)
|
&& Objects.equals(mTimestamps, batteryChartViewModel.mTimestamps)
|
||||||
&& mAxisLabelPosition == batteryChartViewModel.mAxisLabelPosition
|
&& mAxisLabelPosition == batteryChartViewModel.mAxisLabelPosition
|
||||||
&& mSelectedIndex == batteryChartViewModel.mSelectedIndex;
|
&& mSelectedIndex == batteryChartViewModel.mSelectedIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(Locale.ENGLISH,
|
// Generate all the texts and full texts.
|
||||||
"levels: %s,\ntexts: %s,\naxisLabelPosition: %s, selectedIndex: %d",
|
for (int i = 0; i < size(); i++) {
|
||||||
Objects.toString(mLevels), Objects.toString(mTexts), mAxisLabelPosition,
|
getText(i);
|
||||||
mSelectedIndex);
|
getFullText(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StringBuilder()
|
||||||
|
.append("levels: " + Objects.toString(mLevels))
|
||||||
|
.append(", timestamps: " + Objects.toString(mTimestamps))
|
||||||
|
.append(", texts: " + Arrays.toString(mTexts))
|
||||||
|
.append(", fullTexts: " + Arrays.toString(mFullTexts))
|
||||||
|
.append(", axisLabelPosition: " + mAxisLabelPosition)
|
||||||
|
.append(", selectedIndex: " + mSelectedIndex)
|
||||||
|
.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,7 @@ package com.android.settings.fuelgauge.batteryusage;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.atLeast;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@@ -173,22 +174,33 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setBatteryChartViewModel_6Hours() {
|
public void setBatteryChartViewModel_6Hours() {
|
||||||
|
reset(mHourlyChartView);
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
|
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
|
||||||
|
|
||||||
verify(mDailyChartView, atLeastOnce()).setVisibility(View.GONE);
|
verify(mDailyChartView, atLeastOnce()).setVisibility(View.GONE);
|
||||||
verify(mHourlyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
|
verify(mHourlyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
|
||||||
verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
|
// Ignore fast refresh ui from the data processor callback.
|
||||||
|
verify(mHourlyChartView, atLeast(0)).setViewModel(null);
|
||||||
|
verify(mHourlyChartView, atLeastOnce()).setViewModel(new BatteryChartViewModel(
|
||||||
List.of(100, 97, 95),
|
List.of(100, 97, 95),
|
||||||
List.of("8 AM", "10 AM", "12 PM"),
|
List.of(1619251200000L /* 8 AM */,
|
||||||
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
|
1619258400000L /* 10 AM */,
|
||||||
|
1619265600000L /* 12 PM */),
|
||||||
|
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
|
||||||
|
mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setBatteryChartViewModel_60Hours() {
|
public void setBatteryChartViewModel_60Hours() {
|
||||||
BatteryChartViewModel expectedDailyViewModel = new BatteryChartViewModel(
|
BatteryChartViewModel expectedDailyViewModel = new BatteryChartViewModel(
|
||||||
List.of(100, 83, 59, 41),
|
List.of(100, 83, 59, 41),
|
||||||
List.of("Sat", "Sun", "Mon", "Mon"),
|
// "Sat", "Sun", "Mon", "Mon"
|
||||||
BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS);
|
List.of(1619251200000L /* Sat */,
|
||||||
|
1619308800000L /* Sun */,
|
||||||
|
1619395200000L /* Mon */,
|
||||||
|
1619460000000L /* Mon */),
|
||||||
|
BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
|
||||||
|
mBatteryChartPreferenceController.mDailyChartLabelTextGenerator);
|
||||||
|
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
|
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
|
||||||
|
|
||||||
@@ -208,9 +220,17 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
verify(mDailyChartView).setViewModel(expectedDailyViewModel);
|
verify(mDailyChartView).setViewModel(expectedDailyViewModel);
|
||||||
verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
|
verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
|
||||||
List.of(100, 97, 95, 93, 91, 89, 87, 85, 83),
|
List.of(100, 97, 95, 93, 91, 89, 87, 85, 83),
|
||||||
List.of("8 AM", "10 AM", "12 PM", "2 PM", "4 PM", "6 PM", "8 PM", "10 PM",
|
List.of(1619251200000L /* 8 AM */,
|
||||||
"12 AM"),
|
1619258400000L /* 10 AM */,
|
||||||
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
|
1619265600000L /* 12 PM */,
|
||||||
|
1619272800000L /* 2 PM */,
|
||||||
|
1619280000000L /* 4 PM */,
|
||||||
|
1619287200000L /* 6 PM */,
|
||||||
|
1619294400000L /* 8 PM */,
|
||||||
|
1619301600000L /* 10 PM */,
|
||||||
|
1619308800000L /* 12 AM */),
|
||||||
|
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
|
||||||
|
mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
|
||||||
|
|
||||||
reset(mDailyChartView);
|
reset(mDailyChartView);
|
||||||
reset(mHourlyChartView);
|
reset(mHourlyChartView);
|
||||||
@@ -224,9 +244,21 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
verify(mDailyChartView).setViewModel(expectedDailyViewModel);
|
verify(mDailyChartView).setViewModel(expectedDailyViewModel);
|
||||||
BatteryChartViewModel expectedHourlyViewModel = new BatteryChartViewModel(
|
BatteryChartViewModel expectedHourlyViewModel = new BatteryChartViewModel(
|
||||||
List.of(83, 81, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 59),
|
List.of(83, 81, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 59),
|
||||||
List.of("12 AM", "2 AM", "4 AM", "6 AM", "8 AM", "10 AM", "12 PM", "2 PM",
|
List.of(1619308800000L /* 12 AM */,
|
||||||
"4 PM", "6 PM", "8 PM", "10 PM", "12 AM"),
|
1619316000000L /* 2 AM */,
|
||||||
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS);
|
1619323200000L /* 4 AM */,
|
||||||
|
1619330400000L /* 6 AM */,
|
||||||
|
1619337600000L /* 8 AM */,
|
||||||
|
1619344800000L /* 10 AM */,
|
||||||
|
1619352000000L /* 12 PM */,
|
||||||
|
1619359200000L /* 2 PM */,
|
||||||
|
1619366400000L /* 4 PM */,
|
||||||
|
1619373600000L /* 6 PM */,
|
||||||
|
1619380800000L /* 8 PM */,
|
||||||
|
1619388000000L /* 10 PM */,
|
||||||
|
1619395200000L /* 12 AM */),
|
||||||
|
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
|
||||||
|
mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator);
|
||||||
expectedHourlyViewModel.setSelectedIndex(6);
|
expectedHourlyViewModel.setSelectedIndex(6);
|
||||||
verify(mHourlyChartView).setViewModel(expectedHourlyViewModel);
|
verify(mHourlyChartView).setViewModel(expectedHourlyViewModel);
|
||||||
|
|
||||||
@@ -243,9 +275,18 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
verify(mDailyChartView).setViewModel(expectedDailyViewModel);
|
verify(mDailyChartView).setViewModel(expectedDailyViewModel);
|
||||||
verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
|
verify(mHourlyChartView).setViewModel(new BatteryChartViewModel(
|
||||||
List.of(59, 57, 55, 53, 51, 49, 47, 45, 43, 41),
|
List.of(59, 57, 55, 53, 51, 49, 47, 45, 43, 41),
|
||||||
List.of("12 AM", "2 AM", "4 AM", "6 AM", "8 AM", "10 AM", "12 PM", "2 PM",
|
List.of(1619395200000L /* 12 AM */,
|
||||||
"4 PM", "6 PM"),
|
1619402400000L /* 2 AM */,
|
||||||
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
|
1619409600000L /* 4 AM */,
|
||||||
|
1619416800000L /* 6 AM */,
|
||||||
|
1619424000000L /* 8 AM */,
|
||||||
|
1619431200000L /* 10 AM */,
|
||||||
|
1619438400000L /* 12 PM */,
|
||||||
|
1619445600000L /* 2 PM */,
|
||||||
|
1619452800000L /* 4 PM */,
|
||||||
|
1619460000000L /* 6 PM */),
|
||||||
|
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
|
||||||
|
mBatteryChartPreferenceController.mHourlyChartLabelTextGenerator));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -17,17 +17,11 @@ package com.android.settings.fuelgauge.batteryusage;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.Mockito.doReturn;
|
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.LocaleList;
|
import android.os.LocaleList;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
|
||||||
|
|
||||||
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
|
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
@@ -40,8 +34,6 @@ import org.mockito.MockitoAnnotations;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -53,10 +45,6 @@ public final class BatteryChartViewTest {
|
|||||||
private FakeFeatureFactory mFeatureFactory;
|
private FakeFeatureFactory mFeatureFactory;
|
||||||
private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
|
private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
|
||||||
|
|
||||||
@Mock
|
|
||||||
private AccessibilityServiceInfo mMockAccessibilityServiceInfo;
|
|
||||||
@Mock
|
|
||||||
private AccessibilityManager mMockAccessibilityManager;
|
|
||||||
@Mock
|
@Mock
|
||||||
private View mMockView;
|
private View mMockView;
|
||||||
|
|
||||||
@@ -69,42 +57,14 @@ public final class BatteryChartViewTest {
|
|||||||
mContext.getResources().getConfiguration().setLocales(
|
mContext.getResources().getConfiguration().setLocales(
|
||||||
new LocaleList(new Locale("en_US")));
|
new LocaleList(new Locale("en_US")));
|
||||||
mBatteryChartView = new BatteryChartView(mContext);
|
mBatteryChartView = new BatteryChartView(mContext);
|
||||||
doReturn(mMockAccessibilityManager).when(mContext)
|
|
||||||
.getSystemService(AccessibilityManager.class);
|
|
||||||
doReturn("TalkBackService").when(mMockAccessibilityServiceInfo).getId();
|
|
||||||
doReturn(Arrays.asList(mMockAccessibilityServiceInfo))
|
|
||||||
.when(mMockAccessibilityManager)
|
|
||||||
.getEnabledAccessibilityServiceList(anyInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isAccessibilityEnabled_disable_returnFalse() {
|
|
||||||
doReturn(false).when(mMockAccessibilityManager).isEnabled();
|
|
||||||
assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isAccessibilityEnabled_emptyInfo_returnFalse() {
|
|
||||||
doReturn(true).when(mMockAccessibilityManager).isEnabled();
|
|
||||||
doReturn(new ArrayList<AccessibilityServiceInfo>())
|
|
||||||
.when(mMockAccessibilityManager)
|
|
||||||
.getEnabledAccessibilityServiceList(anyInt());
|
|
||||||
|
|
||||||
assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isAccessibilityEnabled_validServiceId_returnTrue() {
|
|
||||||
doReturn(true).when(mMockAccessibilityManager).isEnabled();
|
|
||||||
assertThat(BatteryChartView.isAccessibilityEnabled(mContext)).isTrue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onClick_invokesCallback() {
|
public void onClick_invokesCallback() {
|
||||||
final int originalSelectedIndex = 2;
|
final int originalSelectedIndex = 2;
|
||||||
BatteryChartViewModel batteryChartViewModel = new BatteryChartViewModel(
|
BatteryChartViewModel batteryChartViewModel = new BatteryChartViewModel(
|
||||||
List.of(90, 80, 70, 60), List.of("", "", "", ""),
|
List.of(90, 80, 70, 60), List.of(0L, 0L, 0L, 0L),
|
||||||
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS);
|
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS, null);
|
||||||
batteryChartViewModel.setSelectedIndex(originalSelectedIndex);
|
batteryChartViewModel.setSelectedIndex(originalSelectedIndex);
|
||||||
mBatteryChartView.setViewModel(batteryChartViewModel);
|
mBatteryChartView.setViewModel(batteryChartViewModel);
|
||||||
for (int i = 0; i < mBatteryChartView.mTrapezoidSlots.length; i++) {
|
for (int i = 0; i < mBatteryChartView.mTrapezoidSlots.length; i++) {
|
||||||
@@ -130,116 +90,4 @@ public final class BatteryChartViewTest {
|
|||||||
mBatteryChartView.onClick(mMockView);
|
mBatteryChartView.onClick(mMockView);
|
||||||
assertThat(selectedIndex[0]).isEqualTo(BatteryChartViewModel.SELECTED_INDEX_ALL);
|
assertThat(selectedIndex[0]).isEqualTo(BatteryChartViewModel.SELECTED_INDEX_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void clickable_isChartGraphSlotsEnabledIsFalse_notClickable() {
|
|
||||||
mBatteryChartView.setClickableForce(true);
|
|
||||||
when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
|
|
||||||
.thenReturn(false);
|
|
||||||
|
|
||||||
mBatteryChartView.onAttachedToWindow();
|
|
||||||
|
|
||||||
assertThat(mBatteryChartView.isClickable()).isFalse();
|
|
||||||
assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void clickable_accessibilityIsDisabled_clickable() {
|
|
||||||
mBatteryChartView.setClickableForce(true);
|
|
||||||
when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
|
|
||||||
.thenReturn(true);
|
|
||||||
doReturn(false).when(mMockAccessibilityManager).isEnabled();
|
|
||||||
|
|
||||||
mBatteryChartView.onAttachedToWindow();
|
|
||||||
|
|
||||||
assertThat(mBatteryChartView.isClickable()).isTrue();
|
|
||||||
assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void clickable_accessibilityIsEnabledWithoutValidId_clickable() {
|
|
||||||
mBatteryChartView.setClickableForce(true);
|
|
||||||
when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
|
|
||||||
.thenReturn(true);
|
|
||||||
doReturn(true).when(mMockAccessibilityManager).isEnabled();
|
|
||||||
doReturn(new ArrayList<AccessibilityServiceInfo>())
|
|
||||||
.when(mMockAccessibilityManager)
|
|
||||||
.getEnabledAccessibilityServiceList(anyInt());
|
|
||||||
|
|
||||||
mBatteryChartView.onAttachedToWindow();
|
|
||||||
|
|
||||||
assertThat(mBatteryChartView.isClickable()).isTrue();
|
|
||||||
assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void clickable_accessibilityIsEnabledWithValidId_notClickable() {
|
|
||||||
mBatteryChartView.setClickableForce(true);
|
|
||||||
when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
|
|
||||||
.thenReturn(true);
|
|
||||||
doReturn(true).when(mMockAccessibilityManager).isEnabled();
|
|
||||||
|
|
||||||
mBatteryChartView.onAttachedToWindow();
|
|
||||||
|
|
||||||
assertThat(mBatteryChartView.isClickable()).isFalse();
|
|
||||||
assertThat(mBatteryChartView.mTrapezoidCurvePaint).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void clickable_restoreFromNonClickableState() {
|
|
||||||
final List<Integer> levels = new ArrayList<Integer>();
|
|
||||||
final List<String> texts = new ArrayList<String>();
|
|
||||||
for (int index = 0; index < 13; index++) {
|
|
||||||
levels.add(index + 1);
|
|
||||||
texts.add("");
|
|
||||||
}
|
|
||||||
mBatteryChartView.setViewModel(new BatteryChartViewModel(levels, texts,
|
|
||||||
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS));
|
|
||||||
mBatteryChartView.setClickableForce(true);
|
|
||||||
when(mPowerUsageFeatureProvider.isChartGraphSlotsEnabled(mContext))
|
|
||||||
.thenReturn(true);
|
|
||||||
doReturn(true).when(mMockAccessibilityManager).isEnabled();
|
|
||||||
mBatteryChartView.onAttachedToWindow();
|
|
||||||
// Ensures the testing environment is correct.
|
|
||||||
assertThat(mBatteryChartView.isClickable()).isFalse();
|
|
||||||
// Turns off accessibility service.
|
|
||||||
doReturn(false).when(mMockAccessibilityManager).isEnabled();
|
|
||||||
|
|
||||||
mBatteryChartView.onAttachedToWindow();
|
|
||||||
|
|
||||||
assertThat(mBatteryChartView.isClickable()).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onAttachedToWindow_addAccessibilityStateChangeListener() {
|
|
||||||
mBatteryChartView.onAttachedToWindow();
|
|
||||||
verify(mMockAccessibilityManager)
|
|
||||||
.addAccessibilityStateChangeListener(mBatteryChartView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onDetachedFromWindow_removeAccessibilityStateChangeListener() {
|
|
||||||
mBatteryChartView.onAttachedToWindow();
|
|
||||||
mBatteryChartView.mHandler.postDelayed(
|
|
||||||
mBatteryChartView.mUpdateClickableStateRun, 1000);
|
|
||||||
|
|
||||||
mBatteryChartView.onDetachedFromWindow();
|
|
||||||
|
|
||||||
verify(mMockAccessibilityManager)
|
|
||||||
.removeAccessibilityStateChangeListener(mBatteryChartView);
|
|
||||||
assertThat(mBatteryChartView.mHandler.hasCallbacks(
|
|
||||||
mBatteryChartView.mUpdateClickableStateRun))
|
|
||||||
.isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onAccessibilityStateChanged_postUpdateStateRunnable() {
|
|
||||||
mBatteryChartView.mHandler = spy(mBatteryChartView.mHandler);
|
|
||||||
mBatteryChartView.onAccessibilityStateChanged(/*enabled=*/ true);
|
|
||||||
|
|
||||||
verify(mBatteryChartView.mHandler)
|
|
||||||
.removeCallbacks(mBatteryChartView.mUpdateClickableStateRun);
|
|
||||||
verify(mBatteryChartView.mHandler)
|
|
||||||
.postDelayed(mBatteryChartView.mUpdateClickableStateRun, 500L);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user