1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settingslib; 18 19 import android.content.Context; 20 import android.util.AttributeSet; 21 import android.view.MotionEvent; 22 import android.widget.Switch; 23 24 import androidx.annotation.Keep; 25 import androidx.annotation.Nullable; 26 import androidx.preference.PreferenceViewHolder; 27 28 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 29 import com.android.settingslib.core.instrumentation.SettingsJankMonitor; 30 31 /** 32 * A custom preference that provides inline switch toggle. It has a mandatory field for title, and 33 * optional fields for icon and sub-text. And it can be restricted by admin state. 34 */ 35 public class PrimarySwitchPreference extends RestrictedPreference { 36 37 private Switch mSwitch; 38 private boolean mChecked; 39 private boolean mCheckedSet; 40 private boolean mEnableSwitch = true; 41 PrimarySwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)42 public PrimarySwitchPreference(Context context, AttributeSet attrs, 43 int defStyleAttr, int defStyleRes) { 44 super(context, attrs, defStyleAttr, defStyleRes); 45 } 46 PrimarySwitchPreference(Context context, AttributeSet attrs, int defStyleAttr)47 public PrimarySwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) { 48 super(context, attrs, defStyleAttr); 49 } 50 PrimarySwitchPreference(Context context, AttributeSet attrs)51 public PrimarySwitchPreference(Context context, AttributeSet attrs) { 52 super(context, attrs); 53 } 54 PrimarySwitchPreference(Context context)55 public PrimarySwitchPreference(Context context) { 56 super(context); 57 } 58 59 @Override getSecondTargetResId()60 protected int getSecondTargetResId() { 61 return R.layout.preference_widget_primary_switch; 62 } 63 64 @Override onBindViewHolder(PreferenceViewHolder holder)65 public void onBindViewHolder(PreferenceViewHolder holder) { 66 super.onBindViewHolder(holder); 67 mSwitch = (Switch) holder.findViewById(R.id.switchWidget); 68 if (mSwitch != null) { 69 mSwitch.setOnClickListener(v -> { 70 if (mSwitch != null && !mSwitch.isEnabled()) { 71 return; 72 } 73 final boolean newChecked = !mChecked; 74 if (callChangeListener(newChecked)) { 75 SettingsJankMonitor.detectToggleJank(getKey(), mSwitch); 76 setChecked(newChecked); 77 persistBoolean(newChecked); 78 } 79 }); 80 81 // Consumes move events to ignore drag actions. 82 mSwitch.setOnTouchListener((v, event) -> { 83 return event.getActionMasked() == MotionEvent.ACTION_MOVE; 84 }); 85 86 mSwitch.setContentDescription(getTitle()); 87 mSwitch.setChecked(mChecked); 88 mSwitch.setEnabled(mEnableSwitch); 89 } 90 } 91 isChecked()92 public boolean isChecked() { 93 return mSwitch != null && mChecked; 94 } 95 96 /** 97 * Used to validate the state of mChecked and mCheckedSet when testing, without requiring 98 * that a ViewHolder be bound to the object. 99 */ 100 @Keep 101 @Nullable getCheckedState()102 public Boolean getCheckedState() { 103 return mCheckedSet ? mChecked : null; 104 } 105 106 /** 107 * Set the checked status to be {@code checked}. 108 * 109 * @param checked The new checked status 110 */ setChecked(boolean checked)111 public void setChecked(boolean checked) { 112 // Always set checked the first time; don't assume the field's default of false. 113 final boolean changed = mChecked != checked; 114 if (changed || !mCheckedSet) { 115 mChecked = checked; 116 mCheckedSet = true; 117 if (mSwitch != null) { 118 mSwitch.setChecked(checked); 119 } 120 } 121 } 122 123 /** 124 * Set the Switch to be the status of {@code enabled}. 125 * 126 * @param enabled The new enabled status 127 */ setSwitchEnabled(boolean enabled)128 public void setSwitchEnabled(boolean enabled) { 129 mEnableSwitch = enabled; 130 if (mSwitch != null) { 131 mSwitch.setEnabled(enabled); 132 } 133 } 134 135 /** 136 * If admin is not null, disables the switch. 137 * Otherwise, keep it enabled. 138 */ setDisabledByAdmin(EnforcedAdmin admin)139 public void setDisabledByAdmin(EnforcedAdmin admin) { 140 super.setDisabledByAdmin(admin); 141 setSwitchEnabled(admin == null); 142 } 143 getSwitch()144 public Switch getSwitch() { 145 return mSwitch; 146 } 147 148 @Override shouldHideSecondTarget()149 protected boolean shouldHideSecondTarget() { 150 return getSecondTargetResId() == 0; 151 } 152 } 153