1 /*
2  * Copyright (C) 2024 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.settings.applications.credentials;
18 
19 import android.content.Context;
20 import android.credentials.flags.Flags;
21 import android.util.AttributeSet;
22 import android.view.View;
23 import android.widget.Button;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.Nullable;
27 import androidx.preference.Preference;
28 import androidx.preference.PreferenceViewHolder;
29 
30 import com.android.internal.annotations.VisibleForTesting;
31 import com.android.settings.R;
32 import com.android.settings.widget.GearPreference;
33 
34 /**
35  * This preference is shown at the top of the "passwords & accounts" screen and allows the user to
36  * pick their primary credential manager provider.
37  */
38 public class PrimaryProviderPreference extends GearPreference {
39 
shouldUseNewSettingsUi()40     public static boolean shouldUseNewSettingsUi() {
41         return Flags.newSettingsUi();
42     }
43 
44     private @Nullable Button mChangeButton = null;
45     private @Nullable Button mOpenButton = null;
46     private @Nullable View mButtonFrameView = null;
47     private @Nullable View mGearView = null;
48     private @Nullable Delegate mDelegate = null;
49     private boolean mButtonsCompactMode = false;
50     private boolean mOpenButtonVisible = false;
51 
52     /** Called to send messages back to the parent controller. */
53     public static interface Delegate {
onOpenButtonClicked()54         void onOpenButtonClicked();
55 
onChangeButtonClicked()56         void onChangeButtonClicked();
57     }
58 
PrimaryProviderPreference( @onNull Context context, @NonNull AttributeSet attrs, int defStyleAttr, int defStyleRes)59     public PrimaryProviderPreference(
60             @NonNull Context context,
61             @NonNull AttributeSet attrs,
62             int defStyleAttr,
63             int defStyleRes) {
64         super(context, attrs, defStyleAttr, defStyleRes);
65         initializeNewSettingsUi();
66     }
67 
PrimaryProviderPreference( @onNull Context context, @NonNull AttributeSet attrs)68     public PrimaryProviderPreference(
69            @NonNull Context context,
70            @NonNull AttributeSet attrs) {
71         super(context, attrs);
72         initializeNewSettingsUi();
73     }
74 
initializeNewSettingsUi()75     private void initializeNewSettingsUi() {
76         if (!shouldUseNewSettingsUi()) {
77             return;
78         }
79 
80         // Change the layout to the new settings ui.
81         setLayoutResource(R.layout.preference_credential_manager_with_buttons);
82     }
83 
84     @Override
onBindViewHolder(@onNull PreferenceViewHolder holder)85     public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
86         super.onBindViewHolder(holder);
87 
88         if (shouldUseNewSettingsUi()) {
89             onBindViewHolderNewSettingsUi(holder);
90         } else {
91             onBindViewHolderOldSettingsUi(holder);
92         }
93     }
94 
onBindViewHolderOldSettingsUi(PreferenceViewHolder holder)95     private void onBindViewHolderOldSettingsUi(PreferenceViewHolder holder) {
96         setOnPreferenceClickListener(
97                 new Preference.OnPreferenceClickListener() {
98                     public boolean onPreferenceClick(@NonNull Preference preference) {
99                         if (mDelegate != null) {
100                             mDelegate.onOpenButtonClicked();
101                             return true;
102                         }
103 
104                         return false;
105                     }
106                 });
107 
108         // Setup the gear icon to handle opening the change provider scenario.
109         mGearView = holder.findViewById(R.id.settings_button);
110         mGearView.setVisibility(View.VISIBLE);
111         mGearView.setOnClickListener(
112                 new View.OnClickListener() {
113                     public void onClick(@NonNull View v) {
114                         if (mDelegate != null) {
115                             mDelegate.onChangeButtonClicked();
116                         }
117                     }
118                 });
119     }
120 
onBindViewHolderNewSettingsUi(PreferenceViewHolder holder)121     private void onBindViewHolderNewSettingsUi(PreferenceViewHolder holder) {
122         mOpenButton = (Button) holder.findViewById(R.id.open_button);
123         mOpenButton.setOnClickListener(
124                 new View.OnClickListener() {
125                     public void onClick(@NonNull View v) {
126                         if (mDelegate != null) {
127                             mDelegate.onOpenButtonClicked();
128                         }
129                     }
130                 });
131         setVisibility(mOpenButton, mOpenButtonVisible);
132         holder.itemView.setClickable(false);
133 
134         mChangeButton = (Button) holder.findViewById(R.id.change_button);
135         mChangeButton.setOnClickListener(
136                 new View.OnClickListener() {
137                     public void onClick(@NonNull View v) {
138                         if (mDelegate != null) {
139                             mDelegate.onChangeButtonClicked();
140                         }
141                     }
142                 });
143 
144         mButtonFrameView = holder.findViewById(R.id.credman_button_frame);
145         updateButtonFramePadding();
146     }
147 
setOpenButtonVisible(boolean isVisible)148     public void setOpenButtonVisible(boolean isVisible) {
149         if (mOpenButton != null) {
150             mOpenButton.setVisibility(isVisible ? View.VISIBLE : View.GONE);
151             setVisibility(mOpenButton, isVisible);
152         }
153 
154         mOpenButtonVisible = isVisible;
155     }
156 
updateButtonFramePadding()157     private void updateButtonFramePadding() {
158         if (mButtonFrameView == null) {
159           return;
160         }
161 
162         int paddingLeft = mButtonsCompactMode ?
163             getContext().getResources().getDimensionPixelSize(
164                 R.dimen.credman_primary_provider_pref_left_padding) :
165             getContext().getResources().getDimensionPixelSize(
166                 R.dimen.credman_primary_provider_pref_left_padding_compact);
167 
168         mButtonFrameView.setPadding(
169             paddingLeft,
170             mButtonFrameView.getPaddingTop(),
171             paddingLeft,
172             mButtonFrameView.getPaddingBottom());
173     }
174 
setButtonsCompactMode(boolean isCompactMode)175     public void setButtonsCompactMode(boolean isCompactMode) {
176         mButtonsCompactMode = isCompactMode;
177         updateButtonFramePadding();
178     }
179 
setDelegate(@onNull Delegate delegate)180     public void setDelegate(@NonNull Delegate delegate) {
181         mDelegate = delegate;
182     }
183 
184     @Override
shouldHideSecondTarget()185     protected boolean shouldHideSecondTarget() {
186         return shouldUseNewSettingsUi();
187     }
188 
189     @VisibleForTesting
getOpenButton()190     public @Nullable Button getOpenButton() {
191         return mOpenButton;
192     }
193 
194     @VisibleForTesting
getChangeButton()195     public @Nullable Button getChangeButton() {
196         return mChangeButton;
197     }
198 
199     @VisibleForTesting
getButtonFrameView()200     public @Nullable View getButtonFrameView() {
201         return mButtonFrameView;
202     }
203 
204     @VisibleForTesting
getGearView()205     public @Nullable View getGearView() {
206         return mGearView;
207     }
208 
setVisibility(View view, boolean isVisible)209     private static void setVisibility(View view, boolean isVisible) {
210         view.setVisibility(isVisible ? View.VISIBLE : View.GONE);
211     }
212 }
213