1 /*
2  * Copyright 2019 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.car.ui.preference;
18 
19 import static com.android.car.ui.core.CarUi.MIN_TARGET_API;
20 
21 import android.annotation.TargetApi;
22 import android.content.Context;
23 import android.content.res.TypedArray;
24 import android.util.AttributeSet;
25 import android.view.View;
26 
27 import androidx.annotation.Nullable;
28 import androidx.preference.Preference;
29 import androidx.preference.PreferenceViewHolder;
30 
31 import com.android.car.ui.R;
32 import com.android.car.ui.utils.CarUiUtils;
33 
34 import java.util.function.Consumer;
35 
36 /**
37  * This class extends the base {@link Preference} class. Adds the support to add a drawable icon to
38  * the preference if there is one of fragment, intent or onPreferenceClickListener set.
39  */
40 @SuppressWarnings("AndroidJdkLibsChecker")
41 @TargetApi(MIN_TARGET_API)
42 public class CarUiPreference extends Preference implements DisabledPreferenceCallback,
43         ClickableWhileDisabledPreference {
44     private boolean mShowChevron;
45 
46     private Consumer<Preference> mRestrictedClickListener;
47     private Consumer<Preference> mDisabledClickListener;
48     private boolean mUxRestricted = false;
49     private boolean mIsClickableWhileDisabled = false;
50 
CarUiPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)51     public CarUiPreference(Context context, AttributeSet attrs,
52             int defStyleAttr, int defStyleRes) {
53         super(context, attrs, defStyleAttr, defStyleRes);
54         init(attrs, defStyleAttr, defStyleRes);
55     }
56 
CarUiPreference(Context context, AttributeSet attrs, int defStyleAttr)57     public CarUiPreference(Context context, AttributeSet attrs, int defStyleAttr) {
58         this(context, attrs, defStyleAttr, R.style.Preference_CarUi_Preference);
59     }
60 
CarUiPreference(Context context, AttributeSet attrs)61     public CarUiPreference(Context context, AttributeSet attrs) {
62         this(context, attrs, R.attr.carUiPreferenceStyle);
63     }
64 
CarUiPreference(Context context)65     public CarUiPreference(Context context) {
66         this(context, null);
67     }
68 
init(AttributeSet attrs, int defStyleAttr, int defStyleRes)69     private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
70         TypedArray a = getContext().obtainStyledAttributes(
71                 attrs,
72                 R.styleable.CarUiPreference,
73                 defStyleAttr,
74                 defStyleRes);
75 
76         mShowChevron = a.getBoolean(R.styleable.CarUiPreference_carUiShowChevron, true);
77         mUxRestricted = a.getBoolean(R.styleable.CarUiPreference_car_ui_ux_restricted, false);
78         mIsClickableWhileDisabled = a.getBoolean(
79                 R.styleable.CarUiPreference_carUiClickableWhileDisabled, false);
80         if (mIsClickableWhileDisabled) {
81             super.setShouldDisableView(false);
82         }
83 
84         a.recycle();
85     }
86 
87     @Override
onBindViewHolder(PreferenceViewHolder holder)88     public void onBindViewHolder(PreferenceViewHolder holder) {
89         super.onBindViewHolder(holder);
90 
91         CarUiUtils.makeAllViewsEnabledAndUxRestricted(holder.itemView, isEnabled(),
92                 isUxRestricted());
93     }
94 
95     @Override
onAttached()96     public void onAttached() {
97         super.onAttached();
98 
99         boolean allowChevron = getContext().getResources().getBoolean(
100                 R.bool.car_ui_preference_show_chevron);
101 
102         if (!allowChevron || !mShowChevron) {
103             return;
104         }
105 
106         if (getOnPreferenceClickListener() != null || getIntent() != null
107                 || getFragment() != null) {
108             setWidgetLayoutResource(R.layout.car_ui_preference_chevron);
109         }
110     }
111 
112     /**
113      * An exact copy of {@link androidx.preference.Preference#performClick(View)}
114      * This method was added here because super.performClick(View) is not open
115      * for app usage.
116      */
117     @SuppressWarnings("RestrictTo")
performClickUnrestricted(View v)118     void performClickUnrestricted(View v) {
119         performClick();
120     }
121 
122     @Override
123     @SuppressWarnings("RestrictTo")
performClick()124     public void performClick() {
125         if (!isEnabled() && mIsClickableWhileDisabled) {
126             if (mDisabledClickListener != null) {
127                 mDisabledClickListener.accept(this);
128             }
129         } else if ((isEnabled() || isSelectable()) && isUxRestricted()) {
130             if (mRestrictedClickListener != null) {
131                 mRestrictedClickListener.accept(this);
132             }
133         } else {
134             super.performClick();
135         }
136     }
137 
138     @Override
setShouldDisableView(boolean shouldDisableView)139     public void setShouldDisableView(boolean shouldDisableView) {
140         throw new UnsupportedOperationException("android:shouldDisableView is"
141                 + "unsupported on CarUiPreferences");
142     }
143 
setShowChevron(boolean showChevron)144     public void setShowChevron(boolean showChevron) {
145         mShowChevron = showChevron;
146     }
147 
148     @Override
isUxRestricted()149     public boolean isUxRestricted() {
150         return mUxRestricted;
151     }
152 
153     @Override
setOnClickWhileRestrictedListener(@ullable Consumer<Preference> listener)154     public void setOnClickWhileRestrictedListener(@Nullable Consumer<Preference> listener) {
155         mRestrictedClickListener = listener;
156     }
157 
158     @Nullable
159     @Override
getOnClickWhileRestrictedListener()160     public Consumer<Preference> getOnClickWhileRestrictedListener() {
161         return mRestrictedClickListener;
162     }
163 
164     @Override
setUxRestricted(boolean restricted)165     public void setUxRestricted(boolean restricted) {
166         mUxRestricted = restricted;
167         notifyChanged();
168     }
169 
170     @Override
setClickableWhileDisabled(boolean clickableWhileDisabled)171     public void setClickableWhileDisabled(boolean clickableWhileDisabled) {
172         if (mIsClickableWhileDisabled != clickableWhileDisabled) {
173             super.setShouldDisableView(!clickableWhileDisabled);
174             mIsClickableWhileDisabled = clickableWhileDisabled;
175             notifyChanged();
176         }
177     }
178 
179     @Override
isClickableWhileDisabled()180     public boolean isClickableWhileDisabled() {
181         return mIsClickableWhileDisabled;
182     }
183 
184     @Override
setDisabledClickListener(Consumer<Preference> listener)185     public void setDisabledClickListener(Consumer<Preference> listener) {
186         mDisabledClickListener = listener;
187     }
188 
189     @Override
getDisabledClickListener()190     public Consumer<Preference> getDisabledClickListener() {
191         return mDisabledClickListener;
192     }
193 }
194