1 /*
2  * Copyright (C) 2020 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 
26 import androidx.annotation.CallSuper;
27 import androidx.annotation.LayoutRes;
28 import androidx.annotation.NonNull;
29 import androidx.annotation.Nullable;
30 import androidx.annotation.StyleableRes;
31 import androidx.preference.Preference;
32 
33 import com.android.car.ui.R;
34 
35 import java.util.function.Consumer;
36 
37 /**
38  * A base class for several types of preferences, that all have a main click action along
39  * with a secondary action.
40  */
41 @SuppressWarnings("AndroidJdkLibsChecker")
42 @TargetApi(MIN_TARGET_API)
43 public abstract class CarUiTwoActionBasePreference extends CarUiPreference {
44 
45     protected boolean mSecondaryActionEnabled = true;
46     protected boolean mSecondaryActionVisible = true;
47 
CarUiTwoActionBasePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)48     public CarUiTwoActionBasePreference(Context context,
49             AttributeSet attrs,
50             int defStyleAttr, int defStyleRes) {
51         super(context, attrs, defStyleAttr, defStyleRes);
52         init(attrs);
53     }
54 
CarUiTwoActionBasePreference(Context context, AttributeSet attrs, int defStyleAttr)55     public CarUiTwoActionBasePreference(Context context, AttributeSet attrs, int defStyleAttr) {
56         super(context, attrs, defStyleAttr);
57         init(attrs);
58     }
59 
CarUiTwoActionBasePreference(Context context, AttributeSet attrs)60     public CarUiTwoActionBasePreference(Context context, AttributeSet attrs) {
61         super(context, attrs);
62         init(attrs);
63     }
64 
CarUiTwoActionBasePreference(Context context)65     public CarUiTwoActionBasePreference(Context context) {
66         super(context);
67         init(null);
68     }
69 
70     @CallSuper
init(@ullable AttributeSet attrs)71     protected void init(@Nullable AttributeSet attrs) {
72         setShowChevron(false);
73 
74         TypedArray a = getContext()
75                 .obtainStyledAttributes(attrs, R.styleable.CarUiTwoActionBasePreference);
76         try {
77             disallowResourceIds(a,
78                     R.styleable.CarUiTwoActionBasePreference_carUiLayout,
79                     R.styleable.CarUiTwoActionBasePreference_android_layout,
80                     R.styleable.CarUiTwoActionBasePreference_widgetLayout,
81                     R.styleable.CarUiTwoActionBasePreference_android_widgetLayout);
82         } finally {
83             a.recycle();
84         }
85 
86         a = getContext().obtainStyledAttributes(attrs,
87                 R.styleable.CarUiTwoActionPreference);
88 
89         try {
90             mSecondaryActionVisible = a.getBoolean(
91                     R.styleable.CarUiTwoActionPreference_actionShown, true);
92             mSecondaryActionEnabled = a.getBoolean(
93                     R.styleable.CarUiTwoActionPreference_actionEnabled, true);
94         } finally {
95             a.recycle();
96         }
97     }
98 
99     /**
100      * Returns whether or not the secondary action is enabled.
101      */
isSecondaryActionEnabled()102     public boolean isSecondaryActionEnabled() {
103         return mSecondaryActionEnabled && isEnabled();
104     }
105 
106     /**
107      * Sets whether or not the secondary action is enabled. This is secondary to the overall
108      * {@link #setEnabled(boolean)} of the preference
109      */
setSecondaryActionEnabled(boolean enabled)110     public void setSecondaryActionEnabled(boolean enabled) {
111         mSecondaryActionEnabled = enabled;
112         notifyChanged();
113     }
114 
115     /**
116      * Returns whether or not the secondary action is visible.
117      */
isSecondaryActionVisible()118     public boolean isSecondaryActionVisible() {
119         return mSecondaryActionVisible;
120     }
121 
122     /**
123      * Sets whether or not the secondary action is visible.
124      */
setSecondaryActionVisible(boolean visible)125     public void setSecondaryActionVisible(boolean visible) {
126         mSecondaryActionVisible = visible;
127         notifyChanged();
128     }
129 
130     /**
131      * Like {@link #onClick()}, but for the secondary action.
132      */
performSecondaryActionClick()133     public void performSecondaryActionClick() {
134         if (isSecondaryActionEnabled()) {
135             if (isUxRestricted()) {
136                 Consumer<Preference> restrictedListener = getOnClickWhileRestrictedListener();
137                 if (restrictedListener != null) {
138                     restrictedListener.accept(this);
139                 }
140             } else {
141                 performSecondaryActionClickInternal();
142             }
143         } else if (isClickableWhileDisabled()) {
144             if (getDisabledClickListener() != null) {
145                 getDisabledClickListener().accept(this);
146             }
147         }
148     }
149 
performSecondaryActionClickInternal()150     protected abstract void performSecondaryActionClickInternal();
151 
setLayoutResourceInternal(@ayoutRes int layoutResId)152     protected void setLayoutResourceInternal(@LayoutRes int layoutResId) {
153         super.setLayoutResource(layoutResId);
154     }
155 
156     @Override
setLayoutResource(@ayoutRes int layoutResId)157     public void setLayoutResource(@LayoutRes int layoutResId) {
158         throw new UnsupportedOperationException();
159     }
160 
161     @Override
setWidgetLayoutResource(@ayoutRes int widgetLayoutResId)162     public void setWidgetLayoutResource(@LayoutRes int widgetLayoutResId) {
163         throw new UnsupportedOperationException();
164     }
165 
disallowResourceIds(@onNull TypedArray a, @StyleableRes int ...indices)166     private static void disallowResourceIds(@NonNull TypedArray a, @StyleableRes int ...indices) {
167         for (int index : indices) {
168             if (a.hasValue(index)) {
169                 throw new AssertionError("Setting this attribute is not allowed: "
170                         + a.getResources().getResourceName(index));
171             }
172         }
173     }
174 }
175